change tag creation behaviour

This commit is contained in:
Moritz Hölting 2024-06-18 15:38:23 +02:00
parent 451626312f
commit cf62725a5e
5 changed files with 89 additions and 62 deletions

26
CHANGELOG.md Normal file
View File

@ -0,0 +1,26 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Datapack struct with compile function
- Namespace struct with compile function
- Function struct with compile function
- Tag struct with compile function
- Command struct with compile function
- Raw command
- Comment
- Execute
- Debug
- Group
- Virtual file system
### Changed
### Removed

View File

@ -32,8 +32,7 @@ fn main() {
)),
)));
// get the main function of the namespace "test" and add a command
namespace.get_main_function_mut().add_command("say tick");
dp.add_load("test:foo");
// compile the datapack
let v_folder = dp.compile(&CompileOptions::default());

View File

@ -24,8 +24,6 @@ pub struct Datapack {
pack_format: u8,
supported_formats: Option<RangeInclusive<u8>>,
namespaces: HashMap<String, Namespace>,
tick: Vec<String>,
load: Vec<String>,
custom_files: VFolder,
}
@ -38,8 +36,6 @@ impl Datapack {
pack_format,
supported_formats: None,
namespaces: HashMap::new(),
tick: Vec::new(),
load: Vec::new(),
custom_files: VFolder::new(),
}
}
@ -91,12 +87,16 @@ impl Datapack {
/// Add a function to the tick function list.
pub fn add_tick(&mut self, function: &str) {
self.tick.push(function.to_string());
self.namespace_mut("minecraft")
.tag_mut("tick", tag::TagType::Functions)
.add_value(tag::TagValue::Simple(function.to_string()));
}
/// Add a function to the load function list.
pub fn add_load(&mut self, function: &str) {
self.load.push(function.to_string());
self.namespace_mut("minecraft")
.tag_mut("load", tag::TagType::Functions)
.add_value(tag::TagValue::Simple(function.to_string()));
}
/// Add a custom file to the datapack.
@ -123,28 +123,6 @@ impl Datapack {
data_folder.add_existing_folder(name, namespace_folder);
}
// Compile tick and load tag
if !self.tick.is_empty() {
let mut tick_tag = tag::Tag::new(tag::TagType::Functions, false);
for function in &self.tick {
tick_tag.add_value(tag::TagValue::Simple(function.to_owned()));
}
data_folder.add_file(
"minecraft/tags/function/tick.json",
tick_tag.compile_no_state(options).1,
);
}
if !self.load.is_empty() {
let mut load_tag = tag::Tag::new(tag::TagType::Functions, false);
for function in &self.load {
load_tag.add_value(tag::TagValue::Simple(function.to_owned()));
}
data_folder.add_file(
"minecraft/tags/function/load.json",
load_tag.compile_no_state(options).1,
);
}
root_folder.add_existing_folder("data", data_folder);
root_folder
}

View File

@ -8,7 +8,10 @@ use crate::{
virtual_fs::VFolder,
};
use super::{function::Function, tag::Tag};
use super::{
function::Function,
tag::{Tag, TagType},
};
use std::collections::{HashMap, VecDeque};
/// Namespace of a datapack
@ -17,8 +20,7 @@ use std::collections::{HashMap, VecDeque};
pub struct Namespace {
name: String,
functions: HashMap<String, Function>,
main_function: Function,
tags: HashMap<String, Tag>,
tags: HashMap<(String, TagType), Tag>,
}
impl Namespace {
@ -27,7 +29,6 @@ impl Namespace {
Self {
name: name.to_string(),
functions: HashMap::new(),
main_function: Function::default(),
tags: HashMap::new(),
}
}
@ -38,16 +39,6 @@ impl Namespace {
&self.name
}
/// Get the main function of the namespace.
#[must_use]
pub fn get_main_function(&self) -> &Function {
&self.main_function
}
/// Get the main function of the namespace mutably.
pub fn get_main_function_mut(&mut self) -> &mut Function {
&mut self.main_function
}
/// Get the functions of the namespace.
#[must_use]
pub fn get_functions(&self) -> &HashMap<String, Function> {
@ -56,7 +47,7 @@ impl Namespace {
/// Get the tags of the namespace.
#[must_use]
pub fn get_tags(&self) -> &HashMap<String, Tag> {
pub fn get_tags(&self) -> &HashMap<(String, TagType), Tag> {
&self.tags
}
@ -67,15 +58,25 @@ impl Namespace {
}
/// Mutably get a function by name or create a new one if it doesn't exist.
#[must_use]
pub fn function_mut(&mut self, name: &str) -> &mut Function {
self.functions
.entry(name.to_string())
.or_insert_with(|| Function::new(&self.name, name))
}
/// Add a tag to the namespace.
pub fn add_tag(&mut self, name: &str, tag: Tag) {
self.tags.insert(name.to_string(), tag);
/// Get a tag by name and type.
#[must_use]
pub fn tag(&self, name: &str, tag_type: TagType) -> Option<&Tag> {
self.tags.get(&(name.to_string(), tag_type))
}
/// Mutably get a tag by name and type or create a new one if it doesn't exist.
#[must_use]
pub fn tag_mut(&mut self, name: &str, tag_type: TagType) -> &mut Tag {
self.tags
.entry((name.to_string(), tag_type.clone()))
.or_insert_with(|| Tag::new(tag_type, false))
}
/// Compile the namespace into a virtual folder.
@ -86,16 +87,12 @@ impl Namespace {
let mut root_folder = VFolder::new();
// collect functions
let mut functions = self
let functions = self
.functions
.iter()
.map(|(name, content)| (name.clone(), content.clone()))
.collect::<VecDeque<_>>();
if !self.main_function.get_commands().is_empty() {
functions.push_front(("main".to_string(), self.main_function.clone()));
}
// compile all functions, allow adding new functions while compiling
let mut functions = ExtendableQueue::from(functions);
while let Some((path, function)) = functions.next() {
@ -107,9 +104,15 @@ impl Namespace {
}
// compile tags
for (path, tag) in &self.tags {
let (tag_type, vfile) = tag.compile(options, state);
root_folder.add_file(&format!("tags/{tag_type}/{path}.json"), vfile);
for ((path, tag_type), tag) in &self.tags {
let vfile = tag.compile(options, state);
root_folder.add_file(
&format!(
"tags/{tag_type}/{path}.json",
tag_type = tag_type.to_string()
),
vfile,
);
}
root_folder

View File

@ -24,25 +24,46 @@ impl Tag {
}
}
/// Get the type of the tag.
#[must_use]
pub fn get_type(&self) -> &TagType {
&self.r#type
}
/// Get whether the tag should replace existing values.
#[must_use]
pub fn get_replace(&self) -> bool {
self.replace
}
/// Set whether the tag should replace existing values.
pub fn set_replace(&mut self, replace: bool) {
self.replace = replace;
}
/// Get the values of the tag.
#[must_use]
pub fn get_values(&self) -> &Vec<TagValue> {
&self.values
}
/// Add a value to the tag.
pub fn add_value(&mut self, value: TagValue) {
self.values.push(value);
}
/// Compile the tag into a virtual file without state
pub fn compile_no_state(&self, _options: &CompileOptions) -> (String, VFile) {
pub fn compile_no_state(&self, _options: &CompileOptions) -> VFile {
let json = serde_json::json!({
"replace": self.replace,
"values": self.values.iter().map(TagValue::compile).collect::<Vec<_>>()
});
let type_str = self.r#type.to_string();
let vfile = VFile::Text(serde_json::to_string(&json).expect("Failed to serialize tag"));
(type_str, vfile)
VFile::Text(serde_json::to_string(&json).expect("Failed to serialize tag"))
}
/// Compile the tag into a virtual file.
pub fn compile(&self, options: &CompileOptions, _state: &MutCompilerState) -> (String, VFile) {
pub fn compile(&self, options: &CompileOptions, _state: &MutCompilerState) -> VFile {
self.compile_no_state(options)
}
}
@ -50,7 +71,7 @@ impl Tag {
/// The type of a tag.
#[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TagType {
/// A tag for blocks.
Blocks,