From 6b488c58e4634868bb87feba64c4c86d564625df Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Sun, 29 Mar 2026 17:54:22 -0500 Subject: [PATCH 01/30] Bring over block placing behavior from ferrumc --- Cargo.toml | 6 + src/blocks/Cargo.toml | 19 + src/blocks/build.rs | 39 ++ src/blocks/build_config.toml | 224 ++++++++ src/blocks/crates/build/Cargo.toml | 14 + src/blocks/crates/build/src/complex.rs | 525 ++++++++++++++++++ src/blocks/crates/build/src/config.rs | 44 ++ src/blocks/crates/build/src/lib.rs | 68 +++ src/blocks/crates/build/src/simple.rs | 70 +++ src/blocks/crates/generated/Cargo.toml | 12 + src/blocks/crates/generated/build.rs | 57 ++ src/blocks/crates/generated/src/blocks.rs | 1 + src/blocks/crates/generated/src/lib.rs | 6 + src/blocks/crates/generated/src/simple.rs | 1 + .../crates/generated/src/simple_impl.rs | 1 + src/blocks/crates/property/Cargo.toml | 14 + .../crates/property/src/double_block_half.rs | 24 + src/blocks/crates/property/src/lib.rs | 140 +++++ .../property/src/note_block_instrument.rs | 30 + src/blocks/crates/property/src/simple.rs | 219 ++++++++ src/blocks/src/behavior_trait.rs | 119 ++++ src/blocks/src/lib.rs | 79 +++ 22 files changed, 1712 insertions(+) create mode 100644 src/blocks/Cargo.toml create mode 100644 src/blocks/build.rs create mode 100644 src/blocks/build_config.toml create mode 100644 src/blocks/crates/build/Cargo.toml create mode 100644 src/blocks/crates/build/src/complex.rs create mode 100644 src/blocks/crates/build/src/config.rs create mode 100644 src/blocks/crates/build/src/lib.rs create mode 100644 src/blocks/crates/build/src/simple.rs create mode 100644 src/blocks/crates/generated/Cargo.toml create mode 100644 src/blocks/crates/generated/build.rs create mode 100644 src/blocks/crates/generated/src/blocks.rs create mode 100644 src/blocks/crates/generated/src/lib.rs create mode 100644 src/blocks/crates/generated/src/simple.rs create mode 100644 src/blocks/crates/generated/src/simple_impl.rs create mode 100644 src/blocks/crates/property/Cargo.toml create mode 100644 src/blocks/crates/property/src/double_block_half.rs create mode 100644 src/blocks/crates/property/src/lib.rs create mode 100644 src/blocks/crates/property/src/note_block_instrument.rs create mode 100644 src/blocks/crates/property/src/simple.rs create mode 100644 src/blocks/src/behavior_trait.rs create mode 100644 src/blocks/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e4e4d5b0..3f6bf86e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,10 @@ members = [ "src/base/macros", "src/base/profiling", "src/base/threadpool", + "src/blocks", + "src/blocks/crates/property", + "src/blocks/crates/generated", + "src/blocks/crates/build", "src/bin", "src/commands", "src/components", @@ -115,6 +119,8 @@ debug = true # Workspace members temper-app = { path = "src/app" } temper-anvil = { path = "src/adapters/anvil" } +temper-blocks = { path = "src/blocks" } +temper-block-properties = { path = "src/blocks/crates/property" } temper-config = { path = "src/config" } temper-core = { path = "src/core" } temper-default-commands = { path = "src/default_commands" } diff --git a/src/blocks/Cargo.toml b/src/blocks/Cargo.toml new file mode 100644 index 00000000..ce5adc49 --- /dev/null +++ b/src/blocks/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "temper-blocks" +edition.workspace = true +version = "0.0.1" + +[dependencies] +temper-world = { workspace = true } +temper-block-properties = { workspace = true } +temper-blocks-generated = { path = "crates/generated" } +temper-core = { workspace = true } +temper-macros = { workspace = true } +bevy_math = { workspace = true } + +[build-dependencies] +temper-blocks-build = { path = "crates/build" } +quote = { workspace = true } + +[lints] +workspace = true diff --git a/src/blocks/build.rs b/src/blocks/build.rs new file mode 100644 index 00000000..54590ca1 --- /dev/null +++ b/src/blocks/build.rs @@ -0,0 +1,39 @@ +use temper_blocks_build::complex::fill_complex_block_mappings; +use temper_blocks_build::config::{get_block_states, get_build_config}; +use temper_blocks_build::separate_blocks; +use temper_blocks_build::simple::fill_simple_block_mappings; +use quote::__private::TokenStream; +use quote::quote; +use std::fs; +use std::path::Path; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let build_config = get_build_config(); + let block_states = get_block_states(); + + let mut mappings = Vec::with_capacity(block_states.len()); + mappings.resize(block_states.len(), TokenStream::new()); + let (simple_blocks, complex_blocks) = separate_blocks(block_states); + + let enum_const = fill_simple_block_mappings(simple_blocks, &mut mappings); + let complex_consts = fill_complex_block_mappings(&build_config, complex_blocks, &mut mappings); + + let mapping_const = quote! { + { + use temper_blocks_generated::*; + + #enum_const + #(#complex_consts)* + + &[ + #(#mappings),* + ] + } + }; + + let out_dir = std::env::var_os("OUT_DIR").unwrap(); + let dir = Path::new(&out_dir).join("mappings.rs"); + fs::write(dir, mapping_const.to_string()).unwrap(); +} diff --git a/src/blocks/build_config.toml b/src/blocks/build_config.toml new file mode 100644 index 00000000..65893462 --- /dev/null +++ b/src/blocks/build_config.toml @@ -0,0 +1,224 @@ +# Overrides the default generated struct names (unreadable) for the property map given with the given struct name +[name_overrides] +"snowy" = "SnowyBlock" +"age" = "CropBlock" +"type+waterlogged" = "SlabBlock" +"attached+rotation+waterlogged" = "HangingSignBlock" +"waterlogged" = "WaterloggableBlock" +"thickness+vertical_direction+waterlogged" = "DripstoneBlock" +"stage" = "SaplingBlock" +"rotation+waterlogged" = "SignBlock" +"rotation" = "BannerBlock" +"powered" = "PressurePlateBlock" +"axis" = "PillarBlock" +"axis+creaking_heart_state+natural" = "CreakingHeartBlock" +"bites" = "CakeBlock" +"candles+lit+waterlogged" = "CandleBlock" +"conditional+facing" = "CommandBlock" +"distance+persistent+waterlogged" = "LeavesBlock" +"down+east+north+south+up+waterlogged+west" = "LichenBlock" +"down+east+north+south+up+west" = "LargeMushroomBlock" +"dusted" = "SuspiciousBlock" +"east+north+south+up+waterlogged+west" = "WallBlock" +"east+north+south+waterlogged+west" = "FenceAndPaneBlock" +"extended+facing" = "PistonBlock" +"face+facing+powered" = "ButtonBlock" +"facing" = "FacingBlock" +"facing+flower_amount" = "FlowerCoverBlock" +"facing+half+hinge+open+powered" = "DoorBlock" +"facing+half+open+powered+waterlogged" = "TrapdoorBlock" +"facing+half+shape+waterlogged" = "StairsBlock" +"facing+honey_level" = "HiveBlock" +"facing+in_wall+open+powered" = "FenceGateBlock" +"facing+lit" = "FurnaceBlock" +"facing+lit+signal_fire+waterlogged" = "CampfireBlock" +"facing+mode+powered" = "ComparatorBlock" +"facing+occupied+part" = "BedBlock" +"facing+ominous+vault_state" = "VaultBlock" +"facing+powered" = "WallSkullBlock" +"facing+triggered" = "DispenserBlock" +"facing+type+waterlogged" = "ChestBlock" +"facing+waterlogged" = "WaterloggableWallAttachedBlock" +"half" = "DoublePlantBlock" +"hanging+waterlogged" = "LanternBlock" +"lit" = "CandleCakeBlock" +"lit+powered" = "BulbBlock" +"ominous+trial_spawner_state" = "TrialSpawnerBlock" +"pickles+waterlogged" = "SeaPickleBlock" +"power" = "WeightedPressurePlateBlock" +"powered+rotation" = "SkullBlock" +"powered+shape+waterlogged" = "RedstoneRailBlock" +"shape+waterlogged" = "RailBlock" +"age+berries" = "GlowBerriesBlock" +"age+east+north+south+up+west" = "FireBlock" +"age+facing" = "CocoaBeansBlock" +"age+half" = "PitcherCropBlock" +"age+hanging+stage+waterlogged" = "MangrovePopaguleBlock" +"age+leaves+stage" = "BambooBlock" +"attached+disarmed+east+north+powered+south+west" = "TripwireBlock" +"attached+facing+powered" = "TripwireHookBlock" +"attachment+facing+powered" = "BellBlock" +"axis+waterlogged" = "ChainBlock" +"berries" = "GlowBerriesPlantBlock" +"bloom" = "SculkCatalystBlock" +"bottom+distance+waterlogged" = "ScaffoldingBlock" +"bottom+east+north+south+west" = "PaleMossCarpetBlock" +"can_summon+shrieking+waterlogged" = "SculkShriekerBlock" +"charges" = "RespawnAnchor" +"cracked+facing+waterlogged" = "DecoratedPotBlock" +"crafting+orientation+triggered" = "CrafterBlock" +"delay+facing+locked+powered" = "RepeaterBlock" +"drag" = "BubbleColumnBlock" +"east+north+power+south+west" = "RedstoneWireBlock" +"east+north+south+up+west" = "VineBlock" +"eggs+hatch" = "TurtleEggBlock" +"enabled+facing" = "HopperBlock" +"eye+facing" = "EndPortalBlock" +"face+facing" = "GrindstoneBlock" +"facing+half+waterlogged" = "SmallDripleafBlock" +"facing+has_book+powered" = "LecternBlock" +"facing+open" = "BarrelBlock" +"facing+power+sculk_sensor_phase+waterlogged" = "CalibratedSculkSensorBlock" +"facing+powered+waterlogged" = "LightningRodBlock" +"facing+segment_amount" = "LeafLitterBlock" +"facing+short+type" = "PistonHeadBlock" +"facing+slot_0_occupied+slot_1_occupied+slot_2_occupied+slot_3_occupied+slot_4_occupied+slot_5_occupied" = "ChiseledBookshelfBlock" +"facing+tilt+waterlogged" = "BigDripleafBlock" +"facing+type" = "MovingPistonBlock" +"has_bottle_0+has_bottle_1+has_bottle_2" = "BrewingStandBlock" +"has_record" = "JukeboxBlock" +"hatch" = "SnifferEggBlock" +"instrument+note+powered" = "NoteBlock" +"inverted+power" = "DaylightDetectorBlock" +"layers" = "SnowBlock" +"level+waterlogged" = "LightBlock" +"moisture" = "FarmlandBlock" +"orientation" = "JigsawBlock" +"power+sculk_sensor_phase+waterlogged" = "SculkSensorBlock" +"tip" = "PaleHangingMossBlock" +"unstable" = "TntBlock" + +# Tells the generator to use a different struct for the block specified. +# If the struct is defined above and the property map of the block and struct don't match, the generator will panic +[block_overrides] +"minecraft:frosted_ice" = "FrostedIceBlock" +"minecraft:redstone_ore" = "RedstoneOreBlock" +"minecraft:deepslate_redstone_ore" = "RedstoneOreBlock" +"minecraft:redstone_lamp" = "RedstoneLampBlock" +"minecraft:redstone_torch" = "RedstoneTorchBlock" +"minecraft:chorus_plant" = "ChorusPlantBlock" +"minecraft:lever" = "LeverBlock" +"minecraft:attached_melon_stem" = "StemBlock" +"minecraft:attached_pumpkin_stem" = "StemBlock" +"minecraft:redstone_wall_torch" = "WallRedstoneTorchBlock" +"minecraft:observer" = "ObserverBlock" +"minecraft:composter" = "ComposterBlock" +"minecraft:lava" = "LiquidBlock" +"minecraft:water" = "LiquidBlock" +"minecraft:powder_snow_cauldron" = "LevelCauldronBlock" +"minecraft:water_cauldron" = "LevelCauldronBlock" +"minecraft:target" = "TargetBlock" +"minecraft:structure_block" = "StructureBlock" +"minecraft:test_block" = "TestBlock" + +# From Minecraft's net.minecraft.world.level.block.state.properties.BlockStateProperties class +# +# Maps property names to the type the generator should use in the generated structs. +# If a property name isn't found in this list, the generator will panic. In this case, check to see what the type is and add it below. +# If a name could be multiple types, use a list. The generator will try to decipher the type from the context. +[property_types] +"attached" = "bool" +"berries" = "bool" +"bloom" = "bool" +"bottom" = "bool" +"can_summon" = "bool" +"conditional" = "bool" +"disarmed" = "bool" +"drag" = "bool" +"enabled" = "bool" +"extended" = "bool" +"eye" = "bool" +"falling" = "bool" +"hanging" = "bool" +"has_bottle_0" = "bool" +"has_bottle_1" = "bool" +"has_bottle_2" = "bool" +"has_record" = "bool" +"has_book" = "bool" +"inverted" = "bool" +"in_wall" = "bool" +"lit" = "bool" +"locked" = "bool" +"natural" = "bool" +"occupied" = "bool" +"open" = "bool" +"persistent" = "bool" +"powered" = "bool" +"short" = "bool" +"shrieking" = "bool" +"signal_fire" = "bool" +"snowy" = "bool" +"tip" = "bool" +"triggered" = "bool" +"unstable" = "bool" +"waterlogged" = "bool" +"horizontal_axis" = "Axis" +"axis" = "Axis" +"up" = "bool" +"down" = "bool" +"north" = ["bool", "WallSide", "RedstoneSide"] +"east" = ["bool", "WallSide", "RedstoneSide"] +"south" = ["bool", "WallSide", "RedstoneSide"] +"west" = ["bool", "WallSide", "RedstoneSide"] +"facing" = "Direction" +"flower_amount" = "i32" +"segment_amount" = "i32" +"orientation" = "FrontAndTop" +"face" = "AttachFace" +"attachment" = "BellAttachType" +"half" = ["DoubleBlockHalf", "Half"] +"side_chain" = "SideChainPart" +"shape" = ["RailShape", "StairsShape"] +"age" = "i32" +"bites" = "i32" +"candles" = "i32" +"delay" = "i32" +"distance" = "i32" +"eggs" = "i32" +"hatch" = "i32" +"layers" = "i32" +"level" = "i32" +"honey_level" = "i32" +"moisture" = "i32" +"note" = "i32" +"pickles" = "i32" +"power" = "i32" +"stage" = "i32" +"charges" = "i32" +"hydration" = "i32" +"rotation" = "i32" +"part" = "BedPart" +"type" = ["ChestType", "PistonType", "SlabType"] +"mode" = ["ComparatorMode", "StructureMode", "TestBlockMode"] +"hinge" = "DoorHingeSide" +"instrument" = "NoteBlockInstrument" +"leaves" = "BambooLeaves" +"tilt" = "Tilt" +"vertical_direction" = "Direction" +"thickness" = "DripstoneThickness" +"sculk_sensor_phase" = "SculkSensorPhase" +"slot_0_occupied" = "bool" +"slot_1_occupied" = "bool" +"slot_2_occupied" = "bool" +"slot_3_occupied" = "bool" +"slot_4_occupied" = "bool" +"slot_5_occupied" = "bool" +"dusted" = "i32" +"cracked" = "bool" +"crafting" = "bool" +"trial_spawner_state" = "TrialSpawnerState" +"vault_state" = "VaultState" +"creaking_heart_state" = "CreakingHeartState" +"ominous" = "bool" +"map" = "bool" +"copper_golem_pose" = "CopperGolemPose" \ No newline at end of file diff --git a/src/blocks/crates/build/Cargo.toml b/src/blocks/crates/build/Cargo.toml new file mode 100644 index 00000000..9b51d1fe --- /dev/null +++ b/src/blocks/crates/build/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "temper-blocks-build" +version = "0.1.0" +edition = "2024" + +[dependencies] +temper-block-properties = { path = "../property", features = ["block-struct-generation"] } +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.145" +heck = "0.5" +proc-macro2 = "1.0" +quote = "1.0" +toml = "0.9.8" +fxhash = "0.2.1" diff --git a/src/blocks/crates/build/src/complex.rs b/src/blocks/crates/build/src/complex.rs new file mode 100644 index 00000000..9786e183 --- /dev/null +++ b/src/blocks/crates/build/src/complex.rs @@ -0,0 +1,525 @@ +use crate::config::{BuildConfig, SingleOrMultiple}; +use temper_block_properties::{PropertyDescriptor, TYPES}; +use fxhash::FxHashMap; +use heck::{ToPascalCase, ToShoutySnakeCase, ToSnakeCase}; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; +use std::collections::HashMap; + +struct BlockStateConfiguration<'a> { + name: &'a str, + properties: Vec<(&'a str, &'a str)>, + values: FxHashMap>, +} + +pub struct ComplexBlock { + pub name: String, + pub properties: FxHashMap, +} + +#[allow(clippy::type_complexity)] +pub struct FinalizedConfiguration<'a> { + name: String, + properties: &'a [(&'a str, &'a str)], + associated_blocks: Vec<(&'a str, &'a FxHashMap>)>, +} + +pub fn fill_complex_block_mappings( + build_config: &BuildConfig, + block_states: Vec<(u32, ComplexBlock)>, + mappings: &mut [TokenStream], +) -> Vec { + let (blocks, configs) = dedup_blocks(build_config, &block_states); + + let mut final_configs = collect_configurations(build_config, &configs, &blocks); + final_configs.sort_by(|a, b| a.name.cmp(&b.name)); + + final_configs + .into_iter() + .map(|config| { + let struct_name = format_ident!("{}", config.name); + let vtable_name = format_ident!("VTABLE_{}", config.name.to_shouty_snake_case()); + + config.associated_blocks + .iter() + .for_each(|(_, values)| { + values + .iter() + .for_each(|(id, _)| { + mappings[*id as usize] = quote! { crate::StateBehaviorTable::spin_off(&#vtable_name, #id) } + }); + }); + + quote! { + const #vtable_name: crate::BlockBehaviorTable = crate::BlockBehaviorTable::from::<#struct_name>(); + } + }) + .collect() +} + +#[allow(clippy::type_complexity)] +pub fn generate_complex_blocks( + build_config: &BuildConfig, + block_states: Vec<(u32, ComplexBlock)>, +) -> (Vec<((TokenStream, TokenStream), Ident)>, TokenStream) { + let (blocks, configs) = dedup_blocks(build_config, &block_states); + + let mut finalized_configs = collect_configurations(build_config, &configs, &blocks); + finalized_configs.sort_by(|a, b| a.name.cmp(&b.name)); + + let ((structs, impls), names): ((Vec, Vec), Vec) = + finalized_configs + .into_iter() + .map( + |FinalizedConfiguration { + name, + properties: config, + associated_blocks, + }| { + let fields = config + .iter() + .map(|(name, _)| match *name { + "type" => format_ident!("ty"), + str => format_ident!("{str}"), + }) + .collect::>(); + + let types = config + .iter() + .map(|(_, value)| format_ident!("{value}")) + .collect::>(); + + let struct_name = format_ident!("{name}"); + + match associated_blocks.len() { + 0 => panic!("No blocks for {struct_name}"), + 1 => { + let trait_impl = generate_trait_impls( + &struct_name, + None, + config, + &associated_blocks, + ); + + ( + ( + quote! { + #[allow(unused_imports)] + use temper_block_properties::*; + + #[allow(dead_code)] + #[derive(Clone, Debug)] + pub struct #struct_name { + #(pub #fields: #types,)* + } + }, + quote! { + #[allow(unused_imports)] + use temper_block_properties::*; + use crate::#struct_name; + + #trait_impl + }, + ), + struct_name, + ) + } + _ => { + let mut variants = associated_blocks + .iter() + .map(|(name, _)| { + format_ident!( + "{}", + name.strip_prefix("minecraft:") + .unwrap_or(name) + .to_pascal_case() + ) + }) + .collect::>(); + + variants.sort(); + + let enum_name = format_ident!("{}Type", struct_name); + let trait_impl = generate_trait_impls( + &struct_name, + Some((&enum_name, &variants)), + config, + &associated_blocks, + ); + + ( + ( + quote! { + #[allow(unused_imports)] + use temper_block_properties::*; + + #[allow(dead_code)] + #[derive(Clone, Debug)] + pub enum #enum_name { + #(#variants,)* + } + + #[allow(dead_code)] + #[derive(Clone, Debug)] + pub struct #struct_name { + pub block_type: #enum_name, + #(pub #fields: #types),* + } + }, + quote! { + #[allow(unused_imports)] + use temper_block_properties::*; + use crate::#struct_name; + use crate::#enum_name; + + #trait_impl + }, + ), + struct_name, + ) + } + } + }, + ) + .unzip(); + + let mod_names = names + .iter() + .map(|name| format_ident!("{}", name.to_string().to_snake_case())) + .collect::>(); + + let impl_names = mod_names + .iter() + .map(|name| format_ident!("{}_impl", name)) + .collect::>(); + + let modules = quote! { + #( + mod #mod_names; + mod #impl_names; + pub use #mod_names::*; + )* + }; + + let data = structs + .into_iter() + .zip(impls) + .zip(names) + .collect::>(); + + (data, modules) +} + +fn property_descriptor_of(key: &str) -> &PropertyDescriptor { + TYPES + .get(key) + .unwrap_or_else(|| panic!("Property type for {key} not found!")) +} + +fn get_field_values( + values: &[(&String, &String)], + properties: &[(&str, &str)], +) -> (Vec, Vec) { + values + .iter() + .map(|(field, value)| { + ( + match field.as_str() { + "type" => format_ident!("ty"), + field => format_ident!("{field}"), + }, + { + let ty = &properties + .iter() + .find(|(name1, _)| name1 == field) + .unwrap() + .1; + (property_descriptor_of(ty).ident_for)(value) + }, + ) + }) + .unzip() +} + +#[allow(clippy::type_complexity)] +fn generate_trait_impls( + struct_name: &Ident, + enum_name: Option<(&Ident, &[Ident])>, + properties: &[(&str, &str)], + values: &[(&str, &FxHashMap>)], +) -> TokenStream { + let (from_match_arms, into_match_arms): (Vec, Vec) = match enum_name { + Some((enum_name, enum_variants)) => { + let mut values = values.iter().collect::>(); + values.sort_by_key(|(name, _)| name); + + values.iter() + .flat_map(|(name, values)| { + let name_ident = format_ident!("{}", name.strip_prefix("minecraft:").unwrap_or(name).to_pascal_case()); + + match enum_variants.iter().find(|variant| *variant == &name_ident) { + Some(variant) => { + let mut values = values.iter().collect::>(); + values.sort_by_key(|(id, _)| *id); + + let mut out = Vec::with_capacity(values.len()); + + for (id, values) in values { + let mut values = values + .iter() + .collect::>(); + + values.sort_by_key(|(field, _)| field.as_str()); + + let (fields, values) = get_field_values(&values, properties); + + let data = quote! { + #struct_name { block_type: #enum_name::#variant, #(#fields: #values),* } + }; + + out.push(( + quote! { + #id => Ok(#data) + }, + quote! { + #data => Ok(#id) + } + )) + } + + out + }, + None => panic!("could not find {} enum variant for {}", enum_name, name), + } + }) + .unzip() + } + None => { + let (_, values) = &values[0]; + + let mut values = values.iter().collect::>(); + values.sort_by_key(|(id, _)| *id); + + values + .into_iter() + .map(|(id, values)| { + let mut values = values.iter().collect::>(); + + values.sort_by_key(|(field, _)| field.as_str()); + + let (fields, values) = get_field_values(&values, properties); + + let data = quote! { + #struct_name { #(#fields: #values),* } + }; + + ( + quote! { + #id => Ok(#data) + }, + quote! { + #data => Ok(#id) + }, + ) + }) + .unzip() + } + }; + + quote! { + impl TryFrom for #struct_name { + type Error = (); + + fn try_from(data: u32) -> Result { + match data { + #(#from_match_arms),*, + _ => Err(()) + } + } + } + + impl TryInto for #struct_name { + type Error = (); + + fn try_into(self) -> Result { + #[allow(unreachable_patterns)] + match self { + #(#into_match_arms),*, + _ => Err(()) + } + } + } + } +} + +fn struct_name(config: &BuildConfig, num_structs: usize, properties: &[(&str, &str)]) -> String { + let prop_str = properties.iter().map(|(name, _)| *name).collect::>(); + let prop_str = prop_str.join("+"); + + match config.name_overrides.iter().find(|(key, _)| { + let mut split = key + .split("+") + .map(|str| str.to_string()) + .collect::>(); + split.sort(); + let new_key = split.join("+"); + + new_key == prop_str + }) { + None => format!("GeneratedStruct{}", num_structs), + Some((_, struct_name)) => struct_name.clone(), + } +} + +#[allow(clippy::type_complexity)] +fn dedup_blocks<'a>( + build_config: &'a BuildConfig, + block_states: &'a [(u32, ComplexBlock)], +) -> ( + Vec>, + Vec>, +) { + let mut missing_types = build_config + .property_types + .values() + .flatten() + .filter(|str| !TYPES.contains_key(str.as_str())) + .collect::>(); + + missing_types.sort(); + missing_types.dedup(); + + if !missing_types.is_empty() { + panic!("Missing types for {:?}", missing_types); + } + + let configurations: FxHashMap<&str, FxHashMap>> = block_states + .iter() + .map(|(id, block)| (block.name.as_str(), (*id, &block.properties))) + .fold(FxHashMap::default(), |mut acc, (k, v)| { + acc.entry(k) + .or_insert_with(FxHashMap::default) + .insert(v.0, v.1); + acc + }); + + let blocks = configurations + .into_iter() + .map(|(name, properties)| { + let property_values = properties + .values() + .flat_map(|properties| { + properties.iter().map(|(name, value)| { + let name = name.as_str(); + let value = value.as_str(); + let possible_types: Vec<&str> = match build_config.property_types.get(name) + { + None => panic!("Property type for {name} not found!"), + Some(SingleOrMultiple::Single(ty)) => vec![ty.as_str()], + Some(SingleOrMultiple::Multiple(ty)) => { + ty.iter().map(String::as_str).collect() + } + }; + + (name, (possible_types, value)) + }) + }) + .fold(HashMap::new(), |mut acc, (k, v)| { + acc.entry(k) + .or_insert_with(|| (v.0, Vec::new())) + .1 + .push(v.1); + + acc + }); + + let mut property_map: Vec<(&str, &str)> = property_values + .into_iter() + .map(|(name, (possible_types, values))| { + let property_type = possible_types + .into_iter() + .find(|ty| { + values + .iter() + .all(|value| (property_descriptor_of(ty).matches_values)(value)) + }) + .unwrap_or_else(|| { + panic!("Failed to find property type for values {values:?}") + }); + + (name, property_type) + }) + .collect(); + + property_map.sort(); + + BlockStateConfiguration { + name, + properties: property_map, + values: properties, + } + }) + .collect::>(); + + let mut configs = blocks + .iter() + .map(|block| block.properties.to_vec()) + .collect::>(); + + configs.sort(); + configs.dedup(); + + (blocks, configs) +} + +fn collect_configurations<'a>( + build_config: &'a BuildConfig, + configs: &'a [Vec<(&'a str, &'a str)>], + blocks: &'a [BlockStateConfiguration<'a>], +) -> Vec> { + let mut num_structs = 0; + + configs + .iter() + .flat_map(|config| { + let associated_blocks = blocks + .iter() + .filter(|block| &block.properties == config) + .collect::>(); + + let mut configs = vec![FinalizedConfiguration { + name: struct_name(build_config, num_structs, config), + properties: config, + associated_blocks: Vec::with_capacity(associated_blocks.len()), + }]; + + for block in associated_blocks { + if let Some(name) = build_config.block_overrides.get(block.name) { + match configs + .iter_mut() + .find(|config| config.name == name.as_str()) + { + Some(config) => config.associated_blocks.push((block.name, &block.values)), + None => configs.push(FinalizedConfiguration { + name: name.clone(), + properties: config.as_slice(), + associated_blocks: vec![(block.name, &block.values)], + }), + } + } else { + configs[0] + .associated_blocks + .push((block.name, &block.values)); + } + } + + if configs[0].associated_blocks.is_empty() { + configs.remove(0); + } + + num_structs += 1; + + configs + }) + .collect() +} diff --git a/src/blocks/crates/build/src/config.rs b/src/blocks/crates/build/src/config.rs new file mode 100644 index 00000000..bfcb698e --- /dev/null +++ b/src/blocks/crates/build/src/config.rs @@ -0,0 +1,44 @@ +use crate::BlockState; +use serde::Deserialize; +use std::collections::HashMap; + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum SingleOrMultiple { + Single(String), + Multiple(Vec), +} + +#[derive(Deserialize)] +pub struct BuildConfig { + pub name_overrides: HashMap, + pub block_overrides: HashMap, + pub property_types: HashMap, +} + +pub const BUILD_CONFIG: &str = include_str!("../../../build_config.toml"); +pub const BLOCK_STATES: &str = include_str!("../../../../../assets/data/blockstates.json"); + +pub fn get_build_config() -> BuildConfig { + toml::from_str(BUILD_CONFIG).unwrap() +} + +pub fn get_block_states() -> HashMap { + let out: HashMap = serde_json::from_str(BLOCK_STATES).unwrap(); + + out.into_iter() + .map(|(k, v)| (k.parse::().unwrap(), v)) + .collect() +} + +impl<'a> IntoIterator for &'a SingleOrMultiple { + type Item = &'a String; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + match self { + SingleOrMultiple::Single(v) => vec![v].into_iter(), + SingleOrMultiple::Multiple(vals) => vals.iter().collect::>().into_iter(), + } + } +} diff --git a/src/blocks/crates/build/src/lib.rs b/src/blocks/crates/build/src/lib.rs new file mode 100644 index 00000000..f120c05b --- /dev/null +++ b/src/blocks/crates/build/src/lib.rs @@ -0,0 +1,68 @@ +use crate::complex::ComplexBlock; +use fxhash::FxHashMap; +use serde::Deserialize; +use std::collections::HashMap; +use std::io::Write; + +pub mod complex; +pub mod config; +pub mod simple; + +#[derive(Deserialize, Debug)] +pub struct BlockState { + name: String, + properties: Option>, +} + +#[allow(clippy::type_complexity)] +pub fn separate_blocks( + input: HashMap, +) -> (Vec<(u32, String)>, Vec<(u32, ComplexBlock)>) { + let mut simple_blocks = Vec::new(); + let mut complex_blocks = Vec::new(); + + for (id, state) in input.into_iter() { + match state.properties { + Some(properties) => complex_blocks.push(( + id, + ComplexBlock { + name: state.name, + properties: FxHashMap::from_iter(properties.into_iter()), + }, + )), + None => simple_blocks.push((id, state.name)), + } + } + + (simple_blocks, complex_blocks) +} + +pub fn format_code(unformatted_code: &str) -> String { + let mut child = std::process::Command::new("rustfmt") + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn() + .expect("Failed to spawn rustfmt process."); + + child + .stdin + .take() + .expect("Failed to take rustfmt stdin") + .write_all(unformatted_code.as_bytes()) + .expect("Failed to write to rustfmt stdin."); + + let output = child + .wait_with_output() + .expect("Failed to wait for rustfmt process."); + + if output.status.success() { + String::from_utf8(output.stdout).expect("rustfmt output was not valid UTF-8.") + } else { + panic!( + "rustfmt failed with status: {}\n--- stderr ---\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + } +} diff --git a/src/blocks/crates/build/src/simple.rs b/src/blocks/crates/build/src/simple.rs new file mode 100644 index 00000000..06f47631 --- /dev/null +++ b/src/blocks/crates/build/src/simple.rs @@ -0,0 +1,70 @@ +use heck::ToPascalCase; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub fn fill_simple_block_mappings( + simple_blocks: Vec<(u32, String)>, + mappings: &mut [TokenStream], +) -> TokenStream { + for (id, _) in simple_blocks { + mappings[id as usize] = + quote! { crate::StateBehaviorTable::spin_off(&VTABLE_SIMPLE_BLOCK, #id) }; + } + + quote! { + const VTABLE_SIMPLE_BLOCK: crate::BlockBehaviorTable = crate::BlockBehaviorTable::from::(); + } +} + +pub fn generate_simple_block_enum( + mut simple_blocks: Vec<(u32, String)>, +) -> (TokenStream, TokenStream) { + simple_blocks.sort_by_key(|(id, _)| *id); + + let mut map_entries = Vec::new(); + let mut from_arms = Vec::new(); + let mut enum_variants = Vec::new(); + + for (id, name) in simple_blocks { + let variant = name.strip_prefix("minecraft:").unwrap_or(&name); + let variant = format_ident!("{}", variant.to_pascal_case()); + + enum_variants.push(quote! { #variant }); + from_arms.push(quote! { #id => Ok(SimpleBlock::#variant) }); + map_entries.push(quote! { #id }); + } + + ( + quote! { + #[repr(usize)] + #[derive(Clone, Debug)] + pub enum SimpleBlock { + #(#enum_variants),* + } + }, + quote! { + const SIMPLE_BLOCK_STATE_MAP: &[u32] = &[ + #(#map_entries,)* + ]; + + impl TryFrom for SimpleBlock { + type Error = (); + + fn try_from(data: u32) -> Result { + match data { + #(#from_arms),*, + _ => Err(()) + } + } + } + + impl TryInto for SimpleBlock { + type Error = (); + + fn try_into(self) -> Result { + Ok(SIMPLE_BLOCK_STATE_MAP[self as usize]) + } + } + }, + ) +} diff --git a/src/blocks/crates/generated/Cargo.toml b/src/blocks/crates/generated/Cargo.toml new file mode 100644 index 00000000..8fd32b3a --- /dev/null +++ b/src/blocks/crates/generated/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "temper-blocks-generated" +version = "0.1.0" +edition = "2024" + +[dependencies] +temper-block-properties = { path = "../property" } + +[build-dependencies] +temper-blocks-build = { path = "../build" } +heck = "0.5" +quote = { workspace = true } \ No newline at end of file diff --git a/src/blocks/crates/generated/build.rs b/src/blocks/crates/generated/build.rs new file mode 100644 index 00000000..a0b58a12 --- /dev/null +++ b/src/blocks/crates/generated/build.rs @@ -0,0 +1,57 @@ +use temper_blocks_build::complex::generate_complex_blocks; +use temper_blocks_build::config::{get_block_states, get_build_config}; +use temper_blocks_build::simple::generate_simple_block_enum; +use temper_blocks_build::{format_code, separate_blocks}; +use heck::ToSnakeCase; +use std::fs; + +fn main() { + let build_config = get_build_config(); + let block_states = get_block_states(); + + let (simple_blocks, complex_blocks) = separate_blocks(block_states); + + let (simple_enum, enum_impl) = generate_simple_block_enum(simple_blocks); + let (block_structs, block_mod) = generate_complex_blocks(&build_config, complex_blocks); + + let out_dir = std::env::var("OUT_DIR").unwrap(); + + let enum_impl = quote::quote! { + use crate::SimpleBlock; + + #enum_impl + }; + + fs::write( + format!("{}/blocks.rs", out_dir), + format_code(&block_mod.to_string()), + ) + .unwrap(); + fs::write( + format!("{}/simple.rs", out_dir), + format_code(&simple_enum.to_string()), + ) + .unwrap(); + fs::write( + format!("{}/simple_impl.rs", out_dir), + format_code(&enum_impl.to_string()), + ) + .unwrap(); + + block_structs + .into_iter() + .for_each(|((structure, struct_impl), name)| { + let mod_name = name.to_string().to_snake_case(); + + fs::write( + format!("{}/{}.rs", out_dir, mod_name), + format_code(&structure.to_string()), + ) + .unwrap(); + fs::write( + format!("{}/{}_impl.rs", out_dir, mod_name), + format_code(&struct_impl.to_string()), + ) + .unwrap(); + }); +} diff --git a/src/blocks/crates/generated/src/blocks.rs b/src/blocks/crates/generated/src/blocks.rs new file mode 100644 index 00000000..e45e5b88 --- /dev/null +++ b/src/blocks/crates/generated/src/blocks.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/blocks.rs")); diff --git a/src/blocks/crates/generated/src/lib.rs b/src/blocks/crates/generated/src/lib.rs new file mode 100644 index 00000000..e5fc53e9 --- /dev/null +++ b/src/blocks/crates/generated/src/lib.rs @@ -0,0 +1,6 @@ +mod blocks; +mod simple; +mod simple_impl; + +pub use blocks::*; +pub use simple::*; diff --git a/src/blocks/crates/generated/src/simple.rs b/src/blocks/crates/generated/src/simple.rs new file mode 100644 index 00000000..bbf103d3 --- /dev/null +++ b/src/blocks/crates/generated/src/simple.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/simple.rs")); diff --git a/src/blocks/crates/generated/src/simple_impl.rs b/src/blocks/crates/generated/src/simple_impl.rs new file mode 100644 index 00000000..496435cc --- /dev/null +++ b/src/blocks/crates/generated/src/simple_impl.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/simple_impl.rs")); diff --git a/src/blocks/crates/property/Cargo.toml b/src/blocks/crates/property/Cargo.toml new file mode 100644 index 00000000..86235c0d --- /dev/null +++ b/src/blocks/crates/property/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "temper-block-properties" +version = "0.1.0" +edition = "2024" + +[dependencies] +bevy_math = { workspace = true } +proc-macro2 = { workspace = true, optional = true } +quote = { workspace = true, optional = true } +lazy_static = { workspace = true, optional = true } + +[features] +default = [] +block-struct-generation = ["dep:proc-macro2", "dep:quote", "dep:lazy_static"] \ No newline at end of file diff --git a/src/blocks/crates/property/src/double_block_half.rs b/src/blocks/crates/property/src/double_block_half.rs new file mode 100644 index 00000000..a886bed5 --- /dev/null +++ b/src/blocks/crates/property/src/double_block_half.rs @@ -0,0 +1,24 @@ +use crate::enum_property; +use bevy_math::IVec3; + +enum_property!( + DoubleBlockHalf, + Upper => "upper", + Lower => "lower", +); + +impl DoubleBlockHalf { + pub fn other_half(&self) -> Self { + match self { + Self::Upper => Self::Lower, + Self::Lower => Self::Upper, + } + } + + pub fn direction_to_other(&self) -> IVec3 { + match self { + Self::Upper => IVec3::new(0, -1, 0), + Self::Lower => IVec3::new(0, 1, 0), + } + } +} diff --git a/src/blocks/crates/property/src/lib.rs b/src/blocks/crates/property/src/lib.rs new file mode 100644 index 00000000..5dd3a838 --- /dev/null +++ b/src/blocks/crates/property/src/lib.rs @@ -0,0 +1,140 @@ +use std::str::FromStr; + +mod double_block_half; +mod note_block_instrument; +mod simple; + +pub use double_block_half::DoubleBlockHalf; +pub use note_block_instrument::NoteBlockInstrument; +pub use simple::*; + +#[cfg(feature = "block-struct-generation")] +lazy_static::lazy_static! { + pub static ref TYPES: std::collections::HashMap<&'static str, PropertyDescriptor> = { + let mut map = std::collections::HashMap::new(); + + map.insert("i32", PropertyDescriptor::I32); + map.insert("bool", PropertyDescriptor::BOOL); + map.insert("AttachFace", AttachFace::DESCRIPTOR); + map.insert("Axis", Axis::DESCRIPTOR); + map.insert("BambooLeaves", BambooLeaves::DESCRIPTOR); + map.insert("BedPart", BedPart::DESCRIPTOR); + map.insert("BellAttachType", BellAttachType::DESCRIPTOR); + map.insert("ChestType", ChestType::DESCRIPTOR); + map.insert("CreakingHeartState", CreakingHeartState::DESCRIPTOR); + map.insert("ComparatorMode", ComparatorMode::DESCRIPTOR); + map.insert("Direction", Direction::DESCRIPTOR); + map.insert("DoorHingeSide", DoorHingeSide::DESCRIPTOR); + map.insert("DoubleBlockHalf", DoubleBlockHalf::DESCRIPTOR); + map.insert("DripstoneThickness", DripstoneThickness::DESCRIPTOR); + map.insert("FrontAndTop", FrontAndTop::DESCRIPTOR); + map.insert("Half", Half::DESCRIPTOR); + map.insert("NoteBlockInstrument", NoteBlockInstrument::DESCRIPTOR); + map.insert("PistonType", PistonType::DESCRIPTOR); + map.insert("CopperGolemPose", CopperGolemPose::DESCRIPTOR); + map.insert("RailShape", RailShape::DESCRIPTOR); + map.insert("RedstoneSide", RedstoneSide::DESCRIPTOR); + map.insert("SculkSensorPhase", SculkSensorPhase::DESCRIPTOR); + map.insert("SideChainPart", SideChainPart::DESCRIPTOR); + map.insert("SlabType", SlabType::DESCRIPTOR); + map.insert("StairsShape", StairsShape::DESCRIPTOR); + map.insert("StructureMode", StructureMode::DESCRIPTOR); + map.insert("TestBlockMode", TestBlockMode::DESCRIPTOR); + map.insert("Tilt", Tilt::DESCRIPTOR); + map.insert("TrialSpawnerState", TrialSpawnerState::DESCRIPTOR); + map.insert("VaultState", VaultState::DESCRIPTOR); + map.insert("WallSide", WallSide::DESCRIPTOR); + + map + }; +} + +#[cfg(feature = "block-struct-generation")] +pub struct PropertyDescriptor { + pub matches_values: fn(&str) -> bool, + pub ident_for: fn(&str) -> proc_macro2::TokenStream, +} + +#[cfg(feature = "block-struct-generation")] +impl PropertyDescriptor { + const I32: PropertyDescriptor = PropertyDescriptor { + matches_values: |str| str.parse::().is_ok(), + ident_for: |str| { + let val = str.parse::().expect("failed to parse i32"); + quote::quote! { #val } + }, + }; + + const BOOL: PropertyDescriptor = PropertyDescriptor { + matches_values: |str| matches!(str, "true" | "false"), + ident_for: |str| { + let val = str.parse::().expect("failed to parse bool"); + quote::quote! { #val } + }, + }; +} + +/// Marker trait for types that can be used as block state property values +pub trait BlockStateProperty: FromStr + ToString { + fn values(&self) -> &[&str] { + &[] + } +} + +impl BlockStateProperty for i32 {} +impl BlockStateProperty for bool {} + +/// Helper macro to implement enum property types +#[macro_export] +macro_rules! enum_property { + ($name:ident, $($variant:ident => $variant_str:expr),* $(,)?) => { + #[derive(Clone, Debug)] + pub enum $name { + $($variant),* + } + + #[cfg(feature = "block-struct-generation")] + impl $name { + pub const DESCRIPTOR: $crate::PropertyDescriptor = $crate::PropertyDescriptor { + matches_values: Self::matches_values, + ident_for: Self::ident_for, + }; + + fn matches_values(str: &str) -> bool { + matches!(str, $($variant_str)|*) + } + + fn ident_for(str: &str) -> proc_macro2::TokenStream { + match str { + $($variant_str => quote::quote!{ $name::$variant }),*, + str => panic!("{} is not a valid member of enum property {}", str, stringify!($name)), + } + } + } + + impl std::str::FromStr for $name { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + $($variant_str => Ok($name::$variant)),*, + s => Err(format!("Unknown property for {}: {}", stringify!($name), s)), + } + } + } + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + $($name::$variant => write!(f, $variant_str)),* + } + } + } + + impl $crate::BlockStateProperty for $name { + fn values(&self) -> &[&str] { + &[$($variant_str),*] + } + } + }; +} diff --git a/src/blocks/crates/property/src/note_block_instrument.rs b/src/blocks/crates/property/src/note_block_instrument.rs new file mode 100644 index 00000000..17acd8fa --- /dev/null +++ b/src/blocks/crates/property/src/note_block_instrument.rs @@ -0,0 +1,30 @@ +use crate::enum_property; + +enum_property!( + NoteBlockInstrument, + Harp => "harp", + BaseDrum => "basedrum", + Snare => "snare", + Hat => "hat", + Bass => "bass", + Flute => "flute", + Bell => "bell", + Guitar => "guitar", + Chime => "chime", + Xylophone => "xylophone", + IronXylophone => "iron_xylophone", + CowBell => "cow_bell", + Didgeridoo => "didgeridoo", + Bit => "bit", + Banjo => "banjo", + Pling => "pling", + Zombie => "zombie", + Skeleton => "skeleton", + Creeper => "creeper", + Dragon => "dragon", + WitherSkeleton => "wither_skeleton", + Piglin => "piglin", + CustomHead => "custom_head", +); + +// TODO: return sound events based on the variant diff --git a/src/blocks/crates/property/src/simple.rs b/src/blocks/crates/property/src/simple.rs new file mode 100644 index 00000000..0f2039fd --- /dev/null +++ b/src/blocks/crates/property/src/simple.rs @@ -0,0 +1,219 @@ +/// All of these enums come directly from the enums found in the `net.minecraft.world.level.block.state.properties` package. +use crate::enum_property; + +enum_property!( + AttachFace, + Floor => "floor", + Wall => "wall", + Ceiling => "ceiling", +); + +enum_property!( + Axis, + X => "x", + Y => "y", + Z => "z", +); + +enum_property!( + BambooLeaves, + None => "none", + Small => "small", + Large => "large", +); + +enum_property!( + BedPart, + Head => "head", + Foot => "foot", +); + +enum_property!( + BellAttachType, + Floor => "floor", + Ceiling => "ceiling", + SingleWall => "single_wall", + DoubleWall => "double_wall", +); + +enum_property!( + ChestType, + Single => "single", + Left => "left", + Right => "right", +); + +enum_property!( + ComparatorMode, + Compare => "compare", + Subtract => "subtract", +); + +enum_property!( + CreakingHeartState, + Uprooted => "uprooted", + Dormant => "dormant", + Awake => "awake", +); + +enum_property!( + Direction, + Down => "down", + Up => "up", + North => "north", + South => "south", + East => "east", + West => "west", +); + +enum_property!( + DoorHingeSide, + Left => "left", + Right => "right", +); + +enum_property!( + DripstoneThickness, + TipMerge => "tip_merge", + Tip => "tip", + Frustum => "frustum", + Middle => "middle", + Base => "base", +); + +enum_property!( + FrontAndTop, + DownEast => "down_east", + DownNorth => "down_north", + DownSouth => "down_south", + DownWest => "down_west", + UpEast => "up_east", + UpNorth => "up_north", + UpSouth => "up_south", + UpWest => "up_west", + WestUp => "west_up", + EastUp => "east_up", + NorthUp => "north_up", + SouthUp => "south_up", +); + +enum_property!( + Half, + Top => "top", + Bottom => "bottom", +); + +enum_property!( + CopperGolemPose, + Standing => "standing", + Sitting => "sitting", + Running => "running", + Star => "star", +); + +enum_property!( + PistonType, + Default => "normal", + Sticky => "sticky", +); + +enum_property!( + RailShape, + NorthSouth => "north_south", + EastWest => "east_west", + AscendingEast => "ascending_east", + AscendingWest => "ascending_west", + AscendingNorth => "ascending_north", + AscendingSouth => "ascending_south", + SouthEast => "south_east", + SouthWest => "south_west", + NorthWest => "north_west", + NorthEast => "north_east", +); + +enum_property!( + RedstoneSide, + Up => "up", + Side => "side", + None => "none", +); + +enum_property!( + SculkSensorPhase, + Inactive => "inactive", + Active => "active", + Cooldown => "cooldown", +); + +enum_property!( + SideChainPart, + Unconnected => "unconnected", + Right => "right", + Center => "center", + Left => "left", +); + +enum_property!( + SlabType, + Top => "top", + Bottom => "bottom", + Double => "double", +); + +enum_property!( + StairsShape, + Straight => "straight", + InnerLeft => "inner_left", + InnerRight => "inner_right", + OuterLeft => "outer_left", + OuterRight => "outer_right", +); + +enum_property!( + StructureMode, + Save => "save", + Load => "load", + Corner => "corner", + Data => "data", +); + +enum_property!( + TestBlockMode, + Start => "start", + Log => "log", + Fail => "fail", + Accept => "accept", +); + +enum_property!( + Tilt, + None => "none", + Unstable => "unstable", + Partial => "partial", + Full => "full", +); + +enum_property!( + TrialSpawnerState, + Inactive => "inactive", + WaitingForPlayers => "waiting_for_players", + Active => "active", + WaitingForRewardEjection => "waiting_for_reward_ejection", + EjectingReward => "ejecting_reward", + Cooldown => "cooldown", +); + +enum_property!( + VaultState, + Inactive => "inactive", + Active => "active", + Unlocking => "unlocking", + Ejecting => "ejecting", +); + +enum_property!( + WallSide, + None => "none", + Low => "low", + Tall => "tall", +); diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs new file mode 100644 index 00000000..9c26f517 --- /dev/null +++ b/src/blocks/src/behavior_trait.rs @@ -0,0 +1,119 @@ +use crate::PlacementContext; +use temper_core::pos::BlockPos; +use temper_world::World; + +/// Macro to autogenerate the `BlockBehavior` trait and associated VTable structs. +/// +/// This macro simply exists to make adding methods to blocks easier. It should NOT be used anywhere except in this file, and should also only be used once. +/// See below this macro for where to add functions. +/// +/// The syntax for this macro is as follows: `fn ([mut]; ) [-> ; ]` +/// - `name`: The name of the method +/// - `mut`: Optional, whether the function takes a mutable reference to the block or not +/// - `arguments`: Any additional arguments to the method +/// - `return type`: Optional, what the function returns +/// - `default return value`: Optional, required if return type is set, the default expression to use for blocks that do not implement this method. +macro_rules! block_behavior_trait { + ($(fn $name:ident($($mut_meta:ident)?; $($argument:ident: $ty:ty),*) $(-> $ret:ty; $default:expr)?),* $(,)?) => { + macro_rules! ptr_ret_ty { + (mut) => { + u32 + }; + () => { + () + }; + (mut $ret:ty) => { + (u32, $ret) + }; + ($ret:ty) => { + $ret + }; + } + + macro_rules! lambda_ret_ty { + (mut; $data:expr;) => { + $data + .try_into() + .unwrap_or_else(|_| panic!("Failed to convert block data back into id")) + }; + () => { + () + }; + (mut; $data:expr; $ret:ty) => { + ( + $data + .try_into() + .unwrap_or_else(|_| panic!("Failed to convert block data back into id")), + _ret, + ) + }; + ($ret:ty) => { + _ret + }; + } + + pub trait BlockBehavior: + TryInto + TryFrom + Clone + std::fmt::Debug + { + $( + fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { $($default)? } + )* + } + + impl BlockBehavior for T + where + T: TryInto + TryFrom + Clone + std::fmt::Debug, + { + $( + #[inline(always)] + default fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { $($default)? } + )* + } + + pub struct BlockBehaviorTable { + $( + $name: fn(id: u32, $($argument: $ty),*) -> ptr_ret_ty!{$($mut_meta)?} + ),* + } + + impl BlockBehaviorTable { + pub const fn from() -> Self { + Self { + $( + $name: |id, $($argument),*| { + let $($mut_meta)? data = T::try_from(id).unwrap_or_else(|_| panic!("Failed to convert id to data")); + let _ret = data.$name($($argument),*); + lambda_ret_ty!($($mut_meta; data;)? $($ret)?) + } + ),* + } + } + } + + pub struct StateBehaviorTable { + block: &'static BlockBehaviorTable, + id: u32, + } + + impl StateBehaviorTable { + pub const fn spin_off(block: &'static BlockBehaviorTable, id: u32) -> Self { + Self { block, id } + } + + $( + pub fn $name(&self, $($argument: $ty),*) -> ptr_ret_ty!{$($mut_meta)? $($ret)?} { + (self.block.$name)(self.id, $($argument),*) + } + )* + } + }; +} + +/// This is where methods are defined for blocks. See the macro above for the syntax. +/// +/// This is the only place where the `block_behavior_trait!` macro should be used. +block_behavior_trait!( + fn get_placement_state(mut; _context: PlacementContext, _world: &World, _pos: BlockPos), + fn update(mut; _world: &World, _pos: BlockPos), + fn test(;), +); diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs new file mode 100644 index 00000000..2c9a6a0c --- /dev/null +++ b/src/blocks/src/lib.rs @@ -0,0 +1,79 @@ +#![feature(min_specialization)] + +use bevy_math::DVec2; +use temper_block_properties::SlabType; +use temper_blocks_generated::{SlabBlock, SnowyBlock}; +use temper_core::block::BlockFace; +use temper_macros::match_block; +use temper_world::block_state_id::BlockStateId; +use temper_world::pos::BlockPos; +use temper_world::World; + +mod behavior_trait; + +#[allow(unused_imports)] // Used in the include! +use crate::behavior_trait::BlockBehaviorTable; + +pub use crate::behavior_trait::{BlockBehavior, StateBehaviorTable}; + +pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = + include!(concat!(env!("OUT_DIR"), "/mappings.rs")); + +pub struct PlacementContext { + pub face: BlockFace, + pub cursor: DVec2, +} + +impl BlockBehavior for SlabBlock { + #[inline(always)] + fn get_placement_state(&mut self, context: PlacementContext, world: &World, pos: BlockPos) { + let block = world + .get_block_and_fetch(pos, "overworld") + .unwrap_or(BlockStateId::new(0)); + + self.waterlogged = match_block!("water", block); + self.ty = match context.face { + BlockFace::Top => SlabType::Bottom, + BlockFace::Bottom => SlabType::Top, + _ => { + if context.cursor.y > 0.5 { + SlabType::Top + } else { + SlabType::Bottom + } + } + } + } + + #[inline(always)] + fn test(&self) { + panic!("hello") + } +} + +fn has_snow_above(world: &World, pos: BlockPos) -> bool { + world + .get_block_and_fetch(pos + (0, 1, 0), "overworld") + .is_ok_and(|id| match_block!("snow", id)) +} + +impl BlockBehavior for SnowyBlock { + fn get_placement_state(&mut self, _context: PlacementContext, world: &World, pos: BlockPos) { + self.snowy = has_snow_above(world, pos); + } + + fn update(&mut self, world: &World, pos: BlockPos) { + self.snowy = has_snow_above(world, pos); + } +} + +#[cfg(test)] +mod tests { + use crate::BLOCK_MAPPINGS; + + #[test] + #[ignore] + fn test() { + BLOCK_MAPPINGS[12051].test(); + } +} From 9197b72877666d77c0d9efb3e3ddb52d274bce58 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Sun, 29 Mar 2026 18:33:58 -0500 Subject: [PATCH 02/30] Fix errors --- src/blocks/rust-toolchain.toml | 2 + src/blocks/src/behavior_trait.rs | 18 +++--- src/blocks/src/lib.rs | 15 +++-- src/core/src/block_face.rs | 75 +++++++++++++++++++++++++ src/core/src/lib.rs | 1 + src/game_systems/src/packets/Cargo.toml | 1 + 6 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 src/blocks/rust-toolchain.toml create mode 100644 src/core/src/block_face.rs diff --git a/src/blocks/rust-toolchain.toml b/src/blocks/rust-toolchain.toml new file mode 100644 index 00000000..271800cb --- /dev/null +++ b/src/blocks/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index 9c26f517..f3172ab3 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -22,11 +22,11 @@ macro_rules! block_behavior_trait { () => { () }; - (mut $ret:ty) => { - (u32, $ret) + (mut $retb:ty) => { + (u32, $retb) }; - ($ret:ty) => { - $ret + ($retb:ty) => { + $retb }; } @@ -39,7 +39,7 @@ macro_rules! block_behavior_trait { () => { () }; - (mut; $data:expr; $ret:ty) => { + (mut; $data:expr; $retb:ty) => { ( $data .try_into() @@ -47,7 +47,7 @@ macro_rules! block_behavior_trait { _ret, ) }; - ($ret:ty) => { + ($retb:ty) => { _ret }; } @@ -109,9 +109,9 @@ macro_rules! block_behavior_trait { }; } -/// This is where methods are defined for blocks. See the macro above for the syntax. -/// -/// This is the only place where the `block_behavior_trait!` macro should be used. +// This is where methods are defined for blocks. See the macro above for the syntax. +// +// This is the only place where the `block_behavior_trait!` macro should be used. block_behavior_trait!( fn get_placement_state(mut; _context: PlacementContext, _world: &World, _pos: BlockPos), fn update(mut; _world: &World, _pos: BlockPos), diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index 2c9a6a0c..c1ec3924 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -3,10 +3,11 @@ use bevy_math::DVec2; use temper_block_properties::SlabType; use temper_blocks_generated::{SlabBlock, SnowyBlock}; -use temper_core::block::BlockFace; +use temper_core::block_face::BlockFace; +use temper_core::block_state_id::BlockStateId; +use temper_core::dimension::Dimension; use temper_macros::match_block; -use temper_world::block_state_id::BlockStateId; -use temper_world::pos::BlockPos; +use temper_core::pos::BlockPos; use temper_world::World; mod behavior_trait; @@ -28,7 +29,8 @@ impl BlockBehavior for SlabBlock { #[inline(always)] fn get_placement_state(&mut self, context: PlacementContext, world: &World, pos: BlockPos) { let block = world - .get_block_and_fetch(pos, "overworld") + .get_chunk(pos.chunk(), Dimension::Overworld) + .and_then(|c| Ok(c.get_block(pos.chunk_block_pos()))) .unwrap_or(BlockStateId::new(0)); self.waterlogged = match_block!("water", block); @@ -52,8 +54,11 @@ impl BlockBehavior for SlabBlock { } fn has_snow_above(world: &World, pos: BlockPos) -> bool { + let pos = pos + (0, 1, 0); + world - .get_block_and_fetch(pos + (0, 1, 0), "overworld") + .get_chunk(pos.chunk(), Dimension::Overworld) + .and_then(|c| Ok(c.get_block(pos.chunk_block_pos()))) .is_ok_and(|id| match_block!("snow", id)) } diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs new file mode 100644 index 00000000..e1c2e358 --- /dev/null +++ b/src/core/src/block_face.rs @@ -0,0 +1,75 @@ +use std::io::Read; +use bevy_math::IVec3; +use temper_codec::decode::{NetDecode, NetDecodeOpts}; +use temper_codec::decode::errors::NetDecodeError; +use temper_codec::net_types::var_int::VarInt; +use temper_nbt::tokio::io::AsyncRead; + +#[derive(Debug, Clone)] +pub enum BlockFace { + Top, + Bottom, + North, + South, + East, + West, +} + +impl BlockFace { + pub fn is_x_axis(&self) -> bool { + matches!(self, BlockFace::East | BlockFace::West) + } + + pub fn is_y_axis(&self) -> bool { + matches!(self, BlockFace::Top | BlockFace::Bottom) + } + + pub fn is_z_axis(&self) -> bool { + matches!(self, BlockFace::North | BlockFace::South) + } + + /// Returns the translation vector that will get the block that touches this face. + pub fn translation_vec(&self) -> IVec3 { + match self { + BlockFace::Top => IVec3::new(0, 1, 0), + BlockFace::Bottom => IVec3::new(0, -1, 0), + BlockFace::North => IVec3::new(0, 0, -1), + BlockFace::South => IVec3::new(0, 0, 1), + BlockFace::East => IVec3::new(1, 0, 0), + BlockFace::West => IVec3::new(-1, 0, 0), + } + } +} + +impl NetDecode for BlockFace { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> Result { + let VarInt(data) = VarInt::decode(reader, opts)?; + + match data { + 0 => Ok(BlockFace::Bottom), + 1 => Ok(BlockFace::Top), + 2 => Ok(BlockFace::North), + 3 => Ok(BlockFace::South), + 4 => Ok(BlockFace::West), + 5 => Ok(BlockFace::East), + _ => Err(NetDecodeError::InvalidEnumVariant), + } + } + + async fn decode_async( + reader: &mut R, + opts: &NetDecodeOpts, + ) -> Result { + let VarInt(data) = VarInt::decode_async(reader, opts).await?; + + match data { + 0 => Ok(BlockFace::Bottom), + 1 => Ok(BlockFace::Top), + 2 => Ok(BlockFace::North), + 3 => Ok(BlockFace::South), + 4 => Ok(BlockFace::West), + 5 => Ok(BlockFace::East), + _ => Err(NetDecodeError::InvalidEnumVariant), + } + } +} \ No newline at end of file diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index af38f11f..cb579119 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -7,3 +7,4 @@ pub mod color; pub mod dimension; pub mod mq; pub mod pos; +pub mod block_face; diff --git a/src/game_systems/src/packets/Cargo.toml b/src/game_systems/src/packets/Cargo.toml index efe130c4..ee909cb7 100644 --- a/src/game_systems/src/packets/Cargo.toml +++ b/src/game_systems/src/packets/Cargo.toml @@ -17,6 +17,7 @@ temper-commands = { workspace = true } temper-net-runtime = { workspace = true } temper-codec = { workspace = true } temper-config = { workspace = true } +temper-blocks = { workspace = true } once_cell = { workspace = true } serde_json = { workspace = true } temper-macros = { workspace = true } From 2c131d0a9be96ac112d040bbadbafad840b8bd98 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Sun, 29 Mar 2026 18:36:48 -0500 Subject: [PATCH 03/30] Formatting and clippy --- src/blocks/build.rs | 8 ++++---- src/blocks/src/lib.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/blocks/build.rs b/src/blocks/build.rs index 54590ca1..8f5353e7 100644 --- a/src/blocks/build.rs +++ b/src/blocks/build.rs @@ -1,11 +1,11 @@ -use temper_blocks_build::complex::fill_complex_block_mappings; -use temper_blocks_build::config::{get_block_states, get_build_config}; -use temper_blocks_build::separate_blocks; -use temper_blocks_build::simple::fill_simple_block_mappings; use quote::__private::TokenStream; use quote::quote; use std::fs; use std::path::Path; +use temper_blocks_build::complex::fill_complex_block_mappings; +use temper_blocks_build::config::{get_block_states, get_build_config}; +use temper_blocks_build::separate_blocks; +use temper_blocks_build::simple::fill_simple_block_mappings; fn main() { println!("cargo:rerun-if-changed=build.rs"); diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index c1ec3924..dfa0410a 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -6,8 +6,8 @@ use temper_blocks_generated::{SlabBlock, SnowyBlock}; use temper_core::block_face::BlockFace; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; -use temper_macros::match_block; use temper_core::pos::BlockPos; +use temper_macros::match_block; use temper_world::World; mod behavior_trait; @@ -30,7 +30,7 @@ impl BlockBehavior for SlabBlock { fn get_placement_state(&mut self, context: PlacementContext, world: &World, pos: BlockPos) { let block = world .get_chunk(pos.chunk(), Dimension::Overworld) - .and_then(|c| Ok(c.get_block(pos.chunk_block_pos()))) + .map(|c| c.get_block(pos.chunk_block_pos())) .unwrap_or(BlockStateId::new(0)); self.waterlogged = match_block!("water", block); @@ -58,7 +58,7 @@ fn has_snow_above(world: &World, pos: BlockPos) -> bool { world .get_chunk(pos.chunk(), Dimension::Overworld) - .and_then(|c| Ok(c.get_block(pos.chunk_block_pos()))) + .map(|c| c.get_block(pos.chunk_block_pos())) .is_ok_and(|id| match_block!("snow", id)) } From edce21e622ea0df98b5629d1069a409275fc141b Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Tue, 31 Mar 2026 19:21:54 -0500 Subject: [PATCH 04/30] Add functions to block state id --- src/blocks/src/behavior_trait.rs | 44 +++++++++++++++++++++++++++++++- src/blocks/src/lib.rs | 2 +- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index f3172ab3..b4fd1317 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,4 +1,5 @@ -use crate::PlacementContext; +use temper_core::block_state_id::BlockStateId; +use crate::{PlacementContext, BLOCK_MAPPINGS}; use temper_core::pos::BlockPos; use temper_world::World; @@ -30,6 +31,21 @@ macro_rules! block_behavior_trait { }; } + macro_rules! id_ret_decode { + (mut, $in_data:expr) => { + ($in_data, ()) + }; + (, $in_data:expr) => { + ((), ()) + }; + (mut $retb:ty, $in_data:expr) => { + $in_data + }; + ($retb:ty, $in_data:expr) => { + ((), $retb) + }; + } + macro_rules! lambda_ret_ty { (mut; $data:expr;) => { $data @@ -60,6 +76,13 @@ macro_rules! block_behavior_trait { )* } + #[allow(dead_code)] + pub trait BlockDispatch { + $( + fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { $($default)? } + )* + } + impl BlockBehavior for T where T: TryInto + TryFrom + Clone + std::fmt::Debug, @@ -106,6 +129,25 @@ macro_rules! block_behavior_trait { } )* } + + macro_rules! update_self { + (mut, $s:expr, $new_id:expr) => { + *$s = Self::new($new_id); + }; + (, $s:expr, $new_id:expr) => { + + }; + } + + impl BlockDispatch for BlockStateId { + $( + fn $name(& $($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { + let (_new_id, _ret) = id_ret_decode!{$($mut_meta)? $($ret)?, BLOCK_MAPPINGS[self.raw() as usize].$name($($argument),*)}; + update_self!{$($mut_meta)?, self, _new_id} + _ret + } + )* + } }; } diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index dfa0410a..ae2fcd50 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -15,7 +15,7 @@ mod behavior_trait; #[allow(unused_imports)] // Used in the include! use crate::behavior_trait::BlockBehaviorTable; -pub use crate::behavior_trait::{BlockBehavior, StateBehaviorTable}; +pub use crate::behavior_trait::{BlockBehavior, BlockDispatch, StateBehaviorTable}; pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); From 155e07c684a720c914ddc359b9bf5892e4d43d6e Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Tue, 31 Mar 2026 20:22:09 -0500 Subject: [PATCH 05/30] Implement block placing to test --- .../src/packets/src/place_block.rs | 104 ++++++++++-------- src/net/protocol/src/incoming/place_block.rs | 3 +- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 317adf59..c3ae9d98 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -14,13 +14,16 @@ use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use tracing::{debug, error, trace}; -use bevy_math::DVec3; +use bevy_math::{DVec2, DVec3, Vec2}; use block_placing::PlacedBlocks; use std::collections::HashMap; use temper_components::player::rotation::Rotation; use temper_config::server_config::get_global_config; +use temper_core::block_state_id::ITEM_TO_BLOCK_MAPPING; use temper_core::dimension::Dimension; use temper_core::mq; +use temper_blocks::BlockDispatch; +use temper_core::block_face::BlockFace; use temper_inventories::hotbar::Hotbar; use temper_inventories::inventory::Inventory; use temper_messages::world_change::WorldChange; @@ -110,16 +113,7 @@ pub fn handle( trace!("Block placement out of bounds: {}", block_pos); continue 'ev_loop; } - let offset_pos = block_pos - + match event.face.0 { - 0 => (0, -1, 0), - 1 => (0, 1, 0), - 2 => (0, 0, -1), - 3 => (0, 0, 1), - 4 => (-1, 0, 0), - 5 => (1, 0, 0), - _ => (0, 0, 0), - }; + let offset_pos = block_pos + event.face.translation_vec().into(); let block_clicked = { let chunk = state @@ -165,43 +159,61 @@ pub fn handle( .expect("Failed to load or generate chunk"); chunk.get_block(offset_pos.chunk_block_pos()) }; - - let placed_blocks = block_placing::place_item( - state.0.clone(), - block_placing::BlockPlaceContext { - block_clicked, - block_position: offset_pos, - face_clicked: match event.face.0 { - 0 => block_placing::BlockFace::Bottom, - 1 => block_placing::BlockFace::Top, - 2 => block_placing::BlockFace::North, - 3 => block_placing::BlockFace::South, - 4 => block_placing::BlockFace::West, - 5 => block_placing::BlockFace::East, - _ => { - debug!("Invalid block face"); - continue 'ev_loop; - } - }, - click_position: DVec3::new( - event.cursor_x as f64, - event.cursor_y as f64, - event.cursor_z as f64, - ), - player_position: *pos, - player_rotation: *rot, - item_used: item_id, + + let mut block_state = ITEM_TO_BLOCK_MAPPING + .get() + .unwrap() + .get(&(item_id.as_u32() as i32)) + .copied() + .unwrap(); + + block_state.get_placement_state( + temper_blocks::PlacementContext { + face: event.face, + cursor: DVec2::new(event.cursor_x as _, event.cursor_y as _), }, - ) - .unwrap_or_else(|err| { - error!("Block placement failed: {:?}", err); - PlacedBlocks { - blocks: HashMap::new(), - take_item: false, - } - }); + &state.0.world, + offset_pos, + ); + + let placed_blocks = vec![(block_pos, block_state)]; + + // let placed_blocks = block_placing::place_item( + // state.0.clone(), + // block_placing::BlockPlaceContext { + // block_clicked, + // block_position: offset_pos, + // face_clicked: match event.face.0 { + // 0 => block_placing::BlockFace::Bottom, + // 1 => block_placing::BlockFace::Top, + // 2 => block_placing::BlockFace::North, + // 3 => block_placing::BlockFace::South, + // 4 => block_placing::BlockFace::West, + // 5 => block_placing::BlockFace::East, + // _ => { + // debug!("Invalid block face"); + // continue 'ev_loop; + // } + // }, + // click_position: DVec3::new( + // event.cursor_x as f64, + // event.cursor_y as f64, + // event.cursor_z as f64, + // ), + // player_position: *pos, + // player_rotation: *rot, + // item_used: item_id, + // }, + // ) + // .unwrap_or_else(|err| { + // error!("Block placement failed: {:?}", err); + // PlacedBlocks { + // blocks: HashMap::new(), + // take_item: false, + // } + // }); - for (block_pos, block_state) in placed_blocks.blocks { + for (block_pos, block_state) in placed_blocks { let block_chunk = block_pos.chunk(); world_change.write(WorldChange { chunk: Some(block_chunk), diff --git a/src/net/protocol/src/incoming/place_block.rs b/src/net/protocol/src/incoming/place_block.rs index c3692543..703e88d1 100644 --- a/src/net/protocol/src/incoming/place_block.rs +++ b/src/net/protocol/src/incoming/place_block.rs @@ -1,5 +1,6 @@ use temper_codec::net_types::network_position::NetworkPosition; use temper_codec::net_types::var_int::VarInt; +use temper_core::block_face::BlockFace; use temper_macros::{NetDecode, packet}; #[derive(NetDecode, Debug)] @@ -7,7 +8,7 @@ use temper_macros::{NetDecode, packet}; pub struct PlaceBlock { pub hand: VarInt, pub position: NetworkPosition, - pub face: VarInt, + pub face: BlockFace, pub cursor_x: f32, pub cursor_y: f32, pub cursor_z: f32, From c042da0f949d728fa7ac936f51d660320c9a0d53 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 1 Apr 2026 20:39:35 -0500 Subject: [PATCH 06/30] Add README documentation and unknown block warning --- src/blocks/README.md | 50 ++++++++++++++++++++++++++ src/blocks/crates/build/src/complex.rs | 9 +++++ 2 files changed, 59 insertions(+) create mode 100644 src/blocks/README.md diff --git a/src/blocks/README.md b/src/blocks/README.md new file mode 100644 index 00000000..825f42d9 --- /dev/null +++ b/src/blocks/README.md @@ -0,0 +1,50 @@ +# Temper Blocks + +This is a quick tutorial on how to use this library to create and modify block behavior and structs. + +## Tips and Notes + +- If the build script is emitting a warning about an unknown block, see the **Adding / Modifying Block Structs** section for more information. + +## Creating Block Behavior + +To create a new function for blocks to implement, navigate to the `behavior_trait.rs` file. Due to the complexity of the inner workings of the system, a macro has been built to make creating functions for blocks super easy. The macro syntax is pretty simple: + +```rust +block_behavior_trait!( + fn ([mut]; ) [-> ; {>(); + if name.starts_with("GeneratedStruct") { + println!("cargo::warning=Unknown block type detected. See src/blocks/README.md for more information. (Saved as {}, associated blocks: {:?})", + name, + associated_blocks + .iter() + .map(|(name, _)| name) + ); + } + let struct_name = format_ident!("{name}"); match associated_blocks.len() { From 5ceb126d62d8ce3c8065d381949529fdbf26af92 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 1 Apr 2026 21:57:03 -0500 Subject: [PATCH 07/30] Remove need for min_specialization feature by implementing BlockBehavior trait on block structs --- src/blocks/rust-toolchain.toml | 2 -- src/blocks/src/bed_block.rs | 6 ++++ src/blocks/src/behavior_trait.rs | 10 ------- src/blocks/src/bubble_column.rs | 6 ++++ src/blocks/src/building/mod.rs | 3 ++ src/blocks/src/building/pillar_block.rs | 6 ++++ src/blocks/src/building/simple_block.rs | 6 ++++ src/blocks/src/building/stairs.rs | 6 ++++ src/blocks/src/cake.rs | 6 ++++ src/blocks/src/candle_cake.rs | 6 ++++ src/blocks/src/decorative/banner.rs | 6 ++++ src/blocks/src/decorative/bell.rs | 6 ++++ src/blocks/src/decorative/candle.rs | 6 ++++ src/blocks/src/decorative/chain.rs | 6 ++++ .../src/decorative/chiseled_bookshelf.rs | 6 ++++ src/blocks/src/decorative/decorated_pot.rs | 6 ++++ src/blocks/src/decorative/door.rs | 6 ++++ src/blocks/src/decorative/fence_gate.rs | 6 ++++ src/blocks/src/decorative/fence_pane.rs | 6 ++++ src/blocks/src/decorative/hanging_sign.rs | 6 ++++ src/blocks/src/decorative/lantern.rs | 6 ++++ src/blocks/src/decorative/mod.rs | 16 ++++++++++ src/blocks/src/decorative/note_block.rs | 6 ++++ src/blocks/src/decorative/sign.rs | 6 ++++ src/blocks/src/decorative/trapdoor.rs | 6 ++++ src/blocks/src/decorative/wall.rs | 6 ++++ .../src/decorative/waterloggable_wall.rs | 6 ++++ src/blocks/src/facing_block.rs | 6 ++++ src/blocks/src/fire.rs | 6 ++++ src/blocks/src/functional/barrel.rs | 6 ++++ src/blocks/src/functional/brewing_stand.rs | 6 ++++ src/blocks/src/functional/campfire.rs | 6 ++++ src/blocks/src/functional/cauldron.rs | 6 ++++ src/blocks/src/functional/chest.rs | 6 ++++ src/blocks/src/functional/command_block.rs | 6 ++++ src/blocks/src/functional/composter.rs | 6 ++++ src/blocks/src/functional/end_portal.rs | 6 ++++ src/blocks/src/functional/furnace.rs | 6 ++++ src/blocks/src/functional/grindstone.rs | 6 ++++ src/blocks/src/functional/jigsaw.rs | 6 ++++ src/blocks/src/functional/lectern.rs | 6 ++++ src/blocks/src/functional/light.rs | 6 ++++ src/blocks/src/functional/mod.rs | 19 ++++++++++++ src/blocks/src/functional/respawn_anchor.rs | 6 ++++ src/blocks/src/functional/scaffolding.rs | 6 ++++ src/blocks/src/functional/structure.rs | 6 ++++ src/blocks/src/functional/test.rs | 6 ++++ src/blocks/src/functional/trial_spawner.rs | 6 ++++ src/blocks/src/functional/vault.rs | 6 ++++ src/blocks/src/lib.rs | 18 +++++++++-- src/blocks/src/liquid.rs | 6 ++++ src/blocks/src/nature/bamboo.rs | 6 ++++ src/blocks/src/nature/big_dripleaf.rs | 6 ++++ src/blocks/src/nature/chorus.rs | 6 ++++ src/blocks/src/nature/cocoa_beans.rs | 6 ++++ src/blocks/src/nature/creaking_heart.rs | 6 ++++ src/blocks/src/nature/crop.rs | 6 ++++ src/blocks/src/nature/double_plant_block.rs | 6 ++++ src/blocks/src/nature/dripstone.rs | 6 ++++ src/blocks/src/nature/farmland.rs | 6 ++++ src/blocks/src/nature/flower_cover.rs | 6 ++++ src/blocks/src/nature/frosted_ice.rs | 6 ++++ src/blocks/src/nature/glow_berries.rs | 6 ++++ src/blocks/src/nature/glow_berries_plant.rs | 6 ++++ src/blocks/src/nature/hive.rs | 6 ++++ src/blocks/src/nature/large_mushroom.rs | 6 ++++ src/blocks/src/nature/leaf_litter.rs | 6 ++++ src/blocks/src/nature/leaves.rs | 6 ++++ src/blocks/src/nature/lichen.rs | 6 ++++ src/blocks/src/nature/mangrove_propagule.rs | 6 ++++ src/blocks/src/nature/mod.rs | 30 +++++++++++++++++++ src/blocks/src/nature/pale_hanging_moss.rs | 6 ++++ src/blocks/src/nature/pale_moss_carpet.rs | 6 ++++ src/blocks/src/nature/pitcher_crop.rs | 6 ++++ src/blocks/src/nature/sapling_block.rs | 6 ++++ src/blocks/src/nature/sea_pickle.rs | 6 ++++ src/blocks/src/nature/small_dripleaf.rs | 6 ++++ src/blocks/src/nature/sniffer_egg.rs | 6 ++++ src/blocks/src/nature/snow.rs | 6 ++++ src/blocks/src/nature/stem.rs | 6 ++++ src/blocks/src/nature/turtle_egg.rs | 6 ++++ src/blocks/src/nature/vine.rs | 6 ++++ src/blocks/src/redstone/bulb.rs | 6 ++++ src/blocks/src/redstone/button.rs | 6 ++++ .../src/redstone/calibrated_sculk_sensor.rs | 6 ++++ src/blocks/src/redstone/comparator.rs | 6 ++++ src/blocks/src/redstone/crafter.rs | 6 ++++ src/blocks/src/redstone/daylight_detector.rs | 6 ++++ src/blocks/src/redstone/dispenser.rs | 6 ++++ src/blocks/src/redstone/hopper.rs | 6 ++++ src/blocks/src/redstone/jukebox.rs | 6 ++++ src/blocks/src/redstone/lamp.rs | 6 ++++ src/blocks/src/redstone/lever.rs | 6 ++++ src/blocks/src/redstone/lightning_rod.rs | 6 ++++ src/blocks/src/redstone/mod.rs | 30 +++++++++++++++++++ src/blocks/src/redstone/observer.rs | 6 ++++ src/blocks/src/redstone/ore.rs | 6 ++++ src/blocks/src/redstone/piston/head.rs | 6 ++++ src/blocks/src/redstone/piston/mod.rs | 9 ++++++ src/blocks/src/redstone/piston/moving_head.rs | 6 ++++ src/blocks/src/redstone/pressure_plate.rs | 6 ++++ src/blocks/src/redstone/rail.rs | 6 ++++ src/blocks/src/redstone/redstone_rail.rs | 6 ++++ src/blocks/src/redstone/repeater.rs | 6 ++++ src/blocks/src/redstone/sculk_catalyst.rs | 6 ++++ src/blocks/src/redstone/sculk_sensor.rs | 6 ++++ src/blocks/src/redstone/sculk_shrieker.rs | 6 ++++ src/blocks/src/redstone/target.rs | 6 ++++ src/blocks/src/redstone/tnt.rs | 6 ++++ src/blocks/src/redstone/torch.rs | 6 ++++ src/blocks/src/redstone/tripwire.rs | 6 ++++ src/blocks/src/redstone/tripwire_hook.rs | 6 ++++ src/blocks/src/redstone/wall_torch.rs | 6 ++++ .../src/redstone/weighted_pressure_plate.rs | 6 ++++ src/blocks/src/redstone/wire.rs | 6 ++++ src/blocks/src/skull.rs | 6 ++++ src/blocks/src/suspicious_block.rs | 6 ++++ src/blocks/src/wall_skull.rs | 6 ++++ src/blocks/src/waterloggable_block.rs | 6 ++++ 119 files changed, 783 insertions(+), 14 deletions(-) delete mode 100644 src/blocks/rust-toolchain.toml create mode 100644 src/blocks/src/bed_block.rs create mode 100644 src/blocks/src/bubble_column.rs create mode 100644 src/blocks/src/building/mod.rs create mode 100644 src/blocks/src/building/pillar_block.rs create mode 100644 src/blocks/src/building/simple_block.rs create mode 100644 src/blocks/src/building/stairs.rs create mode 100644 src/blocks/src/cake.rs create mode 100644 src/blocks/src/candle_cake.rs create mode 100644 src/blocks/src/decorative/banner.rs create mode 100644 src/blocks/src/decorative/bell.rs create mode 100644 src/blocks/src/decorative/candle.rs create mode 100644 src/blocks/src/decorative/chain.rs create mode 100644 src/blocks/src/decorative/chiseled_bookshelf.rs create mode 100644 src/blocks/src/decorative/decorated_pot.rs create mode 100644 src/blocks/src/decorative/door.rs create mode 100644 src/blocks/src/decorative/fence_gate.rs create mode 100644 src/blocks/src/decorative/fence_pane.rs create mode 100644 src/blocks/src/decorative/hanging_sign.rs create mode 100644 src/blocks/src/decorative/lantern.rs create mode 100644 src/blocks/src/decorative/mod.rs create mode 100644 src/blocks/src/decorative/note_block.rs create mode 100644 src/blocks/src/decorative/sign.rs create mode 100644 src/blocks/src/decorative/trapdoor.rs create mode 100644 src/blocks/src/decorative/wall.rs create mode 100644 src/blocks/src/decorative/waterloggable_wall.rs create mode 100644 src/blocks/src/facing_block.rs create mode 100644 src/blocks/src/fire.rs create mode 100644 src/blocks/src/functional/barrel.rs create mode 100644 src/blocks/src/functional/brewing_stand.rs create mode 100644 src/blocks/src/functional/campfire.rs create mode 100644 src/blocks/src/functional/cauldron.rs create mode 100644 src/blocks/src/functional/chest.rs create mode 100644 src/blocks/src/functional/command_block.rs create mode 100644 src/blocks/src/functional/composter.rs create mode 100644 src/blocks/src/functional/end_portal.rs create mode 100644 src/blocks/src/functional/furnace.rs create mode 100644 src/blocks/src/functional/grindstone.rs create mode 100644 src/blocks/src/functional/jigsaw.rs create mode 100644 src/blocks/src/functional/lectern.rs create mode 100644 src/blocks/src/functional/light.rs create mode 100644 src/blocks/src/functional/mod.rs create mode 100644 src/blocks/src/functional/respawn_anchor.rs create mode 100644 src/blocks/src/functional/scaffolding.rs create mode 100644 src/blocks/src/functional/structure.rs create mode 100644 src/blocks/src/functional/test.rs create mode 100644 src/blocks/src/functional/trial_spawner.rs create mode 100644 src/blocks/src/functional/vault.rs create mode 100644 src/blocks/src/liquid.rs create mode 100644 src/blocks/src/nature/bamboo.rs create mode 100644 src/blocks/src/nature/big_dripleaf.rs create mode 100644 src/blocks/src/nature/chorus.rs create mode 100644 src/blocks/src/nature/cocoa_beans.rs create mode 100644 src/blocks/src/nature/creaking_heart.rs create mode 100644 src/blocks/src/nature/crop.rs create mode 100644 src/blocks/src/nature/double_plant_block.rs create mode 100644 src/blocks/src/nature/dripstone.rs create mode 100644 src/blocks/src/nature/farmland.rs create mode 100644 src/blocks/src/nature/flower_cover.rs create mode 100644 src/blocks/src/nature/frosted_ice.rs create mode 100644 src/blocks/src/nature/glow_berries.rs create mode 100644 src/blocks/src/nature/glow_berries_plant.rs create mode 100644 src/blocks/src/nature/hive.rs create mode 100644 src/blocks/src/nature/large_mushroom.rs create mode 100644 src/blocks/src/nature/leaf_litter.rs create mode 100644 src/blocks/src/nature/leaves.rs create mode 100644 src/blocks/src/nature/lichen.rs create mode 100644 src/blocks/src/nature/mangrove_propagule.rs create mode 100644 src/blocks/src/nature/mod.rs create mode 100644 src/blocks/src/nature/pale_hanging_moss.rs create mode 100644 src/blocks/src/nature/pale_moss_carpet.rs create mode 100644 src/blocks/src/nature/pitcher_crop.rs create mode 100644 src/blocks/src/nature/sapling_block.rs create mode 100644 src/blocks/src/nature/sea_pickle.rs create mode 100644 src/blocks/src/nature/small_dripleaf.rs create mode 100644 src/blocks/src/nature/sniffer_egg.rs create mode 100644 src/blocks/src/nature/snow.rs create mode 100644 src/blocks/src/nature/stem.rs create mode 100644 src/blocks/src/nature/turtle_egg.rs create mode 100644 src/blocks/src/nature/vine.rs create mode 100644 src/blocks/src/redstone/bulb.rs create mode 100644 src/blocks/src/redstone/button.rs create mode 100644 src/blocks/src/redstone/calibrated_sculk_sensor.rs create mode 100644 src/blocks/src/redstone/comparator.rs create mode 100644 src/blocks/src/redstone/crafter.rs create mode 100644 src/blocks/src/redstone/daylight_detector.rs create mode 100644 src/blocks/src/redstone/dispenser.rs create mode 100644 src/blocks/src/redstone/hopper.rs create mode 100644 src/blocks/src/redstone/jukebox.rs create mode 100644 src/blocks/src/redstone/lamp.rs create mode 100644 src/blocks/src/redstone/lever.rs create mode 100644 src/blocks/src/redstone/lightning_rod.rs create mode 100644 src/blocks/src/redstone/mod.rs create mode 100644 src/blocks/src/redstone/observer.rs create mode 100644 src/blocks/src/redstone/ore.rs create mode 100644 src/blocks/src/redstone/piston/head.rs create mode 100644 src/blocks/src/redstone/piston/mod.rs create mode 100644 src/blocks/src/redstone/piston/moving_head.rs create mode 100644 src/blocks/src/redstone/pressure_plate.rs create mode 100644 src/blocks/src/redstone/rail.rs create mode 100644 src/blocks/src/redstone/redstone_rail.rs create mode 100644 src/blocks/src/redstone/repeater.rs create mode 100644 src/blocks/src/redstone/sculk_catalyst.rs create mode 100644 src/blocks/src/redstone/sculk_sensor.rs create mode 100644 src/blocks/src/redstone/sculk_shrieker.rs create mode 100644 src/blocks/src/redstone/target.rs create mode 100644 src/blocks/src/redstone/tnt.rs create mode 100644 src/blocks/src/redstone/torch.rs create mode 100644 src/blocks/src/redstone/tripwire.rs create mode 100644 src/blocks/src/redstone/tripwire_hook.rs create mode 100644 src/blocks/src/redstone/wall_torch.rs create mode 100644 src/blocks/src/redstone/weighted_pressure_plate.rs create mode 100644 src/blocks/src/redstone/wire.rs create mode 100644 src/blocks/src/skull.rs create mode 100644 src/blocks/src/suspicious_block.rs create mode 100644 src/blocks/src/wall_skull.rs create mode 100644 src/blocks/src/waterloggable_block.rs diff --git a/src/blocks/rust-toolchain.toml b/src/blocks/rust-toolchain.toml deleted file mode 100644 index 271800cb..00000000 --- a/src/blocks/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" \ No newline at end of file diff --git a/src/blocks/src/bed_block.rs b/src/blocks/src/bed_block.rs new file mode 100644 index 00000000..e9fbb78b --- /dev/null +++ b/src/blocks/src/bed_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BedBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BedBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index b4fd1317..e483c267 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -83,16 +83,6 @@ macro_rules! block_behavior_trait { )* } - impl BlockBehavior for T - where - T: TryInto + TryFrom + Clone + std::fmt::Debug, - { - $( - #[inline(always)] - default fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { $($default)? } - )* - } - pub struct BlockBehaviorTable { $( $name: fn(id: u32, $($argument: $ty),*) -> ptr_ret_ty!{$($mut_meta)?} diff --git a/src/blocks/src/bubble_column.rs b/src/blocks/src/bubble_column.rs new file mode 100644 index 00000000..593e885e --- /dev/null +++ b/src/blocks/src/bubble_column.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BubbleColumnBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BubbleColumnBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/building/mod.rs b/src/blocks/src/building/mod.rs new file mode 100644 index 00000000..86cd559c --- /dev/null +++ b/src/blocks/src/building/mod.rs @@ -0,0 +1,3 @@ +mod stairs; +mod pillar_block; +mod simple_block; diff --git a/src/blocks/src/building/pillar_block.rs b/src/blocks/src/building/pillar_block.rs new file mode 100644 index 00000000..f5511df1 --- /dev/null +++ b/src/blocks/src/building/pillar_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PillarBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PillarBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/building/simple_block.rs b/src/blocks/src/building/simple_block.rs new file mode 100644 index 00000000..f054f591 --- /dev/null +++ b/src/blocks/src/building/simple_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SimpleBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SimpleBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/building/stairs.rs b/src/blocks/src/building/stairs.rs new file mode 100644 index 00000000..d6fe2900 --- /dev/null +++ b/src/blocks/src/building/stairs.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::StairsBlock; +use crate::BlockBehavior; + +impl BlockBehavior for StairsBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/cake.rs b/src/blocks/src/cake.rs new file mode 100644 index 00000000..cc9309b5 --- /dev/null +++ b/src/blocks/src/cake.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CakeBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CakeBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/candle_cake.rs b/src/blocks/src/candle_cake.rs new file mode 100644 index 00000000..2dcc7265 --- /dev/null +++ b/src/blocks/src/candle_cake.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CandleCakeBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CandleCakeBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/banner.rs b/src/blocks/src/decorative/banner.rs new file mode 100644 index 00000000..e47dc420 --- /dev/null +++ b/src/blocks/src/decorative/banner.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BannerBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BannerBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/bell.rs b/src/blocks/src/decorative/bell.rs new file mode 100644 index 00000000..eedf1e67 --- /dev/null +++ b/src/blocks/src/decorative/bell.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BellBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BellBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/candle.rs b/src/blocks/src/decorative/candle.rs new file mode 100644 index 00000000..0751b25a --- /dev/null +++ b/src/blocks/src/decorative/candle.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CandleBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CandleBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/chain.rs b/src/blocks/src/decorative/chain.rs new file mode 100644 index 00000000..c68c9db4 --- /dev/null +++ b/src/blocks/src/decorative/chain.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ChainBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ChainBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/chiseled_bookshelf.rs b/src/blocks/src/decorative/chiseled_bookshelf.rs new file mode 100644 index 00000000..8b62ecac --- /dev/null +++ b/src/blocks/src/decorative/chiseled_bookshelf.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ChiseledBookshelfBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ChiseledBookshelfBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/decorated_pot.rs b/src/blocks/src/decorative/decorated_pot.rs new file mode 100644 index 00000000..114ae0b5 --- /dev/null +++ b/src/blocks/src/decorative/decorated_pot.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DecoratedPotBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DecoratedPotBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs new file mode 100644 index 00000000..12d3ec36 --- /dev/null +++ b/src/blocks/src/decorative/door.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DoorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DoorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/fence_gate.rs b/src/blocks/src/decorative/fence_gate.rs new file mode 100644 index 00000000..d435a7a6 --- /dev/null +++ b/src/blocks/src/decorative/fence_gate.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FenceGateBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FenceGateBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs new file mode 100644 index 00000000..d9827017 --- /dev/null +++ b/src/blocks/src/decorative/fence_pane.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FenceAndPaneBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FenceAndPaneBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/hanging_sign.rs b/src/blocks/src/decorative/hanging_sign.rs new file mode 100644 index 00000000..16ba909f --- /dev/null +++ b/src/blocks/src/decorative/hanging_sign.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::HangingSignBlock; +use crate::BlockBehavior; + +impl BlockBehavior for HangingSignBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/lantern.rs b/src/blocks/src/decorative/lantern.rs new file mode 100644 index 00000000..57a1f970 --- /dev/null +++ b/src/blocks/src/decorative/lantern.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LanternBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LanternBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/mod.rs b/src/blocks/src/decorative/mod.rs new file mode 100644 index 00000000..ecd700f6 --- /dev/null +++ b/src/blocks/src/decorative/mod.rs @@ -0,0 +1,16 @@ +mod note_block; +mod chiseled_bookshelf; +mod sign; +mod door; +mod waterloggable_wall; +mod hanging_sign; +mod fence_pane; +mod trapdoor; +mod chain; +mod fence_gate; +mod wall; +mod lantern; +mod bell; +mod banner; +mod candle; +mod decorated_pot; \ No newline at end of file diff --git a/src/blocks/src/decorative/note_block.rs b/src/blocks/src/decorative/note_block.rs new file mode 100644 index 00000000..c2ed2f04 --- /dev/null +++ b/src/blocks/src/decorative/note_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::NoteBlock; +use crate::BlockBehavior; + +impl BlockBehavior for NoteBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/sign.rs b/src/blocks/src/decorative/sign.rs new file mode 100644 index 00000000..2f604895 --- /dev/null +++ b/src/blocks/src/decorative/sign.rs @@ -0,0 +1,6 @@ +use crate::BlockBehavior; +use temper_blocks_generated::SignBlock; + +impl BlockBehavior for SignBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/trapdoor.rs b/src/blocks/src/decorative/trapdoor.rs new file mode 100644 index 00000000..66ea23d6 --- /dev/null +++ b/src/blocks/src/decorative/trapdoor.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TrapdoorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TrapdoorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/wall.rs b/src/blocks/src/decorative/wall.rs new file mode 100644 index 00000000..7b1b1dbe --- /dev/null +++ b/src/blocks/src/decorative/wall.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WallBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WallBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/decorative/waterloggable_wall.rs b/src/blocks/src/decorative/waterloggable_wall.rs new file mode 100644 index 00000000..2e7876d1 --- /dev/null +++ b/src/blocks/src/decorative/waterloggable_wall.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WaterloggableWallAttachedBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WaterloggableWallAttachedBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/facing_block.rs b/src/blocks/src/facing_block.rs new file mode 100644 index 00000000..7b031a8b --- /dev/null +++ b/src/blocks/src/facing_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FacingBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FacingBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/fire.rs b/src/blocks/src/fire.rs new file mode 100644 index 00000000..22073ba3 --- /dev/null +++ b/src/blocks/src/fire.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FireBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FireBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/barrel.rs b/src/blocks/src/functional/barrel.rs new file mode 100644 index 00000000..e4b5f80d --- /dev/null +++ b/src/blocks/src/functional/barrel.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BarrelBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BarrelBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/brewing_stand.rs b/src/blocks/src/functional/brewing_stand.rs new file mode 100644 index 00000000..7ad8caea --- /dev/null +++ b/src/blocks/src/functional/brewing_stand.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BrewingStandBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BrewingStandBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/campfire.rs b/src/blocks/src/functional/campfire.rs new file mode 100644 index 00000000..741b9222 --- /dev/null +++ b/src/blocks/src/functional/campfire.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CampfireBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CampfireBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/cauldron.rs b/src/blocks/src/functional/cauldron.rs new file mode 100644 index 00000000..6ad4ab6d --- /dev/null +++ b/src/blocks/src/functional/cauldron.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LevelCauldronBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LevelCauldronBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/chest.rs b/src/blocks/src/functional/chest.rs new file mode 100644 index 00000000..61aeff05 --- /dev/null +++ b/src/blocks/src/functional/chest.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ChestBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ChestBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/command_block.rs b/src/blocks/src/functional/command_block.rs new file mode 100644 index 00000000..41587647 --- /dev/null +++ b/src/blocks/src/functional/command_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CommandBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CommandBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/composter.rs b/src/blocks/src/functional/composter.rs new file mode 100644 index 00000000..1aeb2cca --- /dev/null +++ b/src/blocks/src/functional/composter.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ComposterBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ComposterBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/end_portal.rs b/src/blocks/src/functional/end_portal.rs new file mode 100644 index 00000000..c7f2b7c9 --- /dev/null +++ b/src/blocks/src/functional/end_portal.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::EndPortalBlock; +use crate::BlockBehavior; + +impl BlockBehavior for EndPortalBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/furnace.rs b/src/blocks/src/functional/furnace.rs new file mode 100644 index 00000000..b025ea47 --- /dev/null +++ b/src/blocks/src/functional/furnace.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FurnaceBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FurnaceBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/grindstone.rs b/src/blocks/src/functional/grindstone.rs new file mode 100644 index 00000000..10c66ca2 --- /dev/null +++ b/src/blocks/src/functional/grindstone.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::GrindstoneBlock; +use crate::BlockBehavior; + +impl BlockBehavior for GrindstoneBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/jigsaw.rs b/src/blocks/src/functional/jigsaw.rs new file mode 100644 index 00000000..37b730b5 --- /dev/null +++ b/src/blocks/src/functional/jigsaw.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::JigsawBlock; +use crate::BlockBehavior; + +impl BlockBehavior for JigsawBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/lectern.rs b/src/blocks/src/functional/lectern.rs new file mode 100644 index 00000000..ac7fa410 --- /dev/null +++ b/src/blocks/src/functional/lectern.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LecternBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LecternBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/light.rs b/src/blocks/src/functional/light.rs new file mode 100644 index 00000000..36918780 --- /dev/null +++ b/src/blocks/src/functional/light.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LightBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LightBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/mod.rs b/src/blocks/src/functional/mod.rs new file mode 100644 index 00000000..4283972e --- /dev/null +++ b/src/blocks/src/functional/mod.rs @@ -0,0 +1,19 @@ +mod brewing_stand; +mod cauldron; +mod end_portal; +mod command_block; +mod lectern; +mod barrel; +mod scaffolding; +mod grindstone; +mod campfire; +mod structure; +mod jigsaw; +mod test; +mod composter; +mod respawn_anchor; +mod trial_spawner; +mod vault; +mod chest; +mod furnace; +mod light; \ No newline at end of file diff --git a/src/blocks/src/functional/respawn_anchor.rs b/src/blocks/src/functional/respawn_anchor.rs new file mode 100644 index 00000000..1b28bb54 --- /dev/null +++ b/src/blocks/src/functional/respawn_anchor.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RespawnAnchor; +use crate::BlockBehavior; + +impl BlockBehavior for RespawnAnchor { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/scaffolding.rs b/src/blocks/src/functional/scaffolding.rs new file mode 100644 index 00000000..ab505f92 --- /dev/null +++ b/src/blocks/src/functional/scaffolding.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ScaffoldingBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ScaffoldingBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/structure.rs b/src/blocks/src/functional/structure.rs new file mode 100644 index 00000000..96405bba --- /dev/null +++ b/src/blocks/src/functional/structure.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::StructureBlock; +use crate::BlockBehavior; + +impl BlockBehavior for StructureBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/test.rs b/src/blocks/src/functional/test.rs new file mode 100644 index 00000000..6f64c205 --- /dev/null +++ b/src/blocks/src/functional/test.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TestBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TestBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/trial_spawner.rs b/src/blocks/src/functional/trial_spawner.rs new file mode 100644 index 00000000..eacbfa44 --- /dev/null +++ b/src/blocks/src/functional/trial_spawner.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TrialSpawnerBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TrialSpawnerBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/functional/vault.rs b/src/blocks/src/functional/vault.rs new file mode 100644 index 00000000..e554cf9c --- /dev/null +++ b/src/blocks/src/functional/vault.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::VaultBlock; +use crate::BlockBehavior; + +impl BlockBehavior for VaultBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index ae2fcd50..2eff793b 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(min_specialization)] - use bevy_math::DVec2; use temper_block_properties::SlabType; use temper_blocks_generated::{SlabBlock, SnowyBlock}; @@ -11,6 +9,22 @@ use temper_macros::match_block; use temper_world::World; mod behavior_trait; +mod liquid; +mod suspicious_block; +mod waterloggable_block; +mod bed_block; +mod facing_block; +mod fire; +mod nature; +mod building; +mod decorative; +mod redstone; +mod cake; +mod functional; +mod candle_cake; +mod bubble_column; +mod skull; +mod wall_skull; #[allow(unused_imports)] // Used in the include! use crate::behavior_trait::BlockBehaviorTable; diff --git a/src/blocks/src/liquid.rs b/src/blocks/src/liquid.rs new file mode 100644 index 00000000..1329a8b4 --- /dev/null +++ b/src/blocks/src/liquid.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LiquidBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LiquidBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/bamboo.rs b/src/blocks/src/nature/bamboo.rs new file mode 100644 index 00000000..a58dca65 --- /dev/null +++ b/src/blocks/src/nature/bamboo.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BambooBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BambooBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/big_dripleaf.rs b/src/blocks/src/nature/big_dripleaf.rs new file mode 100644 index 00000000..fb40ac13 --- /dev/null +++ b/src/blocks/src/nature/big_dripleaf.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BigDripleafBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BigDripleafBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/chorus.rs b/src/blocks/src/nature/chorus.rs new file mode 100644 index 00000000..991ff155 --- /dev/null +++ b/src/blocks/src/nature/chorus.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ChorusPlantBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ChorusPlantBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/cocoa_beans.rs b/src/blocks/src/nature/cocoa_beans.rs new file mode 100644 index 00000000..0d3d0981 --- /dev/null +++ b/src/blocks/src/nature/cocoa_beans.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CocoaBeansBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CocoaBeansBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/creaking_heart.rs b/src/blocks/src/nature/creaking_heart.rs new file mode 100644 index 00000000..a7c4e000 --- /dev/null +++ b/src/blocks/src/nature/creaking_heart.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CreakingHeartBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CreakingHeartBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/crop.rs b/src/blocks/src/nature/crop.rs new file mode 100644 index 00000000..728d70bb --- /dev/null +++ b/src/blocks/src/nature/crop.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CropBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CropBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/double_plant_block.rs b/src/blocks/src/nature/double_plant_block.rs new file mode 100644 index 00000000..a8e84a9c --- /dev/null +++ b/src/blocks/src/nature/double_plant_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DoublePlantBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DoublePlantBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/dripstone.rs b/src/blocks/src/nature/dripstone.rs new file mode 100644 index 00000000..03e50cb2 --- /dev/null +++ b/src/blocks/src/nature/dripstone.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DripstoneBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DripstoneBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/farmland.rs b/src/blocks/src/nature/farmland.rs new file mode 100644 index 00000000..b600f6c0 --- /dev/null +++ b/src/blocks/src/nature/farmland.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FarmlandBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FarmlandBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/flower_cover.rs b/src/blocks/src/nature/flower_cover.rs new file mode 100644 index 00000000..40e622c6 --- /dev/null +++ b/src/blocks/src/nature/flower_cover.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FlowerCoverBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FlowerCoverBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/frosted_ice.rs b/src/blocks/src/nature/frosted_ice.rs new file mode 100644 index 00000000..7354eaa1 --- /dev/null +++ b/src/blocks/src/nature/frosted_ice.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::FrostedIceBlock; +use crate::BlockBehavior; + +impl BlockBehavior for FrostedIceBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/glow_berries.rs b/src/blocks/src/nature/glow_berries.rs new file mode 100644 index 00000000..20fea378 --- /dev/null +++ b/src/blocks/src/nature/glow_berries.rs @@ -0,0 +1,6 @@ +use crate::BlockBehavior; +use temper_blocks_generated::GlowBerriesBlock; + +impl BlockBehavior for GlowBerriesBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/glow_berries_plant.rs b/src/blocks/src/nature/glow_berries_plant.rs new file mode 100644 index 00000000..dc8e5625 --- /dev/null +++ b/src/blocks/src/nature/glow_berries_plant.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::GlowBerriesPlantBlock; +use crate::BlockBehavior; + +impl BlockBehavior for GlowBerriesPlantBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/hive.rs b/src/blocks/src/nature/hive.rs new file mode 100644 index 00000000..e773ca83 --- /dev/null +++ b/src/blocks/src/nature/hive.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::HiveBlock; +use crate::BlockBehavior; + +impl BlockBehavior for HiveBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/large_mushroom.rs b/src/blocks/src/nature/large_mushroom.rs new file mode 100644 index 00000000..a7252b68 --- /dev/null +++ b/src/blocks/src/nature/large_mushroom.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LargeMushroomBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LargeMushroomBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/leaf_litter.rs b/src/blocks/src/nature/leaf_litter.rs new file mode 100644 index 00000000..31862669 --- /dev/null +++ b/src/blocks/src/nature/leaf_litter.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LeafLitterBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LeafLitterBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/leaves.rs b/src/blocks/src/nature/leaves.rs new file mode 100644 index 00000000..ad16d232 --- /dev/null +++ b/src/blocks/src/nature/leaves.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LeavesBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LeavesBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/lichen.rs b/src/blocks/src/nature/lichen.rs new file mode 100644 index 00000000..f7adece8 --- /dev/null +++ b/src/blocks/src/nature/lichen.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LichenBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LichenBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/mangrove_propagule.rs b/src/blocks/src/nature/mangrove_propagule.rs new file mode 100644 index 00000000..4a593435 --- /dev/null +++ b/src/blocks/src/nature/mangrove_propagule.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::MangrovePopaguleBlock; +use crate::BlockBehavior; + +impl BlockBehavior for MangrovePopaguleBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/mod.rs b/src/blocks/src/nature/mod.rs new file mode 100644 index 00000000..5598b899 --- /dev/null +++ b/src/blocks/src/nature/mod.rs @@ -0,0 +1,30 @@ +mod sapling_block; +mod mangrove_propagule; +mod leaves; +mod double_plant_block; +mod creaking_heart; +mod crop; +mod farmland; +mod snow; +mod large_mushroom; +mod stem; +mod vine; +mod lichen; +mod cocoa_beans; +mod pale_moss_carpet; +mod pale_hanging_moss; +mod small_dripleaf; +mod big_dripleaf; +mod leaf_litter; +mod flower_cover; +mod glow_berries; +mod glow_berries_plant; +mod bamboo; +mod sea_pickle; +mod chorus; +mod pitcher_crop; +mod frosted_ice; +mod turtle_egg; +mod sniffer_egg; +mod hive; +mod dripstone; \ No newline at end of file diff --git a/src/blocks/src/nature/pale_hanging_moss.rs b/src/blocks/src/nature/pale_hanging_moss.rs new file mode 100644 index 00000000..51cf5158 --- /dev/null +++ b/src/blocks/src/nature/pale_hanging_moss.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PaleHangingMossBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PaleHangingMossBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/pale_moss_carpet.rs b/src/blocks/src/nature/pale_moss_carpet.rs new file mode 100644 index 00000000..216fe261 --- /dev/null +++ b/src/blocks/src/nature/pale_moss_carpet.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PaleMossCarpetBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PaleMossCarpetBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/pitcher_crop.rs b/src/blocks/src/nature/pitcher_crop.rs new file mode 100644 index 00000000..87829fd8 --- /dev/null +++ b/src/blocks/src/nature/pitcher_crop.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PitcherCropBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PitcherCropBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/sapling_block.rs b/src/blocks/src/nature/sapling_block.rs new file mode 100644 index 00000000..127c2988 --- /dev/null +++ b/src/blocks/src/nature/sapling_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SaplingBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SaplingBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/sea_pickle.rs b/src/blocks/src/nature/sea_pickle.rs new file mode 100644 index 00000000..aaffcfe0 --- /dev/null +++ b/src/blocks/src/nature/sea_pickle.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SeaPickleBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SeaPickleBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/small_dripleaf.rs b/src/blocks/src/nature/small_dripleaf.rs new file mode 100644 index 00000000..a4be5b42 --- /dev/null +++ b/src/blocks/src/nature/small_dripleaf.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SmallDripleafBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SmallDripleafBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/sniffer_egg.rs b/src/blocks/src/nature/sniffer_egg.rs new file mode 100644 index 00000000..12c33190 --- /dev/null +++ b/src/blocks/src/nature/sniffer_egg.rs @@ -0,0 +1,6 @@ +use crate::BlockBehavior; +use temper_blocks_generated::SnifferEggBlock; + +impl BlockBehavior for SnifferEggBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/snow.rs b/src/blocks/src/nature/snow.rs new file mode 100644 index 00000000..3b5a39bb --- /dev/null +++ b/src/blocks/src/nature/snow.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SnowBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SnowBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/stem.rs b/src/blocks/src/nature/stem.rs new file mode 100644 index 00000000..ba054903 --- /dev/null +++ b/src/blocks/src/nature/stem.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::StemBlock; +use crate::BlockBehavior; + +impl BlockBehavior for StemBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/turtle_egg.rs b/src/blocks/src/nature/turtle_egg.rs new file mode 100644 index 00000000..e43798f2 --- /dev/null +++ b/src/blocks/src/nature/turtle_egg.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TurtleEggBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TurtleEggBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/nature/vine.rs b/src/blocks/src/nature/vine.rs new file mode 100644 index 00000000..5c231ec0 --- /dev/null +++ b/src/blocks/src/nature/vine.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::VineBlock; +use crate::BlockBehavior; + +impl BlockBehavior for VineBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/bulb.rs b/src/blocks/src/redstone/bulb.rs new file mode 100644 index 00000000..ca803370 --- /dev/null +++ b/src/blocks/src/redstone/bulb.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::BulbBlock; +use crate::BlockBehavior; + +impl BlockBehavior for BulbBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/button.rs b/src/blocks/src/redstone/button.rs new file mode 100644 index 00000000..719fa38b --- /dev/null +++ b/src/blocks/src/redstone/button.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ButtonBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ButtonBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/calibrated_sculk_sensor.rs b/src/blocks/src/redstone/calibrated_sculk_sensor.rs new file mode 100644 index 00000000..b7a61ae5 --- /dev/null +++ b/src/blocks/src/redstone/calibrated_sculk_sensor.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CalibratedSculkSensorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CalibratedSculkSensorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/comparator.rs b/src/blocks/src/redstone/comparator.rs new file mode 100644 index 00000000..f4dab1e4 --- /dev/null +++ b/src/blocks/src/redstone/comparator.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ComparatorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ComparatorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/crafter.rs b/src/blocks/src/redstone/crafter.rs new file mode 100644 index 00000000..5afabcd3 --- /dev/null +++ b/src/blocks/src/redstone/crafter.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::CrafterBlock; +use crate::BlockBehavior; + +impl BlockBehavior for CrafterBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/daylight_detector.rs b/src/blocks/src/redstone/daylight_detector.rs new file mode 100644 index 00000000..e1ee1fa5 --- /dev/null +++ b/src/blocks/src/redstone/daylight_detector.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DaylightDetectorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DaylightDetectorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/dispenser.rs b/src/blocks/src/redstone/dispenser.rs new file mode 100644 index 00000000..a538588a --- /dev/null +++ b/src/blocks/src/redstone/dispenser.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::DispenserBlock; +use crate::BlockBehavior; + +impl BlockBehavior for DispenserBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/hopper.rs b/src/blocks/src/redstone/hopper.rs new file mode 100644 index 00000000..1e63047c --- /dev/null +++ b/src/blocks/src/redstone/hopper.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::HopperBlock; +use crate::BlockBehavior; + +impl BlockBehavior for HopperBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/jukebox.rs b/src/blocks/src/redstone/jukebox.rs new file mode 100644 index 00000000..8ed0c4a7 --- /dev/null +++ b/src/blocks/src/redstone/jukebox.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::JukeboxBlock; +use crate::BlockBehavior; + +impl BlockBehavior for JukeboxBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/lamp.rs b/src/blocks/src/redstone/lamp.rs new file mode 100644 index 00000000..4026b46c --- /dev/null +++ b/src/blocks/src/redstone/lamp.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RedstoneLampBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RedstoneLampBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/lever.rs b/src/blocks/src/redstone/lever.rs new file mode 100644 index 00000000..705c3901 --- /dev/null +++ b/src/blocks/src/redstone/lever.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LeverBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LeverBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/lightning_rod.rs b/src/blocks/src/redstone/lightning_rod.rs new file mode 100644 index 00000000..92bba853 --- /dev/null +++ b/src/blocks/src/redstone/lightning_rod.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::LightningRodBlock; +use crate::BlockBehavior; + +impl BlockBehavior for LightningRodBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/mod.rs b/src/blocks/src/redstone/mod.rs new file mode 100644 index 00000000..489390b5 --- /dev/null +++ b/src/blocks/src/redstone/mod.rs @@ -0,0 +1,30 @@ +mod dispenser; +mod redstone_rail; +mod tnt; +mod piston; +mod wire; +mod rail; +mod lever; +mod pressure_plate; +mod ore; +mod torch; +mod wall_torch; +mod button; +mod jukebox; +mod repeater; +mod lamp; +mod tripwire; +mod tripwire_hook; +mod bulb; +mod observer; +mod hopper; +mod weighted_pressure_plate; +mod comparator; +mod daylight_detector; +mod target; +mod sculk_sensor; +mod calibrated_sculk_sensor; +mod sculk_catalyst; +mod sculk_shrieker; +mod lightning_rod; +mod crafter; \ No newline at end of file diff --git a/src/blocks/src/redstone/observer.rs b/src/blocks/src/redstone/observer.rs new file mode 100644 index 00000000..786c2a17 --- /dev/null +++ b/src/blocks/src/redstone/observer.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::ObserverBlock; +use crate::BlockBehavior; + +impl BlockBehavior for ObserverBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/ore.rs b/src/blocks/src/redstone/ore.rs new file mode 100644 index 00000000..3587ceb3 --- /dev/null +++ b/src/blocks/src/redstone/ore.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RedstoneOreBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RedstoneOreBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/piston/head.rs b/src/blocks/src/redstone/piston/head.rs new file mode 100644 index 00000000..d250d270 --- /dev/null +++ b/src/blocks/src/redstone/piston/head.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PistonHeadBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PistonHeadBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/piston/mod.rs b/src/blocks/src/redstone/piston/mod.rs new file mode 100644 index 00000000..9dd0c288 --- /dev/null +++ b/src/blocks/src/redstone/piston/mod.rs @@ -0,0 +1,9 @@ +use temper_blocks_generated::PistonBlock; +use crate::BlockBehavior; + +mod head; +mod moving_head; + +impl BlockBehavior for PistonBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/piston/moving_head.rs b/src/blocks/src/redstone/piston/moving_head.rs new file mode 100644 index 00000000..29553b6d --- /dev/null +++ b/src/blocks/src/redstone/piston/moving_head.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::MovingPistonBlock; +use crate::BlockBehavior; + +impl BlockBehavior for MovingPistonBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/pressure_plate.rs b/src/blocks/src/redstone/pressure_plate.rs new file mode 100644 index 00000000..705752a4 --- /dev/null +++ b/src/blocks/src/redstone/pressure_plate.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::PressurePlateBlock; +use crate::BlockBehavior; + +impl BlockBehavior for PressurePlateBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/rail.rs b/src/blocks/src/redstone/rail.rs new file mode 100644 index 00000000..669b5c59 --- /dev/null +++ b/src/blocks/src/redstone/rail.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RailBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RailBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/redstone_rail.rs b/src/blocks/src/redstone/redstone_rail.rs new file mode 100644 index 00000000..ecf4fbf3 --- /dev/null +++ b/src/blocks/src/redstone/redstone_rail.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RedstoneRailBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RedstoneRailBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/repeater.rs b/src/blocks/src/redstone/repeater.rs new file mode 100644 index 00000000..aa453e19 --- /dev/null +++ b/src/blocks/src/redstone/repeater.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RepeaterBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RepeaterBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/sculk_catalyst.rs b/src/blocks/src/redstone/sculk_catalyst.rs new file mode 100644 index 00000000..c8bd9c21 --- /dev/null +++ b/src/blocks/src/redstone/sculk_catalyst.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SculkCatalystBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SculkCatalystBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/sculk_sensor.rs b/src/blocks/src/redstone/sculk_sensor.rs new file mode 100644 index 00000000..a9ce3742 --- /dev/null +++ b/src/blocks/src/redstone/sculk_sensor.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SculkSensorBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SculkSensorBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/sculk_shrieker.rs b/src/blocks/src/redstone/sculk_shrieker.rs new file mode 100644 index 00000000..0a1273d7 --- /dev/null +++ b/src/blocks/src/redstone/sculk_shrieker.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SculkShriekerBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SculkShriekerBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/target.rs b/src/blocks/src/redstone/target.rs new file mode 100644 index 00000000..d877203e --- /dev/null +++ b/src/blocks/src/redstone/target.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TargetBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TargetBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/tnt.rs b/src/blocks/src/redstone/tnt.rs new file mode 100644 index 00000000..050e1ee8 --- /dev/null +++ b/src/blocks/src/redstone/tnt.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TntBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TntBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/torch.rs b/src/blocks/src/redstone/torch.rs new file mode 100644 index 00000000..89a9ae0f --- /dev/null +++ b/src/blocks/src/redstone/torch.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RedstoneTorchBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RedstoneTorchBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/tripwire.rs b/src/blocks/src/redstone/tripwire.rs new file mode 100644 index 00000000..05ea0911 --- /dev/null +++ b/src/blocks/src/redstone/tripwire.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::TripwireBlock; +use crate::BlockBehavior; + +impl BlockBehavior for TripwireBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/tripwire_hook.rs b/src/blocks/src/redstone/tripwire_hook.rs new file mode 100644 index 00000000..1fdabd64 --- /dev/null +++ b/src/blocks/src/redstone/tripwire_hook.rs @@ -0,0 +1,6 @@ +use crate::BlockBehavior; +use temper_blocks_generated::TripwireHookBlock; + +impl BlockBehavior for TripwireHookBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/wall_torch.rs b/src/blocks/src/redstone/wall_torch.rs new file mode 100644 index 00000000..d504d280 --- /dev/null +++ b/src/blocks/src/redstone/wall_torch.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WallRedstoneTorchBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WallRedstoneTorchBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/weighted_pressure_plate.rs b/src/blocks/src/redstone/weighted_pressure_plate.rs new file mode 100644 index 00000000..a2a2ab9b --- /dev/null +++ b/src/blocks/src/redstone/weighted_pressure_plate.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WeightedPressurePlateBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WeightedPressurePlateBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/redstone/wire.rs b/src/blocks/src/redstone/wire.rs new file mode 100644 index 00000000..88e437c1 --- /dev/null +++ b/src/blocks/src/redstone/wire.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::RedstoneWireBlock; +use crate::BlockBehavior; + +impl BlockBehavior for RedstoneWireBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/skull.rs b/src/blocks/src/skull.rs new file mode 100644 index 00000000..a69b27a9 --- /dev/null +++ b/src/blocks/src/skull.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SkullBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SkullBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/suspicious_block.rs b/src/blocks/src/suspicious_block.rs new file mode 100644 index 00000000..d806dc07 --- /dev/null +++ b/src/blocks/src/suspicious_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::SuspiciousBlock; +use crate::BlockBehavior; + +impl BlockBehavior for SuspiciousBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/wall_skull.rs b/src/blocks/src/wall_skull.rs new file mode 100644 index 00000000..a34e169b --- /dev/null +++ b/src/blocks/src/wall_skull.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WallSkullBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WallSkullBlock { + +} \ No newline at end of file diff --git a/src/blocks/src/waterloggable_block.rs b/src/blocks/src/waterloggable_block.rs new file mode 100644 index 00000000..2671e794 --- /dev/null +++ b/src/blocks/src/waterloggable_block.rs @@ -0,0 +1,6 @@ +use temper_blocks_generated::WaterloggableBlock; +use crate::BlockBehavior; + +impl BlockBehavior for WaterloggableBlock { + +} \ No newline at end of file From f9d2499ae9ce297d9eab9e8daa73a21e846bd007 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 1 Apr 2026 22:14:04 -0500 Subject: [PATCH 08/30] Formatting and clippy --- src/blocks/crates/build/src/complex.rs | 2 +- src/blocks/crates/generated/build.rs | 4 +- src/blocks/src/bed_block.rs | 6 +-- src/blocks/src/behavior_trait.rs | 2 +- src/blocks/src/bubble_column.rs | 6 +-- src/blocks/src/building/mod.rs | 2 +- src/blocks/src/building/pillar_block.rs | 6 +-- src/blocks/src/building/simple_block.rs | 6 +-- src/blocks/src/building/stairs.rs | 6 +-- src/blocks/src/cake.rs | 6 +-- src/blocks/src/candle_cake.rs | 6 +-- src/blocks/src/decorative/banner.rs | 6 +-- src/blocks/src/decorative/bell.rs | 6 +-- src/blocks/src/decorative/candle.rs | 6 +-- src/blocks/src/decorative/chain.rs | 6 +-- .../src/decorative/chiseled_bookshelf.rs | 6 +-- src/blocks/src/decorative/decorated_pot.rs | 6 +-- src/blocks/src/decorative/door.rs | 6 +-- src/blocks/src/decorative/fence_gate.rs | 6 +-- src/blocks/src/decorative/fence_pane.rs | 6 +-- src/blocks/src/decorative/hanging_sign.rs | 6 +-- src/blocks/src/decorative/lantern.rs | 6 +-- src/blocks/src/decorative/mod.rs | 22 ++++----- src/blocks/src/decorative/note_block.rs | 6 +-- src/blocks/src/decorative/sign.rs | 4 +- src/blocks/src/decorative/trapdoor.rs | 6 +-- src/blocks/src/decorative/wall.rs | 6 +-- .../src/decorative/waterloggable_wall.rs | 6 +-- src/blocks/src/facing_block.rs | 6 +-- src/blocks/src/fire.rs | 6 +-- src/blocks/src/functional/barrel.rs | 6 +-- src/blocks/src/functional/brewing_stand.rs | 6 +-- src/blocks/src/functional/campfire.rs | 6 +-- src/blocks/src/functional/cauldron.rs | 6 +-- src/blocks/src/functional/chest.rs | 6 +-- src/blocks/src/functional/command_block.rs | 6 +-- src/blocks/src/functional/composter.rs | 6 +-- src/blocks/src/functional/end_portal.rs | 6 +-- src/blocks/src/functional/furnace.rs | 6 +-- src/blocks/src/functional/grindstone.rs | 6 +-- src/blocks/src/functional/jigsaw.rs | 6 +-- src/blocks/src/functional/lectern.rs | 6 +-- src/blocks/src/functional/light.rs | 6 +-- src/blocks/src/functional/mod.rs | 20 ++++---- src/blocks/src/functional/respawn_anchor.rs | 6 +-- src/blocks/src/functional/scaffolding.rs | 6 +-- src/blocks/src/functional/structure.rs | 6 +-- src/blocks/src/functional/test.rs | 6 +-- src/blocks/src/functional/trial_spawner.rs | 6 +-- src/blocks/src/functional/vault.rs | 6 +-- src/blocks/src/lib.rs | 20 ++++---- src/blocks/src/liquid.rs | 6 +-- src/blocks/src/nature/bamboo.rs | 6 +-- src/blocks/src/nature/big_dripleaf.rs | 6 +-- src/blocks/src/nature/chorus.rs | 6 +-- src/blocks/src/nature/cocoa_beans.rs | 6 +-- src/blocks/src/nature/creaking_heart.rs | 6 +-- src/blocks/src/nature/crop.rs | 6 +-- src/blocks/src/nature/double_plant_block.rs | 6 +-- src/blocks/src/nature/dripstone.rs | 6 +-- src/blocks/src/nature/farmland.rs | 6 +-- src/blocks/src/nature/flower_cover.rs | 6 +-- src/blocks/src/nature/frosted_ice.rs | 6 +-- src/blocks/src/nature/glow_berries.rs | 4 +- src/blocks/src/nature/glow_berries_plant.rs | 6 +-- src/blocks/src/nature/hive.rs | 6 +-- src/blocks/src/nature/large_mushroom.rs | 6 +-- src/blocks/src/nature/leaf_litter.rs | 6 +-- src/blocks/src/nature/leaves.rs | 6 +-- src/blocks/src/nature/lichen.rs | 6 +-- src/blocks/src/nature/mangrove_propagule.rs | 6 +-- src/blocks/src/nature/mod.rs | 44 +++++++++--------- src/blocks/src/nature/pale_hanging_moss.rs | 6 +-- src/blocks/src/nature/pale_moss_carpet.rs | 6 +-- src/blocks/src/nature/pitcher_crop.rs | 6 +-- src/blocks/src/nature/sapling_block.rs | 6 +-- src/blocks/src/nature/sea_pickle.rs | 6 +-- src/blocks/src/nature/small_dripleaf.rs | 6 +-- src/blocks/src/nature/sniffer_egg.rs | 4 +- src/blocks/src/nature/snow.rs | 6 +-- src/blocks/src/nature/stem.rs | 6 +-- src/blocks/src/nature/turtle_egg.rs | 6 +-- src/blocks/src/nature/vine.rs | 6 +-- src/blocks/src/redstone/bulb.rs | 6 +-- src/blocks/src/redstone/button.rs | 6 +-- .../src/redstone/calibrated_sculk_sensor.rs | 6 +-- src/blocks/src/redstone/comparator.rs | 6 +-- src/blocks/src/redstone/crafter.rs | 6 +-- src/blocks/src/redstone/daylight_detector.rs | 6 +-- src/blocks/src/redstone/dispenser.rs | 6 +-- src/blocks/src/redstone/hopper.rs | 6 +-- src/blocks/src/redstone/jukebox.rs | 6 +-- src/blocks/src/redstone/lamp.rs | 6 +-- src/blocks/src/redstone/lever.rs | 6 +-- src/blocks/src/redstone/lightning_rod.rs | 6 +-- src/blocks/src/redstone/mod.rs | 46 +++++++++---------- src/blocks/src/redstone/observer.rs | 6 +-- src/blocks/src/redstone/ore.rs | 6 +-- src/blocks/src/redstone/piston/head.rs | 6 +-- src/blocks/src/redstone/piston/mod.rs | 6 +-- src/blocks/src/redstone/piston/moving_head.rs | 6 +-- src/blocks/src/redstone/pressure_plate.rs | 6 +-- src/blocks/src/redstone/rail.rs | 6 +-- src/blocks/src/redstone/redstone_rail.rs | 6 +-- src/blocks/src/redstone/repeater.rs | 6 +-- src/blocks/src/redstone/sculk_catalyst.rs | 6 +-- src/blocks/src/redstone/sculk_sensor.rs | 6 +-- src/blocks/src/redstone/sculk_shrieker.rs | 6 +-- src/blocks/src/redstone/target.rs | 6 +-- src/blocks/src/redstone/tnt.rs | 6 +-- src/blocks/src/redstone/torch.rs | 6 +-- src/blocks/src/redstone/tripwire.rs | 6 +-- src/blocks/src/redstone/tripwire_hook.rs | 4 +- src/blocks/src/redstone/wall_torch.rs | 6 +-- .../src/redstone/weighted_pressure_plate.rs | 6 +-- src/blocks/src/redstone/wire.rs | 6 +-- src/blocks/src/skull.rs | 6 +-- src/blocks/src/suspicious_block.rs | 6 +-- src/blocks/src/wall_skull.rs | 6 +-- src/blocks/src/waterloggable_block.rs | 6 +-- src/core/src/block_face.rs | 6 +-- src/core/src/lib.rs | 2 +- .../src/packets/src/place_block.rs | 18 +++----- 123 files changed, 310 insertions(+), 536 deletions(-) diff --git a/src/blocks/crates/build/src/complex.rs b/src/blocks/crates/build/src/complex.rs index c1f807c1..c7bff083 100644 --- a/src/blocks/crates/build/src/complex.rs +++ b/src/blocks/crates/build/src/complex.rs @@ -1,10 +1,10 @@ use crate::config::{BuildConfig, SingleOrMultiple}; -use temper_block_properties::{PropertyDescriptor, TYPES}; use fxhash::FxHashMap; use heck::{ToPascalCase, ToShoutySnakeCase, ToSnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use std::collections::HashMap; +use temper_block_properties::{PropertyDescriptor, TYPES}; struct BlockStateConfiguration<'a> { name: &'a str, diff --git a/src/blocks/crates/generated/build.rs b/src/blocks/crates/generated/build.rs index a0b58a12..95db2fa5 100644 --- a/src/blocks/crates/generated/build.rs +++ b/src/blocks/crates/generated/build.rs @@ -1,9 +1,9 @@ +use heck::ToSnakeCase; +use std::fs; use temper_blocks_build::complex::generate_complex_blocks; use temper_blocks_build::config::{get_block_states, get_build_config}; use temper_blocks_build::simple::generate_simple_block_enum; use temper_blocks_build::{format_code, separate_blocks}; -use heck::ToSnakeCase; -use std::fs; fn main() { let build_config = get_build_config(); diff --git a/src/blocks/src/bed_block.rs b/src/blocks/src/bed_block.rs index e9fbb78b..6616f7ea 100644 --- a/src/blocks/src/bed_block.rs +++ b/src/blocks/src/bed_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BedBlock; use crate::BlockBehavior; +use temper_blocks_generated::BedBlock; -impl BlockBehavior for BedBlock { - -} \ No newline at end of file +impl BlockBehavior for BedBlock {} diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index e483c267..cbb42a07 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,5 +1,5 @@ -use temper_core::block_state_id::BlockStateId; use crate::{PlacementContext, BLOCK_MAPPINGS}; +use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; use temper_world::World; diff --git a/src/blocks/src/bubble_column.rs b/src/blocks/src/bubble_column.rs index 593e885e..64fbff99 100644 --- a/src/blocks/src/bubble_column.rs +++ b/src/blocks/src/bubble_column.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BubbleColumnBlock; use crate::BlockBehavior; +use temper_blocks_generated::BubbleColumnBlock; -impl BlockBehavior for BubbleColumnBlock { - -} \ No newline at end of file +impl BlockBehavior for BubbleColumnBlock {} diff --git a/src/blocks/src/building/mod.rs b/src/blocks/src/building/mod.rs index 86cd559c..c866d8fa 100644 --- a/src/blocks/src/building/mod.rs +++ b/src/blocks/src/building/mod.rs @@ -1,3 +1,3 @@ -mod stairs; mod pillar_block; mod simple_block; +mod stairs; diff --git a/src/blocks/src/building/pillar_block.rs b/src/blocks/src/building/pillar_block.rs index f5511df1..7e8bb268 100644 --- a/src/blocks/src/building/pillar_block.rs +++ b/src/blocks/src/building/pillar_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PillarBlock; use crate::BlockBehavior; +use temper_blocks_generated::PillarBlock; -impl BlockBehavior for PillarBlock { - -} \ No newline at end of file +impl BlockBehavior for PillarBlock {} diff --git a/src/blocks/src/building/simple_block.rs b/src/blocks/src/building/simple_block.rs index f054f591..d7d069df 100644 --- a/src/blocks/src/building/simple_block.rs +++ b/src/blocks/src/building/simple_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SimpleBlock; use crate::BlockBehavior; +use temper_blocks_generated::SimpleBlock; -impl BlockBehavior for SimpleBlock { - -} \ No newline at end of file +impl BlockBehavior for SimpleBlock {} diff --git a/src/blocks/src/building/stairs.rs b/src/blocks/src/building/stairs.rs index d6fe2900..41d85074 100644 --- a/src/blocks/src/building/stairs.rs +++ b/src/blocks/src/building/stairs.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::StairsBlock; use crate::BlockBehavior; +use temper_blocks_generated::StairsBlock; -impl BlockBehavior for StairsBlock { - -} \ No newline at end of file +impl BlockBehavior for StairsBlock {} diff --git a/src/blocks/src/cake.rs b/src/blocks/src/cake.rs index cc9309b5..59f0b14f 100644 --- a/src/blocks/src/cake.rs +++ b/src/blocks/src/cake.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CakeBlock; use crate::BlockBehavior; +use temper_blocks_generated::CakeBlock; -impl BlockBehavior for CakeBlock { - -} \ No newline at end of file +impl BlockBehavior for CakeBlock {} diff --git a/src/blocks/src/candle_cake.rs b/src/blocks/src/candle_cake.rs index 2dcc7265..01b02f9d 100644 --- a/src/blocks/src/candle_cake.rs +++ b/src/blocks/src/candle_cake.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CandleCakeBlock; use crate::BlockBehavior; +use temper_blocks_generated::CandleCakeBlock; -impl BlockBehavior for CandleCakeBlock { - -} \ No newline at end of file +impl BlockBehavior for CandleCakeBlock {} diff --git a/src/blocks/src/decorative/banner.rs b/src/blocks/src/decorative/banner.rs index e47dc420..9a54e979 100644 --- a/src/blocks/src/decorative/banner.rs +++ b/src/blocks/src/decorative/banner.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BannerBlock; use crate::BlockBehavior; +use temper_blocks_generated::BannerBlock; -impl BlockBehavior for BannerBlock { - -} \ No newline at end of file +impl BlockBehavior for BannerBlock {} diff --git a/src/blocks/src/decorative/bell.rs b/src/blocks/src/decorative/bell.rs index eedf1e67..fd7bd9d2 100644 --- a/src/blocks/src/decorative/bell.rs +++ b/src/blocks/src/decorative/bell.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BellBlock; use crate::BlockBehavior; +use temper_blocks_generated::BellBlock; -impl BlockBehavior for BellBlock { - -} \ No newline at end of file +impl BlockBehavior for BellBlock {} diff --git a/src/blocks/src/decorative/candle.rs b/src/blocks/src/decorative/candle.rs index 0751b25a..5196705e 100644 --- a/src/blocks/src/decorative/candle.rs +++ b/src/blocks/src/decorative/candle.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CandleBlock; use crate::BlockBehavior; +use temper_blocks_generated::CandleBlock; -impl BlockBehavior for CandleBlock { - -} \ No newline at end of file +impl BlockBehavior for CandleBlock {} diff --git a/src/blocks/src/decorative/chain.rs b/src/blocks/src/decorative/chain.rs index c68c9db4..a7b416ab 100644 --- a/src/blocks/src/decorative/chain.rs +++ b/src/blocks/src/decorative/chain.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ChainBlock; use crate::BlockBehavior; +use temper_blocks_generated::ChainBlock; -impl BlockBehavior for ChainBlock { - -} \ No newline at end of file +impl BlockBehavior for ChainBlock {} diff --git a/src/blocks/src/decorative/chiseled_bookshelf.rs b/src/blocks/src/decorative/chiseled_bookshelf.rs index 8b62ecac..cf554ba7 100644 --- a/src/blocks/src/decorative/chiseled_bookshelf.rs +++ b/src/blocks/src/decorative/chiseled_bookshelf.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ChiseledBookshelfBlock; use crate::BlockBehavior; +use temper_blocks_generated::ChiseledBookshelfBlock; -impl BlockBehavior for ChiseledBookshelfBlock { - -} \ No newline at end of file +impl BlockBehavior for ChiseledBookshelfBlock {} diff --git a/src/blocks/src/decorative/decorated_pot.rs b/src/blocks/src/decorative/decorated_pot.rs index 114ae0b5..493276ca 100644 --- a/src/blocks/src/decorative/decorated_pot.rs +++ b/src/blocks/src/decorative/decorated_pot.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DecoratedPotBlock; use crate::BlockBehavior; +use temper_blocks_generated::DecoratedPotBlock; -impl BlockBehavior for DecoratedPotBlock { - -} \ No newline at end of file +impl BlockBehavior for DecoratedPotBlock {} diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs index 12d3ec36..a4dc216e 100644 --- a/src/blocks/src/decorative/door.rs +++ b/src/blocks/src/decorative/door.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DoorBlock; use crate::BlockBehavior; +use temper_blocks_generated::DoorBlock; -impl BlockBehavior for DoorBlock { - -} \ No newline at end of file +impl BlockBehavior for DoorBlock {} diff --git a/src/blocks/src/decorative/fence_gate.rs b/src/blocks/src/decorative/fence_gate.rs index d435a7a6..2b628cdf 100644 --- a/src/blocks/src/decorative/fence_gate.rs +++ b/src/blocks/src/decorative/fence_gate.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FenceGateBlock; use crate::BlockBehavior; +use temper_blocks_generated::FenceGateBlock; -impl BlockBehavior for FenceGateBlock { - -} \ No newline at end of file +impl BlockBehavior for FenceGateBlock {} diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs index d9827017..39c6b101 100644 --- a/src/blocks/src/decorative/fence_pane.rs +++ b/src/blocks/src/decorative/fence_pane.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FenceAndPaneBlock; use crate::BlockBehavior; +use temper_blocks_generated::FenceAndPaneBlock; -impl BlockBehavior for FenceAndPaneBlock { - -} \ No newline at end of file +impl BlockBehavior for FenceAndPaneBlock {} diff --git a/src/blocks/src/decorative/hanging_sign.rs b/src/blocks/src/decorative/hanging_sign.rs index 16ba909f..503e055b 100644 --- a/src/blocks/src/decorative/hanging_sign.rs +++ b/src/blocks/src/decorative/hanging_sign.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::HangingSignBlock; use crate::BlockBehavior; +use temper_blocks_generated::HangingSignBlock; -impl BlockBehavior for HangingSignBlock { - -} \ No newline at end of file +impl BlockBehavior for HangingSignBlock {} diff --git a/src/blocks/src/decorative/lantern.rs b/src/blocks/src/decorative/lantern.rs index 57a1f970..792dabd4 100644 --- a/src/blocks/src/decorative/lantern.rs +++ b/src/blocks/src/decorative/lantern.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LanternBlock; use crate::BlockBehavior; +use temper_blocks_generated::LanternBlock; -impl BlockBehavior for LanternBlock { - -} \ No newline at end of file +impl BlockBehavior for LanternBlock {} diff --git a/src/blocks/src/decorative/mod.rs b/src/blocks/src/decorative/mod.rs index ecd700f6..78cee89a 100644 --- a/src/blocks/src/decorative/mod.rs +++ b/src/blocks/src/decorative/mod.rs @@ -1,16 +1,16 @@ -mod note_block; +mod banner; +mod bell; +mod candle; +mod chain; mod chiseled_bookshelf; -mod sign; +mod decorated_pot; mod door; -mod waterloggable_wall; -mod hanging_sign; +mod fence_gate; mod fence_pane; +mod hanging_sign; +mod lantern; +mod note_block; +mod sign; mod trapdoor; -mod chain; -mod fence_gate; mod wall; -mod lantern; -mod bell; -mod banner; -mod candle; -mod decorated_pot; \ No newline at end of file +mod waterloggable_wall; diff --git a/src/blocks/src/decorative/note_block.rs b/src/blocks/src/decorative/note_block.rs index c2ed2f04..9c1c2117 100644 --- a/src/blocks/src/decorative/note_block.rs +++ b/src/blocks/src/decorative/note_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::NoteBlock; use crate::BlockBehavior; +use temper_blocks_generated::NoteBlock; -impl BlockBehavior for NoteBlock { - -} \ No newline at end of file +impl BlockBehavior for NoteBlock {} diff --git a/src/blocks/src/decorative/sign.rs b/src/blocks/src/decorative/sign.rs index 2f604895..2e3c5519 100644 --- a/src/blocks/src/decorative/sign.rs +++ b/src/blocks/src/decorative/sign.rs @@ -1,6 +1,4 @@ use crate::BlockBehavior; use temper_blocks_generated::SignBlock; -impl BlockBehavior for SignBlock { - -} \ No newline at end of file +impl BlockBehavior for SignBlock {} diff --git a/src/blocks/src/decorative/trapdoor.rs b/src/blocks/src/decorative/trapdoor.rs index 66ea23d6..d9ac4967 100644 --- a/src/blocks/src/decorative/trapdoor.rs +++ b/src/blocks/src/decorative/trapdoor.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TrapdoorBlock; use crate::BlockBehavior; +use temper_blocks_generated::TrapdoorBlock; -impl BlockBehavior for TrapdoorBlock { - -} \ No newline at end of file +impl BlockBehavior for TrapdoorBlock {} diff --git a/src/blocks/src/decorative/wall.rs b/src/blocks/src/decorative/wall.rs index 7b1b1dbe..18842b11 100644 --- a/src/blocks/src/decorative/wall.rs +++ b/src/blocks/src/decorative/wall.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WallBlock; use crate::BlockBehavior; +use temper_blocks_generated::WallBlock; -impl BlockBehavior for WallBlock { - -} \ No newline at end of file +impl BlockBehavior for WallBlock {} diff --git a/src/blocks/src/decorative/waterloggable_wall.rs b/src/blocks/src/decorative/waterloggable_wall.rs index 2e7876d1..efc082b2 100644 --- a/src/blocks/src/decorative/waterloggable_wall.rs +++ b/src/blocks/src/decorative/waterloggable_wall.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WaterloggableWallAttachedBlock; use crate::BlockBehavior; +use temper_blocks_generated::WaterloggableWallAttachedBlock; -impl BlockBehavior for WaterloggableWallAttachedBlock { - -} \ No newline at end of file +impl BlockBehavior for WaterloggableWallAttachedBlock {} diff --git a/src/blocks/src/facing_block.rs b/src/blocks/src/facing_block.rs index 7b031a8b..568a5cee 100644 --- a/src/blocks/src/facing_block.rs +++ b/src/blocks/src/facing_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FacingBlock; use crate::BlockBehavior; +use temper_blocks_generated::FacingBlock; -impl BlockBehavior for FacingBlock { - -} \ No newline at end of file +impl BlockBehavior for FacingBlock {} diff --git a/src/blocks/src/fire.rs b/src/blocks/src/fire.rs index 22073ba3..25a62b04 100644 --- a/src/blocks/src/fire.rs +++ b/src/blocks/src/fire.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FireBlock; use crate::BlockBehavior; +use temper_blocks_generated::FireBlock; -impl BlockBehavior for FireBlock { - -} \ No newline at end of file +impl BlockBehavior for FireBlock {} diff --git a/src/blocks/src/functional/barrel.rs b/src/blocks/src/functional/barrel.rs index e4b5f80d..29874041 100644 --- a/src/blocks/src/functional/barrel.rs +++ b/src/blocks/src/functional/barrel.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BarrelBlock; use crate::BlockBehavior; +use temper_blocks_generated::BarrelBlock; -impl BlockBehavior for BarrelBlock { - -} \ No newline at end of file +impl BlockBehavior for BarrelBlock {} diff --git a/src/blocks/src/functional/brewing_stand.rs b/src/blocks/src/functional/brewing_stand.rs index 7ad8caea..b9f299a6 100644 --- a/src/blocks/src/functional/brewing_stand.rs +++ b/src/blocks/src/functional/brewing_stand.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BrewingStandBlock; use crate::BlockBehavior; +use temper_blocks_generated::BrewingStandBlock; -impl BlockBehavior for BrewingStandBlock { - -} \ No newline at end of file +impl BlockBehavior for BrewingStandBlock {} diff --git a/src/blocks/src/functional/campfire.rs b/src/blocks/src/functional/campfire.rs index 741b9222..a3f6e546 100644 --- a/src/blocks/src/functional/campfire.rs +++ b/src/blocks/src/functional/campfire.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CampfireBlock; use crate::BlockBehavior; +use temper_blocks_generated::CampfireBlock; -impl BlockBehavior for CampfireBlock { - -} \ No newline at end of file +impl BlockBehavior for CampfireBlock {} diff --git a/src/blocks/src/functional/cauldron.rs b/src/blocks/src/functional/cauldron.rs index 6ad4ab6d..c53c0b11 100644 --- a/src/blocks/src/functional/cauldron.rs +++ b/src/blocks/src/functional/cauldron.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LevelCauldronBlock; use crate::BlockBehavior; +use temper_blocks_generated::LevelCauldronBlock; -impl BlockBehavior for LevelCauldronBlock { - -} \ No newline at end of file +impl BlockBehavior for LevelCauldronBlock {} diff --git a/src/blocks/src/functional/chest.rs b/src/blocks/src/functional/chest.rs index 61aeff05..68c5e5b5 100644 --- a/src/blocks/src/functional/chest.rs +++ b/src/blocks/src/functional/chest.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ChestBlock; use crate::BlockBehavior; +use temper_blocks_generated::ChestBlock; -impl BlockBehavior for ChestBlock { - -} \ No newline at end of file +impl BlockBehavior for ChestBlock {} diff --git a/src/blocks/src/functional/command_block.rs b/src/blocks/src/functional/command_block.rs index 41587647..907b938a 100644 --- a/src/blocks/src/functional/command_block.rs +++ b/src/blocks/src/functional/command_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CommandBlock; use crate::BlockBehavior; +use temper_blocks_generated::CommandBlock; -impl BlockBehavior for CommandBlock { - -} \ No newline at end of file +impl BlockBehavior for CommandBlock {} diff --git a/src/blocks/src/functional/composter.rs b/src/blocks/src/functional/composter.rs index 1aeb2cca..30a916ba 100644 --- a/src/blocks/src/functional/composter.rs +++ b/src/blocks/src/functional/composter.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ComposterBlock; use crate::BlockBehavior; +use temper_blocks_generated::ComposterBlock; -impl BlockBehavior for ComposterBlock { - -} \ No newline at end of file +impl BlockBehavior for ComposterBlock {} diff --git a/src/blocks/src/functional/end_portal.rs b/src/blocks/src/functional/end_portal.rs index c7f2b7c9..4aaa9d59 100644 --- a/src/blocks/src/functional/end_portal.rs +++ b/src/blocks/src/functional/end_portal.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::EndPortalBlock; use crate::BlockBehavior; +use temper_blocks_generated::EndPortalBlock; -impl BlockBehavior for EndPortalBlock { - -} \ No newline at end of file +impl BlockBehavior for EndPortalBlock {} diff --git a/src/blocks/src/functional/furnace.rs b/src/blocks/src/functional/furnace.rs index b025ea47..843a8cb4 100644 --- a/src/blocks/src/functional/furnace.rs +++ b/src/blocks/src/functional/furnace.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FurnaceBlock; use crate::BlockBehavior; +use temper_blocks_generated::FurnaceBlock; -impl BlockBehavior for FurnaceBlock { - -} \ No newline at end of file +impl BlockBehavior for FurnaceBlock {} diff --git a/src/blocks/src/functional/grindstone.rs b/src/blocks/src/functional/grindstone.rs index 10c66ca2..e01b161e 100644 --- a/src/blocks/src/functional/grindstone.rs +++ b/src/blocks/src/functional/grindstone.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::GrindstoneBlock; use crate::BlockBehavior; +use temper_blocks_generated::GrindstoneBlock; -impl BlockBehavior for GrindstoneBlock { - -} \ No newline at end of file +impl BlockBehavior for GrindstoneBlock {} diff --git a/src/blocks/src/functional/jigsaw.rs b/src/blocks/src/functional/jigsaw.rs index 37b730b5..b8edc923 100644 --- a/src/blocks/src/functional/jigsaw.rs +++ b/src/blocks/src/functional/jigsaw.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::JigsawBlock; use crate::BlockBehavior; +use temper_blocks_generated::JigsawBlock; -impl BlockBehavior for JigsawBlock { - -} \ No newline at end of file +impl BlockBehavior for JigsawBlock {} diff --git a/src/blocks/src/functional/lectern.rs b/src/blocks/src/functional/lectern.rs index ac7fa410..98d8ebe6 100644 --- a/src/blocks/src/functional/lectern.rs +++ b/src/blocks/src/functional/lectern.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LecternBlock; use crate::BlockBehavior; +use temper_blocks_generated::LecternBlock; -impl BlockBehavior for LecternBlock { - -} \ No newline at end of file +impl BlockBehavior for LecternBlock {} diff --git a/src/blocks/src/functional/light.rs b/src/blocks/src/functional/light.rs index 36918780..2052caeb 100644 --- a/src/blocks/src/functional/light.rs +++ b/src/blocks/src/functional/light.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LightBlock; use crate::BlockBehavior; +use temper_blocks_generated::LightBlock; -impl BlockBehavior for LightBlock { - -} \ No newline at end of file +impl BlockBehavior for LightBlock {} diff --git a/src/blocks/src/functional/mod.rs b/src/blocks/src/functional/mod.rs index 4283972e..efb610f2 100644 --- a/src/blocks/src/functional/mod.rs +++ b/src/blocks/src/functional/mod.rs @@ -1,19 +1,19 @@ +mod barrel; mod brewing_stand; +mod campfire; mod cauldron; -mod end_portal; +mod chest; mod command_block; +mod composter; +mod end_portal; +mod furnace; +mod grindstone; +mod jigsaw; mod lectern; -mod barrel; +mod light; +mod respawn_anchor; mod scaffolding; -mod grindstone; -mod campfire; mod structure; -mod jigsaw; mod test; -mod composter; -mod respawn_anchor; mod trial_spawner; mod vault; -mod chest; -mod furnace; -mod light; \ No newline at end of file diff --git a/src/blocks/src/functional/respawn_anchor.rs b/src/blocks/src/functional/respawn_anchor.rs index 1b28bb54..f610a7e6 100644 --- a/src/blocks/src/functional/respawn_anchor.rs +++ b/src/blocks/src/functional/respawn_anchor.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RespawnAnchor; use crate::BlockBehavior; +use temper_blocks_generated::RespawnAnchor; -impl BlockBehavior for RespawnAnchor { - -} \ No newline at end of file +impl BlockBehavior for RespawnAnchor {} diff --git a/src/blocks/src/functional/scaffolding.rs b/src/blocks/src/functional/scaffolding.rs index ab505f92..856babb7 100644 --- a/src/blocks/src/functional/scaffolding.rs +++ b/src/blocks/src/functional/scaffolding.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ScaffoldingBlock; use crate::BlockBehavior; +use temper_blocks_generated::ScaffoldingBlock; -impl BlockBehavior for ScaffoldingBlock { - -} \ No newline at end of file +impl BlockBehavior for ScaffoldingBlock {} diff --git a/src/blocks/src/functional/structure.rs b/src/blocks/src/functional/structure.rs index 96405bba..f0241f0c 100644 --- a/src/blocks/src/functional/structure.rs +++ b/src/blocks/src/functional/structure.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::StructureBlock; use crate::BlockBehavior; +use temper_blocks_generated::StructureBlock; -impl BlockBehavior for StructureBlock { - -} \ No newline at end of file +impl BlockBehavior for StructureBlock {} diff --git a/src/blocks/src/functional/test.rs b/src/blocks/src/functional/test.rs index 6f64c205..3acb04ad 100644 --- a/src/blocks/src/functional/test.rs +++ b/src/blocks/src/functional/test.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TestBlock; use crate::BlockBehavior; +use temper_blocks_generated::TestBlock; -impl BlockBehavior for TestBlock { - -} \ No newline at end of file +impl BlockBehavior for TestBlock {} diff --git a/src/blocks/src/functional/trial_spawner.rs b/src/blocks/src/functional/trial_spawner.rs index eacbfa44..33d7187c 100644 --- a/src/blocks/src/functional/trial_spawner.rs +++ b/src/blocks/src/functional/trial_spawner.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TrialSpawnerBlock; use crate::BlockBehavior; +use temper_blocks_generated::TrialSpawnerBlock; -impl BlockBehavior for TrialSpawnerBlock { - -} \ No newline at end of file +impl BlockBehavior for TrialSpawnerBlock {} diff --git a/src/blocks/src/functional/vault.rs b/src/blocks/src/functional/vault.rs index e554cf9c..1ebd1554 100644 --- a/src/blocks/src/functional/vault.rs +++ b/src/blocks/src/functional/vault.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::VaultBlock; use crate::BlockBehavior; +use temper_blocks_generated::VaultBlock; -impl BlockBehavior for VaultBlock { - -} \ No newline at end of file +impl BlockBehavior for VaultBlock {} diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index 2eff793b..d141e583 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -8,23 +8,23 @@ use temper_core::pos::BlockPos; use temper_macros::match_block; use temper_world::World; -mod behavior_trait; -mod liquid; -mod suspicious_block; -mod waterloggable_block; mod bed_block; +mod behavior_trait; +mod bubble_column; +mod building; +mod cake; +mod candle_cake; +mod decorative; mod facing_block; mod fire; +mod functional; +mod liquid; mod nature; -mod building; -mod decorative; mod redstone; -mod cake; -mod functional; -mod candle_cake; -mod bubble_column; mod skull; +mod suspicious_block; mod wall_skull; +mod waterloggable_block; #[allow(unused_imports)] // Used in the include! use crate::behavior_trait::BlockBehaviorTable; diff --git a/src/blocks/src/liquid.rs b/src/blocks/src/liquid.rs index 1329a8b4..782f5578 100644 --- a/src/blocks/src/liquid.rs +++ b/src/blocks/src/liquid.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LiquidBlock; use crate::BlockBehavior; +use temper_blocks_generated::LiquidBlock; -impl BlockBehavior for LiquidBlock { - -} \ No newline at end of file +impl BlockBehavior for LiquidBlock {} diff --git a/src/blocks/src/nature/bamboo.rs b/src/blocks/src/nature/bamboo.rs index a58dca65..eca21792 100644 --- a/src/blocks/src/nature/bamboo.rs +++ b/src/blocks/src/nature/bamboo.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BambooBlock; use crate::BlockBehavior; +use temper_blocks_generated::BambooBlock; -impl BlockBehavior for BambooBlock { - -} \ No newline at end of file +impl BlockBehavior for BambooBlock {} diff --git a/src/blocks/src/nature/big_dripleaf.rs b/src/blocks/src/nature/big_dripleaf.rs index fb40ac13..2da3d6c5 100644 --- a/src/blocks/src/nature/big_dripleaf.rs +++ b/src/blocks/src/nature/big_dripleaf.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BigDripleafBlock; use crate::BlockBehavior; +use temper_blocks_generated::BigDripleafBlock; -impl BlockBehavior for BigDripleafBlock { - -} \ No newline at end of file +impl BlockBehavior for BigDripleafBlock {} diff --git a/src/blocks/src/nature/chorus.rs b/src/blocks/src/nature/chorus.rs index 991ff155..20b7016f 100644 --- a/src/blocks/src/nature/chorus.rs +++ b/src/blocks/src/nature/chorus.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ChorusPlantBlock; use crate::BlockBehavior; +use temper_blocks_generated::ChorusPlantBlock; -impl BlockBehavior for ChorusPlantBlock { - -} \ No newline at end of file +impl BlockBehavior for ChorusPlantBlock {} diff --git a/src/blocks/src/nature/cocoa_beans.rs b/src/blocks/src/nature/cocoa_beans.rs index 0d3d0981..f7e601ca 100644 --- a/src/blocks/src/nature/cocoa_beans.rs +++ b/src/blocks/src/nature/cocoa_beans.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CocoaBeansBlock; use crate::BlockBehavior; +use temper_blocks_generated::CocoaBeansBlock; -impl BlockBehavior for CocoaBeansBlock { - -} \ No newline at end of file +impl BlockBehavior for CocoaBeansBlock {} diff --git a/src/blocks/src/nature/creaking_heart.rs b/src/blocks/src/nature/creaking_heart.rs index a7c4e000..ade177db 100644 --- a/src/blocks/src/nature/creaking_heart.rs +++ b/src/blocks/src/nature/creaking_heart.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CreakingHeartBlock; use crate::BlockBehavior; +use temper_blocks_generated::CreakingHeartBlock; -impl BlockBehavior for CreakingHeartBlock { - -} \ No newline at end of file +impl BlockBehavior for CreakingHeartBlock {} diff --git a/src/blocks/src/nature/crop.rs b/src/blocks/src/nature/crop.rs index 728d70bb..144cc60b 100644 --- a/src/blocks/src/nature/crop.rs +++ b/src/blocks/src/nature/crop.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CropBlock; use crate::BlockBehavior; +use temper_blocks_generated::CropBlock; -impl BlockBehavior for CropBlock { - -} \ No newline at end of file +impl BlockBehavior for CropBlock {} diff --git a/src/blocks/src/nature/double_plant_block.rs b/src/blocks/src/nature/double_plant_block.rs index a8e84a9c..8e748545 100644 --- a/src/blocks/src/nature/double_plant_block.rs +++ b/src/blocks/src/nature/double_plant_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DoublePlantBlock; use crate::BlockBehavior; +use temper_blocks_generated::DoublePlantBlock; -impl BlockBehavior for DoublePlantBlock { - -} \ No newline at end of file +impl BlockBehavior for DoublePlantBlock {} diff --git a/src/blocks/src/nature/dripstone.rs b/src/blocks/src/nature/dripstone.rs index 03e50cb2..4a47076d 100644 --- a/src/blocks/src/nature/dripstone.rs +++ b/src/blocks/src/nature/dripstone.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DripstoneBlock; use crate::BlockBehavior; +use temper_blocks_generated::DripstoneBlock; -impl BlockBehavior for DripstoneBlock { - -} \ No newline at end of file +impl BlockBehavior for DripstoneBlock {} diff --git a/src/blocks/src/nature/farmland.rs b/src/blocks/src/nature/farmland.rs index b600f6c0..6ff7a2c2 100644 --- a/src/blocks/src/nature/farmland.rs +++ b/src/blocks/src/nature/farmland.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FarmlandBlock; use crate::BlockBehavior; +use temper_blocks_generated::FarmlandBlock; -impl BlockBehavior for FarmlandBlock { - -} \ No newline at end of file +impl BlockBehavior for FarmlandBlock {} diff --git a/src/blocks/src/nature/flower_cover.rs b/src/blocks/src/nature/flower_cover.rs index 40e622c6..1df9d430 100644 --- a/src/blocks/src/nature/flower_cover.rs +++ b/src/blocks/src/nature/flower_cover.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FlowerCoverBlock; use crate::BlockBehavior; +use temper_blocks_generated::FlowerCoverBlock; -impl BlockBehavior for FlowerCoverBlock { - -} \ No newline at end of file +impl BlockBehavior for FlowerCoverBlock {} diff --git a/src/blocks/src/nature/frosted_ice.rs b/src/blocks/src/nature/frosted_ice.rs index 7354eaa1..dff0d7be 100644 --- a/src/blocks/src/nature/frosted_ice.rs +++ b/src/blocks/src/nature/frosted_ice.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::FrostedIceBlock; use crate::BlockBehavior; +use temper_blocks_generated::FrostedIceBlock; -impl BlockBehavior for FrostedIceBlock { - -} \ No newline at end of file +impl BlockBehavior for FrostedIceBlock {} diff --git a/src/blocks/src/nature/glow_berries.rs b/src/blocks/src/nature/glow_berries.rs index 20fea378..7b7f6163 100644 --- a/src/blocks/src/nature/glow_berries.rs +++ b/src/blocks/src/nature/glow_berries.rs @@ -1,6 +1,4 @@ use crate::BlockBehavior; use temper_blocks_generated::GlowBerriesBlock; -impl BlockBehavior for GlowBerriesBlock { - -} \ No newline at end of file +impl BlockBehavior for GlowBerriesBlock {} diff --git a/src/blocks/src/nature/glow_berries_plant.rs b/src/blocks/src/nature/glow_berries_plant.rs index dc8e5625..e4c488d4 100644 --- a/src/blocks/src/nature/glow_berries_plant.rs +++ b/src/blocks/src/nature/glow_berries_plant.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::GlowBerriesPlantBlock; use crate::BlockBehavior; +use temper_blocks_generated::GlowBerriesPlantBlock; -impl BlockBehavior for GlowBerriesPlantBlock { - -} \ No newline at end of file +impl BlockBehavior for GlowBerriesPlantBlock {} diff --git a/src/blocks/src/nature/hive.rs b/src/blocks/src/nature/hive.rs index e773ca83..e196b850 100644 --- a/src/blocks/src/nature/hive.rs +++ b/src/blocks/src/nature/hive.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::HiveBlock; use crate::BlockBehavior; +use temper_blocks_generated::HiveBlock; -impl BlockBehavior for HiveBlock { - -} \ No newline at end of file +impl BlockBehavior for HiveBlock {} diff --git a/src/blocks/src/nature/large_mushroom.rs b/src/blocks/src/nature/large_mushroom.rs index a7252b68..2a92a2ee 100644 --- a/src/blocks/src/nature/large_mushroom.rs +++ b/src/blocks/src/nature/large_mushroom.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LargeMushroomBlock; use crate::BlockBehavior; +use temper_blocks_generated::LargeMushroomBlock; -impl BlockBehavior for LargeMushroomBlock { - -} \ No newline at end of file +impl BlockBehavior for LargeMushroomBlock {} diff --git a/src/blocks/src/nature/leaf_litter.rs b/src/blocks/src/nature/leaf_litter.rs index 31862669..ad8b29b9 100644 --- a/src/blocks/src/nature/leaf_litter.rs +++ b/src/blocks/src/nature/leaf_litter.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LeafLitterBlock; use crate::BlockBehavior; +use temper_blocks_generated::LeafLitterBlock; -impl BlockBehavior for LeafLitterBlock { - -} \ No newline at end of file +impl BlockBehavior for LeafLitterBlock {} diff --git a/src/blocks/src/nature/leaves.rs b/src/blocks/src/nature/leaves.rs index ad16d232..d532b9ca 100644 --- a/src/blocks/src/nature/leaves.rs +++ b/src/blocks/src/nature/leaves.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LeavesBlock; use crate::BlockBehavior; +use temper_blocks_generated::LeavesBlock; -impl BlockBehavior for LeavesBlock { - -} \ No newline at end of file +impl BlockBehavior for LeavesBlock {} diff --git a/src/blocks/src/nature/lichen.rs b/src/blocks/src/nature/lichen.rs index f7adece8..44218421 100644 --- a/src/blocks/src/nature/lichen.rs +++ b/src/blocks/src/nature/lichen.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LichenBlock; use crate::BlockBehavior; +use temper_blocks_generated::LichenBlock; -impl BlockBehavior for LichenBlock { - -} \ No newline at end of file +impl BlockBehavior for LichenBlock {} diff --git a/src/blocks/src/nature/mangrove_propagule.rs b/src/blocks/src/nature/mangrove_propagule.rs index 4a593435..140a8715 100644 --- a/src/blocks/src/nature/mangrove_propagule.rs +++ b/src/blocks/src/nature/mangrove_propagule.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::MangrovePopaguleBlock; use crate::BlockBehavior; +use temper_blocks_generated::MangrovePopaguleBlock; -impl BlockBehavior for MangrovePopaguleBlock { - -} \ No newline at end of file +impl BlockBehavior for MangrovePopaguleBlock {} diff --git a/src/blocks/src/nature/mod.rs b/src/blocks/src/nature/mod.rs index 5598b899..1c718790 100644 --- a/src/blocks/src/nature/mod.rs +++ b/src/blocks/src/nature/mod.rs @@ -1,30 +1,30 @@ -mod sapling_block; -mod mangrove_propagule; -mod leaves; -mod double_plant_block; +mod bamboo; +mod big_dripleaf; +mod chorus; +mod cocoa_beans; mod creaking_heart; mod crop; +mod double_plant_block; +mod dripstone; mod farmland; -mod snow; -mod large_mushroom; -mod stem; -mod vine; -mod lichen; -mod cocoa_beans; -mod pale_moss_carpet; -mod pale_hanging_moss; -mod small_dripleaf; -mod big_dripleaf; -mod leaf_litter; mod flower_cover; +mod frosted_ice; mod glow_berries; mod glow_berries_plant; -mod bamboo; -mod sea_pickle; -mod chorus; +mod hive; +mod large_mushroom; +mod leaf_litter; +mod leaves; +mod lichen; +mod mangrove_propagule; +mod pale_hanging_moss; +mod pale_moss_carpet; mod pitcher_crop; -mod frosted_ice; -mod turtle_egg; +mod sapling_block; +mod sea_pickle; +mod small_dripleaf; mod sniffer_egg; -mod hive; -mod dripstone; \ No newline at end of file +mod snow; +mod stem; +mod turtle_egg; +mod vine; diff --git a/src/blocks/src/nature/pale_hanging_moss.rs b/src/blocks/src/nature/pale_hanging_moss.rs index 51cf5158..2510c375 100644 --- a/src/blocks/src/nature/pale_hanging_moss.rs +++ b/src/blocks/src/nature/pale_hanging_moss.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PaleHangingMossBlock; use crate::BlockBehavior; +use temper_blocks_generated::PaleHangingMossBlock; -impl BlockBehavior for PaleHangingMossBlock { - -} \ No newline at end of file +impl BlockBehavior for PaleHangingMossBlock {} diff --git a/src/blocks/src/nature/pale_moss_carpet.rs b/src/blocks/src/nature/pale_moss_carpet.rs index 216fe261..b7654db5 100644 --- a/src/blocks/src/nature/pale_moss_carpet.rs +++ b/src/blocks/src/nature/pale_moss_carpet.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PaleMossCarpetBlock; use crate::BlockBehavior; +use temper_blocks_generated::PaleMossCarpetBlock; -impl BlockBehavior for PaleMossCarpetBlock { - -} \ No newline at end of file +impl BlockBehavior for PaleMossCarpetBlock {} diff --git a/src/blocks/src/nature/pitcher_crop.rs b/src/blocks/src/nature/pitcher_crop.rs index 87829fd8..094174d6 100644 --- a/src/blocks/src/nature/pitcher_crop.rs +++ b/src/blocks/src/nature/pitcher_crop.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PitcherCropBlock; use crate::BlockBehavior; +use temper_blocks_generated::PitcherCropBlock; -impl BlockBehavior for PitcherCropBlock { - -} \ No newline at end of file +impl BlockBehavior for PitcherCropBlock {} diff --git a/src/blocks/src/nature/sapling_block.rs b/src/blocks/src/nature/sapling_block.rs index 127c2988..567ff9ce 100644 --- a/src/blocks/src/nature/sapling_block.rs +++ b/src/blocks/src/nature/sapling_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SaplingBlock; use crate::BlockBehavior; +use temper_blocks_generated::SaplingBlock; -impl BlockBehavior for SaplingBlock { - -} \ No newline at end of file +impl BlockBehavior for SaplingBlock {} diff --git a/src/blocks/src/nature/sea_pickle.rs b/src/blocks/src/nature/sea_pickle.rs index aaffcfe0..4c1509af 100644 --- a/src/blocks/src/nature/sea_pickle.rs +++ b/src/blocks/src/nature/sea_pickle.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SeaPickleBlock; use crate::BlockBehavior; +use temper_blocks_generated::SeaPickleBlock; -impl BlockBehavior for SeaPickleBlock { - -} \ No newline at end of file +impl BlockBehavior for SeaPickleBlock {} diff --git a/src/blocks/src/nature/small_dripleaf.rs b/src/blocks/src/nature/small_dripleaf.rs index a4be5b42..1142e481 100644 --- a/src/blocks/src/nature/small_dripleaf.rs +++ b/src/blocks/src/nature/small_dripleaf.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SmallDripleafBlock; use crate::BlockBehavior; +use temper_blocks_generated::SmallDripleafBlock; -impl BlockBehavior for SmallDripleafBlock { - -} \ No newline at end of file +impl BlockBehavior for SmallDripleafBlock {} diff --git a/src/blocks/src/nature/sniffer_egg.rs b/src/blocks/src/nature/sniffer_egg.rs index 12c33190..056478ed 100644 --- a/src/blocks/src/nature/sniffer_egg.rs +++ b/src/blocks/src/nature/sniffer_egg.rs @@ -1,6 +1,4 @@ use crate::BlockBehavior; use temper_blocks_generated::SnifferEggBlock; -impl BlockBehavior for SnifferEggBlock { - -} \ No newline at end of file +impl BlockBehavior for SnifferEggBlock {} diff --git a/src/blocks/src/nature/snow.rs b/src/blocks/src/nature/snow.rs index 3b5a39bb..381109f7 100644 --- a/src/blocks/src/nature/snow.rs +++ b/src/blocks/src/nature/snow.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SnowBlock; use crate::BlockBehavior; +use temper_blocks_generated::SnowBlock; -impl BlockBehavior for SnowBlock { - -} \ No newline at end of file +impl BlockBehavior for SnowBlock {} diff --git a/src/blocks/src/nature/stem.rs b/src/blocks/src/nature/stem.rs index ba054903..d0fb1d3d 100644 --- a/src/blocks/src/nature/stem.rs +++ b/src/blocks/src/nature/stem.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::StemBlock; use crate::BlockBehavior; +use temper_blocks_generated::StemBlock; -impl BlockBehavior for StemBlock { - -} \ No newline at end of file +impl BlockBehavior for StemBlock {} diff --git a/src/blocks/src/nature/turtle_egg.rs b/src/blocks/src/nature/turtle_egg.rs index e43798f2..51c87126 100644 --- a/src/blocks/src/nature/turtle_egg.rs +++ b/src/blocks/src/nature/turtle_egg.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TurtleEggBlock; use crate::BlockBehavior; +use temper_blocks_generated::TurtleEggBlock; -impl BlockBehavior for TurtleEggBlock { - -} \ No newline at end of file +impl BlockBehavior for TurtleEggBlock {} diff --git a/src/blocks/src/nature/vine.rs b/src/blocks/src/nature/vine.rs index 5c231ec0..94620341 100644 --- a/src/blocks/src/nature/vine.rs +++ b/src/blocks/src/nature/vine.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::VineBlock; use crate::BlockBehavior; +use temper_blocks_generated::VineBlock; -impl BlockBehavior for VineBlock { - -} \ No newline at end of file +impl BlockBehavior for VineBlock {} diff --git a/src/blocks/src/redstone/bulb.rs b/src/blocks/src/redstone/bulb.rs index ca803370..207901c3 100644 --- a/src/blocks/src/redstone/bulb.rs +++ b/src/blocks/src/redstone/bulb.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::BulbBlock; use crate::BlockBehavior; +use temper_blocks_generated::BulbBlock; -impl BlockBehavior for BulbBlock { - -} \ No newline at end of file +impl BlockBehavior for BulbBlock {} diff --git a/src/blocks/src/redstone/button.rs b/src/blocks/src/redstone/button.rs index 719fa38b..fbfdc0a9 100644 --- a/src/blocks/src/redstone/button.rs +++ b/src/blocks/src/redstone/button.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ButtonBlock; use crate::BlockBehavior; +use temper_blocks_generated::ButtonBlock; -impl BlockBehavior for ButtonBlock { - -} \ No newline at end of file +impl BlockBehavior for ButtonBlock {} diff --git a/src/blocks/src/redstone/calibrated_sculk_sensor.rs b/src/blocks/src/redstone/calibrated_sculk_sensor.rs index b7a61ae5..0d1300f8 100644 --- a/src/blocks/src/redstone/calibrated_sculk_sensor.rs +++ b/src/blocks/src/redstone/calibrated_sculk_sensor.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CalibratedSculkSensorBlock; use crate::BlockBehavior; +use temper_blocks_generated::CalibratedSculkSensorBlock; -impl BlockBehavior for CalibratedSculkSensorBlock { - -} \ No newline at end of file +impl BlockBehavior for CalibratedSculkSensorBlock {} diff --git a/src/blocks/src/redstone/comparator.rs b/src/blocks/src/redstone/comparator.rs index f4dab1e4..4a0d0042 100644 --- a/src/blocks/src/redstone/comparator.rs +++ b/src/blocks/src/redstone/comparator.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ComparatorBlock; use crate::BlockBehavior; +use temper_blocks_generated::ComparatorBlock; -impl BlockBehavior for ComparatorBlock { - -} \ No newline at end of file +impl BlockBehavior for ComparatorBlock {} diff --git a/src/blocks/src/redstone/crafter.rs b/src/blocks/src/redstone/crafter.rs index 5afabcd3..538be302 100644 --- a/src/blocks/src/redstone/crafter.rs +++ b/src/blocks/src/redstone/crafter.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::CrafterBlock; use crate::BlockBehavior; +use temper_blocks_generated::CrafterBlock; -impl BlockBehavior for CrafterBlock { - -} \ No newline at end of file +impl BlockBehavior for CrafterBlock {} diff --git a/src/blocks/src/redstone/daylight_detector.rs b/src/blocks/src/redstone/daylight_detector.rs index e1ee1fa5..9152b7f5 100644 --- a/src/blocks/src/redstone/daylight_detector.rs +++ b/src/blocks/src/redstone/daylight_detector.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DaylightDetectorBlock; use crate::BlockBehavior; +use temper_blocks_generated::DaylightDetectorBlock; -impl BlockBehavior for DaylightDetectorBlock { - -} \ No newline at end of file +impl BlockBehavior for DaylightDetectorBlock {} diff --git a/src/blocks/src/redstone/dispenser.rs b/src/blocks/src/redstone/dispenser.rs index a538588a..b2bbf5e4 100644 --- a/src/blocks/src/redstone/dispenser.rs +++ b/src/blocks/src/redstone/dispenser.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::DispenserBlock; use crate::BlockBehavior; +use temper_blocks_generated::DispenserBlock; -impl BlockBehavior for DispenserBlock { - -} \ No newline at end of file +impl BlockBehavior for DispenserBlock {} diff --git a/src/blocks/src/redstone/hopper.rs b/src/blocks/src/redstone/hopper.rs index 1e63047c..a05f176a 100644 --- a/src/blocks/src/redstone/hopper.rs +++ b/src/blocks/src/redstone/hopper.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::HopperBlock; use crate::BlockBehavior; +use temper_blocks_generated::HopperBlock; -impl BlockBehavior for HopperBlock { - -} \ No newline at end of file +impl BlockBehavior for HopperBlock {} diff --git a/src/blocks/src/redstone/jukebox.rs b/src/blocks/src/redstone/jukebox.rs index 8ed0c4a7..7e975ce1 100644 --- a/src/blocks/src/redstone/jukebox.rs +++ b/src/blocks/src/redstone/jukebox.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::JukeboxBlock; use crate::BlockBehavior; +use temper_blocks_generated::JukeboxBlock; -impl BlockBehavior for JukeboxBlock { - -} \ No newline at end of file +impl BlockBehavior for JukeboxBlock {} diff --git a/src/blocks/src/redstone/lamp.rs b/src/blocks/src/redstone/lamp.rs index 4026b46c..2e884248 100644 --- a/src/blocks/src/redstone/lamp.rs +++ b/src/blocks/src/redstone/lamp.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RedstoneLampBlock; use crate::BlockBehavior; +use temper_blocks_generated::RedstoneLampBlock; -impl BlockBehavior for RedstoneLampBlock { - -} \ No newline at end of file +impl BlockBehavior for RedstoneLampBlock {} diff --git a/src/blocks/src/redstone/lever.rs b/src/blocks/src/redstone/lever.rs index 705c3901..17333344 100644 --- a/src/blocks/src/redstone/lever.rs +++ b/src/blocks/src/redstone/lever.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LeverBlock; use crate::BlockBehavior; +use temper_blocks_generated::LeverBlock; -impl BlockBehavior for LeverBlock { - -} \ No newline at end of file +impl BlockBehavior for LeverBlock {} diff --git a/src/blocks/src/redstone/lightning_rod.rs b/src/blocks/src/redstone/lightning_rod.rs index 92bba853..a1610a36 100644 --- a/src/blocks/src/redstone/lightning_rod.rs +++ b/src/blocks/src/redstone/lightning_rod.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::LightningRodBlock; use crate::BlockBehavior; +use temper_blocks_generated::LightningRodBlock; -impl BlockBehavior for LightningRodBlock { - -} \ No newline at end of file +impl BlockBehavior for LightningRodBlock {} diff --git a/src/blocks/src/redstone/mod.rs b/src/blocks/src/redstone/mod.rs index 489390b5..7438c999 100644 --- a/src/blocks/src/redstone/mod.rs +++ b/src/blocks/src/redstone/mod.rs @@ -1,30 +1,30 @@ +mod bulb; +mod button; +mod calibrated_sculk_sensor; +mod comparator; +mod crafter; +mod daylight_detector; mod dispenser; -mod redstone_rail; -mod tnt; -mod piston; -mod wire; -mod rail; +mod hopper; +mod jukebox; +mod lamp; mod lever; -mod pressure_plate; +mod lightning_rod; +mod observer; mod ore; -mod torch; -mod wall_torch; -mod button; -mod jukebox; +mod piston; +mod pressure_plate; +mod rail; +mod redstone_rail; mod repeater; -mod lamp; +mod sculk_catalyst; +mod sculk_sensor; +mod sculk_shrieker; +mod target; +mod tnt; +mod torch; mod tripwire; mod tripwire_hook; -mod bulb; -mod observer; -mod hopper; +mod wall_torch; mod weighted_pressure_plate; -mod comparator; -mod daylight_detector; -mod target; -mod sculk_sensor; -mod calibrated_sculk_sensor; -mod sculk_catalyst; -mod sculk_shrieker; -mod lightning_rod; -mod crafter; \ No newline at end of file +mod wire; diff --git a/src/blocks/src/redstone/observer.rs b/src/blocks/src/redstone/observer.rs index 786c2a17..eff40d23 100644 --- a/src/blocks/src/redstone/observer.rs +++ b/src/blocks/src/redstone/observer.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::ObserverBlock; use crate::BlockBehavior; +use temper_blocks_generated::ObserverBlock; -impl BlockBehavior for ObserverBlock { - -} \ No newline at end of file +impl BlockBehavior for ObserverBlock {} diff --git a/src/blocks/src/redstone/ore.rs b/src/blocks/src/redstone/ore.rs index 3587ceb3..421f65a0 100644 --- a/src/blocks/src/redstone/ore.rs +++ b/src/blocks/src/redstone/ore.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RedstoneOreBlock; use crate::BlockBehavior; +use temper_blocks_generated::RedstoneOreBlock; -impl BlockBehavior for RedstoneOreBlock { - -} \ No newline at end of file +impl BlockBehavior for RedstoneOreBlock {} diff --git a/src/blocks/src/redstone/piston/head.rs b/src/blocks/src/redstone/piston/head.rs index d250d270..6bdb4cef 100644 --- a/src/blocks/src/redstone/piston/head.rs +++ b/src/blocks/src/redstone/piston/head.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PistonHeadBlock; use crate::BlockBehavior; +use temper_blocks_generated::PistonHeadBlock; -impl BlockBehavior for PistonHeadBlock { - -} \ No newline at end of file +impl BlockBehavior for PistonHeadBlock {} diff --git a/src/blocks/src/redstone/piston/mod.rs b/src/blocks/src/redstone/piston/mod.rs index 9dd0c288..53fa6668 100644 --- a/src/blocks/src/redstone/piston/mod.rs +++ b/src/blocks/src/redstone/piston/mod.rs @@ -1,9 +1,7 @@ -use temper_blocks_generated::PistonBlock; use crate::BlockBehavior; +use temper_blocks_generated::PistonBlock; mod head; mod moving_head; -impl BlockBehavior for PistonBlock { - -} \ No newline at end of file +impl BlockBehavior for PistonBlock {} diff --git a/src/blocks/src/redstone/piston/moving_head.rs b/src/blocks/src/redstone/piston/moving_head.rs index 29553b6d..0c38afb5 100644 --- a/src/blocks/src/redstone/piston/moving_head.rs +++ b/src/blocks/src/redstone/piston/moving_head.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::MovingPistonBlock; use crate::BlockBehavior; +use temper_blocks_generated::MovingPistonBlock; -impl BlockBehavior for MovingPistonBlock { - -} \ No newline at end of file +impl BlockBehavior for MovingPistonBlock {} diff --git a/src/blocks/src/redstone/pressure_plate.rs b/src/blocks/src/redstone/pressure_plate.rs index 705752a4..34e1a92c 100644 --- a/src/blocks/src/redstone/pressure_plate.rs +++ b/src/blocks/src/redstone/pressure_plate.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::PressurePlateBlock; use crate::BlockBehavior; +use temper_blocks_generated::PressurePlateBlock; -impl BlockBehavior for PressurePlateBlock { - -} \ No newline at end of file +impl BlockBehavior for PressurePlateBlock {} diff --git a/src/blocks/src/redstone/rail.rs b/src/blocks/src/redstone/rail.rs index 669b5c59..ac21e4f1 100644 --- a/src/blocks/src/redstone/rail.rs +++ b/src/blocks/src/redstone/rail.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RailBlock; use crate::BlockBehavior; +use temper_blocks_generated::RailBlock; -impl BlockBehavior for RailBlock { - -} \ No newline at end of file +impl BlockBehavior for RailBlock {} diff --git a/src/blocks/src/redstone/redstone_rail.rs b/src/blocks/src/redstone/redstone_rail.rs index ecf4fbf3..b7c07e91 100644 --- a/src/blocks/src/redstone/redstone_rail.rs +++ b/src/blocks/src/redstone/redstone_rail.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RedstoneRailBlock; use crate::BlockBehavior; +use temper_blocks_generated::RedstoneRailBlock; -impl BlockBehavior for RedstoneRailBlock { - -} \ No newline at end of file +impl BlockBehavior for RedstoneRailBlock {} diff --git a/src/blocks/src/redstone/repeater.rs b/src/blocks/src/redstone/repeater.rs index aa453e19..c15cbd74 100644 --- a/src/blocks/src/redstone/repeater.rs +++ b/src/blocks/src/redstone/repeater.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RepeaterBlock; use crate::BlockBehavior; +use temper_blocks_generated::RepeaterBlock; -impl BlockBehavior for RepeaterBlock { - -} \ No newline at end of file +impl BlockBehavior for RepeaterBlock {} diff --git a/src/blocks/src/redstone/sculk_catalyst.rs b/src/blocks/src/redstone/sculk_catalyst.rs index c8bd9c21..cc6039c2 100644 --- a/src/blocks/src/redstone/sculk_catalyst.rs +++ b/src/blocks/src/redstone/sculk_catalyst.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SculkCatalystBlock; use crate::BlockBehavior; +use temper_blocks_generated::SculkCatalystBlock; -impl BlockBehavior for SculkCatalystBlock { - -} \ No newline at end of file +impl BlockBehavior for SculkCatalystBlock {} diff --git a/src/blocks/src/redstone/sculk_sensor.rs b/src/blocks/src/redstone/sculk_sensor.rs index a9ce3742..46cedbab 100644 --- a/src/blocks/src/redstone/sculk_sensor.rs +++ b/src/blocks/src/redstone/sculk_sensor.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SculkSensorBlock; use crate::BlockBehavior; +use temper_blocks_generated::SculkSensorBlock; -impl BlockBehavior for SculkSensorBlock { - -} \ No newline at end of file +impl BlockBehavior for SculkSensorBlock {} diff --git a/src/blocks/src/redstone/sculk_shrieker.rs b/src/blocks/src/redstone/sculk_shrieker.rs index 0a1273d7..7053e901 100644 --- a/src/blocks/src/redstone/sculk_shrieker.rs +++ b/src/blocks/src/redstone/sculk_shrieker.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SculkShriekerBlock; use crate::BlockBehavior; +use temper_blocks_generated::SculkShriekerBlock; -impl BlockBehavior for SculkShriekerBlock { - -} \ No newline at end of file +impl BlockBehavior for SculkShriekerBlock {} diff --git a/src/blocks/src/redstone/target.rs b/src/blocks/src/redstone/target.rs index d877203e..7baed0a3 100644 --- a/src/blocks/src/redstone/target.rs +++ b/src/blocks/src/redstone/target.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TargetBlock; use crate::BlockBehavior; +use temper_blocks_generated::TargetBlock; -impl BlockBehavior for TargetBlock { - -} \ No newline at end of file +impl BlockBehavior for TargetBlock {} diff --git a/src/blocks/src/redstone/tnt.rs b/src/blocks/src/redstone/tnt.rs index 050e1ee8..ae44feda 100644 --- a/src/blocks/src/redstone/tnt.rs +++ b/src/blocks/src/redstone/tnt.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TntBlock; use crate::BlockBehavior; +use temper_blocks_generated::TntBlock; -impl BlockBehavior for TntBlock { - -} \ No newline at end of file +impl BlockBehavior for TntBlock {} diff --git a/src/blocks/src/redstone/torch.rs b/src/blocks/src/redstone/torch.rs index 89a9ae0f..07c1a93f 100644 --- a/src/blocks/src/redstone/torch.rs +++ b/src/blocks/src/redstone/torch.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RedstoneTorchBlock; use crate::BlockBehavior; +use temper_blocks_generated::RedstoneTorchBlock; -impl BlockBehavior for RedstoneTorchBlock { - -} \ No newline at end of file +impl BlockBehavior for RedstoneTorchBlock {} diff --git a/src/blocks/src/redstone/tripwire.rs b/src/blocks/src/redstone/tripwire.rs index 05ea0911..364b8267 100644 --- a/src/blocks/src/redstone/tripwire.rs +++ b/src/blocks/src/redstone/tripwire.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::TripwireBlock; use crate::BlockBehavior; +use temper_blocks_generated::TripwireBlock; -impl BlockBehavior for TripwireBlock { - -} \ No newline at end of file +impl BlockBehavior for TripwireBlock {} diff --git a/src/blocks/src/redstone/tripwire_hook.rs b/src/blocks/src/redstone/tripwire_hook.rs index 1fdabd64..a14a0c0a 100644 --- a/src/blocks/src/redstone/tripwire_hook.rs +++ b/src/blocks/src/redstone/tripwire_hook.rs @@ -1,6 +1,4 @@ use crate::BlockBehavior; use temper_blocks_generated::TripwireHookBlock; -impl BlockBehavior for TripwireHookBlock { - -} \ No newline at end of file +impl BlockBehavior for TripwireHookBlock {} diff --git a/src/blocks/src/redstone/wall_torch.rs b/src/blocks/src/redstone/wall_torch.rs index d504d280..75016123 100644 --- a/src/blocks/src/redstone/wall_torch.rs +++ b/src/blocks/src/redstone/wall_torch.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WallRedstoneTorchBlock; use crate::BlockBehavior; +use temper_blocks_generated::WallRedstoneTorchBlock; -impl BlockBehavior for WallRedstoneTorchBlock { - -} \ No newline at end of file +impl BlockBehavior for WallRedstoneTorchBlock {} diff --git a/src/blocks/src/redstone/weighted_pressure_plate.rs b/src/blocks/src/redstone/weighted_pressure_plate.rs index a2a2ab9b..ed3af340 100644 --- a/src/blocks/src/redstone/weighted_pressure_plate.rs +++ b/src/blocks/src/redstone/weighted_pressure_plate.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WeightedPressurePlateBlock; use crate::BlockBehavior; +use temper_blocks_generated::WeightedPressurePlateBlock; -impl BlockBehavior for WeightedPressurePlateBlock { - -} \ No newline at end of file +impl BlockBehavior for WeightedPressurePlateBlock {} diff --git a/src/blocks/src/redstone/wire.rs b/src/blocks/src/redstone/wire.rs index 88e437c1..eded0acd 100644 --- a/src/blocks/src/redstone/wire.rs +++ b/src/blocks/src/redstone/wire.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::RedstoneWireBlock; use crate::BlockBehavior; +use temper_blocks_generated::RedstoneWireBlock; -impl BlockBehavior for RedstoneWireBlock { - -} \ No newline at end of file +impl BlockBehavior for RedstoneWireBlock {} diff --git a/src/blocks/src/skull.rs b/src/blocks/src/skull.rs index a69b27a9..e6704b86 100644 --- a/src/blocks/src/skull.rs +++ b/src/blocks/src/skull.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SkullBlock; use crate::BlockBehavior; +use temper_blocks_generated::SkullBlock; -impl BlockBehavior for SkullBlock { - -} \ No newline at end of file +impl BlockBehavior for SkullBlock {} diff --git a/src/blocks/src/suspicious_block.rs b/src/blocks/src/suspicious_block.rs index d806dc07..00604b7f 100644 --- a/src/blocks/src/suspicious_block.rs +++ b/src/blocks/src/suspicious_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::SuspiciousBlock; use crate::BlockBehavior; +use temper_blocks_generated::SuspiciousBlock; -impl BlockBehavior for SuspiciousBlock { - -} \ No newline at end of file +impl BlockBehavior for SuspiciousBlock {} diff --git a/src/blocks/src/wall_skull.rs b/src/blocks/src/wall_skull.rs index a34e169b..8c9b1cae 100644 --- a/src/blocks/src/wall_skull.rs +++ b/src/blocks/src/wall_skull.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WallSkullBlock; use crate::BlockBehavior; +use temper_blocks_generated::WallSkullBlock; -impl BlockBehavior for WallSkullBlock { - -} \ No newline at end of file +impl BlockBehavior for WallSkullBlock {} diff --git a/src/blocks/src/waterloggable_block.rs b/src/blocks/src/waterloggable_block.rs index 2671e794..b877b4de 100644 --- a/src/blocks/src/waterloggable_block.rs +++ b/src/blocks/src/waterloggable_block.rs @@ -1,6 +1,4 @@ -use temper_blocks_generated::WaterloggableBlock; use crate::BlockBehavior; +use temper_blocks_generated::WaterloggableBlock; -impl BlockBehavior for WaterloggableBlock { - -} \ No newline at end of file +impl BlockBehavior for WaterloggableBlock {} diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs index e1c2e358..4a56e1ba 100644 --- a/src/core/src/block_face.rs +++ b/src/core/src/block_face.rs @@ -1,7 +1,7 @@ -use std::io::Read; use bevy_math::IVec3; -use temper_codec::decode::{NetDecode, NetDecodeOpts}; +use std::io::Read; use temper_codec::decode::errors::NetDecodeError; +use temper_codec::decode::{NetDecode, NetDecodeOpts}; use temper_codec::net_types::var_int::VarInt; use temper_nbt::tokio::io::AsyncRead; @@ -72,4 +72,4 @@ impl NetDecode for BlockFace { _ => Err(NetDecodeError::InvalidEnumVariant), } } -} \ No newline at end of file +} diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index cb579119..886ae262 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -2,9 +2,9 @@ pub mod errors; // Core structs/types. Usually used in ECS Components. pub mod block_data; +pub mod block_face; pub mod block_state_id; pub mod color; pub mod dimension; pub mod mq; pub mod pos; -pub mod block_face; diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index c3ae9d98..3b710e17 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -13,17 +13,13 @@ use temper_protocol::outgoing::block_change_ack::BlockChangeAck; use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use tracing::{debug, error, trace}; - -use bevy_math::{DVec2, DVec3, Vec2}; -use block_placing::PlacedBlocks; -use std::collections::HashMap; +use bevy_math::DVec2; +use temper_blocks::BlockDispatch; use temper_components::player::rotation::Rotation; use temper_config::server_config::get_global_config; use temper_core::block_state_id::ITEM_TO_BLOCK_MAPPING; use temper_core::dimension::Dimension; use temper_core::mq; -use temper_blocks::BlockDispatch; -use temper_core::block_face::BlockFace; use temper_inventories::hotbar::Hotbar; use temper_inventories::inventory::Inventory; use temper_messages::world_change::WorldChange; @@ -46,7 +42,7 @@ pub fn handle( mut block_interact: MessageWriter, ) { 'ev_loop: for (event, eid) in receiver.0.try_iter() { - let Ok((entity, conn, inventory, hotbar, pos, rot, sneak)) = query.get(eid) else { + let Ok((entity, conn, inventory, hotbar, _pos, _rot, sneak)) = query.get(eid) else { debug!("Could not get connection for entity {:?}", eid); continue; }; @@ -115,7 +111,7 @@ pub fn handle( } let offset_pos = block_pos + event.face.translation_vec().into(); - let block_clicked = { + let _block_clicked = { let chunk = state .0 .world @@ -159,14 +155,14 @@ pub fn handle( .expect("Failed to load or generate chunk"); chunk.get_block(offset_pos.chunk_block_pos()) }; - + let mut block_state = ITEM_TO_BLOCK_MAPPING .get() .unwrap() .get(&(item_id.as_u32() as i32)) .copied() .unwrap(); - + block_state.get_placement_state( temper_blocks::PlacementContext { face: event.face, @@ -176,7 +172,7 @@ pub fn handle( offset_pos, ); - let placed_blocks = vec![(block_pos, block_state)]; + let placed_blocks = vec![(offset_pos, block_state)]; // let placed_blocks = block_placing::place_item( // state.0.clone(), From 1dbfc6ad5d0858dba569700bdc80e2e1d29eefcf Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Thu, 2 Apr 2026 16:13:03 -0500 Subject: [PATCH 09/30] Allow casting from BlockStateId to specific block struct --- src/blocks/src/behavior_trait.rs | 8 +++++++- src/game_systems/src/packets/src/place_block.rs | 12 ++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index cbb42a07..a64fb6b9 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -78,8 +78,10 @@ macro_rules! block_behavior_trait { #[allow(dead_code)] pub trait BlockDispatch { + fn try_cast(&self) -> Option; + $( - fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { $($default)? } + fn $name(&$($mut_meta)? self, $($argument: $ty),*) $(-> $ret)?; )* } @@ -130,6 +132,10 @@ macro_rules! block_behavior_trait { } impl BlockDispatch for BlockStateId { + fn try_cast(&self) -> Option { + T::try_from(self.raw()).ok() + } + $( fn $name(& $($mut_meta)? self, $($argument: $ty),*) $(-> $ret)? { let (_new_id, _ret) = id_ret_decode!{$($mut_meta)? $($ret)?, BLOCK_MAPPINGS[self.raw() as usize].$name($($argument),*)}; diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 3b710e17..ef989840 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -7,12 +7,6 @@ use temper_components::{bounds::CollisionBounds, player::sneak::SneakState}; use temper_core::pos::BlockPos; use temper_messages::BlockInteractMessage; -use temper_net_runtime::connection::StreamWriter; -use temper_protocol::PlaceBlockReceiver; -use temper_protocol::outgoing::block_change_ack::BlockChangeAck; -use temper_protocol::outgoing::block_update::BlockUpdate; -use temper_state::GlobalStateResource; -use tracing::{debug, error, trace}; use bevy_math::DVec2; use temper_blocks::BlockDispatch; use temper_components::player::rotation::Rotation; @@ -23,7 +17,13 @@ use temper_core::mq; use temper_inventories::hotbar::Hotbar; use temper_inventories::inventory::Inventory; use temper_messages::world_change::WorldChange; +use temper_net_runtime::connection::StreamWriter; +use temper_protocol::PlaceBlockReceiver; +use temper_protocol::outgoing::block_change_ack::BlockChangeAck; +use temper_protocol::outgoing::block_update::BlockUpdate; +use temper_state::GlobalStateResource; use temper_text::{Color, NamedColor, TextComponentBuilder}; +use tracing::{debug, error, trace}; pub fn handle( receiver: Res, From ed73bb88abe71924c7b7d03ac193eb8f0b91116d Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Thu, 2 Apr 2026 21:24:28 -0500 Subject: [PATCH 10/30] Fix bugs with block behavior trait macro --- src/blocks/src/behavior_trait.rs | 17 +++--- src/blocks/src/lib.rs | 53 ++++++++++++------- .../src/packets/src/place_block.rs | 22 ++++---- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index a64fb6b9..2138253d 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -42,7 +42,7 @@ macro_rules! block_behavior_trait { $in_data }; ($retb:ty, $in_data:expr) => { - ((), $retb) + ((), $in_data) }; } @@ -55,16 +55,16 @@ macro_rules! block_behavior_trait { () => { () }; - (mut; $data:expr; $retb:ty) => { + (mut; $data:expr; $retb:ty; $ret_val:expr) => { ( $data .try_into() .unwrap_or_else(|_| panic!("Failed to convert block data back into id")), - _ret, + $ret_val, ) }; - ($retb:ty) => { - _ret + ($retb:ty; $ret_val:expr) => { + $ret_val }; } @@ -87,7 +87,7 @@ macro_rules! block_behavior_trait { pub struct BlockBehaviorTable { $( - $name: fn(id: u32, $($argument: $ty),*) -> ptr_ret_ty!{$($mut_meta)?} + $name: fn(id: u32, $($argument: $ty),*) -> ptr_ret_ty!{$($mut_meta)? $($ret)?} ),* } @@ -98,7 +98,7 @@ macro_rules! block_behavior_trait { $name: |id, $($argument),*| { let $($mut_meta)? data = T::try_from(id).unwrap_or_else(|_| panic!("Failed to convert id to data")); let _ret = data.$name($($argument),*); - lambda_ret_ty!($($mut_meta; data;)? $($ret)?) + lambda_ret_ty!($($mut_meta; data;)? $($ret; _ret)?) } ),* } @@ -151,7 +151,8 @@ macro_rules! block_behavior_trait { // // This is the only place where the `block_behavior_trait!` macro should be used. block_behavior_trait!( - fn get_placement_state(mut; _context: PlacementContext, _world: &World, _pos: BlockPos), + fn get_placement_state(mut; _context: PlacementContext), + fn can_be_replaced(; _context: PlacementContext) -> bool; false, fn update(mut; _world: &World, _pos: BlockPos), fn test(;), ); diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index d141e583..feaa33bd 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -1,4 +1,4 @@ -use bevy_math::DVec2; +use bevy_math::DVec3; use temper_block_properties::SlabType; use temper_blocks_generated::{SlabBlock, SnowyBlock}; use temper_core::block_face::BlockFace; @@ -34,31 +34,46 @@ pub use crate::behavior_trait::{BlockBehavior, BlockDispatch, StateBehaviorTable pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); -pub struct PlacementContext { +pub struct PlacementContext<'a> { pub face: BlockFace, - pub cursor: DVec2, + pub cursor: DVec3, + pub block_clicked: BlockPos, + pub block_pos: BlockPos, + pub level: &'a World, + pub dimension: Dimension, } impl BlockBehavior for SlabBlock { #[inline(always)] - fn get_placement_state(&mut self, context: PlacementContext, world: &World, pos: BlockPos) { - let block = world - .get_chunk(pos.chunk(), Dimension::Overworld) - .map(|c| c.get_block(pos.chunk_block_pos())) + fn get_placement_state(&mut self, context: PlacementContext) { + let block = context + .level + .get_chunk(context.block_pos.chunk(), context.dimension) + .map(|c| c.get_block(context.block_pos.chunk_block_pos())) .unwrap_or(BlockStateId::new(0)); - self.waterlogged = match_block!("water", block); - self.ty = match context.face { - BlockFace::Top => SlabType::Bottom, - BlockFace::Bottom => SlabType::Top, - _ => { - if context.cursor.y > 0.5 { - SlabType::Top - } else { - SlabType::Bottom + self.ty = if block.try_cast::().is_some() { + SlabType::Double + } else { + match context.face { + BlockFace::Top => SlabType::Bottom, + BlockFace::Bottom => SlabType::Top, + _ => { + if context.cursor.y > 0.5 { + SlabType::Top + } else { + SlabType::Bottom + } } } - } + }; + + self.waterlogged = match_block!("water", block); + } + + #[inline(always)] + fn can_be_replaced(&self, _context: PlacementContext) -> bool { + true } #[inline(always)] @@ -77,8 +92,8 @@ fn has_snow_above(world: &World, pos: BlockPos) -> bool { } impl BlockBehavior for SnowyBlock { - fn get_placement_state(&mut self, _context: PlacementContext, world: &World, pos: BlockPos) { - self.snowy = has_snow_above(world, pos); + fn get_placement_state(&mut self, _context: PlacementContext) { + self.snowy = has_snow_above(_context.level, _context.block_pos); } fn update(&mut self, world: &World, pos: BlockPos) { diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index ef989840..f35ee2cf 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -7,7 +7,7 @@ use temper_components::{bounds::CollisionBounds, player::sneak::SneakState}; use temper_core::pos::BlockPos; use temper_messages::BlockInteractMessage; -use bevy_math::DVec2; +use bevy_math::DVec3; use temper_blocks::BlockDispatch; use temper_components::player::rotation::Rotation; use temper_config::server_config::get_global_config; @@ -163,14 +163,18 @@ pub fn handle( .copied() .unwrap(); - block_state.get_placement_state( - temper_blocks::PlacementContext { - face: event.face, - cursor: DVec2::new(event.cursor_x as _, event.cursor_y as _), - }, - &state.0.world, - offset_pos, - ); + block_state.get_placement_state(temper_blocks::PlacementContext { + face: event.face, + cursor: DVec3::new( + event.cursor_x as _, + event.cursor_y as _, + event.cursor_z as _, + ), + block_clicked: block_pos, + block_pos: offset_pos, + level: &state.0.world, + dimension: Dimension::Overworld, + }); let placed_blocks = vec![(offset_pos, block_state)]; From 3b6ed91cd4c14b4559d5aa88f2a186a9de4a49dd Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Sat, 4 Apr 2026 18:42:06 -0500 Subject: [PATCH 11/30] Remove test functions and move SlabBlock and SnowyBlock behavior impls to separate modules --- src/blocks/src/behavior_trait.rs | 1 - src/blocks/src/building/mod.rs | 1 + src/blocks/src/building/slab.rs | 40 +++++++++++++++++ src/blocks/src/lib.rs | 73 -------------------------------- src/blocks/src/nature/mod.rs | 1 + src/blocks/src/nature/snowy.rs | 4 ++ 6 files changed, 46 insertions(+), 74 deletions(-) create mode 100644 src/blocks/src/building/slab.rs create mode 100644 src/blocks/src/nature/snowy.rs diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index 2138253d..ba015d72 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -154,5 +154,4 @@ block_behavior_trait!( fn get_placement_state(mut; _context: PlacementContext), fn can_be_replaced(; _context: PlacementContext) -> bool; false, fn update(mut; _world: &World, _pos: BlockPos), - fn test(;), ); diff --git a/src/blocks/src/building/mod.rs b/src/blocks/src/building/mod.rs index c866d8fa..7ead741d 100644 --- a/src/blocks/src/building/mod.rs +++ b/src/blocks/src/building/mod.rs @@ -1,3 +1,4 @@ mod pillar_block; mod simple_block; +mod slab; mod stairs; diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs new file mode 100644 index 00000000..429a2d2d --- /dev/null +++ b/src/blocks/src/building/slab.rs @@ -0,0 +1,40 @@ +use crate::{BlockBehavior, BlockDispatch, PlacementContext}; +use temper_block_properties::SlabType; +use temper_blocks_generated::SlabBlock; +use temper_core::block_face::BlockFace; +use temper_core::block_state_id::BlockStateId; +use temper_macros::match_block; + +impl BlockBehavior for SlabBlock { + #[inline(always)] + fn get_placement_state(&mut self, context: PlacementContext) { + let block = context + .level + .get_chunk(context.block_pos.chunk(), context.dimension) + .map(|c| c.get_block(context.block_pos.chunk_block_pos())) + .unwrap_or(BlockStateId::new(0)); + + self.ty = if block.try_cast::().is_some() { + SlabType::Double + } else { + match context.face { + BlockFace::Top => SlabType::Bottom, + BlockFace::Bottom => SlabType::Top, + _ => { + if context.cursor.y > 0.5 { + SlabType::Top + } else { + SlabType::Bottom + } + } + } + }; + + self.waterlogged = match_block!("water", block); + } + + #[inline(always)] + fn can_be_replaced(&self, _context: PlacementContext) -> bool { + true + } +} diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index feaa33bd..ca21c89e 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -1,11 +1,7 @@ use bevy_math::DVec3; -use temper_block_properties::SlabType; -use temper_blocks_generated::{SlabBlock, SnowyBlock}; use temper_core::block_face::BlockFace; -use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; -use temper_macros::match_block; use temper_world::World; mod bed_block; @@ -42,72 +38,3 @@ pub struct PlacementContext<'a> { pub level: &'a World, pub dimension: Dimension, } - -impl BlockBehavior for SlabBlock { - #[inline(always)] - fn get_placement_state(&mut self, context: PlacementContext) { - let block = context - .level - .get_chunk(context.block_pos.chunk(), context.dimension) - .map(|c| c.get_block(context.block_pos.chunk_block_pos())) - .unwrap_or(BlockStateId::new(0)); - - self.ty = if block.try_cast::().is_some() { - SlabType::Double - } else { - match context.face { - BlockFace::Top => SlabType::Bottom, - BlockFace::Bottom => SlabType::Top, - _ => { - if context.cursor.y > 0.5 { - SlabType::Top - } else { - SlabType::Bottom - } - } - } - }; - - self.waterlogged = match_block!("water", block); - } - - #[inline(always)] - fn can_be_replaced(&self, _context: PlacementContext) -> bool { - true - } - - #[inline(always)] - fn test(&self) { - panic!("hello") - } -} - -fn has_snow_above(world: &World, pos: BlockPos) -> bool { - let pos = pos + (0, 1, 0); - - world - .get_chunk(pos.chunk(), Dimension::Overworld) - .map(|c| c.get_block(pos.chunk_block_pos())) - .is_ok_and(|id| match_block!("snow", id)) -} - -impl BlockBehavior for SnowyBlock { - fn get_placement_state(&mut self, _context: PlacementContext) { - self.snowy = has_snow_above(_context.level, _context.block_pos); - } - - fn update(&mut self, world: &World, pos: BlockPos) { - self.snowy = has_snow_above(world, pos); - } -} - -#[cfg(test)] -mod tests { - use crate::BLOCK_MAPPINGS; - - #[test] - #[ignore] - fn test() { - BLOCK_MAPPINGS[12051].test(); - } -} diff --git a/src/blocks/src/nature/mod.rs b/src/blocks/src/nature/mod.rs index 1c718790..5dc98248 100644 --- a/src/blocks/src/nature/mod.rs +++ b/src/blocks/src/nature/mod.rs @@ -25,6 +25,7 @@ mod sea_pickle; mod small_dripleaf; mod sniffer_egg; mod snow; +mod snowy; mod stem; mod turtle_egg; mod vine; diff --git a/src/blocks/src/nature/snowy.rs b/src/blocks/src/nature/snowy.rs new file mode 100644 index 00000000..8dfb6ca3 --- /dev/null +++ b/src/blocks/src/nature/snowy.rs @@ -0,0 +1,4 @@ +use crate::BlockBehavior; +use temper_blocks_generated::SnowyBlock; + +impl BlockBehavior for SnowyBlock {} From a1117a2cf3267e4758fa0320ee0fe5029b08f1ac Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 8 Apr 2026 19:04:21 -0500 Subject: [PATCH 12/30] Add more documentation --- src/blocks/README.md | 26 ++++++++++++++++++++++++++ src/blocks/crates/property/src/lib.rs | 11 ++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/blocks/README.md b/src/blocks/README.md index 825f42d9..669d4c7a 100644 --- a/src/blocks/README.md +++ b/src/blocks/README.md @@ -2,6 +2,32 @@ This is a quick tutorial on how to use this library to create and modify block behavior and structs. +## Overview + +This is a brief overview of what this crate is actually doing. This is split up into 2 distinct pieces, +the struct generator and the behavior implementation. + +The struct generator (the `temper-blocks-build` crate) is given the `build_config.toml` and `blockstates.json` files +and generates structs based off of groups of blockstates. For each block in `blockstates.json`, it +figures out which properties that block has. It will then collect blocks that have those same properties +and group them under the same struct. When it's saving the structs, it will look at the `build_config.toml` +file and rename structs according to the names in that file. The `build_config.toml` also provides the struct +names of various block state properties. The list of block state properties Minecraft uses can be found at +`net.minecraft.world.level.block.state.properties.BlockStateProperties` (as of 1.21.11). + +The next step is the block behavior implementations (this is the main crate). To add behavior to blocks, implement +the `BlockBehavior` trait for that block struct. The trait has already been implemented for all block +structs so far (to avoid unsafe features, such as `min_specialization`, it's not the most convenient, but it works). +The build script for this crate uses the `blockstates.json` file to generate a list that maps protocol ids (index) +to block states (value). This list is then used to dispatch behavior functions based on the protocol id. + +This crate also implements a helper trait on `BlockStateId` that allows you to call block functions directly from it +(and it will also be updated if the function mutates the block state). + +As a side note, the `temper-blocks-generated` crate contains the glue code to use the generated structs from +the build crate. The build crate outputs to the build directory and this crate imports those files back in. +Additionally, the `temper-block-properties` crate is where block state property structs and enums can be found. + ## Tips and Notes - If the build script is emitting a warning about an unknown block, see the **Adding / Modifying Block Structs** section for more information. diff --git a/src/blocks/crates/property/src/lib.rs b/src/blocks/crates/property/src/lib.rs index 5dd3a838..0ec4007a 100644 --- a/src/blocks/crates/property/src/lib.rs +++ b/src/blocks/crates/property/src/lib.rs @@ -84,7 +84,16 @@ pub trait BlockStateProperty: FromStr + ToString { impl BlockStateProperty for i32 {} impl BlockStateProperty for bool {} -/// Helper macro to implement enum property types +/// Helper macro to implement enum property types. The syntax is simple: +/// +/// ```rust +/// enum_property!( +/// MyBlockStateProperty, // Enum name +/// A => "a", // Enum variants and their block state property string value +/// West => "west", +/// // Etc... +/// ); +/// ``` #[macro_export] macro_rules! enum_property { ($name:ident, $($variant:ident => $variant_str:expr),* $(,)?) => { From 7c0938410d5d47da0606dbc83e8f7cd9c6112c53 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 6 May 2026 20:26:40 -0500 Subject: [PATCH 13/30] Resolve issues outside of block crate --- src/blocks/crates/property/src/lib.rs | 2 +- src/core/src/block_face.rs | 30 +++++++++---------- .../src/packets/src/place_block.rs | 14 ++++----- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/blocks/crates/property/src/lib.rs b/src/blocks/crates/property/src/lib.rs index 0ec4007a..96c7c4dd 100644 --- a/src/blocks/crates/property/src/lib.rs +++ b/src/blocks/crates/property/src/lib.rs @@ -85,7 +85,7 @@ impl BlockStateProperty for i32 {} impl BlockStateProperty for bool {} /// Helper macro to implement enum property types. The syntax is simple: -/// +/// /// ```rust /// enum_property!( /// MyBlockStateProperty, // Enum name diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs index 4a56e1ba..b081908d 100644 --- a/src/core/src/block_face.rs +++ b/src/core/src/block_face.rs @@ -29,7 +29,7 @@ impl BlockFace { } /// Returns the translation vector that will get the block that touches this face. - pub fn translation_vec(&self) -> IVec3 { + pub fn get_normal(&self) -> IVec3 { match self { BlockFace::Top => IVec3::new(0, 1, 0), BlockFace::Bottom => IVec3::new(0, -1, 0), @@ -41,20 +41,28 @@ impl BlockFace { } } -impl NetDecode for BlockFace { - fn decode(reader: &mut R, opts: &NetDecodeOpts) -> Result { - let VarInt(data) = VarInt::decode(reader, opts)?; +impl TryFrom for BlockFace { + type Error = (); - match data { + fn try_from(value: u32) -> Result { + match value { 0 => Ok(BlockFace::Bottom), 1 => Ok(BlockFace::Top), 2 => Ok(BlockFace::North), 3 => Ok(BlockFace::South), 4 => Ok(BlockFace::West), 5 => Ok(BlockFace::East), - _ => Err(NetDecodeError::InvalidEnumVariant), + _ => Err(()), } } +} + +impl NetDecode for BlockFace { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> Result { + let VarInt(data) = VarInt::decode(reader, opts)?; + + BlockFace::try_from(data as u32).map_err(|_| NetDecodeError::InvalidEnumVariant) + } async fn decode_async( reader: &mut R, @@ -62,14 +70,6 @@ impl NetDecode for BlockFace { ) -> Result { let VarInt(data) = VarInt::decode_async(reader, opts).await?; - match data { - 0 => Ok(BlockFace::Bottom), - 1 => Ok(BlockFace::Top), - 2 => Ok(BlockFace::North), - 3 => Ok(BlockFace::South), - 4 => Ok(BlockFace::West), - 5 => Ok(BlockFace::East), - _ => Err(NetDecodeError::InvalidEnumVariant), - } + BlockFace::try_from(data as u32).map_err(|_| NetDecodeError::InvalidEnumVariant) } } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index f35ee2cf..25ab27f4 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -109,7 +109,7 @@ pub fn handle( trace!("Block placement out of bounds: {}", block_pos); continue 'ev_loop; } - let offset_pos = block_pos + event.face.translation_vec().into(); + let offset_pos = block_pos + event.face.get_normal().into(); let _block_clicked = { let chunk = state @@ -134,9 +134,9 @@ pub fn handle( z_offset_end: 1.0, }, ( - offset_pos.pos.x as f64, - offset_pos.pos.y as f64, - offset_pos.pos.z as f64, + f64::from(offset_pos.pos.x), + f64::from(offset_pos.pos.y), + f64::from(offset_pos.pos.z), ), ) }) @@ -166,9 +166,9 @@ pub fn handle( block_state.get_placement_state(temper_blocks::PlacementContext { face: event.face, cursor: DVec3::new( - event.cursor_x as _, - event.cursor_y as _, - event.cursor_z as _, + f64::from(event.cursor_x), + f64::from(event.cursor_y), + f64::from(event.cursor_z), ), block_clicked: block_pos, block_pos: offset_pos, From 835a9c6442b3b6752d444cd1eaf13362a9c9b4a4 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Tue, 12 May 2026 20:56:20 -0500 Subject: [PATCH 14/30] Formatting fix --- src/base/macros/src/commands/mod.rs | 2 +- src/blocks/crates/build/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/macros/src/commands/mod.rs b/src/base/macros/src/commands/mod.rs index 8f92cefb..9d379739 100644 --- a/src/base/macros/src/commands/mod.rs +++ b/src/base/macros/src/commands/mod.rs @@ -120,7 +120,7 @@ pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream { if let Type::Path(path) = *refr.clone().elem { println!("path reference: {:?}", path.path.segments.clone()); let is_bevy = path.path.segments.iter().any(|seg| { - println!("{}", &seg.ident.to_string()); + println!("{}", seg.ident); &seg.ident.to_string() == "bevy_ecs" }); println!("is bevy? {is_bevy}"); diff --git a/src/blocks/crates/build/src/lib.rs b/src/blocks/crates/build/src/lib.rs index f120c05b..0c2e5c16 100644 --- a/src/blocks/crates/build/src/lib.rs +++ b/src/blocks/crates/build/src/lib.rs @@ -27,7 +27,7 @@ pub fn separate_blocks( id, ComplexBlock { name: state.name, - properties: FxHashMap::from_iter(properties.into_iter()), + properties: FxHashMap::from_iter(properties), }, )), None => simple_blocks.push((id, state.name)), From 1ac4b1f7f14cbefceb05d65ae1ba493ca9216080 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 19:23:22 -0500 Subject: [PATCH 15/30] Remove inline(always) --- src/blocks/src/building/slab.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs index 429a2d2d..9a8af27b 100644 --- a/src/blocks/src/building/slab.rs +++ b/src/blocks/src/building/slab.rs @@ -6,7 +6,6 @@ use temper_core::block_state_id::BlockStateId; use temper_macros::match_block; impl BlockBehavior for SlabBlock { - #[inline(always)] fn get_placement_state(&mut self, context: PlacementContext) { let block = context .level @@ -33,7 +32,6 @@ impl BlockBehavior for SlabBlock { self.waterlogged = match_block!("water", block); } - #[inline(always)] fn can_be_replaced(&self, _context: PlacementContext) -> bool { true } From c8e7d9761205f87a1d71fa1bbeb5a6fba9215042 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 19:23:34 -0500 Subject: [PATCH 16/30] Add data crate for blocks --- Cargo.toml | 2 ++ src/blocks/Cargo.toml | 1 + src/blocks/README.md | 2 ++ src/blocks/crates/data/Cargo.toml | 8 ++++++++ src/blocks/crates/data/src/lib.rs | 9 +++++++++ src/blocks/src/behavior_trait.rs | 3 ++- src/blocks/src/lib.rs | 1 + 7 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/blocks/crates/data/Cargo.toml create mode 100644 src/blocks/crates/data/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 30896856..4a1d44b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "src/blocks/crates/property", "src/blocks/crates/generated", "src/blocks/crates/build", + "src/blocks/crates/data", "src/bin", "src/commands", "src/components", @@ -124,6 +125,7 @@ temper-app = { path = "src/app" } temper-anvil = { path = "src/adapters/anvil" } temper-blocks = { path = "src/blocks" } temper-block-properties = { path = "src/blocks/crates/property" } +temper-block-data = { path = "src/blocks/crates/data" } temper-config = { path = "src/config" } temper-core = { path = "src/core" } temper-default-commands = { path = "src/default_commands" } diff --git a/src/blocks/Cargo.toml b/src/blocks/Cargo.toml index ce5adc49..1a5a80f2 100644 --- a/src/blocks/Cargo.toml +++ b/src/blocks/Cargo.toml @@ -7,6 +7,7 @@ version = "0.0.1" temper-world = { workspace = true } temper-block-properties = { workspace = true } temper-blocks-generated = { path = "crates/generated" } +temper-block-data = { workspace = true } temper-core = { workspace = true } temper-macros = { workspace = true } bevy_math = { workspace = true } diff --git a/src/blocks/README.md b/src/blocks/README.md index 669d4c7a..98511603 100644 --- a/src/blocks/README.md +++ b/src/blocks/README.md @@ -28,6 +28,8 @@ As a side note, the `temper-blocks-generated` crate contains the glue code to us the build crate. The build crate outputs to the build directory and this crate imports those files back in. Additionally, the `temper-block-properties` crate is where block state property structs and enums can be found. +Any data types used exclusively by this crate (for example, the `PlacedBlocks` struct) should be placed in the `temper-block-data` crate. + ## Tips and Notes - If the build script is emitting a warning about an unknown block, see the **Adding / Modifying Block Structs** section for more information. diff --git a/src/blocks/crates/data/Cargo.toml b/src/blocks/crates/data/Cargo.toml new file mode 100644 index 00000000..381d453e --- /dev/null +++ b/src/blocks/crates/data/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "temper-block-data" +version = "0.1.0" +edition = "2024" + +[dependencies] +temper-world = { workspace = true } +temper-core = { workspace = true } \ No newline at end of file diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs new file mode 100644 index 00000000..d7444474 --- /dev/null +++ b/src/blocks/crates/data/src/lib.rs @@ -0,0 +1,9 @@ +use std::collections::HashMap; +use temper_core::block_state_id::BlockStateId; +use temper_core::pos::BlockPos; + +#[derive(Default)] +pub struct PlacedBlocks { + pub blocks: HashMap, + pub take_item: bool, +} \ No newline at end of file diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index ba015d72..f59bd6bb 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,3 +1,4 @@ +use temper_block_data::PlacedBlocks; use crate::{PlacementContext, BLOCK_MAPPINGS}; use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; @@ -151,7 +152,7 @@ macro_rules! block_behavior_trait { // // This is the only place where the `block_behavior_trait!` macro should be used. block_behavior_trait!( - fn get_placement_state(mut; _context: PlacementContext), + fn get_placement_state(mut; _context: PlacementContext) -> PlacedBlocks; PlacedBlocks::default(), fn can_be_replaced(; _context: PlacementContext) -> bool; false, fn update(mut; _world: &World, _pos: BlockPos), ); diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index ca21c89e..9b5b433b 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -26,6 +26,7 @@ mod waterloggable_block; use crate::behavior_trait::BlockBehaviorTable; pub use crate::behavior_trait::{BlockBehavior, BlockDispatch, StateBehaviorTable}; +pub use temper_block_data::*; pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); From d049a303993dda74fa76a5146ac72616d5756520 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 19:36:57 -0500 Subject: [PATCH 17/30] Move PlacementContext struct to block data --- src/blocks/crates/data/Cargo.toml | 4 ++- src/blocks/crates/data/src/lib.rs | 29 ++++++++++++++++++- src/blocks/src/behavior_trait.rs | 4 +-- src/blocks/src/building/slab.rs | 7 +++-- src/blocks/src/lib.rs | 15 ---------- .../src/packets/src/place_block.rs | 3 +- 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/blocks/crates/data/Cargo.toml b/src/blocks/crates/data/Cargo.toml index 381d453e..31811c8a 100644 --- a/src/blocks/crates/data/Cargo.toml +++ b/src/blocks/crates/data/Cargo.toml @@ -5,4 +5,6 @@ edition = "2024" [dependencies] temper-world = { workspace = true } -temper-core = { workspace = true } \ No newline at end of file +temper-core = { workspace = true } +bevy_math = { workspace = true } +temper-components = { workspace = true } \ No newline at end of file diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index d7444474..ebd0d333 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -1,9 +1,36 @@ use std::collections::HashMap; +use bevy_math::DVec3; +use temper_components::player::rotation::Rotation; +use temper_core::block_face::BlockFace; use temper_core::block_state_id::BlockStateId; +use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; +use temper_world::World; -#[derive(Default)] +pub struct PlacementContext<'a> { + pub face: BlockFace, + pub cursor: DVec3, + pub block_clicked: BlockPos, + pub block_pos: BlockPos, + pub level: &'a World, + pub dimension: Dimension, + pub player_rotation: &'a Rotation, +} + +/// Result of the get_placement_state function pub struct PlacedBlocks { + /// Any extra blocks placed by the function pub blocks: HashMap, + + /// Whether an item is taken from the player's inventory or not pub take_item: bool, +} + +impl Default for PlacedBlocks { + fn default() -> Self { + Self { + blocks: HashMap::default(), + take_item: true, + } + } } \ No newline at end of file diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index f59bd6bb..3258abb8 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,5 +1,5 @@ -use temper_block_data::PlacedBlocks; -use crate::{PlacementContext, BLOCK_MAPPINGS}; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use crate::BLOCK_MAPPINGS; use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; use temper_world::World; diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs index 9a8af27b..d125ae52 100644 --- a/src/blocks/src/building/slab.rs +++ b/src/blocks/src/building/slab.rs @@ -1,4 +1,5 @@ -use crate::{BlockBehavior, BlockDispatch, PlacementContext}; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use crate::{BlockBehavior, BlockDispatch}; use temper_block_properties::SlabType; use temper_blocks_generated::SlabBlock; use temper_core::block_face::BlockFace; @@ -6,7 +7,7 @@ use temper_core::block_state_id::BlockStateId; use temper_macros::match_block; impl BlockBehavior for SlabBlock { - fn get_placement_state(&mut self, context: PlacementContext) { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { let block = context .level .get_chunk(context.block_pos.chunk(), context.dimension) @@ -30,6 +31,8 @@ impl BlockBehavior for SlabBlock { }; self.waterlogged = match_block!("water", block); + + PlacedBlocks::default() } fn can_be_replaced(&self, _context: PlacementContext) -> bool { diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index 9b5b433b..fd51d116 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -1,9 +1,3 @@ -use bevy_math::DVec3; -use temper_core::block_face::BlockFace; -use temper_core::dimension::Dimension; -use temper_core::pos::BlockPos; -use temper_world::World; - mod bed_block; mod behavior_trait; mod bubble_column; @@ -30,12 +24,3 @@ pub use temper_block_data::*; pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); - -pub struct PlacementContext<'a> { - pub face: BlockFace, - pub cursor: DVec3, - pub block_clicked: BlockPos, - pub block_pos: BlockPos, - pub level: &'a World, - pub dimension: Dimension, -} diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 25ab27f4..5618e35e 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -42,7 +42,7 @@ pub fn handle( mut block_interact: MessageWriter, ) { 'ev_loop: for (event, eid) in receiver.0.try_iter() { - let Ok((entity, conn, inventory, hotbar, _pos, _rot, sneak)) = query.get(eid) else { + let Ok((entity, conn, inventory, hotbar, _pos, rot, sneak)) = query.get(eid) else { debug!("Could not get connection for entity {:?}", eid); continue; }; @@ -174,6 +174,7 @@ pub fn handle( block_pos: offset_pos, level: &state.0.world, dimension: Dimension::Overworld, + player_rotation: rot }); let placed_blocks = vec![(offset_pos, block_state)]; From 3f78535437333b62dcec63d6992d16d73b47125d Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 19:49:13 -0500 Subject: [PATCH 18/30] Update place block function --- src/blocks/src/behavior_trait.rs | 3 + .../src/packets/src/place_block.rs | 61 ++----------------- 2 files changed, 8 insertions(+), 56 deletions(-) diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index 3258abb8..de763ffa 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -15,6 +15,9 @@ use temper_world::World; /// - `arguments`: Any additional arguments to the method /// - `return type`: Optional, what the function returns /// - `default return value`: Optional, required if return type is set, the default expression to use for blocks that do not implement this method. +/// +/// TODO: Later on, add support for methods like BlockStateId::(base_id) -> (BlockStateId, ). Would be useful for methods like +/// get_placement_state(). macro_rules! block_behavior_trait { ($(fn $name:ident($($mut_meta:ident)?; $($argument:ident: $ty:ty),*) $(-> $ret:ty; $default:expr)?),* $(,)?) => { macro_rules! ptr_ret_ty { diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 5618e35e..ac0daf2b 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -111,15 +111,6 @@ pub fn handle( } let offset_pos = block_pos + event.face.get_normal().into(); - let _block_clicked = { - let chunk = state - .0 - .world - .get_or_generate_chunk(block_pos.chunk(), Dimension::Overworld) - .expect("Failed to load or generate chunk"); - chunk.get_block(block_pos.chunk_block_pos()) - }; - // Check if the block collides with any entities let does_collide = { pos_q.into_iter().any(|(pos, bounds)| { @@ -147,15 +138,6 @@ pub fn handle( continue 'ev_loop; } - let _block_at_pos = { - let chunk = state - .0 - .world - .get_or_generate_chunk(offset_pos.chunk(), Dimension::Overworld) - .expect("Failed to load or generate chunk"); - chunk.get_block(offset_pos.chunk_block_pos()) - }; - let mut block_state = ITEM_TO_BLOCK_MAPPING .get() .unwrap() @@ -163,7 +145,7 @@ pub fn handle( .copied() .unwrap(); - block_state.get_placement_state(temper_blocks::PlacementContext { + let mut placed_blocks = block_state.get_placement_state(temper_blocks::PlacementContext { face: event.face, cursor: DVec3::new( f64::from(event.cursor_x), @@ -177,44 +159,11 @@ pub fn handle( player_rotation: rot }); - let placed_blocks = vec![(offset_pos, block_state)]; - - // let placed_blocks = block_placing::place_item( - // state.0.clone(), - // block_placing::BlockPlaceContext { - // block_clicked, - // block_position: offset_pos, - // face_clicked: match event.face.0 { - // 0 => block_placing::BlockFace::Bottom, - // 1 => block_placing::BlockFace::Top, - // 2 => block_placing::BlockFace::North, - // 3 => block_placing::BlockFace::South, - // 4 => block_placing::BlockFace::West, - // 5 => block_placing::BlockFace::East, - // _ => { - // debug!("Invalid block face"); - // continue 'ev_loop; - // } - // }, - // click_position: DVec3::new( - // event.cursor_x as f64, - // event.cursor_y as f64, - // event.cursor_z as f64, - // ), - // player_position: *pos, - // player_rotation: *rot, - // item_used: item_id, - // }, - // ) - // .unwrap_or_else(|err| { - // error!("Block placement failed: {:?}", err); - // PlacedBlocks { - // blocks: HashMap::new(), - // take_item: false, - // } - // }); + placed_blocks + .blocks + .insert(offset_pos, block_state); - for (block_pos, block_state) in placed_blocks { + for (block_pos, block_state) in placed_blocks.blocks.iter() { let block_chunk = block_pos.chunk(); world_change.write(WorldChange { chunk: Some(block_chunk), From c01ec724a4c7167a1efd6f50aa85477fe9019ef7 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 20:59:19 -0500 Subject: [PATCH 19/30] Fix some bugs with block placing --- src/blocks/Cargo.toml | 1 - src/blocks/crates/build/src/complex.rs | 2 +- src/blocks/crates/build/src/simple.rs | 2 +- src/blocks/crates/data/src/lib.rs | 4 +- src/blocks/src/behavior_trait.rs | 4 +- src/blocks/src/building/slab.rs | 14 +++-- .../src/packets/src/place_block.rs | 56 ++++++++++++------- 7 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/blocks/Cargo.toml b/src/blocks/Cargo.toml index 1a5a80f2..a1a89bbf 100644 --- a/src/blocks/Cargo.toml +++ b/src/blocks/Cargo.toml @@ -10,7 +10,6 @@ temper-blocks-generated = { path = "crates/generated" } temper-block-data = { workspace = true } temper-core = { workspace = true } temper-macros = { workspace = true } -bevy_math = { workspace = true } [build-dependencies] temper-blocks-build = { path = "crates/build" } diff --git a/src/blocks/crates/build/src/complex.rs b/src/blocks/crates/build/src/complex.rs index c7bff083..feb85604 100644 --- a/src/blocks/crates/build/src/complex.rs +++ b/src/blocks/crates/build/src/complex.rs @@ -163,7 +163,7 @@ pub fn generate_complex_blocks( use temper_block_properties::*; #[allow(dead_code)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, Eq, PartialEq)] pub enum #enum_name { #(#variants,)* } diff --git a/src/blocks/crates/build/src/simple.rs b/src/blocks/crates/build/src/simple.rs index 06f47631..ea76c8b0 100644 --- a/src/blocks/crates/build/src/simple.rs +++ b/src/blocks/crates/build/src/simple.rs @@ -37,7 +37,7 @@ pub fn generate_simple_block_enum( ( quote! { #[repr(usize)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, Eq, PartialEq)] pub enum SimpleBlock { #(#enum_variants),* } diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index ebd0d333..773fca12 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use bevy_math::DVec3; +use std::collections::HashMap; use temper_components::player::rotation::Rotation; use temper_core::block_face::BlockFace; use temper_core::block_state_id::BlockStateId; @@ -33,4 +33,4 @@ impl Default for PlacedBlocks { take_item: true, } } -} \ No newline at end of file +} diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index de763ffa..61d19d90 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,5 +1,5 @@ -use temper_block_data::{PlacedBlocks, PlacementContext}; use crate::BLOCK_MAPPINGS; +use temper_block_data::{PlacedBlocks, PlacementContext}; use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; use temper_world::World; @@ -15,7 +15,7 @@ use temper_world::World; /// - `arguments`: Any additional arguments to the method /// - `return type`: Optional, what the function returns /// - `default return value`: Optional, required if return type is set, the default expression to use for blocks that do not implement this method. -/// +/// /// TODO: Later on, add support for methods like BlockStateId::(base_id) -> (BlockStateId, ). Would be useful for methods like /// get_placement_state(). macro_rules! block_behavior_trait { diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs index d125ae52..81f7d369 100644 --- a/src/blocks/src/building/slab.rs +++ b/src/blocks/src/building/slab.rs @@ -1,5 +1,5 @@ -use temper_block_data::{PlacedBlocks, PlacementContext}; use crate::{BlockBehavior, BlockDispatch}; +use temper_block_data::{PlacedBlocks, PlacementContext}; use temper_block_properties::SlabType; use temper_blocks_generated::SlabBlock; use temper_core::block_face::BlockFace; @@ -14,8 +14,14 @@ impl BlockBehavior for SlabBlock { .map(|c| c.get_block(context.block_pos.chunk_block_pos())) .unwrap_or(BlockStateId::new(0)); - self.ty = if block.try_cast::().is_some() { - SlabType::Double + self.ty = if let Some(block) = block.try_cast::() { + if block.block_type == self.block_type { + SlabType::Double + } else { + // This will cause a bug where if you place a slab onto a slab of a different type it will replace the block with the one you're placing, + // but this can't really be fixed until BlockBehavior is updated + return PlacedBlocks::default(); // TODO: When BlockBehavior is updated with a return value for Option, return None here + } } else { match context.face { BlockFace::Top => SlabType::Bottom, @@ -31,7 +37,7 @@ impl BlockBehavior for SlabBlock { }; self.waterlogged = match_block!("water", block); - + PlacedBlocks::default() } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index ac0daf2b..16613d5f 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -7,7 +7,7 @@ use temper_components::{bounds::CollisionBounds, player::sneak::SneakState}; use temper_core::pos::BlockPos; use temper_messages::BlockInteractMessage; -use bevy_math::DVec3; +use bevy_math::{DVec3, IVec3}; use temper_blocks::BlockDispatch; use temper_components::player::rotation::Rotation; use temper_config::server_config::get_global_config; @@ -109,7 +109,14 @@ pub fn handle( trace!("Block placement out of bounds: {}", block_pos); continue 'ev_loop; } - let offset_pos = block_pos + event.face.get_normal().into(); + + let offset_pos = block_pos + + IVec3::new( + (event.cursor_x * 2.0 - 1.0) as i32, + (event.cursor_y * 2.0 - 1.0) as i32, + (event.cursor_z * 2.0 - 1.0) as i32, + ) + .into(); // Check if the block collides with any entities let does_collide = { @@ -145,25 +152,35 @@ pub fn handle( .copied() .unwrap(); - let mut placed_blocks = block_state.get_placement_state(temper_blocks::PlacementContext { - face: event.face, - cursor: DVec3::new( - f64::from(event.cursor_x), - f64::from(event.cursor_y), - f64::from(event.cursor_z), - ), - block_clicked: block_pos, - block_pos: offset_pos, - level: &state.0.world, - dimension: Dimension::Overworld, - player_rotation: rot - }); - - placed_blocks - .blocks - .insert(offset_pos, block_state); + let mut placed_blocks = + block_state.get_placement_state(temper_blocks::PlacementContext { + face: event.face, + cursor: DVec3::new( + f64::from(event.cursor_x), + f64::from(event.cursor_y), + f64::from(event.cursor_z), + ), + block_clicked: block_pos, + block_pos: offset_pos, + level: &state.0.world, + dimension: Dimension::Overworld, + player_rotation: rot, + }); + + placed_blocks.blocks.insert(offset_pos, block_state); for (block_pos, block_state) in placed_blocks.blocks.iter() { + state + .0 + .world + .get_chunk_mut(block_pos.chunk(), Dimension::Overworld) + .map(|mut chunk| { + chunk.set_block(block_pos.chunk_block_pos(), *block_state) + }) + .unwrap_or_else(|_| { + error!("Failed to update chunk {}", block_pos.chunk()) + }); + let block_chunk = block_pos.chunk(); world_change.write(WorldChange { chunk: Some(block_chunk), @@ -194,6 +211,7 @@ pub fn handle( } } } + let ack_packet = BlockChangeAck { sequence: event.sequence, }; From 71e2e6d01e8949815e8699fb1fdaad244c8a5bf6 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 21:19:24 -0500 Subject: [PATCH 20/30] Fix errors from merge --- src/core/src/block_face.rs | 10 ---------- src/game_systems/src/packets/src/place_block.rs | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs index b081908d..632b4073 100644 --- a/src/core/src/block_face.rs +++ b/src/core/src/block_face.rs @@ -3,7 +3,6 @@ use std::io::Read; use temper_codec::decode::errors::NetDecodeError; use temper_codec::decode::{NetDecode, NetDecodeOpts}; use temper_codec::net_types::var_int::VarInt; -use temper_nbt::tokio::io::AsyncRead; #[derive(Debug, Clone)] pub enum BlockFace { @@ -63,13 +62,4 @@ impl NetDecode for BlockFace { BlockFace::try_from(data as u32).map_err(|_| NetDecodeError::InvalidEnumVariant) } - - async fn decode_async( - reader: &mut R, - opts: &NetDecodeOpts, - ) -> Result { - let VarInt(data) = VarInt::decode_async(reader, opts).await?; - - BlockFace::try_from(data as u32).map_err(|_| NetDecodeError::InvalidEnumVariant) - } } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 16613d5f..d064f73a 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -10,7 +10,6 @@ use temper_messages::BlockInteractMessage; use bevy_math::{DVec3, IVec3}; use temper_blocks::BlockDispatch; use temper_components::player::rotation::Rotation; -use temper_config::server_config::get_global_config; use temper_core::block_state_id::ITEM_TO_BLOCK_MAPPING; use temper_core::dimension::Dimension; use temper_core::mq; @@ -196,7 +195,7 @@ pub fn handle( }; let (block_chunk_x, block_chunk_z) = (block_chunk.x(), block_chunk.z()); - let render_distance = get_global_config().chunk_render_distance as i32; + let render_distance = state.0.config.chunk_render_distance as i32; for (_, conn, _, _, pos, _, _) in query.iter() { let chunk = pos.chunk(); let (chunk_x, chunk_z) = (chunk.x(), chunk.z()); From e2bc8b7f4f1123e3bd695f8ea08cb37d151a3238 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 27 May 2026 22:59:12 -0500 Subject: [PATCH 21/30] Move door code from block placing and interactions, remove old interaction code and use new system --- src/blocks/Cargo.toml | 2 + src/blocks/crates/data/src/lib.rs | 14 ++++ src/blocks/src/behavior_trait.rs | 5 +- src/blocks/src/decorative/door.rs | 79 ++++++++++++++++++- src/blocks/src/lib.rs | 12 +++ src/blocks/src/world_extensions.rs | 44 +++++++++++ src/core/src/pos.rs | 20 +++++ src/game_systems/src/interactions/Cargo.toml | 1 + .../interactions/src/interaction_listener.rs | 75 ++++++++---------- .../src/packets/src/player_action.rs | 13 ++- src/game_systems/src/player/Cargo.toml | 1 + .../src/player/src/digging_system.rs | 12 ++- 12 files changed, 218 insertions(+), 60 deletions(-) create mode 100644 src/blocks/src/world_extensions.rs diff --git a/src/blocks/Cargo.toml b/src/blocks/Cargo.toml index a1a89bbf..dbd6cee2 100644 --- a/src/blocks/Cargo.toml +++ b/src/blocks/Cargo.toml @@ -10,6 +10,8 @@ temper-blocks-generated = { path = "crates/generated" } temper-block-data = { workspace = true } temper-core = { workspace = true } temper-macros = { workspace = true } +bevy_math = { workspace = true } +tracing = { workspace = true } [build-dependencies] temper-blocks-build = { path = "crates/build" } diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index 773fca12..b90221db 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -26,6 +26,20 @@ pub struct PlacedBlocks { pub take_item: bool, } +/// Result of the try_break function +#[derive(Default)] +pub struct BrokenBlocks { + /// Any extra blocks broken by the function + pub blocks: Vec, +} + +/// Result of the interact function +#[derive(Default)] +pub struct BlockUpdates { + /// Any other blocks that are updated by the function + pub blocks: HashMap, +} + impl Default for PlacedBlocks { fn default() -> Self { Self { diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index 61d19d90..e55a8beb 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -1,5 +1,5 @@ use crate::BLOCK_MAPPINGS; -use temper_block_data::{PlacedBlocks, PlacementContext}; +use temper_block_data::{BlockUpdates, BrokenBlocks, PlacedBlocks, PlacementContext}; use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; use temper_world::World; @@ -156,6 +156,9 @@ macro_rules! block_behavior_trait { // This is the only place where the `block_behavior_trait!` macro should be used. block_behavior_trait!( fn get_placement_state(mut; _context: PlacementContext) -> PlacedBlocks; PlacedBlocks::default(), + fn interact(mut; _world: &World, _pos: BlockPos) -> BlockUpdates; BlockUpdates::default(), + fn try_break(; _world: &World, _pos: BlockPos) -> BrokenBlocks; BrokenBlocks::default(), + fn can_be_replaced(; _context: PlacementContext) -> bool; false, fn update(mut; _world: &World, _pos: BlockPos), ); diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs index a4dc216e..62902a5f 100644 --- a/src/blocks/src/decorative/door.rs +++ b/src/blocks/src/decorative/door.rs @@ -1,4 +1,81 @@ +use std::collections::HashMap; +use bevy_math::IVec3; +use tracing::error; +use temper_block_data::{BlockUpdates, BrokenBlocks, PlacedBlocks, PlacementContext}; +use temper_block_properties::{Direction, DoorHingeSide, DoubleBlockHalf}; use crate::BlockBehavior; use temper_blocks_generated::DoorBlock; +use temper_core::block_face::BlockFace; +use temper_core::block_state_id::BlockStateId; +use temper_core::pos::BlockPos; +use temper_world::World; +use crate::world_extensions::WorldBlockUpdates; -impl BlockBehavior for DoorBlock {} +impl BlockBehavior for DoorBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + self.facing = match context.face { + BlockFace::North => Direction::South, + BlockFace::South => Direction::North, + BlockFace::East => Direction::West, + BlockFace::West => Direction::East, + BlockFace::Top => { + let yaw = (context.player_rotation.yaw + 180.0) % 360.0; + + match yaw { + 45.0..135.0 => Direction::East, + 135.0..225.0 => Direction::South, + 225.0..315.0 => Direction::West, + _ => Direction::North, + } + }, + _ => { + error!("Invalid block face clicked"); + return PlacedBlocks::default(); // TODO: should return None or Err in the future + } + }; + + self.open = false; + self.powered = false; + self.hinge = DoorHingeSide::Left; + self.half = DoubleBlockHalf::Lower; + + let mut top_half = self.clone(); + top_half.half = DoubleBlockHalf::Upper; + + let mut placed_blocks = PlacedBlocks::default(); + placed_blocks + .blocks + .insert(context.block_pos.above(), BlockStateId::new(top_half.try_into().unwrap())); + + placed_blocks + } + + fn interact(&mut self, world: &World, pos: BlockPos) -> BlockUpdates { + self.open = !self.open; + + let mut blocks = HashMap::new(); + let other_pos = match self.half { + DoubleBlockHalf::Upper => pos.below(), + DoubleBlockHalf::Lower => pos.above(), + }; + + if let Ok(other_state) = world.update_block_cast::(other_pos, |block| block.open = self.open) { + blocks.insert(other_pos, other_state); + } else { + error!("Expected door block at {}, but did not find one!", other_pos); + } + + BlockUpdates { + blocks + } + } + + fn try_break(&self, _world: &World, pos: BlockPos) -> BrokenBlocks { + BrokenBlocks { + blocks: match self.half { + DoubleBlockHalf::Upper => vec![pos.below()], + DoubleBlockHalf::Lower => vec![pos.above()], + } + } + } +} diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index fd51d116..198e057c 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -15,12 +15,24 @@ mod skull; mod suspicious_block; mod wall_skull; mod waterloggable_block; +mod world_extensions; #[allow(unused_imports)] // Used in the include! use crate::behavior_trait::BlockBehaviorTable; pub use crate::behavior_trait::{BlockBehavior, BlockDispatch, StateBehaviorTable}; pub use temper_block_data::*; +use temper_core::block_state_id::BlockStateId; +use temper_core::dimension::Dimension; +use temper_core::pos::BlockPos; +use temper_world::World; pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); + +pub(crate) fn get_block(world: &World, block_pos: BlockPos, dimension: Dimension, default: BlockStateId) -> BlockStateId { + world + .get_chunk(block_pos.chunk(), dimension) + .map(|chunk| chunk.get_block(block_pos.chunk_block_pos())) + .unwrap_or(default) +} \ No newline at end of file diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs new file mode 100644 index 00000000..8fdc919f --- /dev/null +++ b/src/blocks/src/world_extensions.rs @@ -0,0 +1,44 @@ +use temper_core::block_state_id::BlockStateId; +use temper_core::dimension::Dimension; +use temper_core::pos::BlockPos; +use temper_world::{World, WorldError}; +use crate::BlockBehavior; + +// TODO: add dimensions to all these functions + +/// Trait to add useful functions to the World struct +pub trait WorldBlockUpdates { + fn get_block_or_default(&self, block_pos: BlockPos) -> BlockStateId; + + fn update_block(&self, block_pos: BlockPos, callback: impl Fn(BlockStateId) -> BlockStateId) -> Result; + fn update_block_cast(&self, block_pos: BlockPos, callback: impl Fn(&mut T)) -> Result; +} + +impl WorldBlockUpdates for World { + fn get_block_or_default(&self, block_pos: BlockPos) -> BlockStateId { + self + .get_chunk(block_pos.chunk(), Dimension::Overworld) + .map(|chunk| chunk.get_block(block_pos.chunk_block_pos())) + .unwrap_or_default() + } + + fn update_block(&self, block_pos: BlockPos, callback: impl Fn(BlockStateId) -> BlockStateId) -> Result { + self + .get_chunk(block_pos.chunk(), Dimension::Overworld) + .map(|chunk| { + callback(chunk.get_block(block_pos.chunk_block_pos())) + }) + } + + fn update_block_cast(&self, block_pos: BlockPos, callback: impl Fn(&mut T)) -> Result { + self + .get_chunk(block_pos.chunk(), Dimension::Overworld) + .and_then(|chunk| { + let id = chunk.get_block(block_pos.chunk_block_pos()); + let mut id = T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()).map_err(|_| WorldError::InvalidBlock(id))?; + callback(&mut id); + + id.try_into().map(BlockStateId::new).map_err(|_| WorldError::InvalidBlock(BlockStateId::default())) + }) + } +} \ No newline at end of file diff --git a/src/core/src/pos.rs b/src/core/src/pos.rs index 76d4dce0..7a4f23e7 100644 --- a/src/core/src/pos.rs +++ b/src/core/src/pos.rs @@ -60,6 +60,26 @@ impl BlockPos { ), } } + + pub fn above(&self) -> BlockPos { + BlockPos { + pos: IVec3::new( + self.pos.x, + self.pos.y + 1, + self.pos.z, + ) + } + } + + pub fn below(&self) -> BlockPos { + BlockPos { + pos: IVec3::new( + self.pos.x, + self.pos.y - 1, + self.pos.z, + ) + } + } } impl From for BlockPos { diff --git a/src/game_systems/src/interactions/Cargo.toml b/src/game_systems/src/interactions/Cargo.toml index 3387d8d1..e4ae00f3 100644 --- a/src/game_systems/src/interactions/Cargo.toml +++ b/src/game_systems/src/interactions/Cargo.toml @@ -15,6 +15,7 @@ temper-protocol = { workspace = true } temper-state = { workspace = true } temper-world = { workspace = true } tracing = { workspace = true } +temper-blocks = { workspace = true } [dev-dependencies] temper-macros = { workspace = true } diff --git a/src/game_systems/src/interactions/src/interaction_listener.rs b/src/game_systems/src/interactions/src/interaction_listener.rs index ba6c9f97..110d0464 100644 --- a/src/game_systems/src/interactions/src/interaction_listener.rs +++ b/src/game_systems/src/interactions/src/interaction_listener.rs @@ -13,9 +13,8 @@ use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use temper_world::Dimension; use tracing::{debug, error}; - -use crate::block_interactions::{InteractionResult, try_interact}; -use crate::door_interaction::{door_other_half_y_offset, is_open}; +use temper_blocks::BlockDispatch; +use crate::door_interaction::is_open; pub fn handle_block_interact( mut events: MessageReader, @@ -48,58 +47,48 @@ pub fn handle_block_interact( cooldowns.insert(pos, Instant::now()); // Load the chunk and get current block state - let mut chunk = match temper_world::World::get_or_generate_mut( - &state.0.world, - pos.chunk(), - Dimension::Overworld, - ) { - Ok(c) => c, - Err(e) => { - error!("Failed to load chunk for block interaction: {:?}", e); - continue; - } - }; + let mut block_state = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); + let original = block_state.clone(); - let (updates, is_active, new_state) = { - let block_state = chunk.get_block(pos.chunk_block_pos()); - - // Try to interact (toggle) the block - let new_state = match try_interact(block_state) { - InteractionResult::Toggled(new) => new, - _ => continue, - }; + let (updates, is_active) = { + let updates = block_state.interact(&state.0.world, pos); + let mut updates = updates.blocks; + updates.insert(pos, block_state); - chunk.set_block(pos.chunk_block_pos(), new_state); debug!( "Block interact: toggled ({}, {}, {}) from {} to {}", pos.pos.x, pos.pos.y, pos.pos.z, - block_state.raw(), - new_state.raw() + original.raw(), + block_state.raw() ); - let updates = vec![BlockUpdate { - location: NetworkPosition { - x: pos.pos.x, - y: pos.pos.y as i16, - z: pos.pos.z, - }, - block_state_id: VarInt::from(new_state), - }]; + for (pos, block_state) in &updates { + if !state.0.world + .get_chunk_mut(pos.chunk(), Dimension::Overworld) + .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), *block_state)) + .is_ok() { + error!("Attempted to update block at {} to {} but failed. (interaction failure)", pos, block_state.raw()); + } + } - let is_active = is_open(new_state).unwrap_or(false); - (updates, is_active, new_state) + let updates = updates + .into_iter() + .map(|(pos, state)| BlockUpdate { + location: NetworkPosition { + x: pos.pos.x, + y: pos.pos.y as i16, + z: pos.pos.z, + }, + block_state_id: VarInt::from(state), + }) + .collect::>(); + + let is_active = is_open(block_state).unwrap_or(false); + (updates, is_active) }; // chunk lock released here - // If it's a door, let the door handler toggle the other half - if door_other_half_y_offset(new_state).is_some() { - door_toggled_writer.write(DoorToggledEvent { - position: pos, - new_state, - }); - } - // Emit BlockToggledEvent for other systems to react toggled_writer.write(BlockToggledEvent { player: event.player, diff --git a/src/game_systems/src/packets/src/player_action.rs b/src/game_systems/src/packets/src/player_action.rs index 0765434c..6eb2eddf 100644 --- a/src/game_systems/src/packets/src/player_action.rs +++ b/src/game_systems/src/packets/src/player_action.rs @@ -15,6 +15,7 @@ use temper_protocol::outgoing::block_change_ack::BlockChangeAck; use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use tracing::{error, warn}; +use temper_blocks::BlockDispatch; pub fn handle( receiver: Res, @@ -51,18 +52,14 @@ pub fn handle( // --- CREATIVE MODE LOGIC --- // Only instabreak (status 0) is relevant in creative. if event.status.0 == 0 { - let mut chunk = state - .0 - .world - .get_or_generate_mut(pos.chunk(), Dimension::Overworld) - .expect("Failed to load or generate chunk"); - world_change.write(temper_messages::world_change::WorldChange { chunk: Some(pos.chunk()), }); - let broken_positions = - break_block_with_door_half(&mut chunk, pos, &mut block_break_events); + let id = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); + let broken_blocks = id.try_break(&state.0.world, pos); + let mut broken_positions = broken_blocks.blocks; + broken_positions.push(pos); // Broadcast the change for (eid, conn) in &broadcast_query { diff --git a/src/game_systems/src/player/Cargo.toml b/src/game_systems/src/player/Cargo.toml index 49de0134..bb4de5b1 100644 --- a/src/game_systems/src/player/Cargo.toml +++ b/src/game_systems/src/player/Cargo.toml @@ -26,6 +26,7 @@ interactions = { workspace = true } rand = { workspace = true } bitcode = { workspace = true } temper-permissions = { workspace = true } +temper-blocks = { workspace = true } [lints] workspace = true diff --git a/src/game_systems/src/player/src/digging_system.rs b/src/game_systems/src/player/src/digging_system.rs index 1904cdbf..86b55e8c 100644 --- a/src/game_systems/src/player/src/digging_system.rs +++ b/src/game_systems/src/player/src/digging_system.rs @@ -16,6 +16,7 @@ use temper_net_runtime::connection::StreamWriter; use temper_protocol::outgoing::{block_change_ack::BlockChangeAck, block_update::BlockUpdate}; use temper_state::GlobalStateResource; use tracing::{debug, error, warn}; +use temper_blocks::BlockDispatch; // A query for just the components needed to acknowledge a dig packet type DiggingPlayerQuery<'a> = (Entity, &'a StreamWriter, Option<&'a PlayerDigging>); @@ -291,15 +292,12 @@ fn break_block( world_change: &mut MessageWriter, ) { let pos: BlockPos = position.clone().into(); - let mut chunk = state - .0 - .world - .get_or_generate_mut(pos.chunk(), Dimension::Overworld) - .expect("Failed to load or generate chunk"); - debug!("Sending BlockBrokenEvent for block at {:?}", pos.pos); + let id = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); + let broken_blocks = id.try_break(&state.0.world, pos); + let mut broken_positions = broken_blocks.blocks; + broken_positions.push(pos); - let broken_positions = break_block_with_door_half(&mut chunk, pos, block_break_writer); world_change.write(WorldChange { chunk: Some(pos.chunk()), }); From f8c0eb8da3920215f8ee816448aa485cd321f6cb Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Thu, 28 May 2026 13:41:35 -0500 Subject: [PATCH 22/30] Fix block breaking bugs --- src/blocks/src/decorative/door.rs | 14 +++++++++---- src/blocks/src/world_extensions.rs | 9 ++++++++ .../src/packets/src/player_action.rs | 20 +++++++++++++++--- .../src/player/src/digging_system.rs | 20 +++++++++++++++--- src/world/src/helpers.rs | 21 +++++++++++++++++++ src/world/src/lib.rs | 1 + 6 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 src/world/src/helpers.rs diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs index 62902a5f..75dfb02a 100644 --- a/src/blocks/src/decorative/door.rs +++ b/src/blocks/src/decorative/door.rs @@ -70,11 +70,17 @@ impl BlockBehavior for DoorBlock { } } - fn try_break(&self, _world: &World, pos: BlockPos) -> BrokenBlocks { + fn try_break(&self, world: &World, pos: BlockPos) -> BrokenBlocks { + let pos = match self.half { + DoubleBlockHalf::Upper => pos.below(), + DoubleBlockHalf::Lower => pos.above(), + }; + BrokenBlocks { - blocks: match self.half { - DoubleBlockHalf::Upper => vec![pos.below()], - DoubleBlockHalf::Lower => vec![pos.above()], + blocks: if world.block_is::(pos) { + vec![pos] + } else { + vec![] } } } diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs index 8fdc919f..9ace4963 100644 --- a/src/blocks/src/world_extensions.rs +++ b/src/blocks/src/world_extensions.rs @@ -12,6 +12,8 @@ pub trait WorldBlockUpdates { fn update_block(&self, block_pos: BlockPos, callback: impl Fn(BlockStateId) -> BlockStateId) -> Result; fn update_block_cast(&self, block_pos: BlockPos, callback: impl Fn(&mut T)) -> Result; + + fn block_is(&self, block_pos: BlockPos) -> bool; } impl WorldBlockUpdates for World { @@ -41,4 +43,11 @@ impl WorldBlockUpdates for World { id.try_into().map(BlockStateId::new).map_err(|_| WorldError::InvalidBlock(BlockStateId::default())) }) } + + fn block_is(&self, block_pos: BlockPos) -> bool { + self + .get_chunk(block_pos.chunk(), Dimension::Overworld) + .map(|chunk| T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()).is_ok()) + .unwrap_or_default() + } } \ No newline at end of file diff --git a/src/game_systems/src/packets/src/player_action.rs b/src/game_systems/src/packets/src/player_action.rs index 6eb2eddf..6d41d3c5 100644 --- a/src/game_systems/src/packets/src/player_action.rs +++ b/src/game_systems/src/packets/src/player_action.rs @@ -16,6 +16,7 @@ use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use tracing::{error, warn}; use temper_blocks::BlockDispatch; +use temper_macros::block; pub fn handle( receiver: Res, @@ -56,10 +57,23 @@ pub fn handle( chunk: Some(pos.chunk()), }); - let id = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); - let broken_blocks = id.try_break(&state.0.world, pos); - let mut broken_positions = broken_blocks.blocks; + let Ok(id) = state.0.world.get_block(pos, Dimension::Overworld) else { + error!("Couldn't get block at pos {}", pos); + continue; + }; + + let mut broken_positions = id.try_break(&state.0.world, pos).blocks; broken_positions.push(pos); + + for pos in &broken_positions { + block_break_events.write(BlockBrokenEvent { + position: pos.clone(), + }); + + if let Err(world_error) = state.0.world.set_block(*pos, Dimension::Overworld, block!("air")) { + error!("Failed to break block at {}: {}", pos, world_error) + } + } // Broadcast the change for (eid, conn) in &broadcast_query { diff --git a/src/game_systems/src/player/src/digging_system.rs b/src/game_systems/src/player/src/digging_system.rs index 86b55e8c..43893474 100644 --- a/src/game_systems/src/player/src/digging_system.rs +++ b/src/game_systems/src/player/src/digging_system.rs @@ -17,6 +17,7 @@ use temper_protocol::outgoing::{block_change_ack::BlockChangeAck, block_update:: use temper_state::GlobalStateResource; use tracing::{debug, error, warn}; use temper_blocks::BlockDispatch; +use temper_macros::block; // A query for just the components needed to acknowledge a dig packet type DiggingPlayerQuery<'a> = (Entity, &'a StreamWriter, Option<&'a PlayerDigging>); @@ -293,15 +294,28 @@ fn break_block( ) { let pos: BlockPos = position.clone().into(); - let id = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); - let broken_blocks = id.try_break(&state.0.world, pos); - let mut broken_positions = broken_blocks.blocks; + let Ok(id) = state.0.world.get_block(pos, Dimension::Overworld) else { + error!("Failed to get block at {}", pos); + return; + }; + + let mut broken_positions = id.try_break(&state.0.world, pos).blocks; broken_positions.push(pos); world_change.write(WorldChange { chunk: Some(pos.chunk()), }); + for pos in &broken_positions { + block_break_writer.write(temper_messages::BlockBrokenEvent { + position: pos.clone() + }); + + if let Err(world_error) = state.0.world.set_block(*pos, Dimension::Overworld, block!("air")) { + error!("Failed to break block at {}: {}", pos, world_error) + } + } + // Broadcast the block break to all players let block_update_packet = BlockUpdate { location: position.clone(), diff --git a/src/world/src/helpers.rs b/src/world/src/helpers.rs new file mode 100644 index 00000000..78d34ab6 --- /dev/null +++ b/src/world/src/helpers.rs @@ -0,0 +1,21 @@ +use temper_core::block_state_id::BlockStateId; +use temper_core::dimension::Dimension; +use temper_core::pos::BlockPos; +use temper_world_format::errors::WorldError; +use crate::World; + +impl World { + /// Attempts to get a block in the world. Returns an error if the chunk is not accessible + pub fn get_block(&self, pos: BlockPos, dimension: Dimension) -> Result { + self + .get_chunk(pos.chunk(), dimension) + .map(|chunk| chunk.get_block(pos.chunk_block_pos())) + } + + /// Attempts to set a block in the world. Returns an error if the chunk is not mutable + pub fn set_block(&self, pos: BlockPos, dimension: Dimension, block_state_id: BlockStateId) -> Result<(), WorldError> { + self + .get_chunk_mut(pos.chunk(), dimension) + .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), block_state_id)) + } +} \ No newline at end of file diff --git a/src/world/src/lib.rs b/src/world/src/lib.rs index 48e431c3..46c01a0a 100644 --- a/src/world/src/lib.rs +++ b/src/world/src/lib.rs @@ -1,6 +1,7 @@ mod db_wrap; mod importing; pub mod player; +mod helpers; use dashmap::DashMap; use std::fs::create_dir_all; From c4efc8dd844b15264f5ddfc2f853375030ef4ea4 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Thu, 28 May 2026 17:04:15 -0500 Subject: [PATCH 23/30] Cleanup and condense handlers --- src/blocks/crates/data/src/lib.rs | 1 + src/blocks/src/behavior_trait.rs | 4 +- src/blocks/src/decorative/door.rs | 37 ++-- src/blocks/src/lib.rs | 11 -- src/blocks/src/world_extensions.rs | 49 +++--- src/core/src/pos.rs | 12 +- .../interactions/src/block_interactions.rs | 158 ------------------ .../src/interactions/src/door_interaction.rs | 139 --------------- .../interactions/src/interaction_listener.rs | 129 -------------- src/game_systems/src/interactions/src/lib.rs | 138 ++++++++++++++- src/game_systems/src/lib.rs | 3 +- .../src/packets/src/place_block.rs | 55 +++--- .../src/packets/src/player_action.rs | 20 ++- .../src/player/src/digging_system.rs | 15 +- src/game_systems/tests/interactions.rs | 2 - .../tests/interactions/block_interactions.rs | 75 --------- src/messages/src/block_interaction.rs | 18 -- src/messages/src/lib.rs | 4 +- src/world/src/helpers.rs | 25 ++- src/world/src/lib.rs | 2 +- 20 files changed, 251 insertions(+), 646 deletions(-) delete mode 100644 src/game_systems/src/interactions/src/block_interactions.rs delete mode 100644 src/game_systems/src/interactions/src/door_interaction.rs delete mode 100644 src/game_systems/src/interactions/src/interaction_listener.rs delete mode 100644 src/game_systems/tests/interactions.rs delete mode 100644 src/game_systems/tests/interactions/block_interactions.rs diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index b90221db..386c1320 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -7,6 +7,7 @@ use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; use temper_world::World; +#[derive(Clone)] pub struct PlacementContext<'a> { pub face: BlockFace, pub cursor: DVec3, diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index e55a8beb..ffaa169d 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -158,7 +158,9 @@ block_behavior_trait!( fn get_placement_state(mut; _context: PlacementContext) -> PlacedBlocks; PlacedBlocks::default(), fn interact(mut; _world: &World, _pos: BlockPos) -> BlockUpdates; BlockUpdates::default(), fn try_break(; _world: &World, _pos: BlockPos) -> BrokenBlocks; BrokenBlocks::default(), - + + fn is_interactable(;) -> bool; false, + fn can_be_replaced(; _context: PlacementContext) -> bool; false, fn update(mut; _world: &World, _pos: BlockPos), ); diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs index 75dfb02a..d51c3ccb 100644 --- a/src/blocks/src/decorative/door.rs +++ b/src/blocks/src/decorative/door.rs @@ -1,15 +1,14 @@ +use crate::world_extensions::WorldBlockUpdates; +use crate::BlockBehavior; use std::collections::HashMap; -use bevy_math::IVec3; -use tracing::error; use temper_block_data::{BlockUpdates, BrokenBlocks, PlacedBlocks, PlacementContext}; use temper_block_properties::{Direction, DoorHingeSide, DoubleBlockHalf}; -use crate::BlockBehavior; use temper_blocks_generated::DoorBlock; use temper_core::block_face::BlockFace; use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; use temper_world::World; -use crate::world_extensions::WorldBlockUpdates; +use tracing::error; impl BlockBehavior for DoorBlock { fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { @@ -27,7 +26,7 @@ impl BlockBehavior for DoorBlock { 225.0..315.0 => Direction::West, _ => Direction::North, } - }, + } _ => { error!("Invalid block face clicked"); return PlacedBlocks::default(); // TODO: should return None or Err in the future @@ -43,9 +42,10 @@ impl BlockBehavior for DoorBlock { top_half.half = DoubleBlockHalf::Upper; let mut placed_blocks = PlacedBlocks::default(); - placed_blocks - .blocks - .insert(context.block_pos.above(), BlockStateId::new(top_half.try_into().unwrap())); + placed_blocks.blocks.insert( + context.block_pos.above(), + BlockStateId::new(top_half.try_into().unwrap()), + ); placed_blocks } @@ -59,15 +59,18 @@ impl BlockBehavior for DoorBlock { DoubleBlockHalf::Lower => pos.above(), }; - if let Ok(other_state) = world.update_block_cast::(other_pos, |block| block.open = self.open) { + if let Ok(other_state) = + world.update_block_cast::(other_pos, |block| block.open = self.open) + { blocks.insert(other_pos, other_state); } else { - error!("Expected door block at {}, but did not find one!", other_pos); + error!( + "Expected door block at {}, but did not find one!", + other_pos + ); } - BlockUpdates { - blocks - } + BlockUpdates { blocks } } fn try_break(&self, world: &World, pos: BlockPos) -> BrokenBlocks { @@ -75,13 +78,17 @@ impl BlockBehavior for DoorBlock { DoubleBlockHalf::Upper => pos.below(), DoubleBlockHalf::Lower => pos.above(), }; - + BrokenBlocks { blocks: if world.block_is::(pos) { vec![pos] } else { vec![] - } + }, } } + + fn is_interactable(&self) -> bool { + true + } } diff --git a/src/blocks/src/lib.rs b/src/blocks/src/lib.rs index 198e057c..defd59cb 100644 --- a/src/blocks/src/lib.rs +++ b/src/blocks/src/lib.rs @@ -22,17 +22,6 @@ use crate::behavior_trait::BlockBehaviorTable; pub use crate::behavior_trait::{BlockBehavior, BlockDispatch, StateBehaviorTable}; pub use temper_block_data::*; -use temper_core::block_state_id::BlockStateId; -use temper_core::dimension::Dimension; -use temper_core::pos::BlockPos; -use temper_world::World; pub const BLOCK_MAPPINGS: &[StateBehaviorTable] = include!(concat!(env!("OUT_DIR"), "/mappings.rs")); - -pub(crate) fn get_block(world: &World, block_pos: BlockPos, dimension: Dimension, default: BlockStateId) -> BlockStateId { - world - .get_chunk(block_pos.chunk(), dimension) - .map(|chunk| chunk.get_block(block_pos.chunk_block_pos())) - .unwrap_or(default) -} \ No newline at end of file diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs index 9ace4963..da70e9fc 100644 --- a/src/blocks/src/world_extensions.rs +++ b/src/blocks/src/world_extensions.rs @@ -1,53 +1,44 @@ +use crate::BlockBehavior; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; use temper_world::{World, WorldError}; -use crate::BlockBehavior; // TODO: add dimensions to all these functions /// Trait to add useful functions to the World struct pub trait WorldBlockUpdates { - fn get_block_or_default(&self, block_pos: BlockPos) -> BlockStateId; - - fn update_block(&self, block_pos: BlockPos, callback: impl Fn(BlockStateId) -> BlockStateId) -> Result; - fn update_block_cast(&self, block_pos: BlockPos, callback: impl Fn(&mut T)) -> Result; + fn update_block_cast( + &self, + block_pos: BlockPos, + callback: impl Fn(&mut T), + ) -> Result; fn block_is(&self, block_pos: BlockPos) -> bool; } impl WorldBlockUpdates for World { - fn get_block_or_default(&self, block_pos: BlockPos) -> BlockStateId { - self - .get_chunk(block_pos.chunk(), Dimension::Overworld) - .map(|chunk| chunk.get_block(block_pos.chunk_block_pos())) - .unwrap_or_default() - } - - fn update_block(&self, block_pos: BlockPos, callback: impl Fn(BlockStateId) -> BlockStateId) -> Result { - self - .get_chunk(block_pos.chunk(), Dimension::Overworld) - .map(|chunk| { - callback(chunk.get_block(block_pos.chunk_block_pos())) - }) - } - - fn update_block_cast(&self, block_pos: BlockPos, callback: impl Fn(&mut T)) -> Result { - self - .get_chunk(block_pos.chunk(), Dimension::Overworld) + fn update_block_cast( + &self, + block_pos: BlockPos, + callback: impl Fn(&mut T), + ) -> Result { + self.get_chunk(block_pos.chunk(), Dimension::Overworld) .and_then(|chunk| { let id = chunk.get_block(block_pos.chunk_block_pos()); - let mut id = T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()).map_err(|_| WorldError::InvalidBlock(id))?; + let mut id = T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()) + .map_err(|_| WorldError::InvalidBlock(id))?; callback(&mut id); - - id.try_into().map(BlockStateId::new).map_err(|_| WorldError::InvalidBlock(BlockStateId::default())) + + id.try_into() + .map(BlockStateId::new) + .map_err(|_| WorldError::InvalidBlock(BlockStateId::default())) }) } fn block_is(&self, block_pos: BlockPos) -> bool { - self - .get_chunk(block_pos.chunk(), Dimension::Overworld) + self.get_chunk(block_pos.chunk(), Dimension::Overworld) .map(|chunk| T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()).is_ok()) .unwrap_or_default() } -} \ No newline at end of file +} diff --git a/src/core/src/pos.rs b/src/core/src/pos.rs index 7a4f23e7..f22ca563 100644 --- a/src/core/src/pos.rs +++ b/src/core/src/pos.rs @@ -63,21 +63,13 @@ impl BlockPos { pub fn above(&self) -> BlockPos { BlockPos { - pos: IVec3::new( - self.pos.x, - self.pos.y + 1, - self.pos.z, - ) + pos: IVec3::new(self.pos.x, self.pos.y + 1, self.pos.z), } } pub fn below(&self) -> BlockPos { BlockPos { - pos: IVec3::new( - self.pos.x, - self.pos.y - 1, - self.pos.z, - ) + pos: IVec3::new(self.pos.x, self.pos.y - 1, self.pos.z), } } } diff --git a/src/game_systems/src/interactions/src/block_interactions.rs b/src/game_systems/src/interactions/src/block_interactions.rs deleted file mode 100644 index 62b836eb..00000000 --- a/src/game_systems/src/interactions/src/block_interactions.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Direct world block interactions. -//! -//! This module handles interactions with blocks directly in the world (chunks), -//! without creating ECS entities. This is more performant for simple toggleable -//! blocks like doors, levers, trapdoors, and buttons. -//! -//! ## How it works -//! -//! 1. Player right-clicks on a block -//! 2. System checks if the block is "interactive" based on its name -//! 3. If yes, toggle the relevant property (e.g., "open" for doors) -//! 4. Update the block in the chunk -//! 5. Broadcast BlockUpdate to nearby players -//! -//! ## Supported blocks -//! -//! - Doors (oak_door, iron_door, etc.) - toggles "open" property -//! -//! ## Future supported block -//! -//! - Trapdoors - toggles "open" property -//! - Fence gates - toggles "open" property -//! - Levers - toggles "powered" property -//! - Buttons - activates temporarily (TODO: timer system) - -use temper_core::block_data::BlockData; -use temper_core::block_state_id::BlockStateId; -use tracing::{debug, warn}; - -/// Result of attempting to interact with a block. -#[derive(Debug, Clone)] -pub enum InteractionResult { - /// Block was toggled, returns the new BlockStateId - Toggled(BlockStateId), - /// Block is not interactive - NotInteractive, - /// Block state not found (shouldn't happen) - InvalidBlock, -} - -/// Checks if a block is interactive and returns its interaction type. -pub fn get_interaction_type(block_data: &BlockData) -> Option { - let name = &block_data.name; - - // Doors - if name.ends_with("_door") { - return Some(InteractionType::Toggleable("open")); - } - - None -} - -/// Type of interaction for a block. -#[derive(Debug, Clone, Copy)] -pub enum InteractionType { - /// Block toggles between two states (doors, levers) - /// The string is the property name to toggle - Toggleable(&'static str), - // In the future maybe add Momentary or something like that -} - -/// Attempts to interact with a block and returns the new state if successful. -/// -/// This function: -/// 1. Gets the BlockData from the BlockStateId -/// 2. Checks if it's an interactive block -/// 3. Toggles the appropriate property -/// 4. Returns the new BlockStateId -pub fn try_interact(block_state_id: BlockStateId) -> InteractionResult { - debug!( - "try_interact called with block_state_id: {:?} (raw: {})", - block_state_id, - block_state_id.raw() - ); - - // Get the block data - let Some(mut block_data) = block_state_id.to_block_data() else { - warn!( - "try_interact: InvalidBlock - could not convert {:?} to BlockData", - block_state_id - ); - return InteractionResult::InvalidBlock; - }; - - debug!( - "try_interact: block_data name='{}', properties={:?}", - block_data.name, block_data.properties - ); - - // Check if it's interactive - let Some(interaction_type) = get_interaction_type(&block_data) else { - debug!( - "try_interact: block '{}' is not interactive", - block_data.name - ); - return InteractionResult::NotInteractive; - }; - - debug!("try_interact: interaction_type={:?}", interaction_type); - - let Some(properties) = block_data.properties.as_mut() else { - warn!( - "try_interact: interactive block '{}' has no properties", - block_data.name - ); - return InteractionResult::InvalidBlock; - }; - - match interaction_type { - InteractionType::Toggleable(prop_name) => { - let current_value = properties - .get(prop_name) - .map(|s| s.as_str()) - .unwrap_or("false"); - let new_value = if current_value == "true" { - "false" - } else { - "true" - }; - debug!( - "try_interact: toggling '{}' from '{}' to '{}'", - prop_name, current_value, new_value - ); - properties.insert(prop_name.to_string(), new_value.to_string()); - } - } - - debug!( - "try_interact: modified block_data properties={:?}", - block_data.properties - ); - - // Convert back to BlockStateId - let new_state_id = BlockStateId::from_block_data(&block_data); - debug!( - "try_interact: new_state_id={:?} (raw: {})", - new_state_id, - new_state_id.raw() - ); - - if new_state_id.raw() == 0 { - warn!( - "try_interact: WARNING - new_state_id is 0 (air)! BlockData lookup failed for: name='{}', props={:?}", - block_data.name, block_data.properties - ); - } - - InteractionResult::Toggled(new_state_id) -} - -/// Checks if a block is interactive without modifying it. -pub fn is_interactive(block_state_id: BlockStateId) -> bool { - block_state_id - .to_block_data() - .as_ref() - .and_then(get_interaction_type) - .is_some() -} diff --git a/src/game_systems/src/interactions/src/door_interaction.rs b/src/game_systems/src/interactions/src/door_interaction.rs deleted file mode 100644 index 3c15b748..00000000 --- a/src/game_systems/src/interactions/src/door_interaction.rs +++ /dev/null @@ -1,139 +0,0 @@ -use bevy_ecs::prelude::*; -use temper_codec::net_types::network_position::NetworkPosition; -use temper_codec::net_types::var_int::VarInt; -use temper_components::player::position::Position; -use temper_core::block_state_id::BlockStateId; -use temper_core::pos::BlockPos; -use temper_messages::{BlockBrokenEvent, DoorToggledEvent}; -use temper_net_runtime::connection::StreamWriter; -use temper_protocol::outgoing::block_update::BlockUpdate; -use temper_state::GlobalStateResource; -use temper_world::Dimension; -use tracing::{debug, error}; - -use crate::block_interactions::{InteractionResult, try_interact}; - -/// Given a block state, if it's a door, returns the Y offset to the other half. -/// Lower half -> +1, upper half -> -1, not a door -> None. -pub fn door_other_half_y_offset(block_state_id: BlockStateId) -> Option { - let data = block_state_id.to_block_data()?; - if !data.name.ends_with("_door") { - return None; - } - let props = data.properties.as_ref()?; - let half = props.get("half")?; - match half.as_str() { - "lower" => Some(1), - "upper" => Some(-1), - _ => None, - } -} - -/// Gets the "open" state of a door/trapdoor/fence gate. -pub fn is_open(block_state_id: BlockStateId) -> Option { - let block_data = block_state_id.to_block_data()?; - let properties = block_data.properties.as_ref()?; - let open_value = properties.get("open")?; - Some(open_value == "true") -} - -/// Breaks a block and its door-pair (if applicable). -/// Sets both positions to air and emits `BlockBrokenEvent` for each. -/// Returns the list of all positions that were broken (always includes `pos`, -/// and may include the other door half). -pub fn break_block_with_door_half( - chunk: &mut temper_world::MutChunk, - pos: BlockPos, - block_break_writer: &mut MessageWriter, -) -> Vec { - let current_state = chunk.get_block(pos.chunk_block_pos()); - let other_half = door_other_half_y_offset(current_state).map(|y_off| pos + (0, y_off, 0)); - - chunk.set_block(pos.chunk_block_pos(), BlockStateId::default()); - block_break_writer.write(BlockBrokenEvent { position: pos }); - - let mut broken = vec![pos]; - - if let Some(other_pos) = other_half { - chunk.set_block(other_pos.chunk_block_pos(), BlockStateId::default()); - block_break_writer.write(BlockBrokenEvent { - position: other_pos, - }); - debug!( - "Also broke other door half at ({}, {}, {})", - other_pos.pos.x, other_pos.pos.y, other_pos.pos.z - ); - broken.push(other_pos); - } - - broken -} - -/// Reacts to `DoorToggledEvent` and toggles the other half of the door block. -pub fn handle_door_toggled( - mut events: MessageReader, - state: Res, - query: Query<(&StreamWriter, &Position)>, -) { - for event in events.read() { - let pos = event.position; - - let Some(y_offset) = door_other_half_y_offset(event.new_state) else { - continue; - }; - let other_pos = pos + (0, y_offset, 0); - - let update = { - let mut chunk = match temper_world::World::get_or_generate_mut( - &state.0.world, - other_pos.chunk(), - Dimension::Overworld, - ) { - Ok(c) => c, - Err(e) => { - error!("Failed to load chunk for door other half toggle: {:?}", e); - continue; - } - }; - - let other_state = chunk.get_block(other_pos.chunk_block_pos()); - let InteractionResult::Toggled(other_new) = try_interact(other_state) else { - continue; - }; - - chunk.set_block(other_pos.chunk_block_pos(), other_new); - debug!( - "Door other half: toggled ({}, {}, {}) to {}", - other_pos.pos.x, - other_pos.pos.y, - other_pos.pos.z, - other_new.raw() - ); - - BlockUpdate { - location: NetworkPosition { - x: other_pos.pos.x, - y: other_pos.pos.y as i16, - z: other_pos.pos.z, - }, - block_state_id: VarInt::from(other_new), - } - }; // chunk lock released here - - let block_chunk = other_pos.chunk(); - let (block_cx, block_cz) = (block_chunk.x(), block_chunk.z()); - let render_distance = state.0.config.chunk_render_distance as i32; - - for (conn, player_pos) in query.iter() { - let pchunk = player_pos.chunk(); - let (pcx, pcz) = (pchunk.x(), pchunk.z()); - - if (block_cx - pcx).abs() <= render_distance - && (block_cz - pcz).abs() <= render_distance - && let Err(e) = conn.send_packet_ref(&update) - { - error!("Failed to send door half block update: {:?}", e); - } - } - } -} diff --git a/src/game_systems/src/interactions/src/interaction_listener.rs b/src/game_systems/src/interactions/src/interaction_listener.rs deleted file mode 100644 index 110d0464..00000000 --- a/src/game_systems/src/interactions/src/interaction_listener.rs +++ /dev/null @@ -1,129 +0,0 @@ -use bevy_ecs::prelude::*; -use std::collections::HashMap; -use std::time::{Duration, Instant}; -use temper_codec::net_types::network_position::NetworkPosition; -use temper_codec::net_types::var_int::VarInt; -use temper_components::interaction::InteractionCooldown; -use temper_components::player::position::Position; -use temper_core::pos::BlockPos; -use temper_messages::{BlockInteractMessage, BlockToggledEvent, DoorToggledEvent}; -use temper_net_runtime::connection::StreamWriter; -use temper_protocol::outgoing::block_change_ack::BlockChangeAck; -use temper_protocol::outgoing::block_update::BlockUpdate; -use temper_state::GlobalStateResource; -use temper_world::Dimension; -use tracing::{debug, error}; -use temper_blocks::BlockDispatch; -use crate::door_interaction::is_open; - -pub fn handle_block_interact( - mut events: MessageReader, - state: Res, - query: Query<(Entity, &StreamWriter, &Position)>, - mut toggled_writer: MessageWriter, - mut door_toggled_writer: MessageWriter, - mut cooldowns: Local>, -) { - let cooldown_duration = Duration::from_millis(InteractionCooldown::default().cooldown_ms); - - for event in events.read() { - let pos = event.position; - - // Ignore rapid repeated interactions on the same block - if cooldowns - .get(&pos) - .is_some_and(|t| t.elapsed() < cooldown_duration) - { - if let Ok((_, conn, _)) = query.get(event.player) { - let ack = BlockChangeAck { - sequence: event.sequence, - }; - if let Err(e) = conn.send_packet_ref(&ack) { - error!("Failed to send BlockChangeAck (cooldown): {:?}", e); - } - } - continue; - } - cooldowns.insert(pos, Instant::now()); - - // Load the chunk and get current block state - let mut block_state = state.0.world.get_chunk(pos.chunk(), Dimension::Overworld).map(|chunk| chunk.get_block(pos.chunk_block_pos())).unwrap(); - let original = block_state.clone(); - - let (updates, is_active) = { - let updates = block_state.interact(&state.0.world, pos); - let mut updates = updates.blocks; - updates.insert(pos, block_state); - - debug!( - "Block interact: toggled ({}, {}, {}) from {} to {}", - pos.pos.x, - pos.pos.y, - pos.pos.z, - original.raw(), - block_state.raw() - ); - - for (pos, block_state) in &updates { - if !state.0.world - .get_chunk_mut(pos.chunk(), Dimension::Overworld) - .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), *block_state)) - .is_ok() { - error!("Attempted to update block at {} to {} but failed. (interaction failure)", pos, block_state.raw()); - } - } - - let updates = updates - .into_iter() - .map(|(pos, state)| BlockUpdate { - location: NetworkPosition { - x: pos.pos.x, - y: pos.pos.y as i16, - z: pos.pos.z, - }, - block_state_id: VarInt::from(state), - }) - .collect::>(); - - let is_active = is_open(block_state).unwrap_or(false); - (updates, is_active) - }; // chunk lock released here - - // Emit BlockToggledEvent for other systems to react - toggled_writer.write(BlockToggledEvent { - player: event.player, - position: pos, - is_active, - }); - - // Send BlockChangeAck to the player - if let Ok((_, conn, _)) = query.get(event.player) { - let ack = BlockChangeAck { - sequence: event.sequence, - }; - if let Err(e) = conn.send_packet_ref(&ack) { - error!("Failed to send BlockChangeAck: {:?}", e); - } - } - - // Broadcast BlockUpdate to all players within render distance - let block_chunk = pos.chunk(); - let (block_cx, block_cz) = (block_chunk.x(), block_chunk.z()); - let render_distance = state.0.config.chunk_render_distance as i32; - - for (_, conn, player_pos) in query.iter() { - let pchunk = player_pos.chunk(); - let (pcx, pcz) = (pchunk.x(), pchunk.z()); - - if (block_cx - pcx).abs() <= render_distance - && (block_cz - pcz).abs() <= render_distance - { - for update in &updates { - if let Err(e) = conn.send_packet_ref(update) { - error!("Failed to send block update: {:?}", e); - } - } - } - } - } -} diff --git a/src/game_systems/src/interactions/src/lib.rs b/src/game_systems/src/interactions/src/lib.rs index 7daa3fda..36baeac6 100644 --- a/src/game_systems/src/interactions/src/lib.rs +++ b/src/game_systems/src/interactions/src/lib.rs @@ -7,10 +7,138 @@ //! ## How it works //! //! 1. Player right-clicks on a block (PlaceBlock packet) -//! 2. `try_interact()` checks if the block is interactive -//! 3. If yes, toggles the relevant property and returns the new state +//! 2. The `interact()` method is called on the blockstate +//! 3. `interact()` will change the state to the new state and also return any other blocks to update //! 4. The packet handler updates the chunk and broadcasts to players -pub mod block_interactions; -pub mod door_interaction; -pub mod interaction_listener; +use bevy_ecs::change_detection::Res; +use bevy_ecs::entity::Entity; +use bevy_ecs::message::MessageReader; +use bevy_ecs::prelude::{Local, Query}; +use std::collections::HashMap; +use std::time::{Duration, Instant}; +use temper_blocks::BlockDispatch; +use temper_codec::net_types::network_position::NetworkPosition; +use temper_codec::net_types::var_int::VarInt; +use temper_components::InteractionCooldown; +use temper_components::player::position::Position; +use temper_core::dimension::Dimension; +use temper_core::pos::BlockPos; +use temper_messages::BlockInteractMessage; +use temper_net_runtime::connection::StreamWriter; +use temper_protocol::outgoing::block_change_ack::BlockChangeAck; +use temper_protocol::outgoing::block_update::BlockUpdate; +use temper_state::GlobalStateResource; +use tracing::{debug, error}; + +pub fn handle_block_interact( + mut events: MessageReader, + state: Res, + query: Query<(Entity, &StreamWriter, &Position)>, + mut cooldowns: Local>, +) { + let cooldown_duration = Duration::from_millis(InteractionCooldown::default().cooldown_ms); + + for event in events.read() { + let pos = event.position; + + // Ignore rapid repeated interactions on the same block + if cooldowns + .get(&pos) + .is_some_and(|t| t.elapsed() < cooldown_duration) + { + if let Ok((_, conn, _)) = query.get(event.player) { + let ack = BlockChangeAck { + sequence: event.sequence, + }; + if let Err(e) = conn.send_packet_ref(&ack) { + error!("Failed to send BlockChangeAck (cooldown): {:?}", e); + } + } + continue; + } + cooldowns.insert(pos, Instant::now()); + + // Load the chunk and get current block state + let mut block_state = state + .0 + .world + .get_chunk(pos.chunk(), Dimension::Overworld) + .map(|chunk| chunk.get_block(pos.chunk_block_pos())) + .unwrap(); + let original = block_state; + + let updates = { + let updates = block_state.interact(&state.0.world, pos); + let mut updates = updates.blocks; + updates.insert(pos, block_state); + + debug!( + "Block interact: toggled ({}, {}, {}) from {} to {}", + pos.pos.x, + pos.pos.y, + pos.pos.z, + original.raw(), + block_state.raw() + ); + + for (pos, block_state) in &updates { + if !state + .0 + .world + .get_chunk_mut(pos.chunk(), Dimension::Overworld) + .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), *block_state)) + .is_ok() + { + error!( + "Attempted to update block at {} to {} but failed. (interaction failure)", + pos, + block_state.raw() + ); + } + } + + updates + .into_iter() + .map(|(pos, state)| BlockUpdate { + location: NetworkPosition { + x: pos.pos.x, + y: pos.pos.y as i16, + z: pos.pos.z, + }, + block_state_id: VarInt::from(state), + }) + .collect::>() + }; // chunk lock released here + + // Send BlockChangeAck to the player + if let Ok((_, conn, _)) = query.get(event.player) { + let ack = BlockChangeAck { + sequence: event.sequence, + }; + if let Err(e) = conn.send_packet_ref(&ack) { + error!("Failed to send BlockChangeAck: {:?}", e); + } + } + + // Broadcast BlockUpdate to all players within render distance + let block_chunk = pos.chunk(); + let (block_cx, block_cz) = (block_chunk.x(), block_chunk.z()); + let render_distance = state.0.config.chunk_render_distance as i32; + + for (_, conn, player_pos) in query.iter() { + let pchunk = player_pos.chunk(); + let (pcx, pcz) = (pchunk.x(), pchunk.z()); + + if (block_cx - pcx).abs() <= render_distance + && (block_cz - pcz).abs() <= render_distance + { + for update in &updates { + if let Err(e) = conn.send_packet_ref(update) { + error!("Failed to send block update: {:?}", e); + } + } + } + } + } +} diff --git a/src/game_systems/src/lib.rs b/src/game_systems/src/lib.rs index f2a43e60..9ebc6076 100644 --- a/src/game_systems/src/lib.rs +++ b/src/game_systems/src/lib.rs @@ -43,8 +43,7 @@ fn register_tick_systems(schedule: &mut Schedule) { schedule.add_systems(packets::confirm_player_teleport::handle); schedule.add_systems(packets::keep_alive::handle); schedule.add_systems(packets::place_block::handle); - schedule.add_systems(interactions::interaction_listener::handle_block_interact); - schedule.add_systems(interactions::door_interaction::handle_door_toggled); + schedule.add_systems(interactions::handle_block_interact); schedule.add_systems(packets::player_action::handle); schedule.add_systems(packets::player_command::handle); schedule.add_systems(packets::player_input::handle); diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index d064f73a..42284ef1 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -1,6 +1,5 @@ use bevy_ecs::message::MessageWriter; use bevy_ecs::prelude::{Entity, Query, Res}; -use interactions::block_interactions::is_interactive; use temper_codec::net_types::network_position::NetworkPosition; use temper_components::player::position::Position; use temper_components::{bounds::CollisionBounds, player::sneak::SneakState}; @@ -59,7 +58,7 @@ pub fn handle( .get_or_generate_chunk(clicked_pos.chunk(), Dimension::Overworld) .expect("Failed to load chunk for interaction check"); let clicked_block = chunk.get_block(clicked_pos.chunk_block_pos()); - if !sneak.is_sneaking && is_interactive(clicked_block) { + if !sneak.is_sneaking && clicked_block.is_interactable() { block_interact.write(BlockInteractMessage { player: entity, position: clicked_pos, @@ -144,6 +143,34 @@ pub fn handle( continue 'ev_loop; } + let placement_context = temper_blocks::PlacementContext { + face: event.face, + cursor: DVec3::new( + f64::from(event.cursor_x), + f64::from(event.cursor_y), + f64::from(event.cursor_z), + ), + block_clicked: block_pos, + block_pos: offset_pos, + level: &state.0.world, + dimension: Dimension::Overworld, + player_rotation: rot, + }; + + let Ok(can_replace) = state + .0 + .world + .get_block(offset_pos, Dimension::Overworld) + .map(|block| block.can_be_replaced(placement_context.clone())) + else { + error!("Can't get block at {}", offset_pos); + continue 'ev_loop; + }; + + if !can_replace { + continue 'ev_loop; + } + let mut block_state = ITEM_TO_BLOCK_MAPPING .get() .unwrap() @@ -151,20 +178,7 @@ pub fn handle( .copied() .unwrap(); - let mut placed_blocks = - block_state.get_placement_state(temper_blocks::PlacementContext { - face: event.face, - cursor: DVec3::new( - f64::from(event.cursor_x), - f64::from(event.cursor_y), - f64::from(event.cursor_z), - ), - block_clicked: block_pos, - block_pos: offset_pos, - level: &state.0.world, - dimension: Dimension::Overworld, - player_rotation: rot, - }); + let mut placed_blocks = block_state.get_placement_state(placement_context); placed_blocks.blocks.insert(offset_pos, block_state); @@ -172,13 +186,8 @@ pub fn handle( state .0 .world - .get_chunk_mut(block_pos.chunk(), Dimension::Overworld) - .map(|mut chunk| { - chunk.set_block(block_pos.chunk_block_pos(), *block_state) - }) - .unwrap_or_else(|_| { - error!("Failed to update chunk {}", block_pos.chunk()) - }); + .set_block(*block_pos, Dimension::Overworld, *block_state) + .unwrap_or_else(|_| error!("Failed to update block {}", block_pos)); let block_chunk = block_pos.chunk(); world_change.write(WorldChange { diff --git a/src/game_systems/src/packets/src/player_action.rs b/src/game_systems/src/packets/src/player_action.rs index 6d41d3c5..2ef9fa94 100644 --- a/src/game_systems/src/packets/src/player_action.rs +++ b/src/game_systems/src/packets/src/player_action.rs @@ -3,20 +3,19 @@ use temper_components::player::abilities::PlayerAbilities; use temper_messages::BlockBrokenEvent; use temper_messages::player_digging::*; -use interactions::door_interaction::break_block_with_door_half; +use temper_blocks::BlockDispatch; use temper_codec::net_types::network_position::NetworkPosition; use temper_codec::net_types::var_int::VarInt; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; +use temper_macros::block; use temper_net_runtime::connection::StreamWriter; use temper_protocol::PlayerActionReceiver; use temper_protocol::outgoing::block_change_ack::BlockChangeAck; use temper_protocol::outgoing::block_update::BlockUpdate; use temper_state::GlobalStateResource; use tracing::{error, warn}; -use temper_blocks::BlockDispatch; -use temper_macros::block; pub fn handle( receiver: Res, @@ -61,16 +60,19 @@ pub fn handle( error!("Couldn't get block at pos {}", pos); continue; }; - + let mut broken_positions = id.try_break(&state.0.world, pos).blocks; broken_positions.push(pos); - + for pos in &broken_positions { - block_break_events.write(BlockBrokenEvent { - position: pos.clone(), - }); + block_break_events.write(BlockBrokenEvent { position: *pos }); - if let Err(world_error) = state.0.world.set_block(*pos, Dimension::Overworld, block!("air")) { + if let Err(world_error) = + state + .0 + .world + .set_block(*pos, Dimension::Overworld, block!("air")) + { error!("Failed to break block at {}: {}", pos, world_error) } } diff --git a/src/game_systems/src/player/src/digging_system.rs b/src/game_systems/src/player/src/digging_system.rs index 43893474..6e568782 100644 --- a/src/game_systems/src/player/src/digging_system.rs +++ b/src/game_systems/src/player/src/digging_system.rs @@ -1,7 +1,7 @@ use bevy_ecs::prelude::*; use std::time::{Duration, Instant}; -use interactions::door_interaction::break_block_with_door_half; +use temper_blocks::BlockDispatch; use temper_codec::net_types::network_position::NetworkPosition; use temper_codec::net_types::var_int::VarInt; use temper_components::player::abilities::PlayerAbilities; @@ -10,14 +10,13 @@ use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; use temper_data::blocks::types::Block; +use temper_macros::block; use temper_messages::player_digging::*; use temper_messages::world_change::WorldChange; use temper_net_runtime::connection::StreamWriter; use temper_protocol::outgoing::{block_change_ack::BlockChangeAck, block_update::BlockUpdate}; use temper_state::GlobalStateResource; use tracing::{debug, error, warn}; -use temper_blocks::BlockDispatch; -use temper_macros::block; // A query for just the components needed to acknowledge a dig packet type DiggingPlayerQuery<'a> = (Entity, &'a StreamWriter, Option<&'a PlayerDigging>); @@ -307,11 +306,13 @@ fn break_block( }); for pos in &broken_positions { - block_break_writer.write(temper_messages::BlockBrokenEvent { - position: pos.clone() - }); + block_break_writer.write(temper_messages::BlockBrokenEvent { position: *pos }); - if let Err(world_error) = state.0.world.set_block(*pos, Dimension::Overworld, block!("air")) { + if let Err(world_error) = state + .0 + .world + .set_block(*pos, Dimension::Overworld, block!("air")) + { error!("Failed to break block at {}: {}", pos, world_error) } } diff --git a/src/game_systems/tests/interactions.rs b/src/game_systems/tests/interactions.rs deleted file mode 100644 index 35b38d68..00000000 --- a/src/game_systems/tests/interactions.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[path = "interactions/block_interactions.rs"] -mod block_interactions; diff --git a/src/game_systems/tests/interactions/block_interactions.rs b/src/game_systems/tests/interactions/block_interactions.rs deleted file mode 100644 index 8e887fbb..00000000 --- a/src/game_systems/tests/interactions/block_interactions.rs +++ /dev/null @@ -1,75 +0,0 @@ -use interactions::block_interactions::{ - get_interaction_type, is_interactive, try_interact, InteractionResult, InteractionType, -}; -use std::collections::BTreeMap; -use temper_core::block_data::BlockData; -use temper_core::block_state_id::BlockStateId; -use temper_macros::block; - -#[test] -fn door_detection() { - let door_data = BlockData { - name: "minecraft:oak_door".to_string(), - properties: Some(BTreeMap::from([ - ("facing".to_string(), "north".to_string()), - ("open".to_string(), "false".to_string()), - ("half".to_string(), "lower".to_string()), - ("hinge".to_string(), "left".to_string()), - ])), - }; - - assert!(matches!( - get_interaction_type(&door_data), - Some(InteractionType::Toggleable("open")) - )); -} - -#[test] -fn try_interact_opens_door() { - let closed_door = block!("oak_door", { facing: "north", half: "lower", hinge: "left", open: false, powered: false }); - - let result = try_interact(closed_door); - let InteractionResult::Toggled(new_id) = result else { - panic!("Expected Toggled, got {:?}", result); - }; - - let new_data = new_id - .to_block_data() - .expect("new state ID should be valid"); - let props = new_data.properties.expect("door should have properties"); - assert_eq!(props["open"], "true"); -} - -#[test] -fn try_interact_closes_door() { - let open_door = block!("oak_door", { facing: "north", half: "lower", hinge: "left", open: true, powered: false }); - - let result = try_interact(open_door); - let InteractionResult::Toggled(new_id) = result else { - panic!("Expected Toggled, got {:?}", result); - }; - - let new_data = new_id - .to_block_data() - .expect("new state ID should be valid"); - let props = new_data.properties.expect("door should have properties"); - assert_eq!(props["open"], "false"); -} - -#[test] -fn try_interact_not_interactive() { - let stone = block!("stone"); - assert!(matches!( - try_interact(stone), - InteractionResult::NotInteractive - )); -} - -#[test] -fn is_interactive_reports_doors_only() { - let door = block!("oak_door", { facing: "north", half: "lower", hinge: "left", open: false, powered: false }); - let stone = block!("stone"); - - assert!(is_interactive(door)); - assert!(!is_interactive(stone)); -} diff --git a/src/messages/src/block_interaction.rs b/src/messages/src/block_interaction.rs index 162f00d9..dc8c1020 100644 --- a/src/messages/src/block_interaction.rs +++ b/src/messages/src/block_interaction.rs @@ -1,6 +1,5 @@ use bevy_ecs::prelude::{Entity, Message}; use temper_codec::net_types::var_int::VarInt; -use temper_core::block_state_id::BlockStateId; use temper_core::pos::BlockPos; /// Message sent when a player right-clicks an interactive block (door, lever, etc.) @@ -13,20 +12,3 @@ pub struct BlockInteractMessage { pub position: BlockPos, pub sequence: VarInt, } - -/// Emitted when a block has been toggled (door opened/closed, etc.). -/// -/// Fired by the interaction listener after a successful toggle. -#[derive(Message, Clone, Debug)] -pub struct BlockToggledEvent { - pub player: Entity, - pub position: BlockPos, - pub is_active: bool, -} - -/// Emitted when a door block is toggled, so the door system can toggle the other half. -#[derive(Message, Clone, Debug)] -pub struct DoorToggledEvent { - pub position: BlockPos, - pub new_state: BlockStateId, -} diff --git a/src/messages/src/lib.rs b/src/messages/src/lib.rs index bc2db266..4a5ad313 100644 --- a/src/messages/src/lib.rs +++ b/src/messages/src/lib.rs @@ -52,7 +52,7 @@ use crate::particle::SendParticle; use crate::save_chunk_entities::SaveChunkEntities; use crate::teleport_player::TeleportPlayer; pub use block_break::BlockBrokenEvent; -pub use block_interaction::{BlockInteractMessage, BlockToggledEvent, DoorToggledEvent}; +pub use block_interaction::BlockInteractMessage; use temper_commands::messages::{CommandDispatched, ResolvedCommandDispatched}; use world_change::WorldChange; @@ -83,8 +83,6 @@ pub fn register_messages(world: &mut World) { MessageRegistry::register_message::(world); MessageRegistry::register_message::(world); MessageRegistry::register_message::(world); - MessageRegistry::register_message::(world); - MessageRegistry::register_message::(world); MessageRegistry::register_message::(world); MessageRegistry::register_message::(world); MessageRegistry::register_message::(world); diff --git a/src/world/src/helpers.rs b/src/world/src/helpers.rs index 78d34ab6..b176ef5e 100644 --- a/src/world/src/helpers.rs +++ b/src/world/src/helpers.rs @@ -1,21 +1,28 @@ +use crate::World; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; use temper_world_format::errors::WorldError; -use crate::World; impl World { /// Attempts to get a block in the world. Returns an error if the chunk is not accessible - pub fn get_block(&self, pos: BlockPos, dimension: Dimension) -> Result { - self - .get_chunk(pos.chunk(), dimension) + pub fn get_block( + &self, + pos: BlockPos, + dimension: Dimension, + ) -> Result { + self.get_chunk(pos.chunk(), dimension) .map(|chunk| chunk.get_block(pos.chunk_block_pos())) } - + /// Attempts to set a block in the world. Returns an error if the chunk is not mutable - pub fn set_block(&self, pos: BlockPos, dimension: Dimension, block_state_id: BlockStateId) -> Result<(), WorldError> { - self - .get_chunk_mut(pos.chunk(), dimension) + pub fn set_block( + &self, + pos: BlockPos, + dimension: Dimension, + block_state_id: BlockStateId, + ) -> Result<(), WorldError> { + self.get_chunk_mut(pos.chunk(), dimension) .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), block_state_id)) } -} \ No newline at end of file +} diff --git a/src/world/src/lib.rs b/src/world/src/lib.rs index 46c01a0a..482b4761 100644 --- a/src/world/src/lib.rs +++ b/src/world/src/lib.rs @@ -1,7 +1,7 @@ mod db_wrap; +mod helpers; mod importing; pub mod player; -mod helpers; use dashmap::DashMap; use std::fs::create_dir_all; From a7423238e8280cc6ab0ec5d3032a1dfe21958936 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Thu, 28 May 2026 23:50:20 -0500 Subject: [PATCH 24/30] Ensure that can_be_replaced is properly used --- src/blocks/src/building/simple_block.rs | 7 +++- src/game_systems/src/interactions/src/lib.rs | 8 ++--- .../src/packets/src/place_block.rs | 35 +++++++++++++------ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/blocks/src/building/simple_block.rs b/src/blocks/src/building/simple_block.rs index d7d069df..c16fa1d6 100644 --- a/src/blocks/src/building/simple_block.rs +++ b/src/blocks/src/building/simple_block.rs @@ -1,4 +1,9 @@ use crate::BlockBehavior; +use temper_block_data::PlacementContext; use temper_blocks_generated::SimpleBlock; -impl BlockBehavior for SimpleBlock {} +impl BlockBehavior for SimpleBlock { + fn can_be_replaced(&self, _context: PlacementContext) -> bool { + matches!(self, SimpleBlock::Air | SimpleBlock::CaveAir) + } +} diff --git a/src/game_systems/src/interactions/src/lib.rs b/src/game_systems/src/interactions/src/lib.rs index 36baeac6..139af8dd 100644 --- a/src/game_systems/src/interactions/src/lib.rs +++ b/src/game_systems/src/interactions/src/lib.rs @@ -83,17 +83,17 @@ pub fn handle_block_interact( ); for (pos, block_state) in &updates { - if !state + if let Err(error) = state .0 .world .get_chunk_mut(pos.chunk(), Dimension::Overworld) .map(|mut chunk| chunk.set_block(pos.chunk_block_pos(), *block_state)) - .is_ok() { error!( - "Attempted to update block at {} to {} but failed. (interaction failure)", + "Attempted to update block at {} to {} but failed: {}", pos, - block_state.raw() + block_state.raw(), + error ); } } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 42284ef1..78bb5ace 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -23,6 +23,8 @@ use temper_state::GlobalStateResource; use temper_text::{Color, NamedColor, TextComponentBuilder}; use tracing::{debug, error, trace}; +// TODO: in the future this should be reworked so that if a block update exits early the client is informed that the block never updated. +// Currently it spawns ghost blocks if this function exits early (ie continues on to the next update) pub fn handle( receiver: Res, state: Res, @@ -68,6 +70,10 @@ pub fn handle( } } + let ack_packet = BlockChangeAck { + sequence: event.sequence, + }; + match event.hand.0 { 0 => { let Ok(slot) = hotbar.get_selected_item(inventory) else { @@ -157,17 +163,30 @@ pub fn handle( player_rotation: rot, }; - let Ok(can_replace) = state - .0 - .world - .get_block(offset_pos, Dimension::Overworld) - .map(|block| block.can_be_replaced(placement_context.clone())) + let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) else { error!("Can't get block at {}", offset_pos); continue 'ev_loop; }; - if !can_replace { + if !curr_state.can_be_replaced(placement_context.clone()) { + if let Err(err) = conn.send_packet_ref(&ack_packet) { + error!("Failed to send block change ack packet: {:?}", err); + continue 'ev_loop; + } + + if let Err(err) = conn.send_packet(BlockUpdate { + location: NetworkPosition { + x: offset_pos.pos.x, + y: offset_pos.pos.y as i16, + z: offset_pos.pos.z, + }, + block_state_id: curr_state.to_varint(), + }) { + error!("Failed to send block update packet to player: {err}"); + continue 'ev_loop; + } + continue 'ev_loop; } @@ -220,10 +239,6 @@ pub fn handle( } } - let ack_packet = BlockChangeAck { - sequence: event.sequence, - }; - if let Err(err) = conn.send_packet_ref(&ack_packet) { error!("Failed to send block change ack packet: {:?}", err); continue 'ev_loop; From 947b5e9ea0717d1df73c3912a94d1b8f1a7e9baa Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Fri, 29 May 2026 15:08:43 -0500 Subject: [PATCH 25/30] Port fences/glass panes and logs to new system --- src/blocks/src/behavior_trait.rs | 3 +- src/blocks/src/building/pillar_block.rs | 19 ++++- src/blocks/src/building/simple_block.rs | 4 + src/blocks/src/decorative/fence_pane.rs | 75 ++++++++++++++++++- src/blocks/src/liquid.rs | 11 ++- src/blocks/src/world_extensions.rs | 11 +++ .../src/packets/src/place_block.rs | 4 + 7 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src/blocks/src/behavior_trait.rs b/src/blocks/src/behavior_trait.rs index ffaa169d..c6c7b8f9 100644 --- a/src/blocks/src/behavior_trait.rs +++ b/src/blocks/src/behavior_trait.rs @@ -160,7 +160,8 @@ block_behavior_trait!( fn try_break(; _world: &World, _pos: BlockPos) -> BrokenBlocks; BrokenBlocks::default(), fn is_interactable(;) -> bool; false, + fn is_solid(;) -> bool; true, // Used for fence and pane connections fn can_be_replaced(; _context: PlacementContext) -> bool; false, - fn update(mut; _world: &World, _pos: BlockPos), + fn update(mut; _world: &World, _pos: BlockPos) -> bool; false, // The boolean returned is whether to emit more adjacent updates from this block ); diff --git a/src/blocks/src/building/pillar_block.rs b/src/blocks/src/building/pillar_block.rs index 7e8bb268..224154da 100644 --- a/src/blocks/src/building/pillar_block.rs +++ b/src/blocks/src/building/pillar_block.rs @@ -1,4 +1,21 @@ +use std::collections::HashMap; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use temper_block_properties::Axis; use crate::BlockBehavior; use temper_blocks_generated::PillarBlock; +use temper_core::block_face::BlockFace; -impl BlockBehavior for PillarBlock {} +impl BlockBehavior for PillarBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + self.axis = match context.face { + BlockFace::Top | BlockFace::Bottom => Axis::Y, + BlockFace::North | BlockFace::South => Axis::Z, + BlockFace::East | BlockFace::West => Axis::X, + }; + + PlacedBlocks { + take_item: true, + blocks: HashMap::with_capacity(0), + } + } +} diff --git a/src/blocks/src/building/simple_block.rs b/src/blocks/src/building/simple_block.rs index c16fa1d6..e9837b9a 100644 --- a/src/blocks/src/building/simple_block.rs +++ b/src/blocks/src/building/simple_block.rs @@ -3,6 +3,10 @@ use temper_block_data::PlacementContext; use temper_blocks_generated::SimpleBlock; impl BlockBehavior for SimpleBlock { + fn is_solid(&self) -> bool { + !matches!(self, SimpleBlock::Air | SimpleBlock::CaveAir) + } + fn can_be_replaced(&self, _context: PlacementContext) -> bool { matches!(self, SimpleBlock::Air | SimpleBlock::CaveAir) } diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs index 39c6b101..53d48822 100644 --- a/src/blocks/src/decorative/fence_pane.rs +++ b/src/blocks/src/decorative/fence_pane.rs @@ -1,4 +1,73 @@ -use crate::BlockBehavior; -use temper_blocks_generated::FenceAndPaneBlock; +use std::collections::HashMap; +use bevy_math::IVec3; +use tracing::info; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use crate::{BlockBehavior, BlockDispatch}; +use temper_blocks_generated::{FenceAndPaneBlock, FenceAndPaneBlockType, LiquidBlock, LiquidBlockType}; +use temper_core::dimension::Dimension; +use temper_core::pos::BlockPos; +use temper_world::World; +use crate::world_extensions::WorldBlockUpdates; -impl BlockBehavior for FenceAndPaneBlock {} +// North (-Z), East (+X), South (+Z), West (-X) +const SIDE_DIRECTIONS: [(i32, i32); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)]; + +impl BlockBehavior for FenceAndPaneBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + self.waterlogged = context + .level + .block_is_and::( + context.block_pos, + |liquid| matches!(liquid.block_type, LiquidBlockType::Water) + ); + + info!("here"); + + let block_is_pane = is_pane(&self.block_type); + + for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([&mut self.north, &mut self.east, &mut self.south, &mut self.west]) { + let pos = context.block_pos + IVec3::new(*dx, 0, *dz).into(); + let block = context.level.get_block(pos, context.dimension).unwrap_or_default(); + + *flag = !context.level.block_is_and::(pos, |block| block_is_pane ^ is_pane(&block.block_type)) && block.is_solid(); + } + + PlacedBlocks { + take_item: true, + blocks: HashMap::with_capacity(0), + } + } + + fn update(&mut self, world: &World, pos: BlockPos) -> bool { + let block_is_pane = is_pane(&self.block_type); + + let mut changed = false; + + for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([&mut self.north, &mut self.east, &mut self.south, &mut self.west]) { + let pos = pos + IVec3::new(*dx, 0, *dz).into(); + let block = world.get_block(pos, Dimension::Overworld).unwrap_or_default(); + + let original_flag = *flag; + *flag = !world.block_is_and::(pos, |block| block_is_pane ^ is_pane(&block.block_type)) && block.is_solid(); + + changed = changed || (original_flag != *flag); + } + + changed + } +} + +pub fn is_pane(ty: &FenceAndPaneBlockType) -> bool { + matches!( + ty, + FenceAndPaneBlockType::GlassPane | FenceAndPaneBlockType::RedStainedGlassPane | + FenceAndPaneBlockType::OrangeStainedGlassPane | FenceAndPaneBlockType::YellowStainedGlassPane | + FenceAndPaneBlockType::GreenStainedGlassPane | FenceAndPaneBlockType::BlueStainedGlassPane | + FenceAndPaneBlockType::PurpleStainedGlassPane | FenceAndPaneBlockType::PinkStainedGlassPane | + FenceAndPaneBlockType::MagentaStainedGlassPane | FenceAndPaneBlockType::LimeStainedGlassPane | + FenceAndPaneBlockType::LightBlueStainedGlassPane | FenceAndPaneBlockType::WhiteStainedGlassPane | + FenceAndPaneBlockType::LightGrayStainedGlassPane | FenceAndPaneBlockType::GrayStainedGlassPane | + FenceAndPaneBlockType::BlackStainedGlassPane | FenceAndPaneBlockType::BrownStainedGlassPane | + FenceAndPaneBlockType::CyanStainedGlassPane + ) +} diff --git a/src/blocks/src/liquid.rs b/src/blocks/src/liquid.rs index 782f5578..441c18b2 100644 --- a/src/blocks/src/liquid.rs +++ b/src/blocks/src/liquid.rs @@ -1,4 +1,13 @@ +use temper_block_data::PlacementContext; use crate::BlockBehavior; use temper_blocks_generated::LiquidBlock; -impl BlockBehavior for LiquidBlock {} +impl BlockBehavior for LiquidBlock { + fn can_be_replaced(&self, _context: PlacementContext) -> bool { + true + } + + fn is_solid(&self) -> bool { + false + } +} diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs index da70e9fc..03baee0c 100644 --- a/src/blocks/src/world_extensions.rs +++ b/src/blocks/src/world_extensions.rs @@ -15,6 +15,7 @@ pub trait WorldBlockUpdates { ) -> Result; fn block_is(&self, block_pos: BlockPos) -> bool; + fn block_is_and(&self, block_pos: BlockPos, callback: impl Fn(T) -> bool) -> bool; } impl WorldBlockUpdates for World { @@ -41,4 +42,14 @@ impl WorldBlockUpdates for World { .map(|chunk| T::try_from(chunk.get_block(block_pos.chunk_block_pos()).raw()).is_ok()) .unwrap_or_default() } + + fn block_is_and(&self, block_pos: BlockPos, callback: impl Fn(T) -> bool) -> bool { + self.get_chunk(block_pos.chunk(), Dimension::Overworld) + .and_then(|chunk| { + let block_id = chunk.get_block(block_pos.chunk_block_pos()); + let block = T::try_from(block_id.raw()).map_err(|_| WorldError::InvalidBlock(block_id))?; + Ok(callback(block)) + }) + .unwrap_or_default() + } } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 78bb5ace..274907c3 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -25,6 +25,10 @@ use tracing::{debug, error, trace}; // TODO: in the future this should be reworked so that if a block update exits early the client is informed that the block never updated. // Currently it spawns ghost blocks if this function exits early (ie continues on to the next update) +// +// TODO: also create a better block update propagation system. All block updates should happen (preferably) on the same tick to prevent +// visible slowdowns. When a block is placed, all adjacent blocks should be updated. There's already a built in `update` function on +// BlockBehavior that should return whether or not the block changed (if it did then we should keep updating blocks next to that) pub fn handle( receiver: Res, state: Res, From 03b4c009bd68af06e2a4ddd459be427200989c81 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Fri, 29 May 2026 15:25:05 -0500 Subject: [PATCH 26/30] Add roadmap for future versions of block system --- src/blocks/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/blocks/README.md b/src/blocks/README.md index 98511603..0779d574 100644 --- a/src/blocks/README.md +++ b/src/blocks/README.md @@ -75,4 +75,15 @@ The `block_overrides` section is for placing specific blocks into different stru ### Important Note -All block struct names **MUST** be unique. The generated crate will not compile otherwise. \ No newline at end of file +All block struct names **MUST** be unique. The generated crate will not compile otherwise. + +## Roadmap + +Here's a quick roadmap of features that are planned to be added in future versions of this crate: + +- BlockBehavior generator macro as a proc-macro for 100% rust-style function definition syntax +- Better generator functions (like `get_placement_state`), make them more rust-like and return `Option` rather than mutating self directly +- Performance improvements and code-size reduction +- Better struct combination capabilities (combine structs with not identical properties, property serialization depends on the block type set) + - Note to self: this would be super useful for things like torches where they have two different blocks representing the same item. Combining TorchBlock and WallTorchBlock into just TorchBlock would be very helpful +- And of course, more block behavior functions! \ No newline at end of file From a216ea57fe8fa7c55ccf8d2e1fd528a0c67bf4ae Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Fri, 29 May 2026 15:49:54 -0500 Subject: [PATCH 27/30] Allow for reassigning simple blocks to new enums --- src/blocks/build.rs | 3 +- src/blocks/build_config.toml | 4 + src/blocks/crates/build/src/simple.rs | 145 ++++++++++++++++++-------- src/blocks/crates/generated/build.rs | 4 +- 4 files changed, 111 insertions(+), 45 deletions(-) diff --git a/src/blocks/build.rs b/src/blocks/build.rs index 8f5353e7..c8437ebc 100644 --- a/src/blocks/build.rs +++ b/src/blocks/build.rs @@ -9,6 +9,7 @@ use temper_blocks_build::simple::fill_simple_block_mappings; fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=build_config.toml"); let build_config = get_build_config(); let block_states = get_block_states(); @@ -17,7 +18,7 @@ fn main() { mappings.resize(block_states.len(), TokenStream::new()); let (simple_blocks, complex_blocks) = separate_blocks(block_states); - let enum_const = fill_simple_block_mappings(simple_blocks, &mut mappings); + let enum_const = fill_simple_block_mappings(&build_config, simple_blocks, &mut mappings); let complex_consts = fill_complex_block_mappings(&build_config, complex_blocks, &mut mappings); let mapping_const = quote! { diff --git a/src/blocks/build_config.toml b/src/blocks/build_config.toml index 65893462..323ebb7a 100644 --- a/src/blocks/build_config.toml +++ b/src/blocks/build_config.toml @@ -120,6 +120,10 @@ "minecraft:target" = "TargetBlock" "minecraft:structure_block" = "StructureBlock" "minecraft:test_block" = "TestBlock" +"minecraft:torch" = "TorchBlock" +"minecraft:wall_torch" = "WallTorchBlock" +"minecraft:soul_torch" = "TorchBlock" +"minecraft:soul_wall_torch" = "WallTorchBlock" # From Minecraft's net.minecraft.world.level.block.state.properties.BlockStateProperties class # diff --git a/src/blocks/crates/build/src/simple.rs b/src/blocks/crates/build/src/simple.rs index ea76c8b0..c79a7276 100644 --- a/src/blocks/crates/build/src/simple.rs +++ b/src/blocks/crates/build/src/simple.rs @@ -1,70 +1,131 @@ -use heck::ToPascalCase; +use crate::config::BuildConfig; +use heck::{ToPascalCase, ToShoutySnakeCase}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use std::collections::HashMap; + +fn separate_enums( + build_config: &BuildConfig, + mut simple_blocks: Vec<(u32, String)>, +) -> HashMap> { + simple_blocks.sort_by_key(|(id, _)| *id); + + let mut enums = HashMap::new(); + + for (block_id, enum_name) in build_config.block_overrides.iter() { + let Some((idx, _)) = simple_blocks + .iter() + .enumerate() + .find(|(_, (_, id))| id == block_id) + else { + continue; + }; + + let entry = enums.entry(enum_name.clone()).or_insert_with(Vec::new); + + entry.push(simple_blocks.remove(idx)); + } + + enums.insert("SimpleBlock".to_string(), simple_blocks); + + enums +} pub fn fill_simple_block_mappings( + build_config: &BuildConfig, simple_blocks: Vec<(u32, String)>, mappings: &mut [TokenStream], ) -> TokenStream { - for (id, _) in simple_blocks { - mappings[id as usize] = - quote! { crate::StateBehaviorTable::spin_off(&VTABLE_SIMPLE_BLOCK, #id) }; + let enums = separate_enums(build_config, simple_blocks); + + let mut vtables = Vec::new(); + + for (enum_name, variants) in enums { + let vtable_name = format_ident!("VTABLE_{}", enum_name.to_shouty_snake_case()); + let enum_name = format_ident!("{}", enum_name); + + for (id, _) in variants { + mappings[id as usize] = + quote! { crate::StateBehaviorTable::spin_off(&#vtable_name, #id) }; + } + + vtables.push(quote! { + const #vtable_name: crate::BlockBehaviorTable = crate::BlockBehaviorTable::from::<#enum_name>(); + }); } quote! { - const VTABLE_SIMPLE_BLOCK: crate::BlockBehaviorTable = crate::BlockBehaviorTable::from::(); + #(#vtables)* } } pub fn generate_simple_block_enum( - mut simple_blocks: Vec<(u32, String)>, + build_config: &BuildConfig, + simple_blocks: Vec<(u32, String)>, ) -> (TokenStream, TokenStream) { - simple_blocks.sort_by_key(|(id, _)| *id); + let enums = separate_enums(build_config, simple_blocks); - let mut map_entries = Vec::new(); - let mut from_arms = Vec::new(); - let mut enum_variants = Vec::new(); + let (enums, impls): (Vec, Vec) = enums + .into_iter() + .map(|(enum_name, enum_blocks)| { + let mut map_entries = Vec::new(); + let mut from_arms = Vec::new(); + let mut enum_variants = Vec::new(); - for (id, name) in simple_blocks { - let variant = name.strip_prefix("minecraft:").unwrap_or(&name); - let variant = format_ident!("{}", variant.to_pascal_case()); + let map_name = format_ident!("{}_BLOCK_MAP", enum_name.to_shouty_snake_case()); + let enum_name = format_ident!("{}", enum_name); - enum_variants.push(quote! { #variant }); - from_arms.push(quote! { #id => Ok(SimpleBlock::#variant) }); - map_entries.push(quote! { #id }); - } + for (id, name) in enum_blocks { + let variant = name.strip_prefix("minecraft:").unwrap_or(&name); + let variant = format_ident!("{}", variant.to_pascal_case()); - ( - quote! { - #[repr(usize)] - #[derive(Clone, Debug, Eq, PartialEq)] - pub enum SimpleBlock { - #(#enum_variants),* + enum_variants.push(quote! { #variant }); + from_arms.push(quote! { #id => Ok(#enum_name::#variant) }); + map_entries.push(quote! { #id }); } - }, - quote! { - const SIMPLE_BLOCK_STATE_MAP: &[u32] = &[ - #(#map_entries,)* - ]; - impl TryFrom for SimpleBlock { - type Error = (); + ( + quote! { + #[repr(usize)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub enum #enum_name { + #(#enum_variants),* + } + }, + quote! { + const #map_name: &[u32] = &[ + #(#map_entries),* + ]; + + impl TryFrom for #enum_name { + type Error = (); - fn try_from(data: u32) -> Result { - match data { - #(#from_arms),*, - _ => Err(()) + fn try_from(data: u32) -> Result { + match data { + #(#from_arms),*, + _ => Err(()), + } + } } - } - } - impl TryInto for SimpleBlock { - type Error = (); + impl TryInto for #enum_name { + type Error = (); - fn try_into(self) -> Result { - Ok(SIMPLE_BLOCK_STATE_MAP[self as usize]) - } - } + fn try_into(self) -> Result { + Ok(#map_name[self as usize]) + } + } + }, + ) + }) + .unzip(); + + ( + quote! { + #(#enums)* + }, + quote! { + #(#impls)* }, ) } diff --git a/src/blocks/crates/generated/build.rs b/src/blocks/crates/generated/build.rs index 95db2fa5..23b5201d 100644 --- a/src/blocks/crates/generated/build.rs +++ b/src/blocks/crates/generated/build.rs @@ -11,13 +11,13 @@ fn main() { let (simple_blocks, complex_blocks) = separate_blocks(block_states); - let (simple_enum, enum_impl) = generate_simple_block_enum(simple_blocks); + let (simple_enum, enum_impl) = generate_simple_block_enum(&build_config, simple_blocks); let (block_structs, block_mod) = generate_complex_blocks(&build_config, complex_blocks); let out_dir = std::env::var("OUT_DIR").unwrap(); let enum_impl = quote::quote! { - use crate::SimpleBlock; + use crate::*; #enum_impl }; From 15fbe74f298c248f37ceef0416ba318946c56d30 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Fri, 29 May 2026 16:18:22 -0500 Subject: [PATCH 28/30] Port torches to new system --- src/blocks/crates/data/src/lib.rs | 5 ++ src/blocks/src/building/pillar_block.rs | 5 +- src/blocks/src/decorative/fence_pane.rs | 81 +++++++++++++------ src/blocks/src/functional/mod.rs | 1 + src/blocks/src/functional/torch.rs | 81 +++++++++++++++++++ src/blocks/src/liquid.rs | 2 +- src/blocks/src/world_extensions.rs | 15 +++- .../src/packets/src/place_block.rs | 18 +++-- 8 files changed, 168 insertions(+), 40 deletions(-) create mode 100644 src/blocks/src/functional/torch.rs diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index 386c1320..46fa501a 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -25,6 +25,10 @@ pub struct PlacedBlocks { /// Whether an item is taken from the player's inventory or not pub take_item: bool, + + // TODO: when version 2 of the block system is implemented, this can be removed and will be replaced with an Option + /// Whether to place the original block or now + pub place_original: bool, } /// Result of the try_break function @@ -46,6 +50,7 @@ impl Default for PlacedBlocks { Self { blocks: HashMap::default(), take_item: true, + place_original: true, } } } diff --git a/src/blocks/src/building/pillar_block.rs b/src/blocks/src/building/pillar_block.rs index 224154da..a046026d 100644 --- a/src/blocks/src/building/pillar_block.rs +++ b/src/blocks/src/building/pillar_block.rs @@ -1,7 +1,7 @@ +use crate::BlockBehavior; use std::collections::HashMap; use temper_block_data::{PlacedBlocks, PlacementContext}; use temper_block_properties::Axis; -use crate::BlockBehavior; use temper_blocks_generated::PillarBlock; use temper_core::block_face::BlockFace; @@ -12,10 +12,11 @@ impl BlockBehavior for PillarBlock { BlockFace::North | BlockFace::South => Axis::Z, BlockFace::East | BlockFace::West => Axis::X, }; - + PlacedBlocks { take_item: true, blocks: HashMap::with_capacity(0), + place_original: true, } } } diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs index 53d48822..c145211b 100644 --- a/src/blocks/src/decorative/fence_pane.rs +++ b/src/blocks/src/decorative/fence_pane.rs @@ -1,13 +1,14 @@ -use std::collections::HashMap; +use crate::world_extensions::WorldBlockUpdates; +use crate::{BlockBehavior, BlockDispatch}; use bevy_math::IVec3; -use tracing::info; +use std::collections::HashMap; use temper_block_data::{PlacedBlocks, PlacementContext}; -use crate::{BlockBehavior, BlockDispatch}; -use temper_blocks_generated::{FenceAndPaneBlock, FenceAndPaneBlockType, LiquidBlock, LiquidBlockType}; +use temper_blocks_generated::{ + FenceAndPaneBlock, FenceAndPaneBlockType, LiquidBlock, LiquidBlockType, +}; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; use temper_world::World; -use crate::world_extensions::WorldBlockUpdates; // North (-Z), East (+X), South (+Z), West (-X) const SIDE_DIRECTIONS: [(i32, i32); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)]; @@ -16,25 +17,36 @@ impl BlockBehavior for FenceAndPaneBlock { fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { self.waterlogged = context .level - .block_is_and::( - context.block_pos, - |liquid| matches!(liquid.block_type, LiquidBlockType::Water) - ); - - info!("here"); + .block_is_and::(context.block_pos, |liquid| { + matches!(liquid.block_type, LiquidBlockType::Water) + }); let block_is_pane = is_pane(&self.block_type); - for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([&mut self.north, &mut self.east, &mut self.south, &mut self.west]) { + for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([ + &mut self.north, + &mut self.east, + &mut self.south, + &mut self.west, + ]) { let pos = context.block_pos + IVec3::new(*dx, 0, *dz).into(); - let block = context.level.get_block(pos, context.dimension).unwrap_or_default(); + let block = context + .level + .get_block(pos, context.dimension) + .unwrap_or_default(); - *flag = !context.level.block_is_and::(pos, |block| block_is_pane ^ is_pane(&block.block_type)) && block.is_solid(); + *flag = !context + .level + .block_is_and::(pos, |block| { + block_is_pane ^ is_pane(&block.block_type) + }) + && block.is_solid(); } PlacedBlocks { take_item: true, blocks: HashMap::with_capacity(0), + place_original: true, } } @@ -43,12 +55,21 @@ impl BlockBehavior for FenceAndPaneBlock { let mut changed = false; - for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([&mut self.north, &mut self.east, &mut self.south, &mut self.west]) { + for ((dx, dz), flag) in SIDE_DIRECTIONS.iter().zip([ + &mut self.north, + &mut self.east, + &mut self.south, + &mut self.west, + ]) { let pos = pos + IVec3::new(*dx, 0, *dz).into(); - let block = world.get_block(pos, Dimension::Overworld).unwrap_or_default(); + let block = world + .get_block(pos, Dimension::Overworld) + .unwrap_or_default(); let original_flag = *flag; - *flag = !world.block_is_and::(pos, |block| block_is_pane ^ is_pane(&block.block_type)) && block.is_solid(); + *flag = !world.block_is_and::(pos, |block| { + block_is_pane ^ is_pane(&block.block_type) + }) && block.is_solid(); changed = changed || (original_flag != *flag); } @@ -60,14 +81,22 @@ impl BlockBehavior for FenceAndPaneBlock { pub fn is_pane(ty: &FenceAndPaneBlockType) -> bool { matches!( ty, - FenceAndPaneBlockType::GlassPane | FenceAndPaneBlockType::RedStainedGlassPane | - FenceAndPaneBlockType::OrangeStainedGlassPane | FenceAndPaneBlockType::YellowStainedGlassPane | - FenceAndPaneBlockType::GreenStainedGlassPane | FenceAndPaneBlockType::BlueStainedGlassPane | - FenceAndPaneBlockType::PurpleStainedGlassPane | FenceAndPaneBlockType::PinkStainedGlassPane | - FenceAndPaneBlockType::MagentaStainedGlassPane | FenceAndPaneBlockType::LimeStainedGlassPane | - FenceAndPaneBlockType::LightBlueStainedGlassPane | FenceAndPaneBlockType::WhiteStainedGlassPane | - FenceAndPaneBlockType::LightGrayStainedGlassPane | FenceAndPaneBlockType::GrayStainedGlassPane | - FenceAndPaneBlockType::BlackStainedGlassPane | FenceAndPaneBlockType::BrownStainedGlassPane | - FenceAndPaneBlockType::CyanStainedGlassPane + FenceAndPaneBlockType::GlassPane + | FenceAndPaneBlockType::RedStainedGlassPane + | FenceAndPaneBlockType::OrangeStainedGlassPane + | FenceAndPaneBlockType::YellowStainedGlassPane + | FenceAndPaneBlockType::GreenStainedGlassPane + | FenceAndPaneBlockType::BlueStainedGlassPane + | FenceAndPaneBlockType::PurpleStainedGlassPane + | FenceAndPaneBlockType::PinkStainedGlassPane + | FenceAndPaneBlockType::MagentaStainedGlassPane + | FenceAndPaneBlockType::LimeStainedGlassPane + | FenceAndPaneBlockType::LightBlueStainedGlassPane + | FenceAndPaneBlockType::WhiteStainedGlassPane + | FenceAndPaneBlockType::LightGrayStainedGlassPane + | FenceAndPaneBlockType::GrayStainedGlassPane + | FenceAndPaneBlockType::BlackStainedGlassPane + | FenceAndPaneBlockType::BrownStainedGlassPane + | FenceAndPaneBlockType::CyanStainedGlassPane ) } diff --git a/src/blocks/src/functional/mod.rs b/src/blocks/src/functional/mod.rs index efb610f2..2bd61f0f 100644 --- a/src/blocks/src/functional/mod.rs +++ b/src/blocks/src/functional/mod.rs @@ -15,5 +15,6 @@ mod respawn_anchor; mod scaffolding; mod structure; mod test; +mod torch; mod trial_spawner; mod vault; diff --git a/src/blocks/src/functional/torch.rs b/src/blocks/src/functional/torch.rs new file mode 100644 index 00000000..c1aea65d --- /dev/null +++ b/src/blocks/src/functional/torch.rs @@ -0,0 +1,81 @@ +use crate::{BlockBehavior, BlockDispatch}; +use std::collections::HashMap; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use temper_block_properties::Direction; +use temper_blocks_generated::{TorchBlock, WallTorchBlock, WallTorchBlockType}; +use temper_core::block_face::BlockFace; +use temper_core::block_state_id::BlockStateId; + +impl BlockBehavior for TorchBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + place_torch(context, self.clone()) + } + + fn is_solid(&self) -> bool { + false + } +} + +impl BlockBehavior for WallTorchBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + place_torch( + context, + match self.block_type { + WallTorchBlockType::WallTorch => TorchBlock::Torch, + WallTorchBlockType::SoulWallTorch => TorchBlock::SoulTorch, + }, + ) + } + + fn is_solid(&self) -> bool { + false + } +} + +fn place_torch(context: PlacementContext, ty: TorchBlock) -> PlacedBlocks { + let block = match context.face { + BlockFace::Top | BlockFace::Bottom => { + if context + .level + .get_block(context.block_pos.below(), context.dimension) + .unwrap_or_default() + .is_solid() + { + ty.try_into() + .expect("Should be able to convert TorchBlock to id") + } else { + return PlacedBlocks { + blocks: HashMap::with_capacity(0), + take_item: false, + place_original: false, + }; + } + } + face => { + let block_type = match ty { + TorchBlock::Torch => WallTorchBlockType::WallTorch, + TorchBlock::SoulTorch => WallTorchBlockType::SoulWallTorch, + }; + + let facing = match face { + BlockFace::East => Direction::East, + BlockFace::West => Direction::West, + BlockFace::North => Direction::North, + BlockFace::South => Direction::South, + _ => unreachable!(), + }; + + WallTorchBlock { block_type, facing } + .try_into() + .expect("Should be able to convert") + } + }; + + PlacedBlocks { + blocks: [(context.block_pos, BlockStateId::new(block))] + .into_iter() + .collect::>(), + take_item: true, + place_original: false, + } +} diff --git a/src/blocks/src/liquid.rs b/src/blocks/src/liquid.rs index 441c18b2..9e371111 100644 --- a/src/blocks/src/liquid.rs +++ b/src/blocks/src/liquid.rs @@ -1,5 +1,5 @@ -use temper_block_data::PlacementContext; use crate::BlockBehavior; +use temper_block_data::PlacementContext; use temper_blocks_generated::LiquidBlock; impl BlockBehavior for LiquidBlock { diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs index 03baee0c..839b7664 100644 --- a/src/blocks/src/world_extensions.rs +++ b/src/blocks/src/world_extensions.rs @@ -15,7 +15,11 @@ pub trait WorldBlockUpdates { ) -> Result; fn block_is(&self, block_pos: BlockPos) -> bool; - fn block_is_and(&self, block_pos: BlockPos, callback: impl Fn(T) -> bool) -> bool; + fn block_is_and( + &self, + block_pos: BlockPos, + callback: impl Fn(T) -> bool, + ) -> bool; } impl WorldBlockUpdates for World { @@ -43,11 +47,16 @@ impl WorldBlockUpdates for World { .unwrap_or_default() } - fn block_is_and(&self, block_pos: BlockPos, callback: impl Fn(T) -> bool) -> bool { + fn block_is_and( + &self, + block_pos: BlockPos, + callback: impl Fn(T) -> bool, + ) -> bool { self.get_chunk(block_pos.chunk(), Dimension::Overworld) .and_then(|chunk| { let block_id = chunk.get_block(block_pos.chunk_block_pos()); - let block = T::try_from(block_id.raw()).map_err(|_| WorldError::InvalidBlock(block_id))?; + let block = + T::try_from(block_id.raw()).map_err(|_| WorldError::InvalidBlock(block_id))?; Ok(callback(block)) }) .unwrap_or_default() diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 274907c3..383fe20e 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -126,6 +126,12 @@ pub fn handle( ) .into(); + let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) + else { + error!("Can't get block at {}", offset_pos); + continue 'ev_loop; + }; + // Check if the block collides with any entities let does_collide = { pos_q.into_iter().any(|(pos, bounds)| { @@ -148,7 +154,7 @@ pub fn handle( }) }; - if does_collide { + if does_collide && curr_state.is_solid() { trace!("Block placement collided with entity"); continue 'ev_loop; } @@ -167,12 +173,6 @@ pub fn handle( player_rotation: rot, }; - let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) - else { - error!("Can't get block at {}", offset_pos); - continue 'ev_loop; - }; - if !curr_state.can_be_replaced(placement_context.clone()) { if let Err(err) = conn.send_packet_ref(&ack_packet) { error!("Failed to send block change ack packet: {:?}", err); @@ -203,7 +203,9 @@ pub fn handle( let mut placed_blocks = block_state.get_placement_state(placement_context); - placed_blocks.blocks.insert(offset_pos, block_state); + if placed_blocks.place_original { + placed_blocks.blocks.insert(offset_pos, block_state); + } for (block_pos, block_state) in placed_blocks.blocks.iter() { state From b9c7837b2e45e3f5f4b210b75d4c5c963e533b85 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Fri, 29 May 2026 16:21:53 -0500 Subject: [PATCH 29/30] Remove old block-placing crate --- Cargo.toml | 1 - src/game_systems/src/packets/Cargo.toml | 1 - src/world/block-placing/Cargo.toml | 21 -- src/world/block-placing/src/blocks/door.rs | 247 --------------- src/world/block-placing/src/blocks/fence.rs | 202 ------------- src/world/block-placing/src/blocks/logs.rs | 63 ---- src/world/block-placing/src/blocks/mod.rs | 5 - src/world/block-placing/src/blocks/slab.rs | 314 -------------------- src/world/block-placing/src/blocks/torch.rs | 49 --- src/world/block-placing/src/errors.rs | 24 -- src/world/block-placing/src/lib.rs | 112 ------- 11 files changed, 1039 deletions(-) delete mode 100644 src/world/block-placing/Cargo.toml delete mode 100644 src/world/block-placing/src/blocks/door.rs delete mode 100644 src/world/block-placing/src/blocks/fence.rs delete mode 100644 src/world/block-placing/src/blocks/logs.rs delete mode 100644 src/world/block-placing/src/blocks/mod.rs delete mode 100644 src/world/block-placing/src/blocks/slab.rs delete mode 100644 src/world/block-placing/src/blocks/torch.rs delete mode 100644 src/world/block-placing/src/errors.rs delete mode 100644 src/world/block-placing/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 5a4f75ea..f7a3fa87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,6 @@ members = [ "src/text", "src/utils", "src/world", - "src/world/block-placing", "src/world/db", "src/world/format", "src/world/gen", diff --git a/src/game_systems/src/packets/Cargo.toml b/src/game_systems/src/packets/Cargo.toml index 4340fbbf..65c0c69c 100644 --- a/src/game_systems/src/packets/Cargo.toml +++ b/src/game_systems/src/packets/Cargo.toml @@ -21,7 +21,6 @@ temper-blocks = { workspace = true } once_cell = { workspace = true } serde_json = { workspace = true } temper-macros = { workspace = true } -block-placing = { path = "../../../world/block-placing" } temper-entities = { workspace = true } bevy_math = { workspace = true } temper-world = { workspace = true } diff --git a/src/world/block-placing/Cargo.toml b/src/world/block-placing/Cargo.toml deleted file mode 100644 index c447f49c..00000000 --- a/src/world/block-placing/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "block-placing" -version = "0.1.0" -edition = "2024" - -[dependencies] -temper-core = { workspace = true } -temper-world = { workspace = true } -bevy_ecs = { workspace = true } -bevy_math = { workspace = true } -temper-components = { workspace = true } -temper-inventories = { workspace = true } -temper-codec = { workspace = true } -temper-macros = { workspace = true } -temper-state = { workspace = true } -temper-entities = { workspace = true } -tracing = { workspace = true } -thiserror = { workspace = true } - -[lints] -workspace = true diff --git a/src/world/block-placing/src/blocks/door.rs b/src/world/block-placing/src/blocks/door.rs deleted file mode 100644 index 1117b470..00000000 --- a/src/world/block-placing/src/blocks/door.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::errors::BlockPlaceError; -use crate::{BlockFace, BlockStateId}; -use crate::{BlockPlaceContext, PlacableBlock, PlacedBlocks}; -use bevy_math::IVec3; -use std::collections::BTreeMap; -use temper_core::block_data::BlockData; -use temper_core::dimension::Dimension; -use temper_macros::match_block; -use temper_state::GlobalState; -use tracing::error; - -pub(crate) struct PlaceableDoor; - -impl PlacableBlock for PlaceableDoor { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result { - let name = match context.item_used.to_name() { - Some(name) => name, - None => return Err(BlockPlaceError::ItemIdHasNoNameMapping(context.item_used)), - }; - - let target_block = { - let chunk = state - .world - .get_or_generate_chunk(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.get_block(context.block_position.chunk_block_pos()) - }; - if !match_block!("air", target_block) && !match_block!("cave_air", target_block) { - return Err(BlockPlaceError::TargetBlockNotEmpty(context.block_position)); - } - - let block_above = { - let chunk = state - .world - .get_or_generate_chunk(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.get_block((context.block_position.pos + IVec3::new(0, 1, 0)).into()) - }; - if !(match_block!("air", block_above) || match_block!("cave_air", block_above)) { - return Err(BlockPlaceError::TargetBlockNotEmpty( - context.block_position + IVec3::new(0, 1, 0).into(), - )); - }; - let facing = match context.face_clicked { - BlockFace::North => "south", - BlockFace::South => "north", - BlockFace::East => "west", - BlockFace::West => "east", - BlockFace::Top => { - // Facing is determined by player rotation when placing on top face - let yaw = (context.player_rotation.yaw + 180.0) % 360.0; - if (45.0..135.0).contains(&yaw) { - "east" - } else if (135.0..225.0).contains(&yaw) { - "south" - } else if (225.0..315.0).contains(&yaw) { - "west" - } else { - "north" - } - } - _ => return Err(BlockPlaceError::InvalidBlockFace(context.face_clicked)), - }; - let bottom_block = BlockData { - name: name.to_string(), - properties: Some(BTreeMap::from([ - ("facing".to_string(), facing.to_string()), - ("half".to_string(), "lower".to_string()), - ("hinge".to_string(), "left".to_string()), - ("open".to_string(), "false".to_string()), - ("powered".to_string(), "false".to_string()), - ])), - }; - let Some(bottom_block_id) = bottom_block.try_to_block_state_id() else { - error!("Block data '{bottom_block}' could not be converted to a block state ID"); - return Err(BlockPlaceError::BlockNotMappedToBlockStateId(bottom_block)); - }; - { - state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .set_block(context.block_position.chunk_block_pos(), bottom_block_id); - } - - let upper_block = BlockData { - name: name.to_string(), - properties: Some(BTreeMap::from([ - ("facing".to_string(), facing.to_string()), - ("half".to_string(), "upper".to_string()), - ("hinge".to_string(), "left".to_string()), - ("open".to_string(), "false".to_string()), - ("powered".to_string(), "false".to_string()), - ])), - }; - - let Some(upper_block_id) = upper_block.clone().try_to_block_state_id() else { - error!("Block data '{upper_block}' could not be converted to a block state ID"); - return Err(BlockPlaceError::BlockNotMappedToBlockStateId(upper_block)); - }; - { - state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .set_block( - (context.block_position + (0, 1, 0)).chunk_block_pos(), - upper_block_id, - ); - } - - Ok(PlacedBlocks { - blocks: std::collections::HashMap::from([ - (context.block_position, bottom_block_id), - (context.block_position + (0, 1, 0), upper_block_id), - ]), - take_item: true, - }) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::BlockPlaceContext; - use temper_components::player::rotation::Rotation; - use temper_core::dimension::Dimension; - use temper_core::pos::BlockPos; - use temper_macros::{block, item}; - - #[test] - fn test_place_door() { - let (state, _) = temper_state::create_test_state(); - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 64, 0), - face_clicked: BlockFace::Top, - click_position: Default::default(), - item_used: item!("oak_door"), - player_rotation: Rotation { - yaw: 90.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - let result = PlaceableDoor::place(context, state.0.clone()); - assert!(result.is_ok()); - let placed_blocks = result.unwrap(); - assert_eq!(placed_blocks.blocks.len(), 2); - let bottom_block_id = placed_blocks - .blocks - .get(&BlockPos::of(0, 64, 0)) - .expect("Bottom block not placed"); - let upper_block_id = placed_blocks - .blocks - .get(&BlockPos::of(0, 65, 0)) - .expect("Upper block not placed"); - assert_eq!( - state - .0 - .world - .get_or_generate_chunk(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .get_block(BlockPos::of(0, 64, 0).chunk_block_pos()), - *bottom_block_id - ); - assert_eq!( - state - .0 - .world - .get_or_generate_chunk(BlockPos::of(0, 65, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .get_block(BlockPos::of(0, 65, 0).chunk_block_pos()), - *upper_block_id - ); - } - - #[test] - fn test_place_door_with_block_above() { - let (state, _) = temper_state::create_test_state(); - // Place a block above the door position - { - let mut chunk = state - .0 - .world - .get_or_generate_mut(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.set_block(BlockPos::of(0, 65, 0).chunk_block_pos(), block!("stone")); // Some solid block - } - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 64, 0), - face_clicked: BlockFace::Top, - click_position: Default::default(), - item_used: item!("oak_door"), - player_rotation: Rotation { - yaw: 90.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - let result = PlaceableDoor::place(context, state.0.clone()); - assert!( - result.is_err(), - "Placing a door with a block above should return an error" - ); - } - - #[test] - fn test_place_door_on_invalid_face() { - let (state, _) = temper_state::create_test_state(); - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 64, 0), - face_clicked: BlockFace::Bottom, // Invalid face for door placement - click_position: Default::default(), - item_used: item!("oak_door"), - player_rotation: Rotation { - yaw: 90.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - let result = PlaceableDoor::place(context, state.0.clone()); - assert!( - result.is_err(), - "Placing a door on an invalid face should return an error" - ); - match result.err().unwrap() { - BlockPlaceError::InvalidBlockFace(face) => assert_eq!(face, BlockFace::Bottom), - _ => panic!("Expected InvalidBlockFace error"), - } - // Check that no blocks were placed - let chunk = state - .0 - .world - .get_or_generate_chunk(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - assert_eq!( - chunk.get_block(BlockPos::of(0, 64, 0).chunk_block_pos()), - block!("air") - ); - } -} diff --git a/src/world/block-placing/src/blocks/fence.rs b/src/world/block-placing/src/blocks/fence.rs deleted file mode 100644 index c565480d..00000000 --- a/src/world/block-placing/src/blocks/fence.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::BlockStateId; -use crate::errors::BlockPlaceError; -use crate::{BlockPlaceContext, PlacableBlock, PlacedBlocks}; -use bevy_math::IVec3; -use std::collections::{BTreeMap, HashMap}; -use temper_core::block_data::BlockData; -use temper_core::dimension::Dimension; -use temper_macros::match_block; -use temper_state::GlobalState; - -pub(crate) struct PlaceableFence; - -impl PlacableBlock for PlaceableFence { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result { - let name = match context.item_used.to_name() { - Some(name) => name, - None => return Err(BlockPlaceError::ItemIdHasNoNameMapping(context.item_used)), - }; - let target_block = { - let chunk = state - .world - .get_or_generate_chunk(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.get_block(context.block_position.chunk_block_pos()) - }; - if !match_block!("air", target_block) && !match_block!("cave_air", target_block) { - return Err(BlockPlaceError::TargetBlockNotEmpty(context.block_position)); - } - - let mut props = BTreeMap::from([ - ("east".to_string(), "false".to_string()), - ("west".to_string(), "false".to_string()), - ("north".to_string(), "false".to_string()), - ("south".to_string(), "false".to_string()), - ("waterlogged".to_string(), "false".to_string()), - ]); - - let adjacent_positions = [ - (context.block_position + IVec3::new(1, 0, 0).into(), "east"), - (context.block_position + IVec3::new(-1, 0, 0).into(), "west"), - (context.block_position + IVec3::new(0, 0, 1).into(), "south"), - ( - context.block_position + IVec3::new(0, 0, -1).into(), - "north", - ), - ]; - - let mut changed_blocks = HashMap::new(); - - for (pos, direction) in adjacent_positions { - let block_id = { - let chunk = state - .world - .get_or_generate_chunk(pos.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.get_block(pos.chunk_block_pos()) - }; - let block_data = block_id.to_block_data().unwrap_or_else(|| { - panic!("Block ID {} not found in block mappings file", block_id) - }); - let block_name = block_data - .name - .strip_prefix("minecraft:") - .unwrap_or(&block_data.name); - if block_name.ends_with("fence") - || block_name.ends_with("wall") - || block_name.ends_with("fence_gate") - { - props.insert(direction.to_string(), "true".to_string()); - // Update the adjacent block to connect to the new fence - // TODO: This should be moved to a proper block update system that updates all blocks around a changed block, but for now this will do - let mut adjacent_props = block_data.properties.unwrap_or_default(); - let opposite_direction = match direction { - "east" => "west", - "west" => "east", - "north" => "south", - "south" => "north", - _ => unreachable!(), - }; - adjacent_props.insert(opposite_direction.to_string(), "true".to_string()); - let updated_block_data = BlockData { - name: block_data.name.clone(), - properties: Some(adjacent_props), - }; - let updated_block_id = updated_block_data.to_block_state_id(); - state - .world - .get_or_generate_mut(pos.chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .set_block(pos.chunk_block_pos(), updated_block_id); - changed_blocks.insert(pos, updated_block_id); - } - } - - let block_data = BlockData { - name: name.to_string(), - properties: Some(props), - }; - - let block_state_id = block_data.to_block_state_id(); - state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk") - .set_block(context.block_position.chunk_block_pos(), block_state_id); - changed_blocks.insert(context.block_position, block_state_id); - - Ok(PlacedBlocks { - blocks: changed_blocks, - take_item: true, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::BlockFace; - use temper_core::pos::BlockPos; - use temper_macros::item; - use temper_state::create_test_state; - - #[test] - fn test_place_fence() { - let (state, _) = create_test_state(); - let context = BlockPlaceContext { - block_clicked: BlockStateId::new(0), - block_position: BlockPos::of(0, 64, 0), - face_clicked: BlockFace::Top, - click_position: (0.5, 1.0, 0.5).into(), - player_position: (0.0, 64.0, -1.0).into(), - player_rotation: (0.0, 0.0).into(), - item_used: item!("oak_fence"), // Assuming this maps to a fence item - }; - let result = PlaceableFence::place(context, state.0); - assert!(result.is_ok()); - let placed_blocks = result.unwrap(); - assert_eq!(placed_blocks.blocks.len(), 1); - } - - #[test] - fn test_connects_to_neighboring_fences() { - let (state, _) = create_test_state(); - let base_position = BlockPos::of(0, 64, 0); - // Place a fence at the base position - let context1 = BlockPlaceContext { - block_clicked: BlockStateId::new(0), - block_position: base_position, - face_clicked: BlockFace::Top, - click_position: (0.5, 1.0, 0.5).into(), - player_position: (0.0, 64.0, -1.0).into(), - player_rotation: (0.0, 0.0).into(), - item_used: item!("oak_fence"), - }; - PlaceableFence::place(context1, state.0.clone()).unwrap(); - - // Place another fence to the east of the first one - let context2 = BlockPlaceContext { - block_clicked: BlockStateId::new(0), - block_position: base_position + IVec3::new(1, 0, 0).into(), - face_clicked: BlockFace::Top, - click_position: (1.5, 1.0, 0.5).into(), - player_position: (1.0, 64.0, -1.0).into(), - player_rotation: (90.0, 0.0).into(), - item_used: item!("oak_fence"), - }; - PlaceableFence::place(context2, state.0.clone()).unwrap(); - - // Check that both fences have the correct properties to connect to each other - let chunk = state - .0 - .world - .get_or_generate_chunk(base_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - let block_id1 = chunk.get_block(base_position.chunk_block_pos()); - let block_id2 = - chunk.get_block((base_position + IVec3::new(1, 0, 0).into()).chunk_block_pos()); - let block_data1 = block_id1.to_block_data().unwrap(); - let block_data2 = block_id2.to_block_data().unwrap(); - assert_eq!( - block_data1 - .properties - .as_ref() - .unwrap() - .get("east") - .unwrap(), - "true" - ); - assert_eq!( - block_data2 - .properties - .as_ref() - .unwrap() - .get("west") - .unwrap(), - "true" - ); - } -} diff --git a/src/world/block-placing/src/blocks/logs.rs b/src/world/block-placing/src/blocks/logs.rs deleted file mode 100644 index b078b725..00000000 --- a/src/world/block-placing/src/blocks/logs.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::BlockStateId; -use crate::errors::BlockPlaceError; -use crate::{BlockFace, BlockPlaceContext, PlacableBlock, PlacedBlocks}; -use std::collections::BTreeMap; -use temper_core::block_data::BlockData; -use temper_macros::block; -use temper_state::GlobalState; - -pub(crate) struct PlacableLog; - -impl PlacableBlock for PlacableLog { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result { - let target_block = { - let chunk = state - .world - .get_or_generate_mut( - context.block_position.chunk(), - temper_core::dimension::Dimension::Overworld, - ) - .expect("Could not load chunk"); - chunk.get_block(context.block_position.chunk_block_pos()) - }; - if target_block != block!("air") && target_block != block!("cave_air") { - return Err(BlockPlaceError::TargetBlockNotEmpty(context.block_position)); - } - let axis = match context.face_clicked { - BlockFace::Top | BlockFace::Bottom => "y", - BlockFace::North | BlockFace::South => "z", - BlockFace::West | BlockFace::East => "x", - }; - - let block_name = match context.item_used.to_name() { - Some(name) => name, - None => return Err(BlockPlaceError::ItemIdHasNoNameMapping(context.item_used)), - }; - - let block_data = BlockData { - name: block_name, - properties: Some(BTreeMap::from([("axis".to_string(), axis.to_string())])), - }; - - let Some(block_id) = block_data.try_to_block_state_id() else { - return Err(BlockPlaceError::BlockNotMappedToBlockStateId(block_data)); - }; - - state - .world - .get_or_generate_mut( - context.block_position.chunk(), - temper_core::dimension::Dimension::Overworld, - ) - .expect("Could not load chunk") - .set_block(context.block_position.chunk_block_pos(), block_id); - - Ok(PlacedBlocks { - blocks: std::collections::HashMap::from([(context.block_position, block_id)]), - take_item: true, - }) - } -} diff --git a/src/world/block-placing/src/blocks/mod.rs b/src/world/block-placing/src/blocks/mod.rs deleted file mode 100644 index 117addcc..00000000 --- a/src/world/block-placing/src/blocks/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub(crate) mod door; -pub mod fence; -pub(crate) mod logs; -pub mod slab; -pub(super) mod torch; diff --git a/src/world/block-placing/src/blocks/slab.rs b/src/world/block-placing/src/blocks/slab.rs deleted file mode 100644 index 57305bd9..00000000 --- a/src/world/block-placing/src/blocks/slab.rs +++ /dev/null @@ -1,314 +0,0 @@ -use crate::errors::BlockPlaceError; -use crate::{BlockFace, BlockPlaceContext, PlacableBlock, PlacedBlocks}; -use bevy_math::DVec3; -use temper_state::GlobalState; - -pub(crate) struct PlaceableSlab; - -impl PlacableBlock for PlaceableSlab { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result { - fn get_block_data_at( - pos: &temper_core::pos::BlockPos, - state: &GlobalState, - ) -> temper_core::block_data::BlockData { - let chunk = state - .world - .get_or_generate_chunk(pos.chunk(), temper_core::dimension::Dimension::Overworld) - .expect("Could not load chunk"); - let block = chunk.get_block(pos.chunk_block_pos()); - temper_core::block_data::BlockData::from_block_state_id(block) - } - - fn is_same_slab_block(data: &temper_core::block_data::BlockData, block_name: &str) -> bool { - data.name == block_name - && data - .properties - .as_ref() - .and_then(|p| p.get("type")) - .map(|t| t != "double") - .unwrap_or(false) - } - - fn get_clicked_pos( - block_position: &temper_core::pos::BlockPos, - face: &crate::BlockFace, - ) -> temper_core::pos::BlockPos { - match face { - crate::BlockFace::Top => temper_core::pos::BlockPos::of( - block_position.pos.x, - block_position.pos.y - 1, - block_position.pos.z, - ), - crate::BlockFace::Bottom => temper_core::pos::BlockPos::of( - block_position.pos.x, - block_position.pos.y + 1, - block_position.pos.z, - ), - crate::BlockFace::North => temper_core::pos::BlockPos::of( - block_position.pos.x, - block_position.pos.y, - block_position.pos.z + 1, - ), - crate::BlockFace::South => temper_core::pos::BlockPos::of( - block_position.pos.x, - block_position.pos.y, - block_position.pos.z - 1, - ), - crate::BlockFace::East => temper_core::pos::BlockPos::of( - block_position.pos.x - 1, - block_position.pos.y, - block_position.pos.z, - ), - crate::BlockFace::West => temper_core::pos::BlockPos::of( - block_position.pos.x + 1, - block_position.pos.y, - block_position.pos.z, - ), - } - } - - fn get_half(face: &crate::BlockFace, click_position: &DVec3) -> &'static str { - match face { - crate::BlockFace::Top => "bottom", - crate::BlockFace::Bottom => "top", - _ => { - if click_position.y > 0.5 { - "top" - } else { - "bottom" - } - } - } - } - - let block_name = match context.item_used.to_name() { - Some(name) => name, - None => return Err(BlockPlaceError::ItemIdHasNoNameMapping(context.item_used)), - }; - - let clicked_pos = get_clicked_pos(&context.block_position, &context.face_clicked); - - let clicked_block_data = get_block_data_at(&clicked_pos, &state); - - let slab_type = clicked_block_data - .properties - .as_ref() - .and_then(|p| p.get("type")) - .map(|value| value.as_str()); - - let face_is_horizontal = context.face_clicked.is_horizontal(); - let above = context.click_position.y > 0.5; - - let should_combine = if !is_same_slab_block(&clicked_block_data, &block_name) { - false - } else if slab_type == Some("bottom") { - context.face_clicked == BlockFace::Top || above && face_is_horizontal - } else { - context.face_clicked == BlockFace::Bottom || !above && face_is_horizontal - }; - - let (place_position, existing_block_data) = if should_combine { - (clicked_pos, clicked_block_data) - } else { - let existing_block_data = get_block_data_at(&context.block_position, &state); - (context.block_position, existing_block_data) - }; - - let is_same_slab = is_same_slab_block(&existing_block_data, &block_name); - - let block_data = if is_same_slab { - temper_core::block_data::BlockData { - name: block_name.to_string(), - properties: Some(std::collections::BTreeMap::::from([ - ("type".to_string(), "double".to_string()), - ("waterlogged".to_string(), "false".to_string()), - ])), - } - } else if existing_block_data.name == "minecraft:air" { - let half = get_half(&context.face_clicked, &context.click_position); - - temper_core::block_data::BlockData { - name: block_name.to_string(), - properties: Some(std::collections::BTreeMap::::from([ - ("type".to_string(), half.to_string()), - ("waterlogged".to_string(), "false".to_string()), - ])), - } - } else { - // Cancel placement if the location is occupied by a block other than air or a combinable slab, or if it's already a double slab - return Ok(PlacedBlocks { - blocks: std::collections::HashMap::new(), - take_item: false, - }); - }; - - let Some(block_id) = block_data.try_to_block_state_id() else { - return Err(BlockPlaceError::BlockNotMappedToBlockStateId(block_data)); - }; - - state - .world - .get_or_generate_mut( - place_position.chunk(), - temper_core::dimension::Dimension::Overworld, - ) - .expect("Could not load chunk") - .set_block(place_position.chunk_block_pos(), block_id); - - Ok(PlacedBlocks { - blocks: std::collections::HashMap::from([(place_position, block_id)]), - take_item: true, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::BlockStateId; - use std::collections::BTreeMap; - use temper_components::player::rotation::Rotation; - use temper_core::block_data::BlockData; - use temper_core::dimension::Dimension; - use temper_core::pos::BlockPos; - use temper_macros::{block, item}; - - fn slab_block_id(name: &str, slab_type: &str) -> BlockStateId { - let bd = BlockData { - name: name.to_string(), - properties: Some(BTreeMap::from([ - ("type".to_string(), slab_type.to_string()), - ("waterlogged".to_string(), "false".to_string()), - ])), - }; - bd.try_to_block_state_id() - .expect("slab block id should exist") - } - - #[test] - fn test_combine_slab_into_double() { - let (state, _tmp) = temper_state::create_test_state(); - - // Place an oak bottom slab at (0,64,0) - let bottom_id = slab_block_id("minecraft:oak_slab", "bottom"); - { - let mut chunk = state - .0 - .world - .get_or_generate_mut(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.set_block(BlockPos::of(0, 64, 0).chunk_block_pos(), bottom_id); - } - - // Now simulate placing an oak slab by clicking the top face of the block above (so clicked_pos points to 0,64,0) - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 65, 0), - face_clicked: crate::BlockFace::Top, - click_position: Default::default(), - item_used: item!("oak_slab"), - player_rotation: Rotation { - yaw: 0.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - - let result = PlaceableSlab::place(context, state.0.clone()); - assert!(result.is_ok()); - let placed = result.unwrap(); - - // Expect the bottom slab to have been converted to a double at (0,64,0) - let double_id = slab_block_id("minecraft:oak_slab", "double"); - assert_eq!(placed.blocks.len(), 1); - assert_eq!( - placed.blocks.get(&BlockPos::of(0, 64, 0)).copied(), - Some(double_id) - ); - - // And world should reflect the double slab - let chunk = state - .0 - .world - .get_or_generate_chunk(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - assert_eq!( - chunk.get_block(BlockPos::of(0, 64, 0).chunk_block_pos()), - double_id - ); - } - - #[test] - fn test_cancel_when_target_not_air() { - let (state, _tmp) = temper_state::create_test_state(); - - // Put a solid block (stone) at the target position - { - let mut chunk = state - .0 - .world - .get_or_generate_mut(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.set_block(BlockPos::of(0, 64, 0).chunk_block_pos(), block!("stone")); - } - - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 64, 0), - face_clicked: crate::BlockFace::Top, - click_position: Default::default(), - item_used: item!("oak_slab"), - player_rotation: Rotation { - yaw: 0.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - - let result = PlaceableSlab::place(context, state.0.clone()); - assert!(result.is_ok()); - let placed = result.unwrap(); - // Should cancel placement - assert!(placed.blocks.is_empty()); - assert!(!placed.take_item); - } - - #[test] - fn test_cancel_when_target_already_double() { - let (state, _tmp) = temper_state::create_test_state(); - - // Put a double oak slab at (0,64,0) - let double_id = slab_block_id("minecraft:oak_slab", "double"); - { - let mut chunk = state - .0 - .world - .get_or_generate_mut(BlockPos::of(0, 64, 0).chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.set_block(BlockPos::of(0, 64, 0).chunk_block_pos(), double_id); - } - - let context = BlockPlaceContext { - block_clicked: Default::default(), - block_position: BlockPos::of(0, 64, 0), - face_clicked: crate::BlockFace::Top, - click_position: Default::default(), - item_used: item!("oak_slab"), - player_rotation: Rotation { - yaw: 0.0, - pitch: 0.0, - }, - player_position: Default::default(), - }; - - let result = PlaceableSlab::place(context, state.0.clone()); - assert!(result.is_ok()); - let placed = result.unwrap(); - // Should cancel placement because target is already double - assert!(placed.blocks.is_empty()); - assert!(!placed.take_item); - } -} diff --git a/src/world/block-placing/src/blocks/torch.rs b/src/world/block-placing/src/blocks/torch.rs deleted file mode 100644 index 2521d85a..00000000 --- a/src/world/block-placing/src/blocks/torch.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::errors::BlockPlaceError; -use crate::{BlockFace, BlockPlaceContext}; -use crate::{BlockStateId, PlacableBlock, PlacedBlocks}; -use std::collections::HashMap; -use temper_core::dimension::Dimension; -use temper_macros::block; -use temper_state::GlobalState; - -pub(crate) struct PlaceableTorch; - -impl PlacableBlock for PlaceableTorch { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result { - let target_block = { - let chunk = state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld) - .expect("Could not load chunk"); - chunk.get_block(context.block_position.chunk_block_pos()) - }; - if target_block != block!("air") && target_block != block!("cave_air") { - return Err(BlockPlaceError::TargetBlockNotEmpty(context.block_position)); - } - - let block = match context.face_clicked { - BlockFace::Top => block!("torch"), - BlockFace::East => block!("wall_torch", {facing: "east"}), - BlockFace::West => block!("wall_torch", {facing: "west"}), - BlockFace::North => block!("wall_torch", {facing: "north"}), - BlockFace::South => block!("wall_torch", {facing: "south"}), - BlockFace::Bottom => { - return Ok(PlacedBlocks { - blocks: HashMap::new(), - take_item: false, - }); - } // can't place on bottom face - }; - state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld)? - .set_block(context.block_position.chunk_block_pos(), block); - Ok(PlacedBlocks { - blocks: HashMap::from([(context.block_position, block)]), - take_item: true, - }) - } -} diff --git a/src/world/block-placing/src/errors.rs b/src/world/block-placing/src/errors.rs deleted file mode 100644 index 406b24a6..00000000 --- a/src/world/block-placing/src/errors.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::BlockFace; -use temper_core::block_data::BlockData; -use temper_core::pos::BlockPos; -use temper_inventories::item::ItemID; -use temper_world::WorldError; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum BlockPlaceError { - #[error("Invalid block face for placement")] - InvalidBlockFace(BlockFace), - #[error("Target block is not empty")] - TargetBlockNotEmpty(BlockPos), - #[error("Item cannot be placed as a block")] - ItemNotPlaceable(ItemID), - #[error("World Error: {0}")] - WorldError(#[from] WorldError), - #[error("Item can't be mapped to block")] - ItemNotMappedToBlock(ItemID), - #[error("Block can't be mapped to block state id")] - BlockNotMappedToBlockStateId(BlockData), - #[error("Item ID {0} does not have a name mapping")] - ItemIdHasNoNameMapping(ItemID), -} diff --git a/src/world/block-placing/src/lib.rs b/src/world/block-placing/src/lib.rs deleted file mode 100644 index 79ed21ae..00000000 --- a/src/world/block-placing/src/lib.rs +++ /dev/null @@ -1,112 +0,0 @@ -mod blocks; -mod errors; - -use crate::errors::BlockPlaceError; -use bevy_math::DVec3; -use std::collections::HashMap; -use temper_components::player::position::Position; -use temper_components::player::rotation::Rotation; -use temper_core::block_state_id::{ - BlockStateId, ITEM_TO_BLOCK_MAPPING, create_item_to_block_mapping, -}; -use temper_core::dimension::Dimension; -use temper_core::pos::BlockPos; -use temper_inventories::item::ItemID; -use temper_state::GlobalState; - -pub struct PlacedBlocks { - pub blocks: HashMap, - pub take_item: bool, -} - -pub enum PlaceResult { - Placed(PlacedBlocks), - SpawnMob(temper_entities::entity_types::EntityTypeEnum), -} - -pub trait PlacableBlock { - fn place( - context: BlockPlaceContext, - state: GlobalState, - ) -> Result; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum BlockFace { - Top, - Bottom, - North, - South, - West, - East, -} - -impl BlockFace { - pub fn is_vertical(&self) -> bool { - matches!(self, Self::Top | Self::Bottom) - } - - pub fn is_horizontal(&self) -> bool { - matches!(self, Self::North | Self::South | Self::West | Self::East) - } -} - -pub struct BlockPlaceContext { - pub block_clicked: BlockStateId, - pub block_position: BlockPos, - pub face_clicked: BlockFace, - pub click_position: DVec3, - pub player_position: Position, - pub player_rotation: Rotation, - pub item_used: ItemID, -} - -pub fn place_item( - state: GlobalState, - context: BlockPlaceContext, -) -> Result { - let Some(item_name) = context.item_used.to_name() else { - return Err(BlockPlaceError::ItemIdHasNoNameMapping(context.item_used)); - }; - let item_name = item_name.strip_prefix("minecraft:").unwrap_or(&item_name); - - if let Some(entity_type) = item_name - .strip_suffix("_spawn_egg") - .and_then(temper_entities::entity_types::EntityTypeEnum::from_snake_case) - { - return Ok(PlaceResult::SpawnMob(entity_type)); - } - - if item_name == "torch" { - blocks::torch::PlaceableTorch::place(context, state).map(PlaceResult::Placed) - } else if item_name.ends_with("_slab") { - blocks::slab::PlaceableSlab::place(context, state).map(PlaceResult::Placed) - } else if item_name.ends_with("_door") { - blocks::door::PlaceableDoor::place(context, state).map(PlaceResult::Placed) - } else if item_name.ends_with("_log") { - blocks::logs::PlacableLog::place(context, state).map(PlaceResult::Placed) - } else if item_name.ends_with("_fence") { - blocks::fence::PlaceableFence::place(context, state).map(PlaceResult::Placed) - } else { - let block_opt = ITEM_TO_BLOCK_MAPPING - .get_or_init(create_item_to_block_mapping) - .get(&context.item_used.0.0); - if let Some(block) = block_opt { - match state - .world - .get_or_generate_mut(context.block_position.chunk(), Dimension::Overworld) - { - Ok(mut chunk) => { - chunk.set_block(context.block_position.chunk_block_pos(), *block); - Ok(PlaceResult::Placed(PlacedBlocks { - blocks: HashMap::from([(context.block_position, *block)]), - take_item: true, - })) - } - Err(e) => Err(e.into()), - } - } else { - Err(BlockPlaceError::ItemNotPlaceable(context.item_used)) - } - } -} From 6c780b087fb6e2ea48fad1eec70c2db0da205fbc Mon Sep 17 00:00:00 2001 From: ReCore Date: Mon, 1 Jun 2026 11:52:44 +0930 Subject: [PATCH 30/30] Added cache for cooldowns and fixed render distance --- Cargo.toml | 1 + src/game_systems/src/interactions/Cargo.toml | 1 + src/game_systems/src/interactions/src/lib.rs | 37 +++++++++++++------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f7a3fa87..88792e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -232,6 +232,7 @@ uuid = { version = "1.23.1", features = ["v4", "v3", "serde"] } indexmap = { version = "2.14.0", features = ["serde"] } bimap = "0.6.3" arrayvec = "0.7.6" +fastcache = "0.1.7" # Macros lazy_static = "1.5.0" diff --git a/src/game_systems/src/interactions/Cargo.toml b/src/game_systems/src/interactions/Cargo.toml index e4ae00f3..1340034a 100644 --- a/src/game_systems/src/interactions/Cargo.toml +++ b/src/game_systems/src/interactions/Cargo.toml @@ -16,6 +16,7 @@ temper-state = { workspace = true } temper-world = { workspace = true } tracing = { workspace = true } temper-blocks = { workspace = true } +fastcache = { workspace = true } [dev-dependencies] temper-macros = { workspace = true } diff --git a/src/game_systems/src/interactions/src/lib.rs b/src/game_systems/src/interactions/src/lib.rs index 139af8dd..428c6fae 100644 --- a/src/game_systems/src/interactions/src/lib.rs +++ b/src/game_systems/src/interactions/src/lib.rs @@ -15,12 +15,13 @@ use bevy_ecs::change_detection::Res; use bevy_ecs::entity::Entity; use bevy_ecs::message::MessageReader; use bevy_ecs::prelude::{Local, Query}; -use std::collections::HashMap; +use fastcache::Cache; use std::time::{Duration, Instant}; use temper_blocks::BlockDispatch; use temper_codec::net_types::network_position::NetworkPosition; use temper_codec::net_types::var_int::VarInt; use temper_components::InteractionCooldown; +use temper_components::player::client_information::ClientInformationComponent; use temper_components::player::position::Position; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; @@ -34,8 +35,13 @@ use tracing::{debug, error}; pub fn handle_block_interact( mut events: MessageReader, state: Res, - query: Query<(Entity, &StreamWriter, &Position)>, - mut cooldowns: Local>, + query: Query<( + Entity, + &StreamWriter, + &Position, + &ClientInformationComponent, + )>, + mut cooldowns: Local>>, ) { let cooldown_duration = Duration::from_millis(InteractionCooldown::default().cooldown_ms); @@ -43,11 +49,12 @@ pub fn handle_block_interact( let pos = event.position; // Ignore rapid repeated interactions on the same block - if cooldowns - .get(&pos) - .is_some_and(|t| t.elapsed() < cooldown_duration) + if let Some(cooldowns_map) = cooldowns.as_ref() + && cooldowns_map + .get(&pos) + .is_some_and(|t| t.elapsed() < cooldown_duration) { - if let Ok((_, conn, _)) = query.get(event.player) { + if let Ok((_, conn, _, _)) = query.get(event.player) { let ack = BlockChangeAck { sequence: event.sequence, }; @@ -57,7 +64,9 @@ pub fn handle_block_interact( } continue; } - cooldowns.insert(pos, Instant::now()); + cooldowns + .get_or_insert(Cache::new(512, Duration::from_secs(30))) + .insert(pos, Instant::now()); // Load the chunk and get current block state let mut block_state = state @@ -112,7 +121,7 @@ pub fn handle_block_interact( }; // chunk lock released here // Send BlockChangeAck to the player - if let Ok((_, conn, _)) = query.get(event.player) { + if let Ok((_, conn, _, _)) = query.get(event.player) { let ack = BlockChangeAck { sequence: event.sequence, }; @@ -124,14 +133,16 @@ pub fn handle_block_interact( // Broadcast BlockUpdate to all players within render distance let block_chunk = pos.chunk(); let (block_cx, block_cz) = (block_chunk.x(), block_chunk.z()); - let render_distance = state.0.config.chunk_render_distance as i32; + let render_distance = state.0.config.chunk_render_distance; - for (_, conn, player_pos) in query.iter() { + for (_, conn, player_pos, client_info) in query.iter() { let pchunk = player_pos.chunk(); let (pcx, pcz) = (pchunk.x(), pchunk.z()); - if (block_cx - pcx).abs() <= render_distance - && (block_cz - pcz).abs() <= render_distance + let player_render_distance = u32::from(client_info.view_distance).min(render_distance); + + if (block_cx - pcx).abs() <= player_render_distance as i32 + && (block_cz - pcz).abs() <= player_render_distance as i32 { for update in &updates { if let Err(e) = conn.send_packet_ref(update) {