From 7392887c127b1aae0d78d573a02332c2fa2591c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20H=C3=B6lting?= <87192362+moritz-hoelting@users.noreply.github.com> Date: Mon, 7 Apr 2025 13:17:26 +0200 Subject: [PATCH] implement custom uninstall commands --- CHANGELOG.md | 1 + Cargo.toml | 18 ++++++++++------- examples/improved_if_else.rs | 31 +++++++++++++++++++++++++++++ src/datapack/command/execute/mod.rs | 4 ++-- src/datapack/command/mod.rs | 4 ++-- src/datapack/mod.rs | 17 +++++++++++++--- src/lib.rs | 1 + src/virtual_fs.rs | 11 +++++++--- 8 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 examples/improved_if_else.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c9094..df47023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - use "return" command for conditionals instead of data storage when using supported pack format +- update latest datapack format to 61 ### Removed diff --git a/Cargo.toml b/Cargo.toml index e2be020..ad98ab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,16 @@ serde = ["dep:serde"] zip = ["dep:zip"] [dependencies] -chksum-md5 = "0.0.0" -getset = "0.1.2" -serde = { version = "1.0.197", optional = true, features = ["derive"] } -serde_json = "1.0.114" -tracing = "0.1.40" -zip = { version = "2.1.3", default-features = false, features = ["deflate", "time"], optional = true } +chksum-md5 = "0.1.0" +getset = "0.1.5" +serde = { version = "1.0.219", optional = true, features = ["derive"] } +serde_json = "1.0.140" +tracing = "0.1.41" +zip = { version = "2.6.1", default-features = false, features = ["deflate", "time"], optional = true } [dev-dependencies] -tempfile = "3.13.0" +tempfile = "3.19.1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/examples/improved_if_else.rs b/examples/improved_if_else.rs new file mode 100644 index 0000000..0e04aa9 --- /dev/null +++ b/examples/improved_if_else.rs @@ -0,0 +1,31 @@ +use std::path::Path; + +// import the prelude to get all the necessary structs +use shulkerbox::prelude::*; + +fn main() { + let mut dp = Datapack::new("main", 20).with_supported_formats(16..=20); + + // get the namespace "test" + let namespace = dp.namespace_mut("test"); + + // get the function "foo" of the namespace "test" and add some commands + let foo_function = namespace.function_mut("foo"); + + let ex = Execute::If( + Condition::from("entity A"), + Box::new(Execute::Run(Box::new("say A".into()))), + Some(Box::new(Execute::If( + Condition::from("entity B"), + Box::new(Execute::Run(Box::new("say B".into()))), + Some(Box::new(Execute::Run(Box::new("say C".into())))), + ))), + ); + foo_function.add_command(ex); + + // compile the datapack + let v_folder = dp.compile(&CompileOptions::default()); + + // place the compiled datapack in the "./dist" folder + v_folder.place(Path::new("./dist")).unwrap(); +} diff --git a/src/datapack/command/execute/mod.rs b/src/datapack/command/execute/mod.rs index 4ac218b..b56f4ca 100644 --- a/src/datapack/command/execute/mod.rs +++ b/src/datapack/command/execute/mod.rs @@ -234,7 +234,7 @@ impl Execute { Self::If(_, next, el) => { pack_formats.start() >= &4 && next.validate(pack_formats) - && el.as_deref().map_or(true, |el| el.validate(pack_formats)) + && el.as_deref().is_none_or(|el| el.validate(pack_formats)) } Self::Summon(_, next) | Self::On(_, next) => { pack_formats.start() >= &12 && next.validate(pack_formats) @@ -261,7 +261,7 @@ impl Execute { Self::If(cond, then, el) => { cond.contains_macro() || then.contains_macro() - || el.as_deref().map_or(false, Self::contains_macro) + || el.as_deref().is_some_and(Self::contains_macro) } Self::Run(cmd) => cmd.contains_macro(), Self::Runs(cmds) => cmds.iter().any(super::Command::contains_macro), diff --git a/src/datapack/command/mod.rs b/src/datapack/command/mod.rs index eb8f291..30387ee 100644 --- a/src/datapack/command/mod.rs +++ b/src/datapack/command/mod.rs @@ -363,8 +363,8 @@ fn validate_raw_cmd(cmd: &str, pack_formats: &RangeInclusive) -> bool { map }); - cmd.split_ascii_whitespace().next().map_or(true, |cmd| { - cmd_formats.get(cmd).map_or(true, |range| { + cmd.split_ascii_whitespace().next().is_none_or(|cmd| { + cmd_formats.get(cmd).is_none_or(|range| { let start_cmd = range.start(); let end_cmd = range.end(); diff --git a/src/datapack/mod.rs b/src/datapack/mod.rs index a53da14..d1fe153 100644 --- a/src/datapack/mod.rs +++ b/src/datapack/mod.rs @@ -27,11 +27,12 @@ pub struct Datapack { namespaces: BTreeMap, /// Scoreboard name -> (criteria, display name) scoreboards: BTreeMap, Option)>, + uninstall_commands: Vec, custom_files: VFolder, } impl Datapack { - pub const LATEST_FORMAT: u8 = 48; + pub const LATEST_FORMAT: u8 = 61; /// Create a new Minecraft datapack. #[must_use] @@ -43,6 +44,7 @@ impl Datapack { main_namespace_name: main_namespace_name.into(), namespaces: BTreeMap::new(), scoreboards: BTreeMap::new(), + uninstall_commands: Vec::new(), custom_files: VFolder::new(), } } @@ -70,6 +72,7 @@ impl Datapack { /// # Errors /// - If loading the directory fails #[cfg(feature = "fs_access")] + #[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))] pub fn with_template_folder

(self, path: P) -> std::io::Result where P: AsRef, @@ -135,6 +138,11 @@ impl Datapack { &self.scoreboards } + /// Add commands to the uninstall function. + pub fn add_uninstall_commands(&mut self, commands: Vec) { + self.uninstall_commands.extend(commands); + } + /// Add a custom file to the datapack. pub fn add_custom_file(&mut self, path: &str, file: VFile) { self.custom_files.add_file(path, file); @@ -163,7 +171,9 @@ impl Datapack { .map(|(name, namespace)| (name.as_str(), Cow::Borrowed(namespace))) .collect::>(); - let mut uninstall_commands = options.uninstall_function.then(Vec::new); + let mut uninstall_commands = options + .uninstall_function + .then_some(Cow::Borrowed(&self.uninstall_commands)); if !self.scoreboards.is_empty() { let main_namespace = modified_namespaces @@ -185,6 +195,7 @@ impl Datapack { if let Some(uninstall_commands) = uninstall_commands.as_mut() { uninstall_commands + .to_mut() .push(Command::Raw(format!("scoreboard objectives remove {name}"))); } } @@ -213,7 +224,7 @@ impl Datapack { let uninstall_function = main_namespace.to_mut().function_mut("uninstall"); uninstall_function .get_commands_mut() - .extend(uninstall_commands); + .extend(uninstall_commands.into_owned()); } } diff --git a/src/lib.rs b/src/lib.rs index 0330fec..c54ee34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ )] #![warn(clippy::all, clippy::pedantic, clippy::perf)] #![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)] +#![cfg_attr(docsrs, feature(doc_cfg))] pub mod datapack; pub mod util; diff --git a/src/virtual_fs.rs b/src/virtual_fs.rs index 5710d1e..50bdf68 100644 --- a/src/virtual_fs.rs +++ b/src/virtual_fs.rs @@ -131,6 +131,7 @@ impl VFolder { /// # Errors /// - If the folder cannot be written #[cfg(feature = "fs_access")] + #[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))] pub fn place

(&self, path: P) -> std::io::Result<()> where P: AsRef, @@ -162,6 +163,7 @@ impl VFolder { /// # Errors /// - If the zip archive cannot be written #[cfg(all(feature = "fs_access", feature = "zip"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "fs_access", feature = "zip"))))] pub fn zip

(&self, path: P) -> std::io::Result<()> where P: AsRef, @@ -198,6 +200,7 @@ impl VFolder { /// # Errors /// - If the zip archive cannot be written #[cfg(all(feature = "fs_access", feature = "zip"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "fs_access", feature = "zip"))))] pub fn zip_with_comment(&self, path: P, comment: S) -> std::io::Result<()> where P: AsRef, @@ -257,14 +260,14 @@ impl VFolder { /// Recursively merge another folder into this folder. /// Returns a list of paths that were replaced by other. pub fn merge(&mut self, other: Self) -> Vec { - self._merge(other, "") + self.merge_(other, "") } - fn _merge(&mut self, other: Self, prefix: &str) -> Vec { + fn merge_(&mut self, other: Self, prefix: &str) -> Vec { let mut replaced = Vec::new(); for (name, folder) in other.folders { if let Some(existing_folder) = self.folders.get_mut(&name) { - let replaced_folder = existing_folder._merge(folder, &format!("{prefix}{name}/")); + let replaced_folder = existing_folder.merge_(folder, &format!("{prefix}{name}/")); replaced.extend(replaced_folder); } else { self.folders.insert(name, folder); @@ -282,6 +285,7 @@ impl VFolder { } #[cfg(feature = "fs_access")] +#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))] impl TryFrom<&std::path::Path> for VFolder { type Error = std::io::Error; @@ -385,6 +389,7 @@ impl From<&[u8]> for VFile { } #[cfg(feature = "fs_access")] +#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))] impl TryFrom<&std::path::Path> for VFile { type Error = std::io::Error;