From 57abf36a81620eae15a8f13506b21ddd05cc6844 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Wed, 25 Aug 2021 00:05:11 +0200 Subject: [PATCH 1/8] Introduced build script to download vanilla assets; Added a generator for vanilla tags; Implemented parsing of tag files. --- .gitignore | 2 + Cargo.lock | 44 +- feather/datapacks/Cargo.toml | 11 +- feather/datapacks/build.rs | 8 + feather/datapacks/src/id.rs | 14 + feather/datapacks/src/lib.rs | 46 ++- feather/datapacks/src/tag.rs | 244 +++++++++++ feather/datapacks/src/vanilla_tags.rs | 386 ++++++++++++++++++ feather/datapacks/tags.py | 41 ++ feather/datapacks/vanilla_assets/Cargo.toml | 13 + .../vanilla.rs => vanilla_assets/src/lib.rs} | 20 +- 11 files changed, 815 insertions(+), 14 deletions(-) create mode 100644 feather/datapacks/build.rs create mode 100644 feather/datapacks/src/tag.rs create mode 100644 feather/datapacks/src/vanilla_tags.rs create mode 100644 feather/datapacks/tags.py create mode 100644 feather/datapacks/vanilla_assets/Cargo.toml rename feather/datapacks/{src/vanilla.rs => vanilla_assets/src/lib.rs} (84%) diff --git a/.gitignore b/.gitignore index 79c1a3956..b666bdd52 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ .cargo world/ +feather/downloaded +feather/datapacks/minecraft/ /config.toml # Python cache files (libcraft) diff --git a/Cargo.lock b/Cargo.lock index 16f9b1c87..0ce848284 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -834,13 +834,14 @@ version = "0.1.0" dependencies = [ "ahash 0.4.7", "anyhow", + "feather-generated", + "feather-vanilla-assets", "log", "serde", "serde_json", "smartstring", "thiserror", - "ureq", - "zip", + "walkdir", ] [[package]] @@ -973,6 +974,16 @@ dependencies = [ "simple_logger", ] +[[package]] +name = "feather-vanilla-assets" +version = "0.1.0" +dependencies = [ + "anyhow", + "log", + "ureq", + "zip", +] + [[package]] name = "feather-worldgen" version = "0.6.0" @@ -2379,6 +2390,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -3041,6 +3061,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -3395,6 +3426,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/feather/datapacks/Cargo.toml b/feather/datapacks/Cargo.toml index a31e24751..40ec3a614 100644 --- a/feather/datapacks/Cargo.toml +++ b/feather/datapacks/Cargo.toml @@ -1,16 +1,19 @@ [package] name = "feather-datapacks" version = "0.1.0" -authors = [ "caelunshun " ] +authors = [ "koskja ", "caelunshun " ] edition = "2018" [dependencies] ahash = "0.4" -anyhow = "1" log = "0.4" serde = { version = "1", features = [ "derive" ] } serde_json = "1" smartstring = { version = "0.2", features = [ "serde" ] } thiserror = "1" -ureq = { version = "2", default-features = false, features = [ "tls" ] } -zip = "0.5" +feather_generated = { path = "../generated", package = "feather-generated" } +walkdir = "2.3.2" + +[build-dependencies] +vanilla-assets = { path = "./vanilla_assets", package = "feather-vanilla-assets" } +anyhow = "1" \ No newline at end of file diff --git a/feather/datapacks/build.rs b/feather/datapacks/build.rs new file mode 100644 index 000000000..104f12001 --- /dev/null +++ b/feather/datapacks/build.rs @@ -0,0 +1,8 @@ +use std::path::PathBuf; + +fn main() -> anyhow::Result<()> { + if !PathBuf::from("./minecraft").exists() { + vanilla_assets::download_vanilla_assets(&PathBuf::from("../"))?; + } + Ok(()) +} diff --git a/feather/datapacks/src/id.rs b/feather/datapacks/src/id.rs index e0e9beebb..9027a7b5d 100644 --- a/feather/datapacks/src/id.rs +++ b/feather/datapacks/src/id.rs @@ -29,6 +29,20 @@ impl NamespacedId { pub fn name(&self) -> &str { &self.name } + + pub fn from_parts(namespace: &str, name: &str) -> Result { + let namespace = if namespace.is_empty() { + DEFAULT_NAMESPACE + } else { + namespace + }; + validate_namespace(namespace)?; + validate_name(name)?; + Ok(Self { + namespace: SmartString::from(namespace), + name: SmartString::from(name), + }) + } } /// Error returned when a namespaced ID was formatted incorrectly. diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs index a0c705819..76ec79686 100644 --- a/feather/datapacks/src/lib.rs +++ b/feather/datapacks/src/lib.rs @@ -6,19 +6,41 @@ //! This crate also downloads vanilla JARs and assets //! at startup; see `download_vanilla_assets`. +use std::path::Path; + use ahash::AHashMap; +use id::ParseError; use serde::Deserialize; use smartstring::{LazyCompact, SmartString}; -mod vanilla; -pub use vanilla::download_vanilla_assets; mod id; pub use id::NamespacedId; +pub mod tag; +pub use tag::{TagRegistry, TagRegistryBuilder}; +use tag::LoopError; + /// The default namespace for resource locations (NamespacedIds). pub const DEFAULT_NAMESPACE: &str = "minecraft"; +use thiserror::Error; +#[derive(Error, Debug)] +pub enum Error { + #[error("invalid namespaced id: {0}")] + Parse(#[from] ParseError), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error("io error: {0}")] + WalkDir(#[from] walkdir::Error), + #[error("loop detected when parsing tags: {0}")] + FoundLoop(#[from] LoopError), + #[error("invalid tag link: {0} references {1}")] + InvalidLink(NamespacedId, NamespacedId), + #[error("json parsing error: {0}")] + Json(#[from] serde_json::Error), +} + /// The pack.mcmeta file at the root of a datapack. /// /// Formatted with JSON. @@ -33,3 +55,23 @@ pub struct Datapacks { /// The metadata of loaded packs. Keyed by the datapack name. _meta: AHashMap, PackMeta>, } +#[derive(Default)] +pub struct Datapack { + pub advancements: (), + pub loot_tables: (), + pub recipes: (), + pub structures: (), + pub tags: TagRegistry, +} + +impl Datapack { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + pub fn from_folder(dir: &Path) -> Self { + assert!(dir.is_dir(), "not a directory"); + todo!() + } +} diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs new file mode 100644 index 000000000..ea1e5732a --- /dev/null +++ b/feather/datapacks/src/tag.rs @@ -0,0 +1,244 @@ +use std::{ + borrow::Borrow, collections::VecDeque, fmt::Display, fs::File, io::Read, path::Path, + str::FromStr, +}; + +use crate::NamespacedId; +use ahash::{AHashMap, AHashSet}; +use feather_generated::{BlockKind, EntityKind, Item}; +use serde::Deserialize; +use smartstring::{Compact, SmartString}; +use thiserror::Error; +use walkdir::WalkDir; +/// The tag registry builder's purpose is to serve as a stepping stone to construct the full tag registry. +/// Once all datapacks are loaded, the builder resolves all tag "symlinks". +/// An example of this behaviour is the tag `#minecraft:fences`, which includes `minecraft:nether_brick_fence` and `#minecraft:wooden_fences`. +#[derive(Debug, Default)] +pub struct TagRegistryBuilder { + block_map: AHashMap>>, + entity_map: AHashMap>>, + fluid_map: AHashMap>>, + item_map: AHashMap>>, +} + +impl TagRegistryBuilder { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + pub fn from_dir(dir: &Path, namespace: &str) -> Result { + assert!(dir.is_dir()); + let mut this = Self::new(); + let blocks = dir.join("blocks"); + let entity_types = dir.join("entity_types"); + let fluids = dir.join("fluids"); + let items = dir.join("items"); + if blocks.exists() { + Self::fill_map(&blocks, &mut this.block_map, namespace)?; + } + if entity_types.exists() { + Self::fill_map(&entity_types, &mut this.entity_map, namespace)?; + } + if fluids.exists() { + Self::fill_map(&fluids, &mut this.fluid_map, namespace)?; + } + if items.exists() { + Self::fill_map(&items, &mut this.item_map, namespace)?; + } + Ok(this) + } + fn fill_map( + dir: &Path, + map: &mut AHashMap>>, + namespace: &str, + ) -> Result<(), crate::Error> { + for entry in WalkDir::new(dir).into_iter() { + let entry = entry?; + let entry = entry.path(); + if !entry.is_file() { + continue; + } + let path_to_file = entry.parent().unwrap(); + let file_name = entry.file_stem().unwrap(); + let tag_name = std::borrow::Cow::Owned( + path_to_file + .strip_prefix(dir) + .unwrap() + .to_string_lossy() + .replace("\\", "/"), + ) + file_name.to_string_lossy(); + let namespaced = NamespacedId::from_parts(namespace, &tag_name[..])?; + if !map.contains_key(&namespaced) { + map.insert(namespaced.clone(), Default::default()); + } + Self::fill_set(entry, map.get_mut(&namespaced).unwrap())?; + } + Ok(()) + } + fn fill_set(file: &Path, set: &mut AHashSet>) -> Result<(), crate::Error> { + assert!(file.is_file()); + let mut s = String::new(); + File::open(file).unwrap().read_to_string(&mut s).unwrap(); + let file: TagFile = serde_json::from_str(&s[..])?; + if file.replace { + set.clear(); + } + for entry in file.values { + set.insert(SmartString::from(entry)); + } + Ok(()) + } + fn parse( + source: &AHashMap>>, + target: &mut AHashMap>, + ) -> Result<(), crate::Error> { + let mut stack = VecDeque::new(); + for tag in source.keys().cloned() { + if target.contains_key(&tag) { + continue; + } + Self::parse_rec(tag, &mut stack, source, target)?; + } + Ok(()) + } + fn parse_rec( + tag: NamespacedId, + stack: &mut VecDeque, + source: &AHashMap>>, + target: &mut AHashMap>, + ) -> Result<(), crate::Error> { + if stack.contains(&tag) { + return Err(LoopError(stack.iter().cloned().collect()).into()); + } + let set = match source.get(&tag) { + Some(s) => s, + None => return Err(crate::Error::InvalidLink(stack.pop_back().unwrap(), tag)), + }; + assert!(target.insert(tag.clone(), Default::default()).is_none()); + // Parse all child tags + for child in set.iter().filter_map(|s| s.strip_prefix('#')) { + println!("{}", child); + let child = NamespacedId::from_str(child)?; + if !target.contains_key(&child) { + // Skip already parsed tags + stack.push_back(tag.clone()); + Self::parse_rec(child.clone(), stack, source, target)?; + } + for element in target.get(&child).unwrap().clone() { + // Insert freshly child entry + target.get_mut(&tag).unwrap().insert(element); + } + } + let target_entry = target.get_mut(&tag).unwrap(); + + for i in source + .get(&tag) + .unwrap() + .iter() + .filter(|e| !e.starts_with('#')) + { + // Insert all non-tag entries + target_entry.insert(NamespacedId::from_str(i)?); + } + // This tag is now parsed. + stack.pop_back(); + + Ok(()) + } + pub fn build(self) -> Result { + let mut res = TagRegistry::new(); + Self::parse(&self.block_map, &mut res.block_map)?; + Self::parse(&self.entity_map, &mut res.entity_map)?; + Self::parse(&self.fluid_map, &mut res.fluid_map)?; + Self::parse(&self.item_map, &mut res.item_map)?; + Ok(res) + } +} +#[derive(Debug, Default)] +pub struct TagRegistry { + pub block_map: AHashMap>, + pub entity_map: AHashMap>, + pub fluid_map: AHashMap>, + pub item_map: AHashMap>, +} +impl TagRegistry { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + pub fn check_block_tag(&self, block: BlockKind, tag: impl Into) -> bool { + self.block_map + .get(&tag.into()) + .map(|set| set.get(&NamespacedId::from_str(block.name()).unwrap())) + .is_some() + } + pub fn check_entity_tag(&self, entity: EntityKind, tag: impl Into) -> bool { + self.entity_map + .get(&tag.into()) + .map(|set| set.get(&NamespacedId::from_str(entity.name()).unwrap())) + .is_some() + } + pub fn check_fluid_tag(&self, fluid: impl Borrow, tag: impl Into) -> bool { + self.fluid_map + .get(&tag.into()) + .map(|set| set.get(&NamespacedId::from_str(fluid.borrow()).unwrap())) + .is_some() + } + pub fn check_item_tag(&self, item: Item, tag: impl Into) -> bool { + self.item_map + .get(&tag.into()) + .map(|set| set.get(&NamespacedId::from_str(item.name()).unwrap())) + .is_some() + } + pub fn check_for_any_tag(&self, thing: impl Borrow, tag: impl Into) -> bool { + let thing = NamespacedId::from_str(thing.borrow()).unwrap(); + let tag = tag.into(); + self.block_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.entity_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.fluid_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.item_map.get(&tag).map(|s| s.get(&thing)).is_some() + } + fn k( + map: &AHashMap>, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + let mut m = map.iter().collect::>(); + m.sort_by(|a, b| { a.0.cmp(b.0) }); + for (a, b) in m { + writeln!(f, "{}: ", a)?; + let mut n = b.iter().collect::>(); + n.sort(); + for c in n { + writeln!(f, " {}", c)?; + } + } + Ok(()) + } +} +impl Display for TagRegistry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::k(&self.block_map, f)?; + Self::k(&self.entity_map, f)?; + Self::k(&self.fluid_map, f)?; + Self::k(&self.item_map, f)?; + + Ok(()) + } +} +#[derive(Deserialize)] +struct TagFile { + pub replace: bool, + pub values: Vec, +} +#[derive(Debug, Error)] +pub struct LoopError(Vec); +impl Display for LoopError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for entry in &self.0 { + writeln!(f, "{}", entry)?; + } + Ok(()) + } +} diff --git a/feather/datapacks/src/vanilla_tags.rs b/feather/datapacks/src/vanilla_tags.rs new file mode 100644 index 000000000..b4d74186c --- /dev/null +++ b/feather/datapacks/src/vanilla_tags.rs @@ -0,0 +1,386 @@ +#[derive(Copy,Clone,Debug,PartialEq,Eq)] +pub enum VanillaBlockTags { + AcaciaLogs, + Anvil, + BambooPlantableOn, + Banners, + BaseStoneNether, + BaseStoneOverworld, + BeaconBaseBlocks, + Beds, + Beehives, + BeeGrowables, + BirchLogs, + Buttons, + Campfires, + Carpets, + Climbable, + Corals, + CoralBlocks, + CoralPlants, + CrimsonStems, + Crops, + DarkOakLogs, + Doors, + DragonImmune, + EndermanHoldable, + Fences, + FenceGates, + Fire, + Flowers, + FlowerPots, + GoldOres, + GuardedByPiglins, + HoglinRepellents, + Ice, + Impermeable, + InfiniburnEnd, + InfiniburnNether, + InfiniburnOverworld, + JungleLogs, + Leaves, + Logs, + LogsThatBurn, + MushroomGrowBlock, + NonFlammableWood, + Nylium, + OakLogs, + PiglinRepellents, + Planks, + Portals, + PressurePlates, + PreventMobSpawningInside, + Rails, + Sand, + Saplings, + ShulkerBoxes, + Signs, + Slabs, + SmallFlowers, + SoulFireBaseBlocks, + SoulSpeedBlocks, + SpruceLogs, + Stairs, + StandingSigns, + StoneBricks, + StonePressurePlates, + StriderWarmBlocks, + TallFlowers, + Trapdoors, + UnderwaterBonemeals, + UnstableBottomCenter, + ValidSpawn, + Walls, + WallCorals, + WallPostOverride, + WallSigns, + WarpedStems, + WartBlocks, + WitherImmune, + WitherSummonBaseBlocks, + WoodenButtons, + WoodenDoors, + WoodenFences, + WoodenPressurePlates, + WoodenSlabs, + WoodenStairs, + WoodenTrapdoors, + Wool, +} + +#[derive(Copy,Clone,Debug,PartialEq,Eq)] +pub enum VanillaEntityTypes { + Arrows, + BeehiveInhabitors, + ImpactProjectiles, + Raiders, + Skeletons, +} + +#[derive(Copy,Clone,Debug,PartialEq,Eq)] +pub enum VanillaFluidTags { + Lava, + Water, +} + +#[derive(Copy,Clone,Debug,PartialEq,Eq)] +pub enum VanillaItemTags { + AcaciaLogs, + Anvil, + Arrows, + Banners, + BeaconPaymentItems, + Beds, + BirchLogs, + Boats, + Buttons, + Carpets, + Coals, + CreeperDropMusicDiscs, + CrimsonStems, + DarkOakLogs, + Doors, + Fences, + Fishes, + Flowers, + GoldOres, + JungleLogs, + Leaves, + LecternBooks, + Logs, + LogsThatBurn, + MusicDiscs, + NonFlammableWood, + OakLogs, + PiglinLoved, + PiglinRepellents, + Planks, + Rails, + Sand, + Saplings, + Signs, + Slabs, + SmallFlowers, + SoulFireBaseBlocks, + SpruceLogs, + Stairs, + StoneBricks, + StoneCraftingMaterials, + StoneToolMaterials, + TallFlowers, + Trapdoors, + Walls, + WarpedStems, + WoodenButtons, + WoodenDoors, + WoodenFences, + WoodenPressurePlates, + WoodenSlabs, + WoodenStairs, + WoodenTrapdoors, + Wool, +} + +impl VanillaBlockTags { + pub fn name(&self) -> &'static str { + match self { + VanillaBlockTags::AcaciaLogs => "acacia_logs", + VanillaBlockTags::Anvil => "anvil", + VanillaBlockTags::BambooPlantableOn => "bamboo_plantable_on", + VanillaBlockTags::Banners => "banners", + VanillaBlockTags::BaseStoneNether => "base_stone_nether", + VanillaBlockTags::BaseStoneOverworld => "base_stone_overworld", + VanillaBlockTags::BeaconBaseBlocks => "beacon_base_blocks", + VanillaBlockTags::Beds => "beds", + VanillaBlockTags::Beehives => "beehives", + VanillaBlockTags::BeeGrowables => "bee_growables", + VanillaBlockTags::BirchLogs => "birch_logs", + VanillaBlockTags::Buttons => "buttons", + VanillaBlockTags::Campfires => "campfires", + VanillaBlockTags::Carpets => "carpets", + VanillaBlockTags::Climbable => "climbable", + VanillaBlockTags::Corals => "corals", + VanillaBlockTags::CoralBlocks => "coral_blocks", + VanillaBlockTags::CoralPlants => "coral_plants", + VanillaBlockTags::CrimsonStems => "crimson_stems", + VanillaBlockTags::Crops => "crops", + VanillaBlockTags::DarkOakLogs => "dark_oak_logs", + VanillaBlockTags::Doors => "doors", + VanillaBlockTags::DragonImmune => "dragon_immune", + VanillaBlockTags::EndermanHoldable => "enderman_holdable", + VanillaBlockTags::Fences => "fences", + VanillaBlockTags::FenceGates => "fence_gates", + VanillaBlockTags::Fire => "fire", + VanillaBlockTags::Flowers => "flowers", + VanillaBlockTags::FlowerPots => "flower_pots", + VanillaBlockTags::GoldOres => "gold_ores", + VanillaBlockTags::GuardedByPiglins => "guarded_by_piglins", + VanillaBlockTags::HoglinRepellents => "hoglin_repellents", + VanillaBlockTags::Ice => "ice", + VanillaBlockTags::Impermeable => "impermeable", + VanillaBlockTags::InfiniburnEnd => "infiniburn_end", + VanillaBlockTags::InfiniburnNether => "infiniburn_nether", + VanillaBlockTags::InfiniburnOverworld => "infiniburn_overworld", + VanillaBlockTags::JungleLogs => "jungle_logs", + VanillaBlockTags::Leaves => "leaves", + VanillaBlockTags::Logs => "logs", + VanillaBlockTags::LogsThatBurn => "logs_that_burn", + VanillaBlockTags::MushroomGrowBlock => "mushroom_grow_block", + VanillaBlockTags::NonFlammableWood => "non_flammable_wood", + VanillaBlockTags::Nylium => "nylium", + VanillaBlockTags::OakLogs => "oak_logs", + VanillaBlockTags::PiglinRepellents => "piglin_repellents", + VanillaBlockTags::Planks => "planks", + VanillaBlockTags::Portals => "portals", + VanillaBlockTags::PressurePlates => "pressure_plates", + VanillaBlockTags::PreventMobSpawningInside => "prevent_mob_spawning_inside", + VanillaBlockTags::Rails => "rails", + VanillaBlockTags::Sand => "sand", + VanillaBlockTags::Saplings => "saplings", + VanillaBlockTags::ShulkerBoxes => "shulker_boxes", + VanillaBlockTags::Signs => "signs", + VanillaBlockTags::Slabs => "slabs", + VanillaBlockTags::SmallFlowers => "small_flowers", + VanillaBlockTags::SoulFireBaseBlocks => "soul_fire_base_blocks", + VanillaBlockTags::SoulSpeedBlocks => "soul_speed_blocks", + VanillaBlockTags::SpruceLogs => "spruce_logs", + VanillaBlockTags::Stairs => "stairs", + VanillaBlockTags::StandingSigns => "standing_signs", + VanillaBlockTags::StoneBricks => "stone_bricks", + VanillaBlockTags::StonePressurePlates => "stone_pressure_plates", + VanillaBlockTags::StriderWarmBlocks => "strider_warm_blocks", + VanillaBlockTags::TallFlowers => "tall_flowers", + VanillaBlockTags::Trapdoors => "trapdoors", + VanillaBlockTags::UnderwaterBonemeals => "underwater_bonemeals", + VanillaBlockTags::UnstableBottomCenter => "unstable_bottom_center", + VanillaBlockTags::ValidSpawn => "valid_spawn", + VanillaBlockTags::Walls => "walls", + VanillaBlockTags::WallCorals => "wall_corals", + VanillaBlockTags::WallPostOverride => "wall_post_override", + VanillaBlockTags::WallSigns => "wall_signs", + VanillaBlockTags::WarpedStems => "warped_stems", + VanillaBlockTags::WartBlocks => "wart_blocks", + VanillaBlockTags::WitherImmune => "wither_immune", + VanillaBlockTags::WitherSummonBaseBlocks => "wither_summon_base_blocks", + VanillaBlockTags::WoodenButtons => "wooden_buttons", + VanillaBlockTags::WoodenDoors => "wooden_doors", + VanillaBlockTags::WoodenFences => "wooden_fences", + VanillaBlockTags::WoodenPressurePlates => "wooden_pressure_plates", + VanillaBlockTags::WoodenSlabs => "wooden_slabs", + VanillaBlockTags::WoodenStairs => "wooden_stairs", + VanillaBlockTags::WoodenTrapdoors => "wooden_trapdoors", + VanillaBlockTags::Wool => "wool", + } + } + pub fn namespaced_name(&self) -> crate::NamespacedId { + crate::NamespacedId::from_str(self.name()).unwrap() + } +} +impl From for &'static str { + fn from(tag: VanillaBlockTags) -> Self { + tag.name() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaBlockTags) -> Self { + tag.namespaced_name() + } +} +impl VanillaEntityTypes { + pub fn name(&self) -> &'static str { + match self { + VanillaEntityTypes::Arrows => "arrows", + VanillaEntityTypes::BeehiveInhabitors => "beehive_inhabitors", + VanillaEntityTypes::ImpactProjectiles => "impact_projectiles", + VanillaEntityTypes::Raiders => "raiders", + VanillaEntityTypes::Skeletons => "skeletons", + } + } + pub fn namespaced_name(&self) -> crate::NamespacedId { + crate::NamespacedId::from_str(self.name()).unwrap() + } +} +impl From for &'static str { + fn from(tag: VanillaEntityTypes) -> Self { + tag.name() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaEntityTypes) -> Self { + tag.namespaced_name() + } +} +impl VanillaFluidTags { + pub fn name(&self) -> &'static str { + match self { + VanillaFluidTags::Lava => "lava", + VanillaFluidTags::Water => "water", + } + } + pub fn namespaced_name(&self) -> crate::NamespacedId { + crate::NamespacedId::from_str(self.name()).unwrap() + } +} +impl From for &'static str { + fn from(tag: VanillaFluidTags) -> Self { + tag.name() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaFluidTags) -> Self { + tag.namespaced_name() + } +} +impl VanillaItemTags { + pub fn name(&self) -> &'static str { + match self { + VanillaItemTags::AcaciaLogs => "acacia_logs", + VanillaItemTags::Anvil => "anvil", + VanillaItemTags::Arrows => "arrows", + VanillaItemTags::Banners => "banners", + VanillaItemTags::BeaconPaymentItems => "beacon_payment_items", + VanillaItemTags::Beds => "beds", + VanillaItemTags::BirchLogs => "birch_logs", + VanillaItemTags::Boats => "boats", + VanillaItemTags::Buttons => "buttons", + VanillaItemTags::Carpets => "carpets", + VanillaItemTags::Coals => "coals", + VanillaItemTags::CreeperDropMusicDiscs => "creeper_drop_music_discs", + VanillaItemTags::CrimsonStems => "crimson_stems", + VanillaItemTags::DarkOakLogs => "dark_oak_logs", + VanillaItemTags::Doors => "doors", + VanillaItemTags::Fences => "fences", + VanillaItemTags::Fishes => "fishes", + VanillaItemTags::Flowers => "flowers", + VanillaItemTags::GoldOres => "gold_ores", + VanillaItemTags::JungleLogs => "jungle_logs", + VanillaItemTags::Leaves => "leaves", + VanillaItemTags::LecternBooks => "lectern_books", + VanillaItemTags::Logs => "logs", + VanillaItemTags::LogsThatBurn => "logs_that_burn", + VanillaItemTags::MusicDiscs => "music_discs", + VanillaItemTags::NonFlammableWood => "non_flammable_wood", + VanillaItemTags::OakLogs => "oak_logs", + VanillaItemTags::PiglinLoved => "piglin_loved", + VanillaItemTags::PiglinRepellents => "piglin_repellents", + VanillaItemTags::Planks => "planks", + VanillaItemTags::Rails => "rails", + VanillaItemTags::Sand => "sand", + VanillaItemTags::Saplings => "saplings", + VanillaItemTags::Signs => "signs", + VanillaItemTags::Slabs => "slabs", + VanillaItemTags::SmallFlowers => "small_flowers", + VanillaItemTags::SoulFireBaseBlocks => "soul_fire_base_blocks", + VanillaItemTags::SpruceLogs => "spruce_logs", + VanillaItemTags::Stairs => "stairs", + VanillaItemTags::StoneBricks => "stone_bricks", + VanillaItemTags::StoneCraftingMaterials => "stone_crafting_materials", + VanillaItemTags::StoneToolMaterials => "stone_tool_materials", + VanillaItemTags::TallFlowers => "tall_flowers", + VanillaItemTags::Trapdoors => "trapdoors", + VanillaItemTags::Walls => "walls", + VanillaItemTags::WarpedStems => "warped_stems", + VanillaItemTags::WoodenButtons => "wooden_buttons", + VanillaItemTags::WoodenDoors => "wooden_doors", + VanillaItemTags::WoodenFences => "wooden_fences", + VanillaItemTags::WoodenPressurePlates => "wooden_pressure_plates", + VanillaItemTags::WoodenSlabs => "wooden_slabs", + VanillaItemTags::WoodenStairs => "wooden_stairs", + VanillaItemTags::WoodenTrapdoors => "wooden_trapdoors", + VanillaItemTags::Wool => "wool", + } + } + pub fn namespaced_name(&self) -> crate::NamespacedId { + crate::NamespacedId::from_str(self.name()).unwrap() + } +} +impl From for &'static str { + fn from(tag: VanillaItemTags) -> Self { + tag.name() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaItemTags) -> Self { + tag.namespaced_name() + } +} diff --git a/feather/datapacks/tags.py b/feather/datapacks/tags.py new file mode 100644 index 000000000..e8a2bef2a --- /dev/null +++ b/feather/datapacks/tags.py @@ -0,0 +1,41 @@ +from os import listdir +prefix = "minecraft/data/minecraft/tags/" +block_tags = listdir(prefix + "blocks") +entity_types = listdir(prefix + "entity_types") +fluid_tags = listdir(prefix + "fluids") +item_tags = listdir(prefix + "items") +tag_list_list = (block_tags, entity_types, fluid_tags, item_tags) +enum_names = ("VanillaBlockTags", "VanillaEntityTypes", "VanillaFluidTags", "VanillaItemTags") +f = open("src/vanilla_tags.rs", "w") +new_line = "\n" +quotes = "\"" +for (tags, enum_name) in zip(tag_list_list, enum_names): + f.write("#[derive(Copy,Clone,Debug,PartialEq,Eq)]\n") + f.write(f"pub enum {enum_name} {{{new_line}") + for s in tags: + camelcase = ''.join(map(str.title, s[:-5].split('_'))) + f.write(f" {camelcase}, {new_line}") + f.write(f"}}{new_line}{new_line}") +for (tags, enum_name) in zip(tag_list_list, enum_names): + f.write(f"impl {enum_name} {{{new_line}") + f.write(f" pub fn name(&self) -> &'static str {{{new_line}") + f.write(f" match self {{{new_line}") + for s in tags: + snakecase = s[:-5] + camelcase = ''.join(map(str.title, snakecase.split('_'))) + f.write(f" {enum_name}::{camelcase} => {quotes}{snakecase}{quotes}, {new_line}") + f.write(" }\n }\n") + f.write(" pub fn namespaced_name(&self) -> crate::NamespacedId {\n") + f.write(" crate::NamespacedId::from_str(self.name()).unwrap()\n") + f.write(" }\n}\n") + f.write(f"impl From<{enum_name}> for &'static str {{{new_line}") + f.write(f" fn from(tag: {enum_name}) -> Self {{{new_line}") + f.write(" tag.name()\n") + f.write(" }\n}\n") + f.write(f"impl From<{enum_name}> for crate::NamespacedId {{{new_line}") + f.write(f" fn from(tag: {enum_name}) -> Self {{{new_line}") + f.write(" tag.namespaced_name()\n") + f.write(" }\n}\n") + + + diff --git a/feather/datapacks/vanilla_assets/Cargo.toml b/feather/datapacks/vanilla_assets/Cargo.toml new file mode 100644 index 000000000..d64698656 --- /dev/null +++ b/feather/datapacks/vanilla_assets/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "feather-vanilla-assets" +version = "0.1.0" +authors = [ "caelunshun " ] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +ureq = { version = "2", default-features = false, features = [ "tls" ] } +zip = "0.5" +log = "0.4" diff --git a/feather/datapacks/src/vanilla.rs b/feather/datapacks/vanilla_assets/src/lib.rs similarity index 84% rename from feather/datapacks/src/vanilla.rs rename to feather/datapacks/vanilla_assets/src/lib.rs index ec051ce93..a26a2dc6f 100644 --- a/feather/datapacks/src/vanilla.rs +++ b/feather/datapacks/vanilla_assets/src/lib.rs @@ -21,7 +21,6 @@ pub fn download_vanilla_assets(base: &Path) -> anyhow::Result<()> { let jar = download_jar(base) .context("failed to download vanilla server JAR") .context("please make sure you have an Internet connection.")?; - // NB: JAR files are just glorified ZIP files, so we can use the zip crate // to process the data. let mut zip = ZipArchive::new(jar)?; @@ -40,7 +39,12 @@ fn download_jar(base: &Path) -> anyhow::Result { let downloaded_dir = base.join("downloaded"); fs::create_dir_all(&downloaded_dir)?; - let mut file = File::create(downloaded_dir.join(JAR_NAME))?; + let mut file = fs::OpenOptions::new() + .write(true) + .read(true) + .truncate(true) + .create(true) + .open(downloaded_dir.join(JAR_NAME))?; io::copy(&mut data, &mut file)?; Ok(file) @@ -62,10 +66,14 @@ fn create_minecraft_datapack(base: &Path, zip: &mut ZipArchive) -> anyhow: // copy data directory let mut files = Vec::new(); - for file_name in zip.file_names() { - let path = Path::new(file_name); - let path_in_target = fs::canonicalize(target.join(path))?; - if path.starts_with("data") && path_in_target.starts_with(&target) { + for file_name in zip + .file_names() + .map(|s| s.to_owned()) + .collect::>() + { + let path = Path::new(&file_name); + if path.starts_with("data") && zip.by_name(&file_name)?.is_file() { + let path_in_target = target.join(path); files.push((file_name.to_owned(), path_in_target)); } } From 73b73fc032e0302a38cd0e857f7636c4afd69664 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Wed, 25 Aug 2021 00:27:25 +0200 Subject: [PATCH 2/8] Cleanup --- feather/datapacks/src/lib.rs | 3 +-- feather/datapacks/src/tag.rs | 18 +++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs index 76ec79686..143a9ca39 100644 --- a/feather/datapacks/src/lib.rs +++ b/feather/datapacks/src/lib.rs @@ -13,13 +13,12 @@ use id::ParseError; use serde::Deserialize; use smartstring::{LazyCompact, SmartString}; - mod id; pub use id::NamespacedId; pub mod tag; -pub use tag::{TagRegistry, TagRegistryBuilder}; use tag::LoopError; +pub use tag::{TagRegistry, TagRegistryBuilder}; /// The default namespace for resource locations (NamespacedIds). pub const DEFAULT_NAMESPACE: &str = "minecraft"; diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index ea1e5732a..2f0f07894 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -27,25 +27,29 @@ impl TagRegistryBuilder { ..Default::default() } } - pub fn from_dir(dir: &Path, namespace: &str) -> Result { + pub fn add_tags_from_dir(&mut self, dir: &Path, namespace: &str) -> Result<(), crate::Error> { assert!(dir.is_dir()); - let mut this = Self::new(); let blocks = dir.join("blocks"); let entity_types = dir.join("entity_types"); let fluids = dir.join("fluids"); let items = dir.join("items"); if blocks.exists() { - Self::fill_map(&blocks, &mut this.block_map, namespace)?; + Self::fill_map(&blocks, &mut self.block_map, namespace)?; } if entity_types.exists() { - Self::fill_map(&entity_types, &mut this.entity_map, namespace)?; + Self::fill_map(&entity_types, &mut self.entity_map, namespace)?; } if fluids.exists() { - Self::fill_map(&fluids, &mut this.fluid_map, namespace)?; + Self::fill_map(&fluids, &mut self.fluid_map, namespace)?; } if items.exists() { - Self::fill_map(&items, &mut this.item_map, namespace)?; + Self::fill_map(&items, &mut self.item_map, namespace)?; } + Ok(()) + } + pub fn from_dir(dir: &Path, namespace: &str) -> Result { + let mut this = Self::new(); + this.add_tags_from_dir(dir, namespace)?; Ok(this) } fn fill_map( @@ -205,7 +209,7 @@ impl TagRegistry { f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let mut m = map.iter().collect::>(); - m.sort_by(|a, b| { a.0.cmp(b.0) }); + m.sort_by(|a, b| a.0.cmp(b.0)); for (a, b) in m { writeln!(f, "{}: ", a)?; let mut n = b.iter().collect::>(); From 531805b5be2bbbbda592c5983f436e3d5b70dcc1 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Thu, 26 Aug 2021 19:29:13 +0200 Subject: [PATCH 3/8] Send a Tags packet to the client --- Cargo.lock | 4 + feather/blocks/src/lib.rs | 2 - feather/common/Cargo.toml | 1 + feather/common/src/game.rs | 4 + feather/datapacks/Cargo.toml | 4 +- feather/datapacks/src/tag.rs | 102 +++++++++++++++++++--- feather/server/Cargo.toml | 1 + feather/server/src/client.rs | 4 +- feather/server/src/main.rs | 14 ++- feather/server/src/systems/player_join.rs | 2 +- 10 files changed, 116 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ce848284..0b0cadc7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -812,6 +812,7 @@ dependencies = [ "anyhow", "feather-base", "feather-blocks", + "feather-datapacks", "feather-ecs", "feather-generated", "feather-utils", @@ -834,7 +835,9 @@ version = "0.1.0" dependencies = [ "ahash 0.4.7", "anyhow", + "feather-blocks", "feather-generated", + "feather-protocol", "feather-vanilla-assets", "log", "serde", @@ -936,6 +939,7 @@ dependencies = [ "crossbeam-utils", "feather-base", "feather-common", + "feather-datapacks", "feather-ecs", "feather-plugin-host", "feather-protocol", diff --git a/feather/blocks/src/lib.rs b/feather/blocks/src/lib.rs index a3ee8b10c..43311335f 100644 --- a/feather/blocks/src/lib.rs +++ b/feather/blocks/src/lib.rs @@ -94,7 +94,6 @@ impl BlockId { VANILLA_ID_TABLE[self.kind as u16 as usize][self.state as usize] } - /* /// Returns the vanilla fluid ID for this block in case it is a fluid. /// The fluid ID is used in the Tags packet. pub fn vanilla_fluid_id(self) -> Option { @@ -112,7 +111,6 @@ impl BlockId { None } } - */ /// Returns the block corresponding to the given vanilla ID. /// diff --git a/feather/common/Cargo.toml b/feather/common/Cargo.toml index 4560fb162..beb409ec3 100644 --- a/feather/common/Cargo.toml +++ b/feather/common/Cargo.toml @@ -22,4 +22,5 @@ uuid = { version = "0.8", features = [ "v4" ] } libcraft-core = { path = "../../libcraft/core" } rayon = "1.5" worldgen = { path = "../worldgen", package = "feather-worldgen" } +datapacks = { path = "../datapacks", package = "feather-datapacks" } rand = "0.8" \ No newline at end of file diff --git a/feather/common/src/game.rs b/feather/common/src/game.rs index db856e010..1e9fbab87 100644 --- a/feather/common/src/game.rs +++ b/feather/common/src/game.rs @@ -1,6 +1,7 @@ use std::{cell::RefCell, mem, rc::Rc, sync::Arc}; use base::{BlockId, BlockPosition, ChunkPosition, Position, Text, Title}; +use datapacks::TagRegistry; use ecs::{ Ecs, Entity, EntityBuilder, HasEcs, HasResources, NoSuchEntity, Resources, SysResult, SystemExecutor, @@ -54,6 +55,8 @@ pub struct Game { entity_spawn_callbacks: Vec, entity_builder: EntityBuilder, + + pub tag_registry: TagRegistry, } impl Default for Game { @@ -74,6 +77,7 @@ impl Game { tick_count: 0, entity_spawn_callbacks: Vec::new(), entity_builder: EntityBuilder::new(), + tag_registry: TagRegistry::new(), } } diff --git a/feather/datapacks/Cargo.toml b/feather/datapacks/Cargo.toml index 40ec3a614..363d30e32 100644 --- a/feather/datapacks/Cargo.toml +++ b/feather/datapacks/Cargo.toml @@ -11,7 +11,9 @@ serde = { version = "1", features = [ "derive" ] } serde_json = "1" smartstring = { version = "0.2", features = [ "serde" ] } thiserror = "1" -feather_generated = { path = "../generated", package = "feather-generated" } +generated = { path = "../generated", package = "feather-generated" } +blocks = { path = "../blocks", package = "feather-blocks"} +protocol = { path = "../protocol", package = "feather-protocol" } walkdir = "2.3.2" [build-dependencies] diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index 2f0f07894..3603f8306 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -1,11 +1,16 @@ use std::{ - borrow::Borrow, collections::VecDeque, fmt::Display, fs::File, io::Read, path::Path, - str::FromStr, + borrow::Borrow, cell::RefCell, collections::VecDeque, fmt::Display, fs::File, io::Read, + path::Path, str::FromStr, }; use crate::NamespacedId; use ahash::{AHashMap, AHashSet}; -use feather_generated::{BlockKind, EntityKind, Item}; +use blocks::BlockId; +use generated::{BlockKind, EntityKind, Item}; +use protocol::{ + packets::server::{AllTags, Tag}, + VarInt, +}; use serde::Deserialize; use smartstring::{Compact, SmartString}; use thiserror::Error; @@ -122,7 +127,6 @@ impl TagRegistryBuilder { assert!(target.insert(tag.clone(), Default::default()).is_none()); // Parse all child tags for child in set.iter().filter_map(|s| s.strip_prefix('#')) { - println!("{}", child); let child = NamespacedId::from_str(child)?; if !target.contains_key(&child) { // Skip already parsed tags @@ -130,7 +134,7 @@ impl TagRegistryBuilder { Self::parse_rec(child.clone(), stack, source, target)?; } for element in target.get(&child).unwrap().clone() { - // Insert freshly child entry + // Insert child entry target.get_mut(&tag).unwrap().insert(element); } } @@ -159,12 +163,14 @@ impl TagRegistryBuilder { Ok(res) } } +/// A registry for keeping track of tags. #[derive(Debug, Default)] pub struct TagRegistry { - pub block_map: AHashMap>, - pub entity_map: AHashMap>, - pub fluid_map: AHashMap>, - pub item_map: AHashMap>, + block_map: AHashMap>, + entity_map: AHashMap>, + fluid_map: AHashMap>, + item_map: AHashMap>, + cached_packet: RefCell>>, } impl TagRegistry { pub fn new() -> Self { @@ -204,7 +210,75 @@ impl TagRegistry { | self.fluid_map.get(&tag).map(|s| s.get(&thing)).is_some() | self.item_map.get(&tag).map(|s| s.get(&thing)).is_some() } - fn k( + /// Provides an `AllTags` packet for sending to the client. This tag is cached to save some performance. + pub fn all_tags(&self) -> AllTags { + let mut inner = self.cached_packet.borrow_mut(); + if inner.is_some() { + inner.as_ref().unwrap().as_ref().to_owned() + } else { + let tags = self.build_tags_packet(); + *inner = Some(Box::new(tags.clone())); + tags + } + } + fn build_tags_packet(&self) -> AllTags { + let mut block_tags = vec![]; + let mut entity_tags = vec![]; + let mut fluid_tags = vec![]; + let mut item_tags = vec![]; + for (tag_name, block_names) in &self.block_map { + block_tags.push(Tag { + name: tag_name.to_string(), + entries: block_names + .iter() + .map(|e| VarInt(generated::BlockKind::from_name(e.name()).unwrap().id() as i32)) + .collect(), + }); + } + for (tag_name, entity_names) in &self.entity_map { + entity_tags.push(Tag { + name: tag_name.to_string(), + entries: entity_names + .iter() + .map( + |e| VarInt(generated::EntityKind::from_name(e.name()).unwrap().id() as i32), + ) + .collect(), + }); + } + for (tag_name, fluid_names) in &self.fluid_map { + let mut entries = vec![]; + for entry in fluid_names { + let block = match BlockId::from_identifier(&entry.to_string()) { + Some(s) => s, + None => BlockId::from_identifier(&entry.to_string().replace("flowing_", "")) + .unwrap() + .with_water_level(1), + }; + entries.push(VarInt(block.vanilla_fluid_id().unwrap() as i32)); + } + fluid_tags.push(Tag { + name: tag_name.to_string(), + entries, + }); + } + for (tag_name, item_names) in &self.item_map { + item_tags.push(Tag { + name: tag_name.to_string(), + entries: item_names + .iter() + .map(|e| VarInt(generated::Item::from_name(e.name()).unwrap().id() as i32)) + .collect(), + }); + } + AllTags { + block_tags, + item_tags, + fluid_tags, + entity_tags, + } + } + fn display_helper( map: &AHashMap>, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { @@ -223,10 +297,10 @@ impl TagRegistry { } impl Display for TagRegistry { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Self::k(&self.block_map, f)?; - Self::k(&self.entity_map, f)?; - Self::k(&self.fluid_map, f)?; - Self::k(&self.item_map, f)?; + Self::display_helper(&self.block_map, f)?; + Self::display_helper(&self.entity_map, f)?; + Self::display_helper(&self.fluid_map, f)?; + Self::display_helper(&self.item_map, f)?; Ok(()) } diff --git a/feather/server/Cargo.toml b/feather/server/Cargo.toml index 5a1f45a6e..94495869c 100644 --- a/feather/server/Cargo.toml +++ b/feather/server/Cargo.toml @@ -50,6 +50,7 @@ uuid = "0.8" vec-arena = "1" libcraft-core = { path = "../../libcraft/core" } worldgen = { path = "../worldgen", package = "feather-worldgen" } +datapacks = { path = "../datapacks", package = "feather-datapacks" } [features] default = [ "plugin-cranelift" ] diff --git a/feather/server/src/client.rs b/feather/server/src/client.rs index 96cdee503..edefb9c6e 100644 --- a/feather/server/src/client.rs +++ b/feather/server/src/client.rs @@ -178,7 +178,7 @@ impl Client { self.sent_entities.borrow().contains(&network_id) } - pub fn send_join_game(&self, gamemode: Gamemode) { + pub fn send_join_game(&self, gamemode: Gamemode, game: &common::Game) { log::trace!("Sending Join Game to {}", self.username); // Use the dimension codec sent by the default vanilla server. (Data acquired via tools/proxy) let dimension_codec = nbt::Blob::from_reader(&mut Cursor::new(include_bytes!( @@ -207,6 +207,8 @@ impl Client { is_debug: false, is_flat: false, }); + + self.send_packet(game.tag_registry.all_tags()); } pub fn send_brand(&self) { diff --git a/feather/server/src/main.rs b/feather/server/src/main.rs index 615857028..1853d6a71 100644 --- a/feather/server/src/main.rs +++ b/feather/server/src/main.rs @@ -38,6 +38,7 @@ async fn main() -> anyhow::Result<()> { fn init_game(server: Server, config: &Config) -> anyhow::Result { let mut game = Game::new(); + init_registries(&mut game)?; init_systems(&mut game, server); init_world_source(&mut game, config); init_plugin_manager(&mut game)?; @@ -60,9 +61,7 @@ fn init_systems(game: &mut Game, server: Server) { fn init_world_source(game: &mut Game, config: &Config) { // Load chunks from the world save first, - // and fall back to generating a superflat - // world otherwise. This is a placeholder: - // we don't have proper world generation yet. + // and fall back to generating a world otherwise. let seed = 42; // FIXME: load from the level file @@ -84,6 +83,15 @@ fn init_plugin_manager(game: &mut Game) -> anyhow::Result<()> { Ok(()) } +fn init_registries(game: &mut Game) -> anyhow::Result<()> { + game.tag_registry = datapacks::TagRegistryBuilder::from_dir( + std::path::Path::new("./feather/datapacks/minecraft/data/minecraft/tags"), + "minecraft", + )? + .build()?; + Ok(()) +} + fn print_systems(systems: &SystemExecutor) { let systems: Vec<&str> = systems.system_names().collect(); log::debug!("---SYSTEMS---\n{:#?}\n", systems); diff --git a/feather/server/src/systems/player_join.rs b/feather/server/src/systems/player_join.rs index a6d9d242e..ce6be4f4a 100644 --- a/feather/server/src/systems/player_join.rs +++ b/feather/server/src/systems/player_join.rs @@ -26,7 +26,7 @@ fn poll_new_players(game: &mut Game, server: &mut Server) -> SysResult { fn accept_new_player(game: &mut Game, server: &mut Server, client_id: ClientId) -> SysResult { let client = server.clients.get(client_id).unwrap(); - client.send_join_game(server.options.default_gamemode); + client.send_join_game(server.options.default_gamemode, game); client.send_brand(); let mut builder = game.create_entity_builder(Position::default(), EntityInit::Player); From 508a1e1939dffeb9900403d4ff7fe6ac0dee8c76 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Fri, 27 Aug 2021 17:50:51 +0200 Subject: [PATCH 4/8] Changed error handling and added tracing; Introduced helper types for serialization; Implmented the recipe registry that discards "special" recipes. --- feather/common/src/game.rs | 5 +- feather/datapacks/src/lib.rs | 17 +- feather/datapacks/src/recipe.rs | 364 +++++++++++++++++++++++++ feather/datapacks/src/serde_helpers.rs | 71 +++++ feather/datapacks/src/tag.rs | 56 ++-- feather/server/src/main.rs | 3 + 6 files changed, 492 insertions(+), 24 deletions(-) create mode 100644 feather/datapacks/src/recipe.rs create mode 100644 feather/datapacks/src/serde_helpers.rs diff --git a/feather/common/src/game.rs b/feather/common/src/game.rs index 1e9fbab87..54604e9bc 100644 --- a/feather/common/src/game.rs +++ b/feather/common/src/game.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, mem, rc::Rc, sync::Arc}; use base::{BlockId, BlockPosition, ChunkPosition, Position, Text, Title}; -use datapacks::TagRegistry; +use datapacks::{RecipeRegistry, TagRegistry}; use ecs::{ Ecs, Entity, EntityBuilder, HasEcs, HasResources, NoSuchEntity, Resources, SysResult, SystemExecutor, @@ -57,6 +57,8 @@ pub struct Game { entity_builder: EntityBuilder, pub tag_registry: TagRegistry, + + pub recipe_registry: RecipeRegistry, } impl Default for Game { @@ -78,6 +80,7 @@ impl Game { entity_spawn_callbacks: Vec::new(), entity_builder: EntityBuilder::new(), tag_registry: TagRegistry::new(), + recipe_registry: RecipeRegistry::new(), } } diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs index 143a9ca39..915df7eb0 100644 --- a/feather/datapacks/src/lib.rs +++ b/feather/datapacks/src/lib.rs @@ -16,16 +16,22 @@ use smartstring::{LazyCompact, SmartString}; mod id; pub use id::NamespacedId; +mod serde_helpers; +pub(crate) use serde_helpers::*; + pub mod tag; use tag::LoopError; pub use tag::{TagRegistry, TagRegistryBuilder}; +pub mod recipe; +pub use recipe::RecipeRegistry; + /// The default namespace for resource locations (NamespacedIds). pub const DEFAULT_NAMESPACE: &str = "minecraft"; use thiserror::Error; #[derive(Error, Debug)] -pub enum Error { +pub enum TagLoadError { #[error("invalid namespaced id: {0}")] Parse(#[from] ParseError), #[error(transparent)] @@ -39,6 +45,15 @@ pub enum Error { #[error("json parsing error: {0}")] Json(#[from] serde_json::Error), } +#[derive(Error, Debug)] +pub enum RecipeLoadError { + #[error("invalid namespaced id: {0}")] + Parse(#[from] ParseError), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error("json parsing error: {0}")] + Json(#[from] serde_json::Error), +} /// The pack.mcmeta file at the root of a datapack. /// diff --git a/feather/datapacks/src/recipe.rs b/feather/datapacks/src/recipe.rs new file mode 100644 index 000000000..296295367 --- /dev/null +++ b/feather/datapacks/src/recipe.rs @@ -0,0 +1,364 @@ +use std::{collections::HashMap, fs::File, io::Read, path::Path}; + +use crate::{NamespacedId, SerdeItem, SerdeItemStack, TagRegistry}; +use generated::{Item, ItemStack}; +use serde::{Deserialize, Serialize}; +use smartstring::{Compact, SmartString}; +/// A registry for keeping track of recipes. +#[derive(Clone, Debug, Default)] +pub struct RecipeRegistry { + pub blast: Vec, + pub camp: Vec, + pub shaped: Vec, + pub shapeless: Vec, + pub smelt: Vec, + pub smith: Vec, + pub smoke: Vec, + pub stone: Vec, +} +impl RecipeRegistry { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + pub fn from_dir(path: &Path) -> Result { + let mut this = Self::new(); + this.add_from_dir(path)?; + Ok(this) + } + pub fn add_from_dir(&mut self, path: &Path) -> Result<(), crate::RecipeLoadError> { + for file in std::fs::read_dir(path)? { + let path = file?.path(); + log::trace!("{}", path.to_string_lossy()); + match Recipe::from_file(&path)? { + Recipe::Blasting(recipe) => self.blast.push(recipe), + Recipe::Campfire(recipe) => self.camp.push(recipe), + Recipe::Shaped(recipe) => self.shaped.push(recipe), + Recipe::Shapeless(recipe) => self.shapeless.push(recipe), + Recipe::Smelting(recipe) => self.smelt.push(recipe), + Recipe::Smithing(recipe) => self.smith.push(recipe), + Recipe::Smoking(recipe) => self.smoke.push(recipe), + Recipe::Stonecutting(recipe) => self.stone.push(recipe), + Recipe::Special => {} + } + } + Ok(()) + } + pub fn match_blasting(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + self.blast + .iter() + .find_map(|r| r.match_self(item, tag_registry)) + } + pub fn match_campfire_cooking( + &self, + item: Item, + tag_registry: &TagRegistry, + ) -> Option<(Item, f32)> { + self.camp + .iter() + .find_map(|r| r.match_self(item, tag_registry)) + } + pub fn match_shapeless<'a>( + &self, + items: impl Iterator, + tag_registry: &TagRegistry, + ) -> Option { + let items: Vec = items.copied().collect(); + self.shapeless + .iter() + .find_map(|r| r.match_self(items.iter(), tag_registry)) + } + pub fn match_smelting(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + self.smelt + .iter() + .find_map(|r| r.match_self(item, tag_registry)) + } + pub fn match_smithing( + &self, + base: Item, + addition: Item, + tag_registry: &TagRegistry, + ) -> Option { + self.smith + .iter() + .find_map(|r| r.match_self(base, addition, tag_registry)) + } + pub fn match_smoking(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + self.smoke + .iter() + .find_map(|r| r.match_self(item, tag_registry)) + } + pub fn match_stonecutting(&self, item: Item, tag_registry: &TagRegistry) -> Option { + self.stone + .iter() + .find_map(|r| r.match_self(item, tag_registry)) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum Recipe { + #[serde(rename = "minecraft:blasting")] + Blasting(BlastingRecipe), + #[serde(rename = "minecraft:campfire_cooking")] + Campfire(CampfireRecipe), + #[serde(rename = "minecraft:crafting_shaped")] + Shaped(ShapedRecipe), + #[serde(rename = "minecraft:crafting_shapeless")] + Shapeless(ShapelessRecipe), + #[serde(rename = "minecraft:smelting")] + Smelting(SmeltingRecipe), + #[serde(rename = "minecraft:smithing")] + Smithing(SmithingRecipe), + #[serde(rename = "minecraft:smoking")] + Smoking(SmokingRecipe), + #[serde(rename = "minecraft:stonecutting")] + Stonecutting(StonecuttingRecipe), + #[serde(alias = "minecraft:crafting_special_armordye")] + #[serde(alias = "minecraft:crafting_special_bannerduplicate")] + #[serde(alias = "minecraft:crafting_special_bookcloning")] + #[serde(alias = "minecraft:crafting_special_firework_rocket")] + #[serde(alias = "minecraft:crafting_special_firework_star")] + #[serde(alias = "minecraft:crafting_special_firework_star_fade")] + #[serde(alias = "minecraft:crafting_special_mapcloning")] + #[serde(alias = "minecraft:crafting_special_mapextending")] + #[serde(alias = "minecraft:crafting_special_repairitem")] + #[serde(alias = "minecraft:crafting_special_shielddecoration")] + #[serde(alias = "minecraft:crafting_special_shulkerboxcoloring")] + #[serde(alias = "minecraft:crafting_special_tippedarrow")] + #[serde(alias = "minecraft:crafting_special_suspiciousstew")] + Special, +} +impl Recipe { + pub fn from_file(path: &Path) -> Result { + let mut s = String::new(); + File::open(path)?.read_to_string(&mut s)?; + let k = serde_json::from_str(&s)?; + Ok(k) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +struct Single { + item: Option, + tag: Option, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged)] +enum Ingredient { + One(Single), + Array(Vec), +} +impl Single { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.item + .as_ref() + .map(|s| item.name() == s.name()) + .unwrap_or(false) + | self + .tag + .as_ref() + .map(|s| tag_registry.check_item_tag(item, s)) + .unwrap_or(false) + } +} +impl Ingredient { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + match self { + Ingredient::One(o) => o.matches(item, tag_registry), + Ingredient::Array(vec) => vec.iter().any(|o| o.matches(item, tag_registry)), + } + } +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SmeltingRecipe { + group: Option>, + ingredient: Ingredient, + result: SerdeItem, + experience: f32, + #[serde(default = "default_smelting_time")] + cookingtime: u32, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SmokingRecipe { + group: Option>, + ingredient: Ingredient, + result: SerdeItem, + experience: f32, + #[serde(default = "default_smoking_time")] + cookingtime: u32, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlastingRecipe { + group: Option>, + ingredient: Ingredient, + result: SerdeItem, + experience: f32, + #[serde(default = "default_blasting_time")] + cookingtime: u32, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CampfireRecipe { + group: Option>, + ingredient: Ingredient, + result: SerdeItem, + experience: f32, + #[serde(default = "default_campfire_time")] + cookingtime: u32, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ShapelessRecipe { + group: Option>, + ingredients: Vec, + result: SerdeItemStack, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ShapedRecipe { + group: Option>, + pattern: Vec>, + key: HashMap, Ingredient>, + result: SerdeItemStack, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SmithingRecipe { + group: Option>, + base: Ingredient, + addition: Ingredient, + result: SerdeItemStack, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StonecuttingRecipe { + group: Option>, + ingredient: Ingredient, + result: SerdeItem, + count: u32, +} +impl SmeltingRecipe { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.ingredient.matches(item, tag_registry) + } + pub fn match_self(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + if self.matches(item, tag_registry) { + Some((self.result.into(), self.experience)) + } else { + None + } + } +} +impl SmokingRecipe { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.ingredient.matches(item, tag_registry) + } + pub fn match_self(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + if self.matches(item, tag_registry) { + Some((self.result.into(), self.experience)) + } else { + None + } + } +} +impl BlastingRecipe { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.ingredient.matches(item, tag_registry) + } + pub fn match_self(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + if self.matches(item, tag_registry) { + Some((self.result.into(), self.experience)) + } else { + None + } + } +} +impl CampfireRecipe { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.ingredient.matches(item, tag_registry) + } + pub fn match_self(&self, item: Item, tag_registry: &TagRegistry) -> Option<(Item, f32)> { + if self.matches(item, tag_registry) { + Some((self.result.into(), self.experience)) + } else { + None + } + } +} +impl ShapelessRecipe { + pub fn matches<'a>( + &self, + items: impl Iterator, + tag_registry: &TagRegistry, + ) -> bool { + let mut counter = self.ingredients.clone(); + for i in items { + match counter + .iter() + .enumerate() + .find(|(_, ing)| ing.matches(*i, tag_registry)) + { + Some((index, _)) => { + counter.remove(index); + } + None => return false, + }; + } + true + } + pub fn match_self<'a>( + &self, + items: impl Iterator, + tag_registry: &TagRegistry, + ) -> Option { + if self.matches(items, tag_registry) { + Some(self.result.into()) + } else { + None + } + } +} +impl ShapedRecipe { + // TODO: Decide how to pass the crafting grid +} +impl SmithingRecipe { + pub fn matches(&self, base: Item, addition: Item, tag_registry: &TagRegistry) -> bool { + self.base.matches(base, tag_registry) && self.addition.matches(addition, tag_registry) + } + pub fn match_self( + &self, + base: Item, + addition: Item, + tag_registry: &TagRegistry, + ) -> Option { + if self.matches(base, addition, tag_registry) { + Some(self.result.item.into()) + } else { + None + } + } +} +impl StonecuttingRecipe { + pub fn matches(&self, item: Item, tag_registry: &TagRegistry) -> bool { + self.ingredient.matches(item, tag_registry) + } + pub fn match_self(&self, item: Item, tag_registry: &TagRegistry) -> Option { + if self.matches(item, tag_registry) { + Some(ItemStack { + item: self.result.into(), + count: self.count, + damage: None, + }) + } else { + None + } + } +} +pub fn default_smelting_time() -> u32 { + 200 +} +pub fn default_smoking_time() -> u32 { + 100 +} +pub fn default_blasting_time() -> u32 { + 100 +} +pub fn default_campfire_time() -> u32 { + 100 +} diff --git a/feather/datapacks/src/serde_helpers.rs b/feather/datapacks/src/serde_helpers.rs new file mode 100644 index 000000000..a300396a6 --- /dev/null +++ b/feather/datapacks/src/serde_helpers.rs @@ -0,0 +1,71 @@ +use generated::{Item, ItemStack}; +use serde::{Deserialize, Serialize}; + +pub fn default_count() -> u32 { + 1 +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SerdeItem(Item); + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)] +pub struct SerdeItemStack { + pub item: SerdeItem, + #[serde(default = "default_count")] + pub count: u32, + pub damage: Option, +} +impl From for ItemStack { + fn from(s: SerdeItemStack) -> Self { + Self { + item: s.item.into(), + count: s.count, + damage: s.damage, + } + } +} +impl From for SerdeItemStack { + fn from(s: ItemStack) -> Self { + Self { + item: s.item.into(), + count: s.count, + damage: s.damage, + } + } +} +impl From for Item { + fn from(s: SerdeItem) -> Self { + s.0 + } +} +impl From for SerdeItem { + fn from(s: Item) -> Self { + Self(s) + } +} + +impl Serialize for SerdeItem { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = self.0.name().to_owned(); + s.insert_str(0, "minecraft:"); + s.serialize(serializer) + } +} +impl<'de> Deserialize<'de> for SerdeItem { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let string = String::deserialize(deserializer)?; + Ok(Self( + Item::from_name(match string.strip_prefix("minecraft:") { + Some(s) => s, + None => &string, + }) + .unwrap(), + )) + } +} diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index 3603f8306..77a171ab7 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -32,7 +32,11 @@ impl TagRegistryBuilder { ..Default::default() } } - pub fn add_tags_from_dir(&mut self, dir: &Path, namespace: &str) -> Result<(), crate::Error> { + pub fn add_tags_from_dir( + &mut self, + dir: &Path, + namespace: &str, + ) -> Result<(), crate::TagLoadError> { assert!(dir.is_dir()); let blocks = dir.join("blocks"); let entity_types = dir.join("entity_types"); @@ -52,7 +56,7 @@ impl TagRegistryBuilder { } Ok(()) } - pub fn from_dir(dir: &Path, namespace: &str) -> Result { + pub fn from_dir(dir: &Path, namespace: &str) -> Result { let mut this = Self::new(); this.add_tags_from_dir(dir, namespace)?; Ok(this) @@ -61,13 +65,14 @@ impl TagRegistryBuilder { dir: &Path, map: &mut AHashMap>>, namespace: &str, - ) -> Result<(), crate::Error> { + ) -> Result<(), crate::TagLoadError> { for entry in WalkDir::new(dir).into_iter() { let entry = entry?; let entry = entry.path(); if !entry.is_file() { continue; } + log::trace!("{}", entry.to_string_lossy()); let path_to_file = entry.parent().unwrap(); let file_name = entry.file_stem().unwrap(); let tag_name = std::borrow::Cow::Owned( @@ -85,7 +90,10 @@ impl TagRegistryBuilder { } Ok(()) } - fn fill_set(file: &Path, set: &mut AHashSet>) -> Result<(), crate::Error> { + fn fill_set( + file: &Path, + set: &mut AHashSet>, + ) -> Result<(), crate::TagLoadError> { assert!(file.is_file()); let mut s = String::new(); File::open(file).unwrap().read_to_string(&mut s).unwrap(); @@ -101,7 +109,7 @@ impl TagRegistryBuilder { fn parse( source: &AHashMap>>, target: &mut AHashMap>, - ) -> Result<(), crate::Error> { + ) -> Result<(), crate::TagLoadError> { let mut stack = VecDeque::new(); for tag in source.keys().cloned() { if target.contains_key(&tag) { @@ -116,13 +124,18 @@ impl TagRegistryBuilder { stack: &mut VecDeque, source: &AHashMap>>, target: &mut AHashMap>, - ) -> Result<(), crate::Error> { + ) -> Result<(), crate::TagLoadError> { if stack.contains(&tag) { return Err(LoopError(stack.iter().cloned().collect()).into()); } let set = match source.get(&tag) { Some(s) => s, - None => return Err(crate::Error::InvalidLink(stack.pop_back().unwrap(), tag)), + None => { + return Err(crate::TagLoadError::InvalidLink( + stack.pop_back().unwrap(), + tag, + )) + } }; assert!(target.insert(tag.clone(), Default::default()).is_none()); // Parse all child tags @@ -154,7 +167,7 @@ impl TagRegistryBuilder { Ok(()) } - pub fn build(self) -> Result { + pub fn build(self) -> Result { let mut res = TagRegistry::new(); Self::parse(&self.block_map, &mut res.block_map)?; Self::parse(&self.entity_map, &mut res.entity_map)?; @@ -178,37 +191,36 @@ impl TagRegistry { ..Default::default() } } - pub fn check_block_tag(&self, block: BlockKind, tag: impl Into) -> bool { + pub fn check_block_tag(&self, block: BlockKind, tag: &NamespacedId) -> bool { self.block_map - .get(&tag.into()) + .get(tag) .map(|set| set.get(&NamespacedId::from_str(block.name()).unwrap())) .is_some() } - pub fn check_entity_tag(&self, entity: EntityKind, tag: impl Into) -> bool { + pub fn check_entity_tag(&self, entity: EntityKind, tag: &NamespacedId) -> bool { self.entity_map - .get(&tag.into()) + .get(tag) .map(|set| set.get(&NamespacedId::from_str(entity.name()).unwrap())) .is_some() } - pub fn check_fluid_tag(&self, fluid: impl Borrow, tag: impl Into) -> bool { + pub fn check_fluid_tag(&self, fluid: impl Borrow, tag: &NamespacedId) -> bool { self.fluid_map - .get(&tag.into()) + .get(tag) .map(|set| set.get(&NamespacedId::from_str(fluid.borrow()).unwrap())) .is_some() } - pub fn check_item_tag(&self, item: Item, tag: impl Into) -> bool { + pub fn check_item_tag(&self, item: Item, tag: &NamespacedId) -> bool { self.item_map - .get(&tag.into()) + .get(tag) .map(|set| set.get(&NamespacedId::from_str(item.name()).unwrap())) .is_some() } - pub fn check_for_any_tag(&self, thing: impl Borrow, tag: impl Into) -> bool { + pub fn check_for_any_tag(&self, thing: impl Borrow, tag: &NamespacedId) -> bool { let thing = NamespacedId::from_str(thing.borrow()).unwrap(); - let tag = tag.into(); - self.block_map.get(&tag).map(|s| s.get(&thing)).is_some() - | self.entity_map.get(&tag).map(|s| s.get(&thing)).is_some() - | self.fluid_map.get(&tag).map(|s| s.get(&thing)).is_some() - | self.item_map.get(&tag).map(|s| s.get(&thing)).is_some() + self.block_map.get(tag).map(|s| s.get(&thing)).is_some() + | self.entity_map.get(tag).map(|s| s.get(&thing)).is_some() + | self.fluid_map.get(tag).map(|s| s.get(&thing)).is_some() + | self.item_map.get(tag).map(|s| s.get(&thing)).is_some() } /// Provides an `AllTags` packet for sending to the client. This tag is cached to save some performance. pub fn all_tags(&self) -> AllTags { diff --git a/feather/server/src/main.rs b/feather/server/src/main.rs index 1853d6a71..63eb13e06 100644 --- a/feather/server/src/main.rs +++ b/feather/server/src/main.rs @@ -89,6 +89,9 @@ fn init_registries(game: &mut Game) -> anyhow::Result<()> { "minecraft", )? .build()?; + game.recipe_registry = datapacks::recipe::RecipeRegistry::from_dir(std::path::Path::new( + "./feather/datapacks/minecraft/data/minecraft/recipes", + ))?; Ok(()) } From 3b2915f0976442c8c649c8988ca26991a53ca10d Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Fri, 27 Aug 2021 19:11:26 +0200 Subject: [PATCH 5/8] Made the vanilla tag enums public --- feather/datapacks/src/lib.rs | 2 ++ feather/datapacks/src/tag.rs | 2 ++ feather/datapacks/src/vanilla_tags.rs | 1 + feather/datapacks/tags.py | 1 + 4 files changed, 6 insertions(+) diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs index 915df7eb0..ce5cbe93c 100644 --- a/feather/datapacks/src/lib.rs +++ b/feather/datapacks/src/lib.rs @@ -23,6 +23,8 @@ pub mod tag; use tag::LoopError; pub use tag::{TagRegistry, TagRegistryBuilder}; +mod vanilla_tags; + pub mod recipe; pub use recipe::RecipeRegistry; diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index 77a171ab7..a6882aa30 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -15,6 +15,8 @@ use serde::Deserialize; use smartstring::{Compact, SmartString}; use thiserror::Error; use walkdir::WalkDir; + +pub use crate::vanilla_tags::*; /// The tag registry builder's purpose is to serve as a stepping stone to construct the full tag registry. /// Once all datapacks are loaded, the builder resolves all tag "symlinks". /// An example of this behaviour is the tag `#minecraft:fences`, which includes `minecraft:nether_brick_fence` and `#minecraft:wooden_fences`. diff --git a/feather/datapacks/src/vanilla_tags.rs b/feather/datapacks/src/vanilla_tags.rs index b4d74186c..79ca90ef0 100644 --- a/feather/datapacks/src/vanilla_tags.rs +++ b/feather/datapacks/src/vanilla_tags.rs @@ -1,3 +1,4 @@ +use std::str::FromStr; #[derive(Copy,Clone,Debug,PartialEq,Eq)] pub enum VanillaBlockTags { AcaciaLogs, diff --git a/feather/datapacks/tags.py b/feather/datapacks/tags.py index e8a2bef2a..a1a1842a6 100644 --- a/feather/datapacks/tags.py +++ b/feather/datapacks/tags.py @@ -9,6 +9,7 @@ f = open("src/vanilla_tags.rs", "w") new_line = "\n" quotes = "\"" +f.write("use std::str::FromStr;\n") for (tags, enum_name) in zip(tag_list_list, enum_names): f.write("#[derive(Copy,Clone,Debug,PartialEq,Eq)]\n") f.write(f"pub enum {enum_name} {{{new_line}") From e4cb67682a5a24ab7a3edafd170f46c0dbc25982 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Fri, 27 Aug 2021 19:16:33 +0200 Subject: [PATCH 6/8] Stop generator from conflicting with cargo fmt --- feather/datapacks/src/vanilla_tags.rs | 596 +++++++++++++------------- feather/datapacks/tags.py | 6 +- 2 files changed, 301 insertions(+), 301 deletions(-) diff --git a/feather/datapacks/src/vanilla_tags.rs b/feather/datapacks/src/vanilla_tags.rs index 79ca90ef0..dd82d5248 100644 --- a/feather/datapacks/src/vanilla_tags.rs +++ b/feather/datapacks/src/vanilla_tags.rs @@ -1,256 +1,256 @@ use std::str::FromStr; -#[derive(Copy,Clone,Debug,PartialEq,Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VanillaBlockTags { - AcaciaLogs, - Anvil, - BambooPlantableOn, - Banners, - BaseStoneNether, - BaseStoneOverworld, - BeaconBaseBlocks, - Beds, - Beehives, - BeeGrowables, - BirchLogs, - Buttons, - Campfires, - Carpets, - Climbable, - Corals, - CoralBlocks, - CoralPlants, - CrimsonStems, - Crops, - DarkOakLogs, - Doors, - DragonImmune, - EndermanHoldable, - Fences, - FenceGates, - Fire, - Flowers, - FlowerPots, - GoldOres, - GuardedByPiglins, - HoglinRepellents, - Ice, - Impermeable, - InfiniburnEnd, - InfiniburnNether, - InfiniburnOverworld, - JungleLogs, - Leaves, - Logs, - LogsThatBurn, - MushroomGrowBlock, - NonFlammableWood, - Nylium, - OakLogs, - PiglinRepellents, - Planks, - Portals, - PressurePlates, - PreventMobSpawningInside, - Rails, - Sand, - Saplings, - ShulkerBoxes, - Signs, - Slabs, - SmallFlowers, - SoulFireBaseBlocks, - SoulSpeedBlocks, - SpruceLogs, - Stairs, - StandingSigns, - StoneBricks, - StonePressurePlates, - StriderWarmBlocks, - TallFlowers, - Trapdoors, - UnderwaterBonemeals, - UnstableBottomCenter, - ValidSpawn, - Walls, - WallCorals, - WallPostOverride, - WallSigns, - WarpedStems, - WartBlocks, - WitherImmune, - WitherSummonBaseBlocks, - WoodenButtons, - WoodenDoors, - WoodenFences, - WoodenPressurePlates, - WoodenSlabs, - WoodenStairs, - WoodenTrapdoors, - Wool, + AcaciaLogs, + Anvil, + BambooPlantableOn, + Banners, + BaseStoneNether, + BaseStoneOverworld, + BeaconBaseBlocks, + Beds, + Beehives, + BeeGrowables, + BirchLogs, + Buttons, + Campfires, + Carpets, + Climbable, + Corals, + CoralBlocks, + CoralPlants, + CrimsonStems, + Crops, + DarkOakLogs, + Doors, + DragonImmune, + EndermanHoldable, + Fences, + FenceGates, + Fire, + Flowers, + FlowerPots, + GoldOres, + GuardedByPiglins, + HoglinRepellents, + Ice, + Impermeable, + InfiniburnEnd, + InfiniburnNether, + InfiniburnOverworld, + JungleLogs, + Leaves, + Logs, + LogsThatBurn, + MushroomGrowBlock, + NonFlammableWood, + Nylium, + OakLogs, + PiglinRepellents, + Planks, + Portals, + PressurePlates, + PreventMobSpawningInside, + Rails, + Sand, + Saplings, + ShulkerBoxes, + Signs, + Slabs, + SmallFlowers, + SoulFireBaseBlocks, + SoulSpeedBlocks, + SpruceLogs, + Stairs, + StandingSigns, + StoneBricks, + StonePressurePlates, + StriderWarmBlocks, + TallFlowers, + Trapdoors, + UnderwaterBonemeals, + UnstableBottomCenter, + ValidSpawn, + Walls, + WallCorals, + WallPostOverride, + WallSigns, + WarpedStems, + WartBlocks, + WitherImmune, + WitherSummonBaseBlocks, + WoodenButtons, + WoodenDoors, + WoodenFences, + WoodenPressurePlates, + WoodenSlabs, + WoodenStairs, + WoodenTrapdoors, + Wool, } -#[derive(Copy,Clone,Debug,PartialEq,Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VanillaEntityTypes { - Arrows, - BeehiveInhabitors, - ImpactProjectiles, - Raiders, - Skeletons, + Arrows, + BeehiveInhabitors, + ImpactProjectiles, + Raiders, + Skeletons, } -#[derive(Copy,Clone,Debug,PartialEq,Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VanillaFluidTags { - Lava, - Water, + Lava, + Water, } -#[derive(Copy,Clone,Debug,PartialEq,Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VanillaItemTags { - AcaciaLogs, - Anvil, - Arrows, - Banners, - BeaconPaymentItems, - Beds, - BirchLogs, - Boats, - Buttons, - Carpets, - Coals, - CreeperDropMusicDiscs, - CrimsonStems, - DarkOakLogs, - Doors, - Fences, - Fishes, - Flowers, - GoldOres, - JungleLogs, - Leaves, - LecternBooks, - Logs, - LogsThatBurn, - MusicDiscs, - NonFlammableWood, - OakLogs, - PiglinLoved, - PiglinRepellents, - Planks, - Rails, - Sand, - Saplings, - Signs, - Slabs, - SmallFlowers, - SoulFireBaseBlocks, - SpruceLogs, - Stairs, - StoneBricks, - StoneCraftingMaterials, - StoneToolMaterials, - TallFlowers, - Trapdoors, - Walls, - WarpedStems, - WoodenButtons, - WoodenDoors, - WoodenFences, - WoodenPressurePlates, - WoodenSlabs, - WoodenStairs, - WoodenTrapdoors, - Wool, + AcaciaLogs, + Anvil, + Arrows, + Banners, + BeaconPaymentItems, + Beds, + BirchLogs, + Boats, + Buttons, + Carpets, + Coals, + CreeperDropMusicDiscs, + CrimsonStems, + DarkOakLogs, + Doors, + Fences, + Fishes, + Flowers, + GoldOres, + JungleLogs, + Leaves, + LecternBooks, + Logs, + LogsThatBurn, + MusicDiscs, + NonFlammableWood, + OakLogs, + PiglinLoved, + PiglinRepellents, + Planks, + Rails, + Sand, + Saplings, + Signs, + Slabs, + SmallFlowers, + SoulFireBaseBlocks, + SpruceLogs, + Stairs, + StoneBricks, + StoneCraftingMaterials, + StoneToolMaterials, + TallFlowers, + Trapdoors, + Walls, + WarpedStems, + WoodenButtons, + WoodenDoors, + WoodenFences, + WoodenPressurePlates, + WoodenSlabs, + WoodenStairs, + WoodenTrapdoors, + Wool, } impl VanillaBlockTags { pub fn name(&self) -> &'static str { match self { - VanillaBlockTags::AcaciaLogs => "acacia_logs", - VanillaBlockTags::Anvil => "anvil", - VanillaBlockTags::BambooPlantableOn => "bamboo_plantable_on", - VanillaBlockTags::Banners => "banners", - VanillaBlockTags::BaseStoneNether => "base_stone_nether", - VanillaBlockTags::BaseStoneOverworld => "base_stone_overworld", - VanillaBlockTags::BeaconBaseBlocks => "beacon_base_blocks", - VanillaBlockTags::Beds => "beds", - VanillaBlockTags::Beehives => "beehives", - VanillaBlockTags::BeeGrowables => "bee_growables", - VanillaBlockTags::BirchLogs => "birch_logs", - VanillaBlockTags::Buttons => "buttons", - VanillaBlockTags::Campfires => "campfires", - VanillaBlockTags::Carpets => "carpets", - VanillaBlockTags::Climbable => "climbable", - VanillaBlockTags::Corals => "corals", - VanillaBlockTags::CoralBlocks => "coral_blocks", - VanillaBlockTags::CoralPlants => "coral_plants", - VanillaBlockTags::CrimsonStems => "crimson_stems", - VanillaBlockTags::Crops => "crops", - VanillaBlockTags::DarkOakLogs => "dark_oak_logs", - VanillaBlockTags::Doors => "doors", - VanillaBlockTags::DragonImmune => "dragon_immune", - VanillaBlockTags::EndermanHoldable => "enderman_holdable", - VanillaBlockTags::Fences => "fences", - VanillaBlockTags::FenceGates => "fence_gates", - VanillaBlockTags::Fire => "fire", - VanillaBlockTags::Flowers => "flowers", - VanillaBlockTags::FlowerPots => "flower_pots", - VanillaBlockTags::GoldOres => "gold_ores", - VanillaBlockTags::GuardedByPiglins => "guarded_by_piglins", - VanillaBlockTags::HoglinRepellents => "hoglin_repellents", - VanillaBlockTags::Ice => "ice", - VanillaBlockTags::Impermeable => "impermeable", - VanillaBlockTags::InfiniburnEnd => "infiniburn_end", - VanillaBlockTags::InfiniburnNether => "infiniburn_nether", - VanillaBlockTags::InfiniburnOverworld => "infiniburn_overworld", - VanillaBlockTags::JungleLogs => "jungle_logs", - VanillaBlockTags::Leaves => "leaves", - VanillaBlockTags::Logs => "logs", - VanillaBlockTags::LogsThatBurn => "logs_that_burn", - VanillaBlockTags::MushroomGrowBlock => "mushroom_grow_block", - VanillaBlockTags::NonFlammableWood => "non_flammable_wood", - VanillaBlockTags::Nylium => "nylium", - VanillaBlockTags::OakLogs => "oak_logs", - VanillaBlockTags::PiglinRepellents => "piglin_repellents", - VanillaBlockTags::Planks => "planks", - VanillaBlockTags::Portals => "portals", - VanillaBlockTags::PressurePlates => "pressure_plates", - VanillaBlockTags::PreventMobSpawningInside => "prevent_mob_spawning_inside", - VanillaBlockTags::Rails => "rails", - VanillaBlockTags::Sand => "sand", - VanillaBlockTags::Saplings => "saplings", - VanillaBlockTags::ShulkerBoxes => "shulker_boxes", - VanillaBlockTags::Signs => "signs", - VanillaBlockTags::Slabs => "slabs", - VanillaBlockTags::SmallFlowers => "small_flowers", - VanillaBlockTags::SoulFireBaseBlocks => "soul_fire_base_blocks", - VanillaBlockTags::SoulSpeedBlocks => "soul_speed_blocks", - VanillaBlockTags::SpruceLogs => "spruce_logs", - VanillaBlockTags::Stairs => "stairs", - VanillaBlockTags::StandingSigns => "standing_signs", - VanillaBlockTags::StoneBricks => "stone_bricks", - VanillaBlockTags::StonePressurePlates => "stone_pressure_plates", - VanillaBlockTags::StriderWarmBlocks => "strider_warm_blocks", - VanillaBlockTags::TallFlowers => "tall_flowers", - VanillaBlockTags::Trapdoors => "trapdoors", - VanillaBlockTags::UnderwaterBonemeals => "underwater_bonemeals", - VanillaBlockTags::UnstableBottomCenter => "unstable_bottom_center", - VanillaBlockTags::ValidSpawn => "valid_spawn", - VanillaBlockTags::Walls => "walls", - VanillaBlockTags::WallCorals => "wall_corals", - VanillaBlockTags::WallPostOverride => "wall_post_override", - VanillaBlockTags::WallSigns => "wall_signs", - VanillaBlockTags::WarpedStems => "warped_stems", - VanillaBlockTags::WartBlocks => "wart_blocks", - VanillaBlockTags::WitherImmune => "wither_immune", - VanillaBlockTags::WitherSummonBaseBlocks => "wither_summon_base_blocks", - VanillaBlockTags::WoodenButtons => "wooden_buttons", - VanillaBlockTags::WoodenDoors => "wooden_doors", - VanillaBlockTags::WoodenFences => "wooden_fences", - VanillaBlockTags::WoodenPressurePlates => "wooden_pressure_plates", - VanillaBlockTags::WoodenSlabs => "wooden_slabs", - VanillaBlockTags::WoodenStairs => "wooden_stairs", - VanillaBlockTags::WoodenTrapdoors => "wooden_trapdoors", - VanillaBlockTags::Wool => "wool", + VanillaBlockTags::AcaciaLogs => "acacia_logs", + VanillaBlockTags::Anvil => "anvil", + VanillaBlockTags::BambooPlantableOn => "bamboo_plantable_on", + VanillaBlockTags::Banners => "banners", + VanillaBlockTags::BaseStoneNether => "base_stone_nether", + VanillaBlockTags::BaseStoneOverworld => "base_stone_overworld", + VanillaBlockTags::BeaconBaseBlocks => "beacon_base_blocks", + VanillaBlockTags::Beds => "beds", + VanillaBlockTags::Beehives => "beehives", + VanillaBlockTags::BeeGrowables => "bee_growables", + VanillaBlockTags::BirchLogs => "birch_logs", + VanillaBlockTags::Buttons => "buttons", + VanillaBlockTags::Campfires => "campfires", + VanillaBlockTags::Carpets => "carpets", + VanillaBlockTags::Climbable => "climbable", + VanillaBlockTags::Corals => "corals", + VanillaBlockTags::CoralBlocks => "coral_blocks", + VanillaBlockTags::CoralPlants => "coral_plants", + VanillaBlockTags::CrimsonStems => "crimson_stems", + VanillaBlockTags::Crops => "crops", + VanillaBlockTags::DarkOakLogs => "dark_oak_logs", + VanillaBlockTags::Doors => "doors", + VanillaBlockTags::DragonImmune => "dragon_immune", + VanillaBlockTags::EndermanHoldable => "enderman_holdable", + VanillaBlockTags::Fences => "fences", + VanillaBlockTags::FenceGates => "fence_gates", + VanillaBlockTags::Fire => "fire", + VanillaBlockTags::Flowers => "flowers", + VanillaBlockTags::FlowerPots => "flower_pots", + VanillaBlockTags::GoldOres => "gold_ores", + VanillaBlockTags::GuardedByPiglins => "guarded_by_piglins", + VanillaBlockTags::HoglinRepellents => "hoglin_repellents", + VanillaBlockTags::Ice => "ice", + VanillaBlockTags::Impermeable => "impermeable", + VanillaBlockTags::InfiniburnEnd => "infiniburn_end", + VanillaBlockTags::InfiniburnNether => "infiniburn_nether", + VanillaBlockTags::InfiniburnOverworld => "infiniburn_overworld", + VanillaBlockTags::JungleLogs => "jungle_logs", + VanillaBlockTags::Leaves => "leaves", + VanillaBlockTags::Logs => "logs", + VanillaBlockTags::LogsThatBurn => "logs_that_burn", + VanillaBlockTags::MushroomGrowBlock => "mushroom_grow_block", + VanillaBlockTags::NonFlammableWood => "non_flammable_wood", + VanillaBlockTags::Nylium => "nylium", + VanillaBlockTags::OakLogs => "oak_logs", + VanillaBlockTags::PiglinRepellents => "piglin_repellents", + VanillaBlockTags::Planks => "planks", + VanillaBlockTags::Portals => "portals", + VanillaBlockTags::PressurePlates => "pressure_plates", + VanillaBlockTags::PreventMobSpawningInside => "prevent_mob_spawning_inside", + VanillaBlockTags::Rails => "rails", + VanillaBlockTags::Sand => "sand", + VanillaBlockTags::Saplings => "saplings", + VanillaBlockTags::ShulkerBoxes => "shulker_boxes", + VanillaBlockTags::Signs => "signs", + VanillaBlockTags::Slabs => "slabs", + VanillaBlockTags::SmallFlowers => "small_flowers", + VanillaBlockTags::SoulFireBaseBlocks => "soul_fire_base_blocks", + VanillaBlockTags::SoulSpeedBlocks => "soul_speed_blocks", + VanillaBlockTags::SpruceLogs => "spruce_logs", + VanillaBlockTags::Stairs => "stairs", + VanillaBlockTags::StandingSigns => "standing_signs", + VanillaBlockTags::StoneBricks => "stone_bricks", + VanillaBlockTags::StonePressurePlates => "stone_pressure_plates", + VanillaBlockTags::StriderWarmBlocks => "strider_warm_blocks", + VanillaBlockTags::TallFlowers => "tall_flowers", + VanillaBlockTags::Trapdoors => "trapdoors", + VanillaBlockTags::UnderwaterBonemeals => "underwater_bonemeals", + VanillaBlockTags::UnstableBottomCenter => "unstable_bottom_center", + VanillaBlockTags::ValidSpawn => "valid_spawn", + VanillaBlockTags::Walls => "walls", + VanillaBlockTags::WallCorals => "wall_corals", + VanillaBlockTags::WallPostOverride => "wall_post_override", + VanillaBlockTags::WallSigns => "wall_signs", + VanillaBlockTags::WarpedStems => "warped_stems", + VanillaBlockTags::WartBlocks => "wart_blocks", + VanillaBlockTags::WitherImmune => "wither_immune", + VanillaBlockTags::WitherSummonBaseBlocks => "wither_summon_base_blocks", + VanillaBlockTags::WoodenButtons => "wooden_buttons", + VanillaBlockTags::WoodenDoors => "wooden_doors", + VanillaBlockTags::WoodenFences => "wooden_fences", + VanillaBlockTags::WoodenPressurePlates => "wooden_pressure_plates", + VanillaBlockTags::WoodenSlabs => "wooden_slabs", + VanillaBlockTags::WoodenStairs => "wooden_stairs", + VanillaBlockTags::WoodenTrapdoors => "wooden_trapdoors", + VanillaBlockTags::Wool => "wool", } } pub fn namespaced_name(&self) -> crate::NamespacedId { @@ -270,11 +270,11 @@ impl From for crate::NamespacedId { impl VanillaEntityTypes { pub fn name(&self) -> &'static str { match self { - VanillaEntityTypes::Arrows => "arrows", - VanillaEntityTypes::BeehiveInhabitors => "beehive_inhabitors", - VanillaEntityTypes::ImpactProjectiles => "impact_projectiles", - VanillaEntityTypes::Raiders => "raiders", - VanillaEntityTypes::Skeletons => "skeletons", + VanillaEntityTypes::Arrows => "arrows", + VanillaEntityTypes::BeehiveInhabitors => "beehive_inhabitors", + VanillaEntityTypes::ImpactProjectiles => "impact_projectiles", + VanillaEntityTypes::Raiders => "raiders", + VanillaEntityTypes::Skeletons => "skeletons", } } pub fn namespaced_name(&self) -> crate::NamespacedId { @@ -294,8 +294,8 @@ impl From for crate::NamespacedId { impl VanillaFluidTags { pub fn name(&self) -> &'static str { match self { - VanillaFluidTags::Lava => "lava", - VanillaFluidTags::Water => "water", + VanillaFluidTags::Lava => "lava", + VanillaFluidTags::Water => "water", } } pub fn namespaced_name(&self) -> crate::NamespacedId { @@ -315,60 +315,60 @@ impl From for crate::NamespacedId { impl VanillaItemTags { pub fn name(&self) -> &'static str { match self { - VanillaItemTags::AcaciaLogs => "acacia_logs", - VanillaItemTags::Anvil => "anvil", - VanillaItemTags::Arrows => "arrows", - VanillaItemTags::Banners => "banners", - VanillaItemTags::BeaconPaymentItems => "beacon_payment_items", - VanillaItemTags::Beds => "beds", - VanillaItemTags::BirchLogs => "birch_logs", - VanillaItemTags::Boats => "boats", - VanillaItemTags::Buttons => "buttons", - VanillaItemTags::Carpets => "carpets", - VanillaItemTags::Coals => "coals", - VanillaItemTags::CreeperDropMusicDiscs => "creeper_drop_music_discs", - VanillaItemTags::CrimsonStems => "crimson_stems", - VanillaItemTags::DarkOakLogs => "dark_oak_logs", - VanillaItemTags::Doors => "doors", - VanillaItemTags::Fences => "fences", - VanillaItemTags::Fishes => "fishes", - VanillaItemTags::Flowers => "flowers", - VanillaItemTags::GoldOres => "gold_ores", - VanillaItemTags::JungleLogs => "jungle_logs", - VanillaItemTags::Leaves => "leaves", - VanillaItemTags::LecternBooks => "lectern_books", - VanillaItemTags::Logs => "logs", - VanillaItemTags::LogsThatBurn => "logs_that_burn", - VanillaItemTags::MusicDiscs => "music_discs", - VanillaItemTags::NonFlammableWood => "non_flammable_wood", - VanillaItemTags::OakLogs => "oak_logs", - VanillaItemTags::PiglinLoved => "piglin_loved", - VanillaItemTags::PiglinRepellents => "piglin_repellents", - VanillaItemTags::Planks => "planks", - VanillaItemTags::Rails => "rails", - VanillaItemTags::Sand => "sand", - VanillaItemTags::Saplings => "saplings", - VanillaItemTags::Signs => "signs", - VanillaItemTags::Slabs => "slabs", - VanillaItemTags::SmallFlowers => "small_flowers", - VanillaItemTags::SoulFireBaseBlocks => "soul_fire_base_blocks", - VanillaItemTags::SpruceLogs => "spruce_logs", - VanillaItemTags::Stairs => "stairs", - VanillaItemTags::StoneBricks => "stone_bricks", - VanillaItemTags::StoneCraftingMaterials => "stone_crafting_materials", - VanillaItemTags::StoneToolMaterials => "stone_tool_materials", - VanillaItemTags::TallFlowers => "tall_flowers", - VanillaItemTags::Trapdoors => "trapdoors", - VanillaItemTags::Walls => "walls", - VanillaItemTags::WarpedStems => "warped_stems", - VanillaItemTags::WoodenButtons => "wooden_buttons", - VanillaItemTags::WoodenDoors => "wooden_doors", - VanillaItemTags::WoodenFences => "wooden_fences", - VanillaItemTags::WoodenPressurePlates => "wooden_pressure_plates", - VanillaItemTags::WoodenSlabs => "wooden_slabs", - VanillaItemTags::WoodenStairs => "wooden_stairs", - VanillaItemTags::WoodenTrapdoors => "wooden_trapdoors", - VanillaItemTags::Wool => "wool", + VanillaItemTags::AcaciaLogs => "acacia_logs", + VanillaItemTags::Anvil => "anvil", + VanillaItemTags::Arrows => "arrows", + VanillaItemTags::Banners => "banners", + VanillaItemTags::BeaconPaymentItems => "beacon_payment_items", + VanillaItemTags::Beds => "beds", + VanillaItemTags::BirchLogs => "birch_logs", + VanillaItemTags::Boats => "boats", + VanillaItemTags::Buttons => "buttons", + VanillaItemTags::Carpets => "carpets", + VanillaItemTags::Coals => "coals", + VanillaItemTags::CreeperDropMusicDiscs => "creeper_drop_music_discs", + VanillaItemTags::CrimsonStems => "crimson_stems", + VanillaItemTags::DarkOakLogs => "dark_oak_logs", + VanillaItemTags::Doors => "doors", + VanillaItemTags::Fences => "fences", + VanillaItemTags::Fishes => "fishes", + VanillaItemTags::Flowers => "flowers", + VanillaItemTags::GoldOres => "gold_ores", + VanillaItemTags::JungleLogs => "jungle_logs", + VanillaItemTags::Leaves => "leaves", + VanillaItemTags::LecternBooks => "lectern_books", + VanillaItemTags::Logs => "logs", + VanillaItemTags::LogsThatBurn => "logs_that_burn", + VanillaItemTags::MusicDiscs => "music_discs", + VanillaItemTags::NonFlammableWood => "non_flammable_wood", + VanillaItemTags::OakLogs => "oak_logs", + VanillaItemTags::PiglinLoved => "piglin_loved", + VanillaItemTags::PiglinRepellents => "piglin_repellents", + VanillaItemTags::Planks => "planks", + VanillaItemTags::Rails => "rails", + VanillaItemTags::Sand => "sand", + VanillaItemTags::Saplings => "saplings", + VanillaItemTags::Signs => "signs", + VanillaItemTags::Slabs => "slabs", + VanillaItemTags::SmallFlowers => "small_flowers", + VanillaItemTags::SoulFireBaseBlocks => "soul_fire_base_blocks", + VanillaItemTags::SpruceLogs => "spruce_logs", + VanillaItemTags::Stairs => "stairs", + VanillaItemTags::StoneBricks => "stone_bricks", + VanillaItemTags::StoneCraftingMaterials => "stone_crafting_materials", + VanillaItemTags::StoneToolMaterials => "stone_tool_materials", + VanillaItemTags::TallFlowers => "tall_flowers", + VanillaItemTags::Trapdoors => "trapdoors", + VanillaItemTags::Walls => "walls", + VanillaItemTags::WarpedStems => "warped_stems", + VanillaItemTags::WoodenButtons => "wooden_buttons", + VanillaItemTags::WoodenDoors => "wooden_doors", + VanillaItemTags::WoodenFences => "wooden_fences", + VanillaItemTags::WoodenPressurePlates => "wooden_pressure_plates", + VanillaItemTags::WoodenSlabs => "wooden_slabs", + VanillaItemTags::WoodenStairs => "wooden_stairs", + VanillaItemTags::WoodenTrapdoors => "wooden_trapdoors", + VanillaItemTags::Wool => "wool", } } pub fn namespaced_name(&self) -> crate::NamespacedId { diff --git a/feather/datapacks/tags.py b/feather/datapacks/tags.py index a1a1842a6..2e7fb8ed4 100644 --- a/feather/datapacks/tags.py +++ b/feather/datapacks/tags.py @@ -11,11 +11,11 @@ quotes = "\"" f.write("use std::str::FromStr;\n") for (tags, enum_name) in zip(tag_list_list, enum_names): - f.write("#[derive(Copy,Clone,Debug,PartialEq,Eq)]\n") + f.write("#[derive(Copy, Clone, Debug, PartialEq, Eq)]\n") f.write(f"pub enum {enum_name} {{{new_line}") for s in tags: camelcase = ''.join(map(str.title, s[:-5].split('_'))) - f.write(f" {camelcase}, {new_line}") + f.write(f" {camelcase},{new_line}") f.write(f"}}{new_line}{new_line}") for (tags, enum_name) in zip(tag_list_list, enum_names): f.write(f"impl {enum_name} {{{new_line}") @@ -24,7 +24,7 @@ for s in tags: snakecase = s[:-5] camelcase = ''.join(map(str.title, snakecase.split('_'))) - f.write(f" {enum_name}::{camelcase} => {quotes}{snakecase}{quotes}, {new_line}") + f.write(f" {enum_name}::{camelcase} => {quotes}{snakecase}{quotes},{new_line}") f.write(" }\n }\n") f.write(" pub fn namespaced_name(&self) -> crate::NamespacedId {\n") f.write(" crate::NamespacedId::from_str(self.name()).unwrap()\n") From 042443908fb3145a5cbece7eb9c4f67cc81c3c6a Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Fri, 27 Aug 2021 19:43:46 +0200 Subject: [PATCH 7/8] Into --- feather/datapacks/src/tag.rs | 48 +++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index a6882aa30..d1b6a42da 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -193,36 +193,56 @@ impl TagRegistry { ..Default::default() } } - pub fn check_block_tag(&self, block: BlockKind, tag: &NamespacedId) -> bool { + pub fn check_block_tag(&self, block: BlockKind, tag: &T) -> bool + where + T: Into + Clone, + { self.block_map - .get(tag) + .get(&tag.clone().into()) .map(|set| set.get(&NamespacedId::from_str(block.name()).unwrap())) + .flatten() .is_some() } - pub fn check_entity_tag(&self, entity: EntityKind, tag: &NamespacedId) -> bool { + pub fn check_entity_tag(&self, entity: EntityKind, tag: &T) -> bool + where + T: Into + Clone, + { self.entity_map - .get(tag) + .get(&tag.clone().into()) .map(|set| set.get(&NamespacedId::from_str(entity.name()).unwrap())) + .flatten() .is_some() } - pub fn check_fluid_tag(&self, fluid: impl Borrow, tag: &NamespacedId) -> bool { + pub fn check_fluid_tag(&self, fluid: BlockKind, tag: &T) -> bool + where + T: Into + Clone, + { self.fluid_map - .get(tag) - .map(|set| set.get(&NamespacedId::from_str(fluid.borrow()).unwrap())) + .get(&tag.clone().into()) + .map(|set| set.get(&NamespacedId::from_str(fluid.name()).unwrap())) + .flatten() .is_some() } - pub fn check_item_tag(&self, item: Item, tag: &NamespacedId) -> bool { + pub fn check_item_tag(&self, item: Item, tag: &T) -> bool + where + T: Into + Clone, + { self.item_map - .get(tag) + .get(&tag.clone().into()) .map(|set| set.get(&NamespacedId::from_str(item.name()).unwrap())) + .flatten() .is_some() } - pub fn check_for_any_tag(&self, thing: impl Borrow, tag: &NamespacedId) -> bool { + pub fn check_for_any_tag(&self, thing: impl Borrow, tag: &T) -> bool + where + T: Into + Clone, + { let thing = NamespacedId::from_str(thing.borrow()).unwrap(); - self.block_map.get(tag).map(|s| s.get(&thing)).is_some() - | self.entity_map.get(tag).map(|s| s.get(&thing)).is_some() - | self.fluid_map.get(tag).map(|s| s.get(&thing)).is_some() - | self.item_map.get(tag).map(|s| s.get(&thing)).is_some() + let tag = tag.clone().into(); + self.block_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.entity_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.fluid_map.get(&tag).map(|s| s.get(&thing)).is_some() + | self.item_map.get(&tag).map(|s| s.get(&thing)).is_some() } /// Provides an `AllTags` packet for sending to the client. This tag is cached to save some performance. pub fn all_tags(&self) -> AllTags { From 92d8e3afe65cf336b0be1727240a1f7eb4a3cc01 Mon Sep 17 00:00:00 2001 From: koskja <87826472+koskja@users.noreply.github.com> Date: Mon, 6 Sep 2021 19:38:14 +0200 Subject: [PATCH 8/8] Moved tags generator to feather-generated --- feather/datapacks/src/lib.rs | 2 - feather/datapacks/src/tag.rs | 22 +++++++++- feather/datapacks/tags.py | 42 ------------------- feather/generated/generators/tags.py | 33 +++++++++++++++ feather/generated/src/lib.rs | 2 + .../src/vanilla_tags.rs | 34 +-------------- 6 files changed, 57 insertions(+), 78 deletions(-) delete mode 100644 feather/datapacks/tags.py create mode 100644 feather/generated/generators/tags.py rename feather/{datapacks => generated}/src/vanilla_tags.rs (92%) diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs index ce5cbe93c..915df7eb0 100644 --- a/feather/datapacks/src/lib.rs +++ b/feather/datapacks/src/lib.rs @@ -23,8 +23,6 @@ pub mod tag; use tag::LoopError; pub use tag::{TagRegistry, TagRegistryBuilder}; -mod vanilla_tags; - pub mod recipe; pub use recipe::RecipeRegistry; diff --git a/feather/datapacks/src/tag.rs b/feather/datapacks/src/tag.rs index d1b6a42da..6f4800208 100644 --- a/feather/datapacks/src/tag.rs +++ b/feather/datapacks/src/tag.rs @@ -16,7 +16,7 @@ use smartstring::{Compact, SmartString}; use thiserror::Error; use walkdir::WalkDir; -pub use crate::vanilla_tags::*; +pub use generated::vanilla_tags::*; /// The tag registry builder's purpose is to serve as a stepping stone to construct the full tag registry. /// Once all datapacks are loaded, the builder resolves all tag "symlinks". /// An example of this behaviour is the tag `#minecraft:fences`, which includes `minecraft:nether_brick_fence` and `#minecraft:wooden_fences`. @@ -354,3 +354,23 @@ impl Display for LoopError { Ok(()) } } +impl From for crate::NamespacedId { + fn from(tag: VanillaBlockTags) -> Self { + NamespacedId::from_str(tag.name()).unwrap() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaEntityTypes) -> Self { + NamespacedId::from_str(tag.name()).unwrap() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaFluidTags) -> Self { + NamespacedId::from_str(tag.name()).unwrap() + } +} +impl From for crate::NamespacedId { + fn from(tag: VanillaItemTags) -> Self { + NamespacedId::from_str(tag.name()).unwrap() + } +} diff --git a/feather/datapacks/tags.py b/feather/datapacks/tags.py deleted file mode 100644 index 2e7fb8ed4..000000000 --- a/feather/datapacks/tags.py +++ /dev/null @@ -1,42 +0,0 @@ -from os import listdir -prefix = "minecraft/data/minecraft/tags/" -block_tags = listdir(prefix + "blocks") -entity_types = listdir(prefix + "entity_types") -fluid_tags = listdir(prefix + "fluids") -item_tags = listdir(prefix + "items") -tag_list_list = (block_tags, entity_types, fluid_tags, item_tags) -enum_names = ("VanillaBlockTags", "VanillaEntityTypes", "VanillaFluidTags", "VanillaItemTags") -f = open("src/vanilla_tags.rs", "w") -new_line = "\n" -quotes = "\"" -f.write("use std::str::FromStr;\n") -for (tags, enum_name) in zip(tag_list_list, enum_names): - f.write("#[derive(Copy, Clone, Debug, PartialEq, Eq)]\n") - f.write(f"pub enum {enum_name} {{{new_line}") - for s in tags: - camelcase = ''.join(map(str.title, s[:-5].split('_'))) - f.write(f" {camelcase},{new_line}") - f.write(f"}}{new_line}{new_line}") -for (tags, enum_name) in zip(tag_list_list, enum_names): - f.write(f"impl {enum_name} {{{new_line}") - f.write(f" pub fn name(&self) -> &'static str {{{new_line}") - f.write(f" match self {{{new_line}") - for s in tags: - snakecase = s[:-5] - camelcase = ''.join(map(str.title, snakecase.split('_'))) - f.write(f" {enum_name}::{camelcase} => {quotes}{snakecase}{quotes},{new_line}") - f.write(" }\n }\n") - f.write(" pub fn namespaced_name(&self) -> crate::NamespacedId {\n") - f.write(" crate::NamespacedId::from_str(self.name()).unwrap()\n") - f.write(" }\n}\n") - f.write(f"impl From<{enum_name}> for &'static str {{{new_line}") - f.write(f" fn from(tag: {enum_name}) -> Self {{{new_line}") - f.write(" tag.name()\n") - f.write(" }\n}\n") - f.write(f"impl From<{enum_name}> for crate::NamespacedId {{{new_line}") - f.write(f" fn from(tag: {enum_name}) -> Self {{{new_line}") - f.write(" tag.namespaced_name()\n") - f.write(" }\n}\n") - - - diff --git a/feather/generated/generators/tags.py b/feather/generated/generators/tags.py new file mode 100644 index 000000000..8ebc8e2ce --- /dev/null +++ b/feather/generated/generators/tags.py @@ -0,0 +1,33 @@ +from os import listdir +import common +prefix = "../datapacks/minecraft/data/minecraft/tags/" +block_tags = listdir(prefix + "blocks") +entity_types = listdir(prefix + "entity_types") +fluid_tags = listdir(prefix + "fluids") +item_tags = listdir(prefix + "items") +tag_list_list = (block_tags, entity_types, fluid_tags, item_tags) +enum_names = ("VanillaBlockTags", "VanillaEntityTypes", "VanillaFluidTags", "VanillaItemTags") +new_line = "\n" +quotes = "\"" +output = "" +for (tags, enum_name) in zip(tag_list_list, enum_names): + output += "#[derive(Copy, Clone, Debug, PartialEq, Eq)]\n" + output += f"pub enum {enum_name} {{{new_line}" + for s in tags: + camelcase = ''.join(map(str.title, s[:-5].split('_'))) + output += f" {camelcase},{new_line}" + output += f"}}{new_line}{new_line}" +for (tags, enum_name) in zip(tag_list_list, enum_names): + output += f"impl {enum_name} {{{new_line}" + output += f" pub fn name(&self) -> &'static str {{{new_line}" + output += f" match self {{{new_line}" + for s in tags: + snakecase = s[:-5] + camelcase = ''.join(map(str.title, snakecase.split('_'))) + output += f" {enum_name}::{camelcase} => {quotes}{snakecase}{quotes},{new_line}" + output += " }\n }\n}\n" + output += f"impl From<{enum_name}> for &'static str {{{new_line}" + output += f" fn from(tag: {enum_name}) -> Self {{{new_line}" + output += " tag.name()\n" + output += " }\n}\n" +common.output("src/vanilla_tags.rs", output) \ No newline at end of file diff --git a/feather/generated/src/lib.rs b/feather/generated/src/lib.rs index ba9575b0a..01a61fa93 100644 --- a/feather/generated/src/lib.rs +++ b/feather/generated/src/lib.rs @@ -15,6 +15,8 @@ mod item; mod particle; #[allow(clippy::all)] mod simplified_block; +#[allow(clippy::all)] +pub mod vanilla_tags; pub use biome::Biome; pub use block::BlockKind; diff --git a/feather/datapacks/src/vanilla_tags.rs b/feather/generated/src/vanilla_tags.rs similarity index 92% rename from feather/datapacks/src/vanilla_tags.rs rename to feather/generated/src/vanilla_tags.rs index dd82d5248..9c7706e9d 100644 --- a/feather/datapacks/src/vanilla_tags.rs +++ b/feather/generated/src/vanilla_tags.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +// This file is @generated. Please do not edit. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VanillaBlockTags { AcaciaLogs, @@ -253,20 +253,12 @@ impl VanillaBlockTags { VanillaBlockTags::Wool => "wool", } } - pub fn namespaced_name(&self) -> crate::NamespacedId { - crate::NamespacedId::from_str(self.name()).unwrap() - } } impl From for &'static str { fn from(tag: VanillaBlockTags) -> Self { tag.name() } } -impl From for crate::NamespacedId { - fn from(tag: VanillaBlockTags) -> Self { - tag.namespaced_name() - } -} impl VanillaEntityTypes { pub fn name(&self) -> &'static str { match self { @@ -277,20 +269,12 @@ impl VanillaEntityTypes { VanillaEntityTypes::Skeletons => "skeletons", } } - pub fn namespaced_name(&self) -> crate::NamespacedId { - crate::NamespacedId::from_str(self.name()).unwrap() - } } impl From for &'static str { fn from(tag: VanillaEntityTypes) -> Self { tag.name() } } -impl From for crate::NamespacedId { - fn from(tag: VanillaEntityTypes) -> Self { - tag.namespaced_name() - } -} impl VanillaFluidTags { pub fn name(&self) -> &'static str { match self { @@ -298,20 +282,12 @@ impl VanillaFluidTags { VanillaFluidTags::Water => "water", } } - pub fn namespaced_name(&self) -> crate::NamespacedId { - crate::NamespacedId::from_str(self.name()).unwrap() - } } impl From for &'static str { fn from(tag: VanillaFluidTags) -> Self { tag.name() } } -impl From for crate::NamespacedId { - fn from(tag: VanillaFluidTags) -> Self { - tag.namespaced_name() - } -} impl VanillaItemTags { pub fn name(&self) -> &'static str { match self { @@ -371,17 +347,9 @@ impl VanillaItemTags { VanillaItemTags::Wool => "wool", } } - pub fn namespaced_name(&self) -> crate::NamespacedId { - crate::NamespacedId::from_str(self.name()).unwrap() - } } impl From for &'static str { fn from(tag: VanillaItemTags) -> Self { tag.name() } } -impl From for crate::NamespacedId { - fn from(tag: VanillaItemTags) -> Self { - tag.namespaced_name() - } -}