implement custom uninstall commands
This commit is contained in:
parent
e9f2b9b91d
commit
7392887c12
|
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- use "return" command for conditionals instead of data storage when using supported pack format
|
- use "return" command for conditionals instead of data storage when using supported pack format
|
||||||
|
- update latest datapack format to 61
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -20,12 +20,16 @@ serde = ["dep:serde"]
|
||||||
zip = ["dep:zip"]
|
zip = ["dep:zip"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chksum-md5 = "0.0.0"
|
chksum-md5 = "0.1.0"
|
||||||
getset = "0.1.2"
|
getset = "0.1.5"
|
||||||
serde = { version = "1.0.197", optional = true, features = ["derive"] }
|
serde = { version = "1.0.219", optional = true, features = ["derive"] }
|
||||||
serde_json = "1.0.114"
|
serde_json = "1.0.140"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.41"
|
||||||
zip = { version = "2.1.3", default-features = false, features = ["deflate", "time"], optional = true }
|
zip = { version = "2.6.1", default-features = false, features = ["deflate", "time"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.13.0"
|
tempfile = "3.19.1"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -234,7 +234,7 @@ impl Execute {
|
||||||
Self::If(_, next, el) => {
|
Self::If(_, next, el) => {
|
||||||
pack_formats.start() >= &4
|
pack_formats.start() >= &4
|
||||||
&& next.validate(pack_formats)
|
&& 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) => {
|
Self::Summon(_, next) | Self::On(_, next) => {
|
||||||
pack_formats.start() >= &12 && next.validate(pack_formats)
|
pack_formats.start() >= &12 && next.validate(pack_formats)
|
||||||
|
@ -261,7 +261,7 @@ impl Execute {
|
||||||
Self::If(cond, then, el) => {
|
Self::If(cond, then, el) => {
|
||||||
cond.contains_macro()
|
cond.contains_macro()
|
||||||
|| then.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::Run(cmd) => cmd.contains_macro(),
|
||||||
Self::Runs(cmds) => cmds.iter().any(super::Command::contains_macro),
|
Self::Runs(cmds) => cmds.iter().any(super::Command::contains_macro),
|
||||||
|
|
|
@ -363,8 +363,8 @@ fn validate_raw_cmd(cmd: &str, pack_formats: &RangeInclusive<u8>) -> bool {
|
||||||
map
|
map
|
||||||
});
|
});
|
||||||
|
|
||||||
cmd.split_ascii_whitespace().next().map_or(true, |cmd| {
|
cmd.split_ascii_whitespace().next().is_none_or(|cmd| {
|
||||||
cmd_formats.get(cmd).map_or(true, |range| {
|
cmd_formats.get(cmd).is_none_or(|range| {
|
||||||
let start_cmd = range.start();
|
let start_cmd = range.start();
|
||||||
let end_cmd = range.end();
|
let end_cmd = range.end();
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,12 @@ pub struct Datapack {
|
||||||
namespaces: BTreeMap<String, Namespace>,
|
namespaces: BTreeMap<String, Namespace>,
|
||||||
/// Scoreboard name -> (criteria, display name)
|
/// Scoreboard name -> (criteria, display name)
|
||||||
scoreboards: BTreeMap<String, (Option<String>, Option<String>)>,
|
scoreboards: BTreeMap<String, (Option<String>, Option<String>)>,
|
||||||
|
uninstall_commands: Vec<Command>,
|
||||||
custom_files: VFolder,
|
custom_files: VFolder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Datapack {
|
impl Datapack {
|
||||||
pub const LATEST_FORMAT: u8 = 48;
|
pub const LATEST_FORMAT: u8 = 61;
|
||||||
|
|
||||||
/// Create a new Minecraft datapack.
|
/// Create a new Minecraft datapack.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -43,6 +44,7 @@ impl Datapack {
|
||||||
main_namespace_name: main_namespace_name.into(),
|
main_namespace_name: main_namespace_name.into(),
|
||||||
namespaces: BTreeMap::new(),
|
namespaces: BTreeMap::new(),
|
||||||
scoreboards: BTreeMap::new(),
|
scoreboards: BTreeMap::new(),
|
||||||
|
uninstall_commands: Vec::new(),
|
||||||
custom_files: VFolder::new(),
|
custom_files: VFolder::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +72,7 @@ impl Datapack {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - If loading the directory fails
|
/// - If loading the directory fails
|
||||||
#[cfg(feature = "fs_access")]
|
#[cfg(feature = "fs_access")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))]
|
||||||
pub fn with_template_folder<P>(self, path: P) -> std::io::Result<Self>
|
pub fn with_template_folder<P>(self, path: P) -> std::io::Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>,
|
P: AsRef<std::path::Path>,
|
||||||
|
@ -135,6 +138,11 @@ impl Datapack {
|
||||||
&self.scoreboards
|
&self.scoreboards
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add commands to the uninstall function.
|
||||||
|
pub fn add_uninstall_commands(&mut self, commands: Vec<Command>) {
|
||||||
|
self.uninstall_commands.extend(commands);
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a custom file to the datapack.
|
/// Add a custom file to the datapack.
|
||||||
pub fn add_custom_file(&mut self, path: &str, file: VFile) {
|
pub fn add_custom_file(&mut self, path: &str, file: VFile) {
|
||||||
self.custom_files.add_file(path, file);
|
self.custom_files.add_file(path, file);
|
||||||
|
@ -163,7 +171,9 @@ impl Datapack {
|
||||||
.map(|(name, namespace)| (name.as_str(), Cow::Borrowed(namespace)))
|
.map(|(name, namespace)| (name.as_str(), Cow::Borrowed(namespace)))
|
||||||
.collect::<BTreeMap<_, _>>();
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
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() {
|
if !self.scoreboards.is_empty() {
|
||||||
let main_namespace = modified_namespaces
|
let main_namespace = modified_namespaces
|
||||||
|
@ -185,6 +195,7 @@ impl Datapack {
|
||||||
|
|
||||||
if let Some(uninstall_commands) = uninstall_commands.as_mut() {
|
if let Some(uninstall_commands) = uninstall_commands.as_mut() {
|
||||||
uninstall_commands
|
uninstall_commands
|
||||||
|
.to_mut()
|
||||||
.push(Command::Raw(format!("scoreboard objectives remove {name}")));
|
.push(Command::Raw(format!("scoreboard objectives remove {name}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +224,7 @@ impl Datapack {
|
||||||
let uninstall_function = main_namespace.to_mut().function_mut("uninstall");
|
let uninstall_function = main_namespace.to_mut().function_mut("uninstall");
|
||||||
uninstall_function
|
uninstall_function
|
||||||
.get_commands_mut()
|
.get_commands_mut()
|
||||||
.extend(uninstall_commands);
|
.extend(uninstall_commands.into_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::all, clippy::pedantic, clippy::perf)]
|
#![warn(clippy::all, clippy::pedantic, clippy::perf)]
|
||||||
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
|
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
|
||||||
pub mod datapack;
|
pub mod datapack;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
|
@ -131,6 +131,7 @@ impl VFolder {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - If the folder cannot be written
|
/// - If the folder cannot be written
|
||||||
#[cfg(feature = "fs_access")]
|
#[cfg(feature = "fs_access")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))]
|
||||||
pub fn place<P>(&self, path: P) -> std::io::Result<()>
|
pub fn place<P>(&self, path: P) -> std::io::Result<()>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>,
|
P: AsRef<std::path::Path>,
|
||||||
|
@ -162,6 +163,7 @@ impl VFolder {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - If the zip archive cannot be written
|
/// - If the zip archive cannot be written
|
||||||
#[cfg(all(feature = "fs_access", feature = "zip"))]
|
#[cfg(all(feature = "fs_access", feature = "zip"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "fs_access", feature = "zip"))))]
|
||||||
pub fn zip<P>(&self, path: P) -> std::io::Result<()>
|
pub fn zip<P>(&self, path: P) -> std::io::Result<()>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>,
|
P: AsRef<std::path::Path>,
|
||||||
|
@ -198,6 +200,7 @@ impl VFolder {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - If the zip archive cannot be written
|
/// - If the zip archive cannot be written
|
||||||
#[cfg(all(feature = "fs_access", feature = "zip"))]
|
#[cfg(all(feature = "fs_access", feature = "zip"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "fs_access", feature = "zip"))))]
|
||||||
pub fn zip_with_comment<P, S>(&self, path: P, comment: S) -> std::io::Result<()>
|
pub fn zip_with_comment<P, S>(&self, path: P, comment: S) -> std::io::Result<()>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>,
|
P: AsRef<std::path::Path>,
|
||||||
|
@ -257,14 +260,14 @@ impl VFolder {
|
||||||
/// Recursively merge another folder into this folder.
|
/// Recursively merge another folder into this folder.
|
||||||
/// Returns a list of paths that were replaced by other.
|
/// Returns a list of paths that were replaced by other.
|
||||||
pub fn merge(&mut self, other: Self) -> Vec<String> {
|
pub fn merge(&mut self, other: Self) -> Vec<String> {
|
||||||
self._merge(other, "")
|
self.merge_(other, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _merge(&mut self, other: Self, prefix: &str) -> Vec<String> {
|
fn merge_(&mut self, other: Self, prefix: &str) -> Vec<String> {
|
||||||
let mut replaced = Vec::new();
|
let mut replaced = Vec::new();
|
||||||
for (name, folder) in other.folders {
|
for (name, folder) in other.folders {
|
||||||
if let Some(existing_folder) = self.folders.get_mut(&name) {
|
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);
|
replaced.extend(replaced_folder);
|
||||||
} else {
|
} else {
|
||||||
self.folders.insert(name, folder);
|
self.folders.insert(name, folder);
|
||||||
|
@ -282,6 +285,7 @@ impl VFolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fs_access")]
|
#[cfg(feature = "fs_access")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))]
|
||||||
impl TryFrom<&std::path::Path> for VFolder {
|
impl TryFrom<&std::path::Path> for VFolder {
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
|
||||||
|
@ -385,6 +389,7 @@ impl From<&[u8]> for VFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fs_access")]
|
#[cfg(feature = "fs_access")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "fs_access")))]
|
||||||
impl TryFrom<&std::path::Path> for VFile {
|
impl TryFrom<&std::path::Path> for VFile {
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue