cobble_core/instance/
resourcepacks.rs

1use crate::error::CobbleResult;
2use crate::minecraft::{load_resourcepacks, parse_resourcepack, Resourcepack, ResourcepackType};
3use crate::Instance;
4use std::path::{Path, PathBuf};
5use tokio::fs::create_dir_all;
6
7impl Instance {
8    /// Path to the .minecraft/resourcepacks or .minecraft/texturepacks folder.
9    #[cfg_attr(doc_cfg, doc(cfg(feature = "resourcepacks")))]
10    pub fn resourcepacks_path(&self) -> PathBuf {
11        let mut resourcepacks_path = self.dot_minecraft_path();
12
13        match self.resourcepacks_type() {
14            ResourcepackType::Resourcepack => resourcepacks_path.push("resourcepacks"),
15            ResourcepackType::Texturepack => resourcepacks_path.push("texturepacks"),
16        }
17
18        resourcepacks_path
19    }
20
21    /// Gets whether the instance uses resource- or texturepacks.
22    #[cfg_attr(doc_cfg, doc(cfg(feature = "resourcepacks")))]
23    pub fn resourcepacks_type(&self) -> ResourcepackType {
24        if Resourcepack::TEXTUREPACK_VERSIONS.contains(&self.version.as_str()) {
25            ResourcepackType::Texturepack
26        } else {
27            ResourcepackType::Resourcepack
28        }
29    }
30
31    /// Loads all resourcepacks from this instance.
32    #[cfg_attr(doc_cfg, doc(cfg(feature = "resourcepacks")))]
33    pub async fn load_resourcepacks(&self) -> CobbleResult<Vec<Resourcepack>> {
34        load_resourcepacks(self.dot_minecraft_path()).await
35    }
36
37    /// Adds a resourcepack.
38    /// Tries to put it in the apropriate folder for the current version.
39    /// If it fails to determine the correct folder, it assumes the instance uses resourcepacks.
40    ///
41    /// Returns `None` when `src` is not a valid resourcepack.
42    #[instrument(name = "add_resourcepack", level = "trace", skip_all, fields(src))]
43    #[cfg_attr(doc_cfg, doc(cfg(feature = "resourcepacks")))]
44    pub async fn add_resourcepack(
45        &self,
46        src: impl AsRef<Path>,
47    ) -> CobbleResult<Option<Resourcepack>> {
48        let _type = self.resourcepacks_type();
49
50        trace!("Validating src...");
51        if parse_resourcepack(PathBuf::from(src.as_ref()), _type)
52            .await?
53            .is_none()
54        {
55            return Ok(None);
56        }
57
58        trace!("Building new path for resourcepack");
59        let file_name = src
60            .as_ref()
61            .file_name()
62            .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "Path ends with '..'"))?;
63        let mut resourcepack_path = self.resourcepacks_path();
64        resourcepack_path.push(file_name);
65        tracing::Span::current().record("dest", resourcepack_path.to_string_lossy().to_string());
66
67        if let Some(parent) = resourcepack_path.parent() {
68            trace!("Creating resourcepacks folder...");
69            create_dir_all(parent).await?;
70        }
71
72        trace!("Copying resourcepack...");
73        tokio::fs::copy(src, &resourcepack_path).await?;
74
75        trace!("Parsing new resourcepack...");
76        let resourcepack = parse_resourcepack(resourcepack_path, _type).await?;
77        Ok(resourcepack)
78    }
79}