add group options for always extracting and manually loading macros
This commit is contained in:
		
							parent
							
								
									b6ecdf6385
								
							
						
					
					
						commit
						89709834da
					
				| 
						 | 
					@ -5,6 +5,7 @@ use std::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
 | 
					    datapack::command::Group,
 | 
				
			||||||
    prelude::Command,
 | 
					    prelude::Command,
 | 
				
			||||||
    util::{
 | 
					    util::{
 | 
				
			||||||
        compile::{CompileOptions, CompiledCommand, FunctionCompilerState, MutCompilerState},
 | 
					        compile::{CompileOptions, CompiledCommand, FunctionCompilerState, MutCompilerState},
 | 
				
			||||||
| 
						 | 
					@ -78,7 +79,7 @@ fn compile_using_data_storage(
 | 
				
			||||||
    #[allow(clippy::option_if_let_else)]
 | 
					    #[allow(clippy::option_if_let_else)]
 | 
				
			||||||
    let then = if let Some(success_uid) = require_grouping_uid.as_deref() {
 | 
					    let then = if let Some(success_uid) = require_grouping_uid.as_deref() {
 | 
				
			||||||
        // prepare commands for grouping
 | 
					        // prepare commands for grouping
 | 
				
			||||||
        let mut group_cmd = match then.clone() {
 | 
					        let mut group_cmds = match then.clone() {
 | 
				
			||||||
            Execute::Run(cmd) => vec![*cmd],
 | 
					            Execute::Run(cmd) => vec![*cmd],
 | 
				
			||||||
            Execute::Runs(cmds) => cmds,
 | 
					            Execute::Runs(cmds) => cmds,
 | 
				
			||||||
            ex => vec![Command::Execute(ex)],
 | 
					            ex => vec![Command::Execute(ex)],
 | 
				
			||||||
| 
						 | 
					@ -86,13 +87,13 @@ fn compile_using_data_storage(
 | 
				
			||||||
        // add success condition to the group
 | 
					        // add success condition to the group
 | 
				
			||||||
        // this condition will be checked after the group ran to determine if the else part should be executed
 | 
					        // this condition will be checked after the group ran to determine if the else part should be executed
 | 
				
			||||||
        if el.is_some() && str_cond.len() <= 1 {
 | 
					        if el.is_some() && str_cond.len() <= 1 {
 | 
				
			||||||
            group_cmd.push(
 | 
					            group_cmds.push(
 | 
				
			||||||
                format!("data modify storage shulkerbox:cond {success_uid} set value true")
 | 
					                format!("data modify storage shulkerbox:cond {success_uid} set value true")
 | 
				
			||||||
                    .as_str()
 | 
					                    .as_str()
 | 
				
			||||||
                    .into(),
 | 
					                    .into(),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let group = Command::Group(group_cmd);
 | 
					        let group = Command::Group(Group::new(group_cmds));
 | 
				
			||||||
        let allows_prefix = !group.forbid_prefix();
 | 
					        let allows_prefix = !group.forbid_prefix();
 | 
				
			||||||
        group
 | 
					        group
 | 
				
			||||||
            .compile(options, global_state, function_state)
 | 
					            .compile(options, global_state, function_state)
 | 
				
			||||||
| 
						 | 
					@ -227,7 +228,7 @@ fn compile_since_20_format(
 | 
				
			||||||
                global_state,
 | 
					                global_state,
 | 
				
			||||||
                function_state,
 | 
					                function_state,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            let group = Command::Group(group_cmds);
 | 
					            let group = Command::Group(Group::new(group_cmds));
 | 
				
			||||||
            let cmds = group.compile(options, global_state, function_state);
 | 
					            let cmds = group.compile(options, global_state, function_state);
 | 
				
			||||||
            if contains_macros {
 | 
					            if contains_macros {
 | 
				
			||||||
                cmds.into_iter()
 | 
					                cmds.into_iter()
 | 
				
			||||||
| 
						 | 
					@ -254,7 +255,7 @@ fn compile_since_20_format(
 | 
				
			||||||
            Execute::Runs(cmds) => cmds,
 | 
					            Execute::Runs(cmds) => cmds,
 | 
				
			||||||
            ex => vec![Command::Execute(ex)],
 | 
					            ex => vec![Command::Execute(ex)],
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let group_cmd = Command::Group(then_cmds);
 | 
					        let group_cmd = Command::Group(Group::new(then_cmds));
 | 
				
			||||||
        let then_cmd = if group_cmd.forbid_prefix() {
 | 
					        let then_cmd = if group_cmd.forbid_prefix() {
 | 
				
			||||||
            group_cmd
 | 
					            group_cmd
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -346,7 +347,7 @@ fn handle_return_group_case_since_20(
 | 
				
			||||||
        Execute::Runs(cmds) => cmds,
 | 
					        Execute::Runs(cmds) => cmds,
 | 
				
			||||||
        ex => vec![Command::Execute(ex)],
 | 
					        ex => vec![Command::Execute(ex)],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    let group = Command::Group(then_cmd);
 | 
					    let group = Command::Group(Group::new(then_cmd));
 | 
				
			||||||
    let then_cmd_concat = if group.forbid_prefix() {
 | 
					    let then_cmd_concat = if group.forbid_prefix() {
 | 
				
			||||||
        group
 | 
					        group
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,12 @@
 | 
				
			||||||
use std::{collections::HashSet, ops::RangeInclusive, string::ToString};
 | 
					use std::{collections::HashSet, ops::RangeInclusive, string::ToString};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::Command;
 | 
					use super::Command;
 | 
				
			||||||
use crate::util::{
 | 
					use crate::{
 | 
				
			||||||
    compile::{CompileOptions, CompiledCommand, FunctionCompilerState, MutCompilerState},
 | 
					    datapack::command::Group,
 | 
				
			||||||
    ExtendableQueue, MacroString,
 | 
					    util::{
 | 
				
			||||||
 | 
					        compile::{CompileOptions, CompiledCommand, FunctionCompilerState, MutCompilerState},
 | 
				
			||||||
 | 
					        ExtendableQueue, MacroString,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod conditional;
 | 
					mod conditional;
 | 
				
			||||||
| 
						 | 
					@ -162,7 +165,7 @@ impl Execute {
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .collect(),
 | 
					                .collect(),
 | 
				
			||||||
            Self::Runs(commands) => {
 | 
					            Self::Runs(commands) => {
 | 
				
			||||||
                let group = Command::Group(commands.clone());
 | 
					                let group = Command::Group(Group::new(commands.clone()));
 | 
				
			||||||
                group
 | 
					                group
 | 
				
			||||||
                    .compile(options, global_state, function_state)
 | 
					                    .compile(options, global_state, function_state)
 | 
				
			||||||
                    .into_iter()
 | 
					                    .into_iter()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
mod execute;
 | 
					mod execute;
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::{HashMap, HashSet},
 | 
					    collections::{HashMap, HashSet},
 | 
				
			||||||
 | 
					    hash::Hash,
 | 
				
			||||||
    ops::RangeInclusive,
 | 
					    ops::RangeInclusive,
 | 
				
			||||||
    sync::LazyLock,
 | 
					    sync::LazyLock,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -33,7 +34,7 @@ pub enum Command {
 | 
				
			||||||
    /// Execute command
 | 
					    /// Execute command
 | 
				
			||||||
    Execute(Execute),
 | 
					    Execute(Execute),
 | 
				
			||||||
    /// Group of commands to be called instantly after each other
 | 
					    /// Group of commands to be called instantly after each other
 | 
				
			||||||
    Group(Vec<Command>),
 | 
					    Group(Group),
 | 
				
			||||||
    /// Comment to be added to the function
 | 
					    /// Comment to be added to the function
 | 
				
			||||||
    Comment(String),
 | 
					    Comment(String),
 | 
				
			||||||
    /// Return value
 | 
					    /// Return value
 | 
				
			||||||
| 
						 | 
					@ -64,7 +65,7 @@ impl Command {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Self::Debug(message) => compile_debug(message, options),
 | 
					            Self::Debug(message) => compile_debug(message, options),
 | 
				
			||||||
            Self::Execute(ex) => ex.compile(options, global_state, function_state),
 | 
					            Self::Execute(ex) => ex.compile(options, global_state, function_state),
 | 
				
			||||||
            Self::Group(commands) => compile_group(commands, options, global_state, function_state),
 | 
					            Self::Group(group) => group.compile(options, global_state, function_state),
 | 
				
			||||||
            Self::Comment(comment) => {
 | 
					            Self::Comment(comment) => {
 | 
				
			||||||
                vec![CompiledCommand::new("#".to_string() + comment).with_forbid_prefix(true)]
 | 
					                vec![CompiledCommand::new("#".to_string() + comment).with_forbid_prefix(true)]
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -101,7 +102,8 @@ impl Command {
 | 
				
			||||||
            Self::Raw(cmd) => cmd.split('\n').count(),
 | 
					            Self::Raw(cmd) => cmd.split('\n').count(),
 | 
				
			||||||
            Self::UsesMacro(cmd) => cmd.line_count(),
 | 
					            Self::UsesMacro(cmd) => cmd.line_count(),
 | 
				
			||||||
            Self::Execute(ex) => ex.get_count(options),
 | 
					            Self::Execute(ex) => ex.get_count(options),
 | 
				
			||||||
            Self::Group(_) | Self::Return(_) => 1,
 | 
					            Self::Group(group) => group.get_count(options),
 | 
				
			||||||
 | 
					            Self::Return(_) => 1,
 | 
				
			||||||
            Self::Concat(a, b) => a.get_count(options) + b.get_count(options) - 1,
 | 
					            Self::Concat(a, b) => a.get_count(options) + b.get_count(options) - 1,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -135,7 +137,7 @@ impl Command {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Self::Raw(_) | Self::Comment(_) => false,
 | 
					            Self::Raw(_) | Self::Comment(_) => false,
 | 
				
			||||||
            Self::UsesMacro(s) | Self::Debug(s) => s.contains_macro(),
 | 
					            Self::UsesMacro(s) | Self::Debug(s) => s.contains_macro(),
 | 
				
			||||||
            Self::Group(commands) => group_contains_macro(commands),
 | 
					            Self::Group(group) => group.contains_macro(),
 | 
				
			||||||
            Self::Execute(ex) => ex.contains_macro(),
 | 
					            Self::Execute(ex) => ex.contains_macro(),
 | 
				
			||||||
            Self::Return(ret) => match ret {
 | 
					            Self::Return(ret) => match ret {
 | 
				
			||||||
                ReturnCommand::Value(value) => value.contains_macro(),
 | 
					                ReturnCommand::Value(value) => value.contains_macro(),
 | 
				
			||||||
| 
						 | 
					@ -151,7 +153,7 @@ impl Command {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Self::Raw(_) | Self::Comment(_) => HashSet::new(),
 | 
					            Self::Raw(_) | Self::Comment(_) => HashSet::new(),
 | 
				
			||||||
            Self::UsesMacro(s) | Self::Debug(s) => s.get_macros(),
 | 
					            Self::UsesMacro(s) | Self::Debug(s) => s.get_macros(),
 | 
				
			||||||
            Self::Group(commands) => group_get_macros(commands),
 | 
					            Self::Group(group) => group.get_macros(),
 | 
				
			||||||
            Self::Execute(ex) => ex.get_macros(),
 | 
					            Self::Execute(ex) => ex.get_macros(),
 | 
				
			||||||
            Self::Return(ret) => match ret {
 | 
					            Self::Return(ret) => match ret {
 | 
				
			||||||
                ReturnCommand::Value(value) => value.get_macros(),
 | 
					                ReturnCommand::Value(value) => value.get_macros(),
 | 
				
			||||||
| 
						 | 
					@ -171,7 +173,7 @@ impl Command {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Self::Comment(_) => true,
 | 
					            Self::Comment(_) => true,
 | 
				
			||||||
            Self::Raw(_) | Self::Debug(_) | Self::Execute(_) | Self::UsesMacro(_) => false,
 | 
					            Self::Raw(_) | Self::Debug(_) | Self::Execute(_) | Self::UsesMacro(_) => false,
 | 
				
			||||||
            Self::Group(commands) => commands.len() == 1 && commands[0].forbid_prefix(),
 | 
					            Self::Group(group) => group.forbid_prefix(),
 | 
				
			||||||
            Self::Return(ret) => match ret {
 | 
					            Self::Return(ret) => match ret {
 | 
				
			||||||
                ReturnCommand::Value(_) => false,
 | 
					                ReturnCommand::Value(_) => false,
 | 
				
			||||||
                ReturnCommand::Command(cmd) => cmd.forbid_prefix(),
 | 
					                ReturnCommand::Command(cmd) => cmd.forbid_prefix(),
 | 
				
			||||||
| 
						 | 
					@ -190,7 +192,7 @@ impl Command {
 | 
				
			||||||
            Self::Execute(exec) => exec.contains_return(),
 | 
					            Self::Execute(exec) => exec.contains_return(),
 | 
				
			||||||
            Self::Raw(cmd) => cmd.starts_with("return "),
 | 
					            Self::Raw(cmd) => cmd.starts_with("return "),
 | 
				
			||||||
            Self::UsesMacro(m) => m.compile().starts_with("return "),
 | 
					            Self::UsesMacro(m) => m.compile().starts_with("return "),
 | 
				
			||||||
            Self::Group(g) => g.iter().any(Self::contains_return),
 | 
					            Self::Group(g) => g.contains_return(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -211,6 +213,335 @@ impl From<&mut Function> for Command {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Represents a group of commands to be executed in sequence.
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct Group {
 | 
				
			||||||
 | 
					    /// The commands in the group.
 | 
				
			||||||
 | 
					    commands: Vec<Command>,
 | 
				
			||||||
 | 
					    /// Whether to always create a function for this group, even if it contains only one command.
 | 
				
			||||||
 | 
					    always_create_function: bool,
 | 
				
			||||||
 | 
					    /// Optional name for the data storage used for arguments.
 | 
				
			||||||
 | 
					    data_storage_name: Option<String>,
 | 
				
			||||||
 | 
					    /// Optional set of macros that should not be passed to the function, even though they are contained.
 | 
				
			||||||
 | 
					    /// This can be used together with `data_storage_name` to dynamically pass arguments to the function.
 | 
				
			||||||
 | 
					    block_pass_macros: Option<HashSet<String>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Group {
 | 
				
			||||||
 | 
					    /// Create a new group of commands.
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new(commands: Vec<Command>) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            commands,
 | 
				
			||||||
 | 
					            always_create_function: false,
 | 
				
			||||||
 | 
					            data_storage_name: None,
 | 
				
			||||||
 | 
					            block_pass_macros: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn always_create_function(mut self, always_create_function: bool) -> Self {
 | 
				
			||||||
 | 
					        self.always_create_function = always_create_function;
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn block_pass_macros(mut self, block: HashSet<String>) -> Self {
 | 
				
			||||||
 | 
					        self.block_pass_macros = Some(block);
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn data_storage_name(mut self, name: String) -> Self {
 | 
				
			||||||
 | 
					        self.data_storage_name = Some(name);
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Compile the execute command into a list of compiled commands.
 | 
				
			||||||
 | 
					    #[expect(clippy::too_many_lines)]
 | 
				
			||||||
 | 
					    #[tracing::instrument(skip_all, fields(commands = ?self.commands))]
 | 
				
			||||||
 | 
					    pub fn compile(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        options: &CompileOptions,
 | 
				
			||||||
 | 
					        global_state: &MutCompilerState,
 | 
				
			||||||
 | 
					        function_state: &FunctionCompilerState,
 | 
				
			||||||
 | 
					    ) -> Vec<CompiledCommand> {
 | 
				
			||||||
 | 
					        let command_count = self
 | 
				
			||||||
 | 
					            .commands
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|cmd| cmd.get_count(options))
 | 
				
			||||||
 | 
					            .sum::<usize>();
 | 
				
			||||||
 | 
					        // only create a function if there are more than one command
 | 
				
			||||||
 | 
					        match command_count {
 | 
				
			||||||
 | 
					            0 if !self.always_create_function => Vec::new(),
 | 
				
			||||||
 | 
					            1 if !self.always_create_function => {
 | 
				
			||||||
 | 
					                self.commands[0].compile(options, global_state, function_state)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => {
 | 
				
			||||||
 | 
					                let pass_macros = self.contains_macro();
 | 
				
			||||||
 | 
					                let contains_return = self.contains_return();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // calculate a hashed path for the function in the `sb` subfolder
 | 
				
			||||||
 | 
					                let function_path = Self::generate_function_path(function_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let namespace = function_state.namespace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // create a new function with the commands
 | 
				
			||||||
 | 
					                let mut function = Function::new(namespace, &function_path);
 | 
				
			||||||
 | 
					                function
 | 
				
			||||||
 | 
					                    .get_commands_mut()
 | 
				
			||||||
 | 
					                    .extend(self.commands.iter().cloned());
 | 
				
			||||||
 | 
					                function_state.add_function(&function_path, function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut function_invocation = format!("function {namespace}:{function_path}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let additional_return_cmds = if contains_return {
 | 
				
			||||||
 | 
					                    let full_path = format!("{namespace}:{function_path}");
 | 
				
			||||||
 | 
					                    let return_data_path = md5::hash(&full_path).to_hex_lowercase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let pre_cmds = Command::Raw(format!(
 | 
				
			||||||
 | 
					                        "data remove storage shulkerbox:return {return_data_path}"
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
 | 
					                    .compile(options, global_state, function_state)
 | 
				
			||||||
 | 
					                    .into_iter()
 | 
				
			||||||
 | 
					                    .map(|c| c.with_forbid_prefix(true))
 | 
				
			||||||
 | 
					                    .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					                    let post_condition = Condition::Atom(
 | 
				
			||||||
 | 
					                        format!("data storage shulkerbox:return {return_data_path}").into(),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let post_cmd_store = global_state
 | 
				
			||||||
 | 
					                    .read()
 | 
				
			||||||
 | 
					                    .unwrap()
 | 
				
			||||||
 | 
					                    .functions_with_special_return
 | 
				
			||||||
 | 
					                    .get(&format!(
 | 
				
			||||||
 | 
					                        "{}:{}",
 | 
				
			||||||
 | 
					                        function_state.namespace(),
 | 
				
			||||||
 | 
					                        function_state.path()
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
 | 
					                    .cloned().map(|parent_return_data_path| {
 | 
				
			||||||
 | 
					                        Command::Execute(Execute::If(
 | 
				
			||||||
 | 
					                        post_condition.clone(),
 | 
				
			||||||
 | 
					                        Box::new(Execute::Run(Box::new(Command::Raw(format!(
 | 
				
			||||||
 | 
					                            "data modify storage shulkerbox:return {parent_return_data_path} set from storage shulkerbox:return {return_data_path}"
 | 
				
			||||||
 | 
					                        ))))),
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let post_cmd_return = Command::Execute(Execute::If(
 | 
				
			||||||
 | 
					                        post_condition,
 | 
				
			||||||
 | 
					                        Box::new(Execute::Run(Box::new(Command::Raw(format!(
 | 
				
			||||||
 | 
					                            "return run data get storage shulkerbox:return {return_data_path}"
 | 
				
			||||||
 | 
					                        ))))),
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let post_cmds = post_cmd_store
 | 
				
			||||||
 | 
					                        .into_iter()
 | 
				
			||||||
 | 
					                        .chain(std::iter::once(post_cmd_return))
 | 
				
			||||||
 | 
					                        .flat_map(|cmd| cmd.compile(options, global_state, function_state))
 | 
				
			||||||
 | 
					                        .map(|c| c.with_forbid_prefix(true))
 | 
				
			||||||
 | 
					                        .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    global_state
 | 
				
			||||||
 | 
					                        .write()
 | 
				
			||||||
 | 
					                        .unwrap()
 | 
				
			||||||
 | 
					                        .functions_with_special_return
 | 
				
			||||||
 | 
					                        .insert(full_path, return_data_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Some((pre_cmds, post_cmds))
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let prepare_data_storage = if pass_macros {
 | 
				
			||||||
 | 
					                    let contained_macros = self.get_macros();
 | 
				
			||||||
 | 
					                    let not_all_macros_blocked = self
 | 
				
			||||||
 | 
					                        .block_pass_macros
 | 
				
			||||||
 | 
					                        .as_ref()
 | 
				
			||||||
 | 
					                        .is_none_or(|b| contained_macros.iter().any(|&m| !b.contains(m)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if !contained_macros.is_empty()
 | 
				
			||||||
 | 
					                        && (self.data_storage_name.is_some() || not_all_macros_blocked)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        use std::fmt::Write as _;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // WARNING: this seems to be the only way to pass macros to the function called.
 | 
				
			||||||
 | 
					                        // Because everything is passed as a string, it looses one "level" of escaping per pass.
 | 
				
			||||||
 | 
					                        let macros_block = self
 | 
				
			||||||
 | 
					                            .get_macros()
 | 
				
			||||||
 | 
					                            .into_iter()
 | 
				
			||||||
 | 
					                            .filter(|&m| {
 | 
				
			||||||
 | 
					                                self.block_pass_macros
 | 
				
			||||||
 | 
					                                    .as_ref()
 | 
				
			||||||
 | 
					                                    .is_none_or(|b| !b.contains(m))
 | 
				
			||||||
 | 
					                            })
 | 
				
			||||||
 | 
					                            .map(|m| format!(r#"{m}:"$({m})""#))
 | 
				
			||||||
 | 
					                            .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					                            .join(",");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if let Some(data_storage_name) = self.data_storage_name.as_deref() {
 | 
				
			||||||
 | 
					                            let _ =
 | 
				
			||||||
 | 
					                                write!(function_invocation, " with storage {data_storage_name}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            not_all_macros_blocked.then(|| {
 | 
				
			||||||
 | 
					                                CompiledCommand::new(format!(
 | 
				
			||||||
 | 
					                                    "data merge storage {data_storage_name} {{{macros_block}}}"
 | 
				
			||||||
 | 
					                                ))
 | 
				
			||||||
 | 
					                                .with_contains_macros(true)
 | 
				
			||||||
 | 
					                            })
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            let _ = write!(function_invocation, " {{{macros_block}}}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            None
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        None
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if let Some((mut pre_cmds, post_cmds)) = additional_return_cmds {
 | 
				
			||||||
 | 
					                    if let Some(prepare_datastorage_cmd) = prepare_data_storage {
 | 
				
			||||||
 | 
					                        pre_cmds.push(prepare_datastorage_cmd);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    pre_cmds.push(
 | 
				
			||||||
 | 
					                        CompiledCommand::new(function_invocation)
 | 
				
			||||||
 | 
					                            .with_contains_macros(pass_macros && self.data_storage_name.is_none()),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    pre_cmds.extend(post_cmds);
 | 
				
			||||||
 | 
					                    pre_cmds
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    prepare_data_storage
 | 
				
			||||||
 | 
					                        .into_iter()
 | 
				
			||||||
 | 
					                        .chain(std::iter::once(
 | 
				
			||||||
 | 
					                            CompiledCommand::new(function_invocation).with_contains_macros(
 | 
				
			||||||
 | 
					                                pass_macros && self.data_storage_name.is_none(),
 | 
				
			||||||
 | 
					                            ),
 | 
				
			||||||
 | 
					                        ))
 | 
				
			||||||
 | 
					                        .collect()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Check whether the group contains a macro.
 | 
				
			||||||
 | 
					    pub fn contains_macro(&self) -> bool {
 | 
				
			||||||
 | 
					        self.commands.iter().any(Command::contains_macro)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Check whether the group contains a return command.
 | 
				
			||||||
 | 
					    pub fn contains_return(&self) -> bool {
 | 
				
			||||||
 | 
					        self.commands.iter().any(Command::contains_return)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Generate a unique function path based on the function state.
 | 
				
			||||||
 | 
					    fn generate_function_path(function_state: &FunctionCompilerState) -> String {
 | 
				
			||||||
 | 
					        let uid = function_state.request_uid();
 | 
				
			||||||
 | 
					        let function_path = function_state.path();
 | 
				
			||||||
 | 
					        let function_path = function_path.strip_prefix("sb/").unwrap_or(function_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pre_hash_path = function_path.to_owned() + ":" + &uid.to_string();
 | 
				
			||||||
 | 
					        let hash = md5::hash(pre_hash_path).to_hex_lowercase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        "sb/".to_string() + function_path + "/" + &hash[..16]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns the names of the macros used
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn get_macros(&self) -> HashSet<&str> {
 | 
				
			||||||
 | 
					        let mut macros = HashSet::new();
 | 
				
			||||||
 | 
					        for cmd in &self.commands {
 | 
				
			||||||
 | 
					            macros.extend(cmd.get_macros());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        macros
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Check whether the group should not have a prefix.
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn forbid_prefix(&self) -> bool {
 | 
				
			||||||
 | 
					        self.commands.len() == 1 && self.commands[0].forbid_prefix()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get the count of the commands this command will compile into.
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    fn get_count(&self, options: &CompileOptions) -> usize {
 | 
				
			||||||
 | 
					        let command_count = self
 | 
				
			||||||
 | 
					            .commands
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|cmd| cmd.get_count(options))
 | 
				
			||||||
 | 
					            .sum::<usize>();
 | 
				
			||||||
 | 
					        // only create a function if there are more than one command
 | 
				
			||||||
 | 
					        match command_count {
 | 
				
			||||||
 | 
					            0 if !self.always_create_function => 0,
 | 
				
			||||||
 | 
					            1 if !self.always_create_function => 1,
 | 
				
			||||||
 | 
					            _ => {
 | 
				
			||||||
 | 
					                let pass_macros = self.contains_macro();
 | 
				
			||||||
 | 
					                let contains_return = self.contains_return();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let additional_return_cmds = if contains_return {
 | 
				
			||||||
 | 
					                    let post_cmd_store = Command::Execute(Execute::If(
 | 
				
			||||||
 | 
					                        Condition::Atom("".into()),
 | 
				
			||||||
 | 
					                        Box::new(Execute::Run(Box::new(Command::Raw(String::new())))),
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
 | 
					                    .get_count(options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let post_cmd_return = Command::Execute(Execute::If(
 | 
				
			||||||
 | 
					                        Condition::Atom("".into()),
 | 
				
			||||||
 | 
					                        Box::new(Execute::Run(Box::new(Command::Raw(String::new())))),
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
 | 
					                    .get_count(options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let post_cmds = post_cmd_store + post_cmd_return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Some(post_cmds + 1)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let prepare_data_storage = if pass_macros {
 | 
				
			||||||
 | 
					                    let contained_macros = self.get_macros();
 | 
				
			||||||
 | 
					                    let not_all_macros_blocked = self
 | 
				
			||||||
 | 
					                        .block_pass_macros
 | 
				
			||||||
 | 
					                        .as_ref()
 | 
				
			||||||
 | 
					                        .is_none_or(|b| contained_macros.iter().any(|&m| !b.contains(m)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    !contained_macros.is_empty()
 | 
				
			||||||
 | 
					                        && (self.data_storage_name.is_some() || not_all_macros_blocked)
 | 
				
			||||||
 | 
					                            & self.data_storage_name.is_some()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    false
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                additional_return_cmds.map_or_else(
 | 
				
			||||||
 | 
					                    || 1 + usize::from(prepare_data_storage),
 | 
				
			||||||
 | 
					                    |additional_return_cmds| {
 | 
				
			||||||
 | 
					                        additional_return_cmds + 1 + usize::from(prepare_data_storage)
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Hash for Group {
 | 
				
			||||||
 | 
					    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					        self.commands.hash(state);
 | 
				
			||||||
 | 
					        self.always_create_function.hash(state);
 | 
				
			||||||
 | 
					        if let Some(block) = &self.block_pass_macros {
 | 
				
			||||||
 | 
					            #[expect(clippy::collection_is_never_read)]
 | 
				
			||||||
 | 
					            let mut block_vec = block.iter().collect::<Vec<_>>();
 | 
				
			||||||
 | 
					            block_vec.sort();
 | 
				
			||||||
 | 
					            block_vec.hash(state);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a command that returns a value.
 | 
					/// Represents a command that returns a value.
 | 
				
			||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
					#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
| 
						 | 
					@ -232,144 +563,6 @@ fn compile_debug(message: &MacroString, option: &CompileOptions) -> Vec<Compiled
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tracing::instrument(skip_all, fields(commands = ?commands))]
 | 
					 | 
				
			||||||
fn compile_group(
 | 
					 | 
				
			||||||
    commands: &[Command],
 | 
					 | 
				
			||||||
    options: &CompileOptions,
 | 
					 | 
				
			||||||
    global_state: &MutCompilerState,
 | 
					 | 
				
			||||||
    function_state: &FunctionCompilerState,
 | 
					 | 
				
			||||||
) -> Vec<CompiledCommand> {
 | 
					 | 
				
			||||||
    let command_count = commands
 | 
					 | 
				
			||||||
        .iter()
 | 
					 | 
				
			||||||
        .map(|cmd| cmd.get_count(options))
 | 
					 | 
				
			||||||
        .sum::<usize>();
 | 
					 | 
				
			||||||
    // only create a function if there are more than one command
 | 
					 | 
				
			||||||
    match command_count {
 | 
					 | 
				
			||||||
        0 => Vec::new(),
 | 
					 | 
				
			||||||
        1 => commands[0].compile(options, global_state, function_state),
 | 
					 | 
				
			||||||
        _ => {
 | 
					 | 
				
			||||||
            let pass_macros = group_contains_macro(commands);
 | 
					 | 
				
			||||||
            let contains_return = commands.iter().any(Command::contains_return);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // calculate a hashed path for the function in the `sb` subfolder
 | 
					 | 
				
			||||||
            let function_path = generate_group_function_path(function_state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let namespace = function_state.namespace();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // create a new function with the commands
 | 
					 | 
				
			||||||
            let mut function = Function::new(namespace, &function_path);
 | 
					 | 
				
			||||||
            function.get_commands_mut().extend(commands.iter().cloned());
 | 
					 | 
				
			||||||
            function_state.add_function(&function_path, function);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let mut function_invocation = format!("function {namespace}:{function_path}");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let additional_return_cmds = if contains_return {
 | 
					 | 
				
			||||||
                let full_path = format!("{namespace}:{function_path}");
 | 
					 | 
				
			||||||
                let return_data_path = md5::hash(&full_path).to_hex_lowercase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let pre_cmds = Command::Raw(format!(
 | 
					 | 
				
			||||||
                    "data remove storage shulkerbox:return {return_data_path}"
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
                .compile(options, global_state, function_state)
 | 
					 | 
				
			||||||
                .into_iter()
 | 
					 | 
				
			||||||
                .map(|c| c.with_forbid_prefix(true))
 | 
					 | 
				
			||||||
                .collect::<Vec<_>>();
 | 
					 | 
				
			||||||
                let post_condition = Condition::Atom(
 | 
					 | 
				
			||||||
                    format!("data storage shulkerbox:return {return_data_path}").into(),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let post_cmd_store = global_state
 | 
					 | 
				
			||||||
                    .read()
 | 
					 | 
				
			||||||
                    .unwrap()
 | 
					 | 
				
			||||||
                    .functions_with_special_return
 | 
					 | 
				
			||||||
                    .get(&format!(
 | 
					 | 
				
			||||||
                        "{}:{}",
 | 
					 | 
				
			||||||
                        function_state.namespace(),
 | 
					 | 
				
			||||||
                        function_state.path()
 | 
					 | 
				
			||||||
                    ))
 | 
					 | 
				
			||||||
                    .cloned().map(|parent_return_data_path| {
 | 
					 | 
				
			||||||
                        Command::Execute(Execute::If(
 | 
					 | 
				
			||||||
                        post_condition.clone(),
 | 
					 | 
				
			||||||
                        Box::new(Execute::Run(Box::new(Command::Raw(format!(
 | 
					 | 
				
			||||||
                            "data modify storage shulkerbox:return {parent_return_data_path} set from storage shulkerbox:return {return_data_path}"
 | 
					 | 
				
			||||||
                        ))))),
 | 
					 | 
				
			||||||
                        None,
 | 
					 | 
				
			||||||
                    ))
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let post_cmd_return = Command::Execute(Execute::If(
 | 
					 | 
				
			||||||
                    post_condition,
 | 
					 | 
				
			||||||
                    Box::new(Execute::Run(Box::new(Command::Raw(format!(
 | 
					 | 
				
			||||||
                        "return run data get storage shulkerbox:return {return_data_path}"
 | 
					 | 
				
			||||||
                    ))))),
 | 
					 | 
				
			||||||
                    None,
 | 
					 | 
				
			||||||
                ));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let post_cmds = post_cmd_store
 | 
					 | 
				
			||||||
                    .into_iter()
 | 
					 | 
				
			||||||
                    .chain(std::iter::once(post_cmd_return))
 | 
					 | 
				
			||||||
                    .flat_map(|cmd| cmd.compile(options, global_state, function_state))
 | 
					 | 
				
			||||||
                    .map(|c| c.with_forbid_prefix(true))
 | 
					 | 
				
			||||||
                    .collect::<Vec<_>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                global_state
 | 
					 | 
				
			||||||
                    .write()
 | 
					 | 
				
			||||||
                    .unwrap()
 | 
					 | 
				
			||||||
                    .functions_with_special_return
 | 
					 | 
				
			||||||
                    .insert(full_path, return_data_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Some((pre_cmds, post_cmds))
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if pass_macros {
 | 
					 | 
				
			||||||
                // WARNING: this seems to be the only way to pass macros to the function called.
 | 
					 | 
				
			||||||
                // Because everything is passed as a string, it looses one "level" of escaping per pass.
 | 
					 | 
				
			||||||
                let macros_block = group_get_macros(commands)
 | 
					 | 
				
			||||||
                    .into_iter()
 | 
					 | 
				
			||||||
                    .map(|m| format!(r#"{m}:"$({m})""#))
 | 
					 | 
				
			||||||
                    .collect::<Vec<_>>()
 | 
					 | 
				
			||||||
                    .join(",");
 | 
					 | 
				
			||||||
                function_invocation.push_str(&format!(" {{{macros_block}}}"));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if let Some((mut pre_cmds, post_cmds)) = additional_return_cmds {
 | 
					 | 
				
			||||||
                pre_cmds.push(
 | 
					 | 
				
			||||||
                    CompiledCommand::new(function_invocation).with_contains_macros(pass_macros),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                pre_cmds.extend(post_cmds);
 | 
					 | 
				
			||||||
                pre_cmds
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                vec![CompiledCommand::new(function_invocation).with_contains_macros(pass_macros)]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn generate_group_function_path(function_state: &FunctionCompilerState) -> String {
 | 
					 | 
				
			||||||
    let uid = function_state.request_uid();
 | 
					 | 
				
			||||||
    let function_path = function_state.path();
 | 
					 | 
				
			||||||
    let function_path = function_path.strip_prefix("sb/").unwrap_or(function_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pre_hash_path = function_path.to_owned() + ":" + &uid.to_string();
 | 
					 | 
				
			||||||
    let hash = md5::hash(pre_hash_path).to_hex_lowercase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    "sb/".to_string() + function_path + "/" + &hash[..16]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn group_contains_macro(commands: &[Command]) -> bool {
 | 
					 | 
				
			||||||
    commands.iter().any(Command::contains_macro)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn group_get_macros(commands: &[Command]) -> HashSet<&str> {
 | 
					 | 
				
			||||||
    let mut macros = HashSet::new();
 | 
					 | 
				
			||||||
    for cmd in commands {
 | 
					 | 
				
			||||||
        macros.extend(cmd.get_macros());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    macros
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ReturnCommand {
 | 
					impl ReturnCommand {
 | 
				
			||||||
    pub fn compile(
 | 
					    pub fn compile(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
| 
						 | 
					@ -400,12 +593,12 @@ impl ReturnCommand {
 | 
				
			||||||
                vec![store_cmd, return_cmd]
 | 
					                vec![store_cmd, return_cmd]
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (Self::Command(cmd), None) => {
 | 
					            (Self::Command(cmd), None) => {
 | 
				
			||||||
                let compiled_cmd = Command::Group(vec![*cmd.clone()]).compile(
 | 
					                let compiled_cmd = Command::Group(Group::new(vec![*cmd.clone()])).compile(
 | 
				
			||||||
                    options,
 | 
					                    options,
 | 
				
			||||||
                    global_state,
 | 
					                    global_state,
 | 
				
			||||||
                    function_state,
 | 
					                    function_state,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                let compiled_cmd = compiled_cmd
 | 
					                let compiled_cmd = dbg!(compiled_cmd)
 | 
				
			||||||
                    .into_iter()
 | 
					                    .into_iter()
 | 
				
			||||||
                    .next()
 | 
					                    .next()
 | 
				
			||||||
                    .expect("group will always return exactly one command");
 | 
					                    .expect("group will always return exactly one command");
 | 
				
			||||||
| 
						 | 
					@ -414,7 +607,9 @@ impl ReturnCommand {
 | 
				
			||||||
            (Self::Command(cmd), Some(data_path)) => {
 | 
					            (Self::Command(cmd), Some(data_path)) => {
 | 
				
			||||||
                let compiled_cmd = Command::Execute(Execute::Store(
 | 
					                let compiled_cmd = Command::Execute(Execute::Store(
 | 
				
			||||||
                    format!("result storage shulkerbox:return {data_path} int 1.0").into(),
 | 
					                    format!("result storage shulkerbox:return {data_path} int 1.0").into(),
 | 
				
			||||||
                    Box::new(Execute::Run(Box::new(Command::Group(vec![*cmd.clone()])))),
 | 
					                    Box::new(Execute::Run(Box::new(Command::Group(Group::new(vec![
 | 
				
			||||||
 | 
					                        *cmd.clone(),
 | 
				
			||||||
 | 
					                    ]))))),
 | 
				
			||||||
                ))
 | 
					                ))
 | 
				
			||||||
                .compile(options, global_state, function_state);
 | 
					                .compile(options, global_state, function_state);
 | 
				
			||||||
                let compiled_cmd = compiled_cmd
 | 
					                let compiled_cmd = compiled_cmd
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ mod command;
 | 
				
			||||||
mod function;
 | 
					mod function;
 | 
				
			||||||
mod namespace;
 | 
					mod namespace;
 | 
				
			||||||
pub mod tag;
 | 
					pub mod tag;
 | 
				
			||||||
pub use command::{Command, Condition, Execute, ReturnCommand};
 | 
					pub use command::{Command, Condition, Execute, Group, ReturnCommand};
 | 
				
			||||||
pub use function::Function;
 | 
					pub use function::Function;
 | 
				
			||||||
pub use namespace::Namespace;
 | 
					pub use namespace::Namespace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ pub struct Datapack {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Datapack {
 | 
					impl Datapack {
 | 
				
			||||||
    pub const LATEST_FORMAT: u8 = 61;
 | 
					    pub const LATEST_FORMAT: u8 = 81;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Create a new Minecraft datapack.
 | 
					    /// Create a new Minecraft datapack.
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue