From b0bd992adcff71ee294dd05060e00e652f62a7b2 Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Sun, 16 Mar 2025 13:41:17 -0500 Subject: [PATCH] Fluid physics fixes (#210) * start fixing code related to fluid physics * implement force_solid for blocks * afk pool test --- azalea-block/src/behavior.rs | 1 - azalea-block/src/generated.rs | 388 +++++++++--------- azalea-client/src/entity_query.rs | 4 +- azalea-client/src/plugins/brand.rs | 2 +- azalea-core/src/aabb.rs | 70 ++-- azalea-core/src/delta.rs | 4 +- azalea-core/src/direction.rs | 2 +- azalea-core/src/position.rs | 25 ++ azalea-entity/src/lib.rs | 4 +- azalea-physics/src/clip.rs | 11 - .../src/collision/entity_collisions.rs | 97 +++++ azalea-physics/src/collision/mod.rs | 10 +- azalea-physics/src/collision/shape.rs | 11 +- .../src/collision/world_collisions.rs | 220 +++++++--- azalea-physics/src/fluids.rs | 64 +-- azalea-physics/src/lib.rs | 59 ++- azalea-physics/src/travel.rs | 131 +++++- azalea-physics/tests/physics.rs | 138 +++++++ azalea-protocol/src/connect.rs | 2 +- azalea/src/accept_resource_packs.rs | 6 +- codegen/genblocks.py | 3 +- codegen/lib/code/blocks.py | 13 +- codegen/lib/extract.py | 23 +- codegen/lib/mappings.py | 1 - 24 files changed, 888 insertions(+), 401 deletions(-) create mode 100644 azalea-physics/src/collision/entity_collisions.rs diff --git a/azalea-block/src/behavior.rs b/azalea-block/src/behavior.rs index aeae8a74..37487b35 100755 --- a/azalea-block/src/behavior.rs +++ b/azalea-block/src/behavior.rs @@ -56,7 +56,6 @@ impl BlockBehavior { self } - // TODO: currently unused pub fn force_solid(mut self, force_solid: bool) -> Self { self.force_solid = Some(force_solid); self diff --git a/azalea-block/src/generated.rs b/azalea-block/src/generated.rs index de360550..afc131c3 100755 --- a/azalea-block/src/generated.rs +++ b/azalea-block/src/generated.rs @@ -2352,7 +2352,7 @@ make_block_states! { "extended": Extended(false), "facing": FacingCubic::North, }, - cobweb => BlockBehavior::new().requires_correct_tool_for_drops().strength(4.0, 4.0), {}, + cobweb => BlockBehavior::new().requires_correct_tool_for_drops().strength(4.0, 4.0).force_solid(true), {}, short_grass => BlockBehavior::new(), {}, fern => BlockBehavior::new(), {}, dead_bush => BlockBehavior::new(), {}, @@ -2385,7 +2385,7 @@ make_block_states! { green_wool => BlockBehavior::new().strength(0.8, 0.8), {}, red_wool => BlockBehavior::new().strength(0.8, 0.8), {}, black_wool => BlockBehavior::new().strength(0.8, 0.8), {}, - moving_piston => BlockBehavior::new().destroy_time(-1.0), { + moving_piston => BlockBehavior::new().destroy_time(-1.0).force_solid(true), { "type": PistonType::Normal, "facing": FacingCubic::North, }, @@ -2474,43 +2474,43 @@ make_block_states! { "facing": FacingCardinal::North, "lit": Lit(false), }, - oak_sign => BlockBehavior::new().strength(1.0, 1.0), { + oak_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": OakSignRotation::_0, "waterlogged": Waterlogged(false), }, - spruce_sign => BlockBehavior::new().strength(1.0, 1.0), { + spruce_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": SpruceSignRotation::_0, "waterlogged": Waterlogged(false), }, - birch_sign => BlockBehavior::new().strength(1.0, 1.0), { + birch_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": BirchSignRotation::_0, "waterlogged": Waterlogged(false), }, - acacia_sign => BlockBehavior::new().strength(1.0, 1.0), { + acacia_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": AcaciaSignRotation::_0, "waterlogged": Waterlogged(false), }, - cherry_sign => BlockBehavior::new().strength(1.0, 1.0), { + cherry_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": CherrySignRotation::_0, "waterlogged": Waterlogged(false), }, - jungle_sign => BlockBehavior::new().strength(1.0, 1.0), { + jungle_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": JungleSignRotation::_0, "waterlogged": Waterlogged(false), }, - dark_oak_sign => BlockBehavior::new().strength(1.0, 1.0), { + dark_oak_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": DarkOakSignRotation::_0, "waterlogged": Waterlogged(false), }, - pale_oak_sign => BlockBehavior::new(), { + pale_oak_sign => BlockBehavior::new().force_solid(true), { "rotation": PaleOakSignRotation::_0, "waterlogged": Waterlogged(false), }, - mangrove_sign => BlockBehavior::new().strength(1.0, 1.0), { + mangrove_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": MangroveSignRotation::_0, "waterlogged": Waterlogged(false), }, - bamboo_sign => BlockBehavior::new().strength(1.0, 1.0), { + bamboo_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": BambooSignRotation::_0, "waterlogged": Waterlogged(false), }, @@ -2521,7 +2521,7 @@ make_block_states! { "open": Open(false), "powered": Powered(false), }, - ladder => BlockBehavior::new().strength(0.4, 0.4), { + ladder => BlockBehavior::new().strength(0.4, 0.4).force_solid(false), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, @@ -2535,151 +2535,151 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - oak_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + oak_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - spruce_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + spruce_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - birch_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + birch_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - acacia_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + acacia_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - cherry_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + cherry_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - jungle_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + jungle_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - dark_oak_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + dark_oak_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - pale_oak_wall_sign => BlockBehavior::new(), { + pale_oak_wall_sign => BlockBehavior::new().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - mangrove_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + mangrove_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - bamboo_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + bamboo_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - oak_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + oak_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": OakHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - spruce_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + spruce_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": SpruceHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - birch_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + birch_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": BirchHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - acacia_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + acacia_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": AcaciaHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - cherry_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + cherry_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": CherryHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - jungle_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + jungle_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": JungleHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - dark_oak_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + dark_oak_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": DarkOakHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - pale_oak_hanging_sign => BlockBehavior::new(), { + pale_oak_hanging_sign => BlockBehavior::new().force_solid(true), { "attached": Attached(false), "rotation": PaleOakHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - crimson_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + crimson_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": CrimsonHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - warped_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + warped_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": WarpedHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - mangrove_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + mangrove_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": MangroveHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - bamboo_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + bamboo_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "attached": Attached(false), "rotation": BambooHangingSignRotation::_0, "waterlogged": Waterlogged(false), }, - oak_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + oak_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - spruce_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + spruce_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - birch_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + birch_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - acacia_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + acacia_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - cherry_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + cherry_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - jungle_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + jungle_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - dark_oak_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + dark_oak_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - pale_oak_wall_hanging_sign => BlockBehavior::new(), { + pale_oak_wall_hanging_sign => BlockBehavior::new().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - mangrove_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + mangrove_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - crimson_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + crimson_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - warped_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + warped_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - bamboo_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0), { + bamboo_wall_hanging_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, @@ -2688,7 +2688,7 @@ make_block_states! { "facing": FacingCardinal::North, "powered": Powered(false), }, - stone_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5), { + stone_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, iron_door => BlockBehavior::new().requires_correct_tool_for_drops().strength(5.0, 5.0), { @@ -2698,34 +2698,34 @@ make_block_states! { "open": Open(false), "powered": Powered(false), }, - oak_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + oak_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - spruce_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + spruce_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - birch_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + birch_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - jungle_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + jungle_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - acacia_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + acacia_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - cherry_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + cherry_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - dark_oak_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + dark_oak_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - pale_oak_pressure_plate => BlockBehavior::new(), { + pale_oak_pressure_plate => BlockBehavior::new().force_solid(true), { "powered": Powered(false), }, - mangrove_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + mangrove_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - bamboo_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + bamboo_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, redstone_ore => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.0, 3.0), { @@ -2746,7 +2746,7 @@ make_block_states! { "facing": FacingCardinal::North, "powered": Powered(false), }, - snow => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.1, 0.1), { + snow => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.1, 0.1).force_solid(false), { "layers": SnowLayers::_1, }, ice => BlockBehavior::new().strength(0.5, 0.5).friction(0.98), {}, @@ -2761,7 +2761,7 @@ make_block_states! { jukebox => BlockBehavior::new().strength(2.0, 6.0), { "has_record": HasRecord(false), }, - oak_fence => BlockBehavior::new().strength(2.0, 3.0), { + oak_fence => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "east": East(false), "north": North(false), "south": South(false), @@ -2791,7 +2791,7 @@ make_block_states! { jack_o_lantern => BlockBehavior::new().strength(1.0, 1.0), { "facing": FacingCardinal::North, }, - cake => BlockBehavior::new().strength(0.5, 0.5), { + cake => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "bites": CakeBites::_0, }, repeater => BlockBehavior::new(), { @@ -2929,7 +2929,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": West(false), }, - chain => BlockBehavior::new().requires_correct_tool_for_drops().strength(5.0, 6.0), { + chain => BlockBehavior::new().requires_correct_tool_for_drops().strength(5.0, 6.0).force_solid(true), { "axis": Axis::Y, "waterlogged": Waterlogged(false), }, @@ -2979,7 +2979,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": West(false), }, - oak_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + oak_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), @@ -3123,7 +3123,7 @@ make_block_states! { "facing": FacingCubic::North, }, beacon => BlockBehavior::new().strength(3.0, 3.0), {}, - cobblestone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + cobblestone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -3131,7 +3131,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - mossy_cobblestone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + mossy_cobblestone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -3294,10 +3294,10 @@ make_block_states! { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - light_weighted_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5), { + light_weighted_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5).force_solid(true), { "power": LightWeightedPressurePlatePower::_0, }, - heavy_weighted_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5), { + heavy_weighted_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5).force_solid(true), { "power": HeavyWeightedPressurePlatePower::_0, }, comparator => BlockBehavior::new(), { @@ -3594,100 +3594,100 @@ make_block_states! { large_fern => BlockBehavior::new(), { "half": Half::Lower, }, - white_banner => BlockBehavior::new().strength(1.0, 1.0), { + white_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": WhiteBannerRotation::_0, }, - orange_banner => BlockBehavior::new().strength(1.0, 1.0), { + orange_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": OrangeBannerRotation::_0, }, - magenta_banner => BlockBehavior::new().strength(1.0, 1.0), { + magenta_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": MagentaBannerRotation::_0, }, - light_blue_banner => BlockBehavior::new().strength(1.0, 1.0), { + light_blue_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": LightBlueBannerRotation::_0, }, - yellow_banner => BlockBehavior::new().strength(1.0, 1.0), { + yellow_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": YellowBannerRotation::_0, }, - lime_banner => BlockBehavior::new().strength(1.0, 1.0), { + lime_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": LimeBannerRotation::_0, }, - pink_banner => BlockBehavior::new().strength(1.0, 1.0), { + pink_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": PinkBannerRotation::_0, }, - gray_banner => BlockBehavior::new().strength(1.0, 1.0), { + gray_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": GrayBannerRotation::_0, }, - light_gray_banner => BlockBehavior::new().strength(1.0, 1.0), { + light_gray_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": LightGrayBannerRotation::_0, }, - cyan_banner => BlockBehavior::new().strength(1.0, 1.0), { + cyan_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": CyanBannerRotation::_0, }, - purple_banner => BlockBehavior::new().strength(1.0, 1.0), { + purple_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": PurpleBannerRotation::_0, }, - blue_banner => BlockBehavior::new().strength(1.0, 1.0), { + blue_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": BlueBannerRotation::_0, }, - brown_banner => BlockBehavior::new().strength(1.0, 1.0), { + brown_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": BrownBannerRotation::_0, }, - green_banner => BlockBehavior::new().strength(1.0, 1.0), { + green_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": GreenBannerRotation::_0, }, - red_banner => BlockBehavior::new().strength(1.0, 1.0), { + red_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": RedBannerRotation::_0, }, - black_banner => BlockBehavior::new().strength(1.0, 1.0), { + black_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": BlackBannerRotation::_0, }, - white_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + white_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - orange_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + orange_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - magenta_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + magenta_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - light_blue_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + light_blue_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - yellow_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + yellow_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - lime_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + lime_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - pink_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + pink_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - gray_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + gray_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - light_gray_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + light_gray_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - cyan_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + cyan_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - purple_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + purple_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - blue_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + blue_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - brown_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + brown_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - green_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + green_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - red_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + red_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, - black_wall_banner => BlockBehavior::new().strength(1.0, 1.0), { + black_wall_banner => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, }, red_sandstone => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.8, 0.8), {}, @@ -3803,55 +3803,55 @@ make_block_states! { smooth_sandstone => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), {}, smooth_quartz => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), {}, smooth_red_sandstone => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), {}, - spruce_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + spruce_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - birch_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + birch_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - jungle_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + jungle_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - acacia_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + acacia_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - cherry_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + cherry_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - dark_oak_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + dark_oak_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - pale_oak_fence_gate => BlockBehavior::new(), { + pale_oak_fence_gate => BlockBehavior::new().force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - mangrove_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + mangrove_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - bamboo_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + bamboo_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), @@ -3983,10 +3983,10 @@ make_block_states! { "open": Open(false), "powered": Powered(false), }, - end_rod => BlockBehavior::new(), { + end_rod => BlockBehavior::new().force_solid(false), { "facing": FacingCubic::Up, }, - chorus_plant => BlockBehavior::new().strength(0.4, 0.4), { + chorus_plant => BlockBehavior::new().strength(0.4, 0.4).force_solid(false), { "down": Down(false), "east": East(false), "north": North(false), @@ -3994,7 +3994,7 @@ make_block_states! { "up": Up(false), "west": West(false), }, - chorus_flower => BlockBehavior::new().strength(0.4, 0.4), { + chorus_flower => BlockBehavior::new().strength(0.4, 0.4).force_solid(false), { "age": ChorusFlowerAge::_0, }, purpur_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, @@ -4045,55 +4045,55 @@ make_block_states! { "facing": FacingCubic::South, "powered": Powered(false), }, - shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - white_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + white_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - orange_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + orange_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - magenta_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + magenta_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - light_blue_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + light_blue_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - yellow_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + yellow_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - lime_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + lime_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - pink_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + pink_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - gray_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + gray_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - light_gray_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + light_gray_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - cyan_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + cyan_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - purple_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + purple_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - blue_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + blue_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - brown_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + brown_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - green_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + green_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - red_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + red_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, - black_shulker_box => BlockBehavior::new().strength(2.0, 2.0), { + black_shulker_box => BlockBehavior::new().strength(2.0, 2.0).force_solid(true), { "facing": FacingCubic::Up, }, white_glazed_terracotta => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.4, 1.4), { @@ -4181,36 +4181,36 @@ make_block_states! { }, kelp_plant => BlockBehavior::new(), {}, dried_kelp_block => BlockBehavior::new().strength(0.5, 2.5), {}, - turtle_egg => BlockBehavior::new().strength(0.5, 0.5), { + turtle_egg => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "eggs": TurtleEggEggs::_1, "hatch": TurtleEggHatch::_0, }, sniffer_egg => BlockBehavior::new().strength(0.5, 0.5), { "hatch": SnifferEggHatch::_0, }, - dead_tube_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, - dead_brain_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, - dead_bubble_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, - dead_fire_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, - dead_horn_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, + dead_tube_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), {}, + dead_brain_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), {}, + dead_bubble_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), {}, + dead_fire_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), {}, + dead_horn_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), {}, tube_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, brain_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, bubble_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, fire_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, horn_coral_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), {}, - dead_tube_coral => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_tube_coral => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_brain_coral => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_brain_coral => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_bubble_coral => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_bubble_coral => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_fire_coral => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_fire_coral => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_horn_coral => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_horn_coral => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, tube_coral => BlockBehavior::new(), { @@ -4228,19 +4228,19 @@ make_block_states! { horn_coral => BlockBehavior::new(), { "waterlogged": Waterlogged(true), }, - dead_tube_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_tube_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_brain_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_brain_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_bubble_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_bubble_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_fire_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_fire_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, - dead_horn_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_horn_coral_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "waterlogged": Waterlogged(true), }, tube_coral_fan => BlockBehavior::new(), { @@ -4258,23 +4258,23 @@ make_block_states! { horn_coral_fan => BlockBehavior::new(), { "waterlogged": Waterlogged(true), }, - dead_tube_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_tube_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(true), }, - dead_brain_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_brain_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(true), }, - dead_bubble_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_bubble_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(true), }, - dead_fire_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_fire_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(true), }, - dead_horn_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops(), { + dead_horn_coral_wall_fan => BlockBehavior::new().requires_correct_tool_for_drops().force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(true), }, @@ -4303,11 +4303,11 @@ make_block_states! { "waterlogged": Waterlogged(true), }, blue_ice => BlockBehavior::new().strength(2.8, 2.8).friction(0.989), {}, - conduit => BlockBehavior::new().strength(3.0, 3.0), { + conduit => BlockBehavior::new().strength(3.0, 3.0).force_solid(true), { "waterlogged": Waterlogged(true), }, - bamboo_sapling => BlockBehavior::new().strength(1.0, 1.0), {}, - bamboo => BlockBehavior::new().strength(1.0, 1.0), { + bamboo_sapling => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), {}, + bamboo => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "age": BambooAge::_0, "leaves": Leaves::None, "stage": BambooStage::_0, @@ -4454,7 +4454,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4462,7 +4462,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - prismarine_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + prismarine_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4470,7 +4470,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - red_sandstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.8, 0.8), { + red_sandstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.8, 0.8).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4478,7 +4478,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - mossy_stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + mossy_stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4486,7 +4486,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - granite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + granite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4494,7 +4494,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4502,7 +4502,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - mud_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 3.0), { + mud_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 3.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4510,7 +4510,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - nether_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + nether_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4518,7 +4518,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - andesite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + andesite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4526,7 +4526,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - red_nether_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + red_nether_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4534,7 +4534,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - sandstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.8, 0.8), { + sandstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.8, 0.8).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4542,7 +4542,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - end_stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.0, 9.0), { + end_stone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.0, 9.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4550,7 +4550,7 @@ make_block_states! { "waterlogged": Waterlogged(false), "west": WallWest::None, }, - diorite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + diorite_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4593,16 +4593,16 @@ make_block_states! { stonecutter => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 3.5), { "facing": FacingCardinal::North, }, - bell => BlockBehavior::new().requires_correct_tool_for_drops().strength(5.0, 5.0), { + bell => BlockBehavior::new().requires_correct_tool_for_drops().strength(5.0, 5.0).force_solid(true), { "attachment": Attachment::Floor, "facing": FacingCardinal::North, "powered": Powered(false), }, - lantern => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 3.5), { + lantern => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 3.5).force_solid(true), { "hanging": Hanging(false), "waterlogged": Waterlogged(false), }, - soul_lantern => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 3.5), { + soul_lantern => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 3.5).force_solid(true), { "hanging": Hanging(false), "waterlogged": Waterlogged(false), }, @@ -4672,10 +4672,10 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - crimson_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + crimson_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, - warped_pressure_plate => BlockBehavior::new().strength(0.5, 0.5), { + warped_pressure_plate => BlockBehavior::new().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, crimson_fence => BlockBehavior::new().strength(2.0, 3.0), { @@ -4706,13 +4706,13 @@ make_block_states! { "powered": Powered(false), "waterlogged": Waterlogged(false), }, - crimson_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + crimson_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), "powered": Powered(false), }, - warped_fence_gate => BlockBehavior::new().strength(2.0, 3.0), { + warped_fence_gate => BlockBehavior::new().strength(2.0, 3.0).force_solid(true), { "facing": FacingCardinal::North, "in_wall": InWall(false), "open": Open(false), @@ -4754,19 +4754,19 @@ make_block_states! { "open": Open(false), "powered": Powered(false), }, - crimson_sign => BlockBehavior::new().strength(1.0, 1.0), { + crimson_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": CrimsonSignRotation::_0, "waterlogged": Waterlogged(false), }, - warped_sign => BlockBehavior::new().strength(1.0, 1.0), { + warped_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "rotation": WarpedSignRotation::_0, "waterlogged": Waterlogged(false), }, - crimson_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + crimson_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, - warped_wall_sign => BlockBehavior::new().strength(1.0, 1.0), { + warped_wall_sign => BlockBehavior::new().strength(1.0, 1.0).force_solid(true), { "facing": FacingCardinal::North, "waterlogged": Waterlogged(false), }, @@ -4810,7 +4810,7 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - blackstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + blackstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4836,7 +4836,7 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - polished_blackstone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + polished_blackstone_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -4855,7 +4855,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - polished_blackstone_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5), { + polished_blackstone_pressure_plate => BlockBehavior::new().requires_correct_tool_for_drops().strength(0.5, 0.5).force_solid(true), { "powered": Powered(false), }, polished_blackstone_button => BlockBehavior::new().strength(0.5, 0.5), { @@ -4863,7 +4863,7 @@ make_block_states! { "facing": FacingCardinal::North, "powered": Powered(false), }, - polished_blackstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0), { + polished_blackstone_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(2.0, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5012,7 +5012,7 @@ make_block_states! { }, amethyst_block => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 1.5), {}, budding_amethyst => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 1.5), {}, - amethyst_cluster => BlockBehavior::new().strength(1.5, 1.5), { + amethyst_cluster => BlockBehavior::new().strength(1.5, 1.5).force_solid(true), { "facing": FacingCubic::Up, "waterlogged": Waterlogged(false), }, @@ -5039,7 +5039,7 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - tuff_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + tuff_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5058,7 +5058,7 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - polished_tuff_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + polished_tuff_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5078,7 +5078,7 @@ make_block_states! { "shape": StairShape::Straight, "waterlogged": Waterlogged(false), }, - tuff_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0), { + tuff_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(1.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5102,7 +5102,7 @@ make_block_states! { "waterlogged": Waterlogged(false), }, sculk => BlockBehavior::new().strength(0.2, 0.2), {}, - sculk_vein => BlockBehavior::new().strength(0.2, 0.2), { + sculk_vein => BlockBehavior::new().strength(0.2, 0.2).force_solid(true), { "down": Down(false), "east": East(false), "north": North(false), @@ -5393,12 +5393,12 @@ make_block_states! { "lit": Lit(false), "powered": Powered(false), }, - lightning_rod => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.0, 6.0), { + lightning_rod => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.0, 6.0).force_solid(true), { "facing": FacingCubic::Up, "powered": Powered(false), "waterlogged": Waterlogged(false), }, - pointed_dripstone => BlockBehavior::new().strength(1.5, 3.0), { + pointed_dripstone => BlockBehavior::new().strength(1.5, 3.0).force_solid(true), { "thickness": Thickness::Tip, "vertical_direction": VerticalDirection::Up, "waterlogged": Waterlogged(false), @@ -5412,15 +5412,15 @@ make_block_states! { "berries": Berries(false), }, spore_blossom => BlockBehavior::new(), {}, - azalea => BlockBehavior::new(), {}, - flowering_azalea => BlockBehavior::new(), {}, + azalea => BlockBehavior::new().force_solid(false), {}, + flowering_azalea => BlockBehavior::new().force_solid(false), {}, moss_carpet => BlockBehavior::new().strength(0.1, 0.1), {}, pink_petals => BlockBehavior::new(), { "facing": FacingCardinal::North, "flower_amount": PinkPetalsFlowerAmount::_1, }, moss_block => BlockBehavior::new().strength(0.1, 0.1), {}, - big_dripleaf => BlockBehavior::new().strength(0.1, 0.1), { + big_dripleaf => BlockBehavior::new().strength(0.1, 0.1).force_solid(false), { "facing": FacingCardinal::North, "tilt": Tilt::None, "waterlogged": Waterlogged(false), @@ -5453,7 +5453,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - cobbled_deepslate_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0), { + cobbled_deepslate_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5472,7 +5472,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - polished_deepslate_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0), { + polished_deepslate_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5491,7 +5491,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - deepslate_tile_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0), { + deepslate_tile_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, @@ -5510,7 +5510,7 @@ make_block_states! { "type": Type::Bottom, "waterlogged": Waterlogged(false), }, - deepslate_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0), { + deepslate_brick_wall => BlockBehavior::new().requires_correct_tool_for_drops().strength(3.5, 6.0).force_solid(true), { "east": WallEast::None, "north": WallNorth::None, "south": WallSouth::None, diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs index be892ee5..c711253a 100644 --- a/azalea-client/src/entity_query.rs +++ b/azalea-client/src/entity_query.rs @@ -106,9 +106,7 @@ where fn find(&self, ecs_lock: Arc>) -> Option { let mut ecs = ecs_lock.lock(); let mut query = ecs.query_filtered::<(Entity, Q), Filter>(); - let entity = query.iter(&ecs).find(|(_, q)| (self)(q)).map(|(e, _)| e); - - entity + query.iter(&ecs).find(|(_, q)| (self)(q)).map(|(e, _)| e) } } diff --git a/azalea-client/src/plugins/brand.rs b/azalea-client/src/plugins/brand.rs index e15a6c67..5ee8e52c 100644 --- a/azalea-client/src/plugins/brand.rs +++ b/azalea-client/src/plugins/brand.rs @@ -24,7 +24,7 @@ impl Plugin for BrandPlugin { } } -fn handle_end_login_state( +pub fn handle_end_login_state( mut removed: RemovedComponents, query: Query<&ClientInformation>, mut send_packet_events: EventWriter, diff --git a/azalea-core/src/aabb.rs b/azalea-core/src/aabb.rs index fe45c35e..6796e79c 100755 --- a/azalea-core/src/aabb.rs +++ b/azalea-core/src/aabb.rs @@ -26,26 +26,26 @@ pub struct ClipPointOpts<'a> { } impl AABB { - pub fn contract(&self, x: f64, y: f64, z: f64) -> AABB { + pub fn contract(&self, amount: Vec3) -> AABB { let mut min = self.min; let mut max = self.max; - if x < 0.0 { - min.x -= x; - } else if x > 0.0 { - max.x -= x; + if amount.x < 0.0 { + min.x -= amount.x; + } else if amount.x > 0.0 { + max.x -= amount.x; } - if y < 0.0 { - min.y -= y; - } else if y > 0.0 { - max.y -= y; + if amount.y < 0.0 { + min.y -= amount.y; + } else if amount.y > 0.0 { + max.y -= amount.y; } - if z < 0.0 { - min.z -= z; - } else if z > 0.0 { - max.z -= z; + if amount.z < 0.0 { + min.z -= amount.z; + } else if amount.z > 0.0 { + max.z -= amount.z; } AABB { min, max } @@ -84,20 +84,23 @@ impl AABB { } } - pub fn inflate(&self, x: f64, y: f64, z: f64) -> AABB { - let min_x = self.min.x - x; - let min_y = self.min.y - y; - let min_z = self.min.z - z; + pub fn inflate(&self, amount: Vec3) -> AABB { + let min_x = self.min.x - amount.x; + let min_y = self.min.y - amount.y; + let min_z = self.min.z - amount.z; - let max_x = self.max.x + x; - let max_y = self.max.y + y; - let max_z = self.max.z + z; + let max_x = self.max.x + amount.x; + let max_y = self.max.y + amount.y; + let max_z = self.max.z + amount.z; AABB { min: Vec3::new(min_x, min_y, min_z), max: Vec3::new(max_x, max_y, max_z), } } + pub fn inflate_all(&self, amount: f64) -> AABB { + self.inflate(Vec3::new(amount, amount, amount)) + } pub fn intersect(&self, other: &AABB) -> AABB { let min_x = self.min.x.max(other.min.x); @@ -144,17 +147,17 @@ impl AABB { && self.min.z < other.max.z && self.max.z > other.min.z } - pub fn intersects_vec3(&self, other: &Vec3, other2: &Vec3) -> bool { + pub fn intersects_vec3(&self, corner1: &Vec3, corner2: &Vec3) -> bool { self.intersects_aabb(&AABB { min: Vec3::new( - other.x.min(other2.x), - other.y.min(other2.y), - other.z.min(other2.z), + corner1.x.min(corner2.x), + corner1.y.min(corner2.y), + corner1.z.min(corner2.z), ), max: Vec3::new( - other.x.max(other2.x), - other.y.max(other2.y), - other.z.max(other2.z), + corner1.x.max(corner2.x), + corner1.y.max(corner2.y), + corner1.z.max(corner2.z), ), }) } @@ -183,12 +186,11 @@ impl AABB { ) } - pub fn deflate(&mut self, x: f64, y: f64, z: f64) -> AABB { - self.inflate(-x, -y, -z) + pub fn deflate(&self, amount: Vec3) -> AABB { + self.inflate(Vec3::new(-amount.x, -amount.y, -amount.z)) } - - pub fn deflate_all(&mut self, amount: f64) -> AABB { - self.deflate(amount, amount, amount) + pub fn deflate_all(&self, amount: f64) -> AABB { + self.deflate(Vec3::new(amount, amount, amount)) } pub fn clip(&self, min: &Vec3, max: &Vec3) -> Option { @@ -434,11 +436,11 @@ impl AABB { let new_center = center + vector; for aabb in boxes { - let inflated = aabb.inflate( + let inflated = aabb.inflate(Vec3::new( self.get_size(Axis::X) * 0.5, self.get_size(Axis::Y) * 0.5, self.get_size(Axis::Z) * 0.5, - ); + )); if inflated.contains(&new_center) || inflated.contains(¢er) { return true; } diff --git a/azalea-core/src/delta.rs b/azalea-core/src/delta.rs index 238262a2..dd598f77 100755 --- a/azalea-core/src/delta.rs +++ b/azalea-core/src/delta.rs @@ -51,8 +51,8 @@ impl Vec3 { pub fn normalize(&self) -> Vec3 { let length = f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z); - if length < 1e-4 { - return Vec3::default(); + if length < 1e-5 { + return Vec3::ZERO; } Vec3 { x: self.x / length, diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs index d458f487..656cab1b 100755 --- a/azalea-core/src/direction.rs +++ b/azalea-core/src/direction.rs @@ -17,9 +17,9 @@ pub enum Direction { impl Direction { pub const HORIZONTAL: [Direction; 4] = [ Direction::North, + Direction::East, Direction::South, Direction::West, - Direction::East, ]; pub const VERTICAL: [Direction; 2] = [Direction::Down, Direction::Up]; diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs index cba58415..5d923d39 100755 --- a/azalea-core/src/position.rs +++ b/azalea-core/src/position.rs @@ -309,6 +309,21 @@ impl Vec3 { let z = self.z * (x_delta as f64) - self.x * (y_delta as f64); Vec3 { x, y, z } } + + pub fn to_block_pos_floor(&self) -> BlockPos { + BlockPos { + x: self.x.floor() as i32, + y: self.y.floor() as i32, + z: self.z.floor() as i32, + } + } + pub fn to_block_pos_ceil(&self) -> BlockPos { + BlockPos { + x: self.x.ceil() as i32, + y: self.y.ceil() as i32, + z: self.z.ceil() as i32, + } + } } /// The coordinates of a block in the world. For entities (if the coordinate @@ -600,6 +615,16 @@ impl From for ChunkPos { ChunkPos { x: pos.x, z: pos.z } } } +impl From<&Vec3> for ChunkSectionPos { + fn from(pos: &Vec3) -> Self { + ChunkSectionPos::from(&BlockPos::from(pos)) + } +} +impl From for ChunkSectionPos { + fn from(pos: Vec3) -> Self { + ChunkSectionPos::from(&pos) + } +} impl From<&BlockPos> for ChunkBlockPos { #[inline] diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs index 49e42017..4893878a 100644 --- a/azalea-entity/src/lib.rs +++ b/azalea-entity/src/lib.rs @@ -209,8 +209,8 @@ impl From<&LastSentPosition> for BlockPos { /// /// If this is true, the entity will try to jump every tick. It's equivalent to /// the space key being held in vanilla. -#[derive(Debug, Component, Copy, Clone, Deref, DerefMut, Default)] -pub struct Jumping(bool); +#[derive(Debug, Component, Copy, Clone, Deref, DerefMut, Default, PartialEq, Eq)] +pub struct Jumping(pub bool); /// A component that contains the direction an entity is looking. #[derive(Debug, Component, Copy, Clone, Default, PartialEq, AzBuf)] diff --git a/azalea-physics/src/clip.rs b/azalea-physics/src/clip.rs index ea5940a5..7c16f5d4 100644 --- a/azalea-physics/src/clip.rs +++ b/azalea-physics/src/clip.rs @@ -11,9 +11,7 @@ use azalea_core::{ math::{self, EPSILON, lerp}, position::{BlockPos, Vec3}, }; -use azalea_inventory::ItemStack; use azalea_world::ChunkStorage; -use bevy_ecs::entity::Entity; use crate::collision::{BlockWithShape, EMPTY_SHAPE, VoxelShape}; @@ -92,15 +90,6 @@ impl FluidPickType { } } -#[derive(Debug, Clone)] -pub struct EntityCollisionContext { - pub descending: bool, - pub entity_bottom: f64, - pub held_item: ItemStack, - // pub can_stand_on_fluid: Box bool>, - pub entity: Entity, -} - pub fn clip(chunk_storage: &ChunkStorage, context: ClipContext) -> BlockHitResult { traverse_blocks( context.from, diff --git a/azalea-physics/src/collision/entity_collisions.rs b/azalea-physics/src/collision/entity_collisions.rs new file mode 100644 index 00000000..1300cf34 --- /dev/null +++ b/azalea-physics/src/collision/entity_collisions.rs @@ -0,0 +1,97 @@ +use azalea_core::aabb::AABB; +use azalea_entity::{ + LocalEntity, Physics, + metadata::{AbstractBoat, Shulker}, +}; +use azalea_world::Instance; +use bevy_ecs::{ + entity::Entity, + query::{Or, With, Without}, + system::Query, +}; +use tracing::error; + +use super::VoxelShape; + +/// This query matches on entities that we can collide with. That is, boats and +/// shulkers. +/// +/// If you want to use this in a more complex query, use +/// [`CollidableEntityFilter`] as a filter instead. +pub type CollidableEntityQuery<'world, 'state> = Query<'world, 'state, (), CollidableEntityFilter>; +/// This filter matches on entities that we can collide with (boats and +/// shulkers). +/// +/// Use [`CollidableEntityQuery`] if you want an empty query that matches with +/// this. +pub type CollidableEntityFilter = Or<(With, With)>; + +pub type PhysicsQuery<'world, 'state, 'a> = + Query<'world, 'state, &'a Physics, Without>; + +pub fn get_entity_collisions( + world: &Instance, + aabb: &AABB, + source_entity: Option, + physics_query: &PhysicsQuery, + collidable_entity_query: &CollidableEntityQuery, +) -> Vec { + if aabb.size() < 1.0E-7 { + return vec![]; + } + + let collision_predicate = |entity| collidable_entity_query.get(entity).is_ok(); + + let collidable_entities = get_entities( + world, + source_entity, + &aabb.inflate_all(1.0E-7), + &collision_predicate, + physics_query, + ); + + collidable_entities + .into_iter() + .map(|(_entity, aabb)| VoxelShape::from(aabb)) + .collect() +} + +/// Return all entities that are colliding with the given bounding box and match +/// the given predicate. +/// +/// `source_entity` is the entity that the bounding box belongs to, and won't be +/// one of the returned entities. +pub fn get_entities( + world: &Instance, + source_entity: Option, + aabb: &AABB, + predicate: &dyn Fn(Entity) -> bool, + physics_query: &PhysicsQuery, +) -> Vec<(Entity, AABB)> { + let mut matches = Vec::new(); + + super::world_collisions::for_entities_in_chunks_colliding_with( + world, + aabb, + |_chunk_pos, entities_in_chunk| { + // now check if the entity itself collides + for &candidate in entities_in_chunk { + if Some(candidate) != source_entity && predicate(candidate) { + let Ok(physics) = physics_query.get(candidate) else { + error!( + "Entity {candidate} (found from for_entities_in_chunks_colliding_with) is missing required components." + ); + continue; + }; + + let candidate_aabb = physics.bounding_box; + if aabb.intersects_aabb(&candidate_aabb) { + matches.push((candidate, physics.bounding_box)); + } + } + } + }, + ); + + matches +} diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index 540cf7d4..77af1232 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -1,8 +1,9 @@ mod blocks; mod discrete_voxel_shape; +pub mod entity_collisions; mod mergers; mod shape; -mod world_collisions; +pub mod world_collisions; use std::{ops::Add, sync::LazyLock}; @@ -279,7 +280,7 @@ fn collide_bounding_box( // TODO: world border let block_collisions = - get_block_collisions(world, entity_bounding_box.expand_towards(movement)); + get_block_collisions(world, &entity_bounding_box.expand_towards(movement)); collision_boxes.extend(block_collisions); collide_with_shapes(movement, *entity_bounding_box, &collision_boxes) } @@ -392,6 +393,11 @@ fn calculate_shape_for_fluid(amount: u8) -> VoxelShape { /// /// This is marked as deprecated in Minecraft. pub fn legacy_blocks_motion(block: BlockState) -> bool { + if block == BlockState::AIR { + // fast path + return false; + } + let registry_block = azalea_registry::Block::from(block); legacy_calculate_solid(block) && registry_block != azalea_registry::Block::Cobweb diff --git a/azalea-physics/src/collision/shape.rs b/azalea-physics/src/collision/shape.rs index 726e62ad..fc5615c3 100755 --- a/azalea-physics/src/collision/shape.rs +++ b/azalea-physics/src/collision/shape.rs @@ -194,7 +194,7 @@ impl Shapes { } /// Check if the op is true anywhere when joining the two shapes - /// vanilla calls this joinIsNotEmpty + /// vanilla calls this joinIsNotEmpty (join_is_not_empty). pub fn matches_anywhere( a: &VoxelShape, b: &VoxelShape, @@ -574,13 +574,18 @@ impl VoxelShape { } } -impl From for VoxelShape { - fn from(aabb: AABB) -> Self { +impl From<&AABB> for VoxelShape { + fn from(aabb: &AABB) -> Self { box_shape( aabb.min.x, aabb.min.y, aabb.min.z, aabb.max.x, aabb.max.y, aabb.max.z, ) } } +impl From for VoxelShape { + fn from(aabb: AABB) -> Self { + VoxelShape::from(&aabb) + } +} #[derive(Clone, PartialEq, Debug)] pub struct ArrayVoxelShape { diff --git a/azalea-physics/src/collision/world_collisions.rs b/azalea-physics/src/collision/world_collisions.rs index 3aede743..ded31275 100644 --- a/azalea-physics/src/collision/world_collisions.rs +++ b/azalea-physics/src/collision/world_collisions.rs @@ -1,19 +1,21 @@ -use std::sync::Arc; +use std::{collections::HashSet, sync::Arc}; -use azalea_block::BlockState; +use azalea_block::{BlockState, fluid_state::FluidState}; use azalea_core::{ - cursor3d::{Cursor3d, CursorIterationType}, + cursor3d::{Cursor3d, CursorIteration, CursorIterationType}, math::EPSILON, - position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos}, + position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos, Vec3}, }; +use azalea_inventory::ItemStack; use azalea_world::{Chunk, Instance}; +use bevy_ecs::entity::Entity; use parking_lot::RwLock; use super::{BLOCK_SHAPE, Shapes}; use crate::collision::{AABB, BlockWithShape, VoxelShape}; -pub fn get_block_collisions(world: &Instance, aabb: AABB) -> Vec { - let mut state = BlockCollisionsState::new(world, aabb); +pub fn get_block_collisions(world: &Instance, aabb: &AABB) -> Vec { + let mut state = BlockCollisionsState::new(world, aabb, EntityCollisionContext::of(None)); let mut block_collisions = Vec::new(); let initial_chunk_pos = ChunkPos::from(state.cursor.origin()); @@ -21,52 +23,36 @@ pub fn get_block_collisions(world: &Instance, aabb: AABB) -> Vec { let initial_chunk = initial_chunk.as_deref().map(RwLock::read); while let Some(item) = state.cursor.next() { - if item.iteration_type == CursorIterationType::Corner { - continue; - } + state.compute_next( + item, + &mut block_collisions, + initial_chunk_pos, + initial_chunk.as_deref(), + ); + } - let item_chunk_pos = ChunkPos::from(item.pos); - let block_state: BlockState = if item_chunk_pos == initial_chunk_pos { - match &initial_chunk { - Some(initial_chunk) => initial_chunk - .get(&ChunkBlockPos::from(item.pos), state.world.chunks.min_y) - .unwrap_or(BlockState::AIR), - _ => BlockState::AIR, - } - } else { - state.get_block_state(item.pos) - }; + block_collisions +} - if block_state.is_air() { - // fast path since we can't collide with air - continue; - } +pub fn get_block_and_liquid_collisions(world: &Instance, aabb: &AABB) -> Vec { + let mut state = BlockCollisionsState::new( + world, + aabb, + EntityCollisionContext::of(None).with_include_liquids(true), + ); + let mut block_collisions = Vec::new(); - // TODO: continue if self.only_suffocating_blocks and the block is not - // suffocating + let initial_chunk_pos = ChunkPos::from(state.cursor.origin()); + let initial_chunk = world.chunks.get(&initial_chunk_pos); + let initial_chunk = initial_chunk.as_deref().map(RwLock::read); - // if it's a full block do a faster collision check - if block_state.is_collision_shape_full() { - if !state.aabb.intersects_aabb(&AABB { - min: item.pos.to_vec3_floored(), - max: (item.pos + 1).to_vec3_floored(), - }) { - continue; - } - - block_collisions.push(BLOCK_SHAPE.move_relative(item.pos.to_vec3_floored())); - continue; - } - - let block_shape = state.get_block_shape(block_state); - - let block_shape = block_shape.move_relative(item.pos.to_vec3_floored()); - // if the entity shape and block shape don't collide, continue - if !Shapes::matches_anywhere(&block_shape, &state.entity_shape, |a, b| a && b) { - continue; - } - - block_collisions.push(block_shape); + while let Some(item) = state.cursor.next() { + state.compute_next( + item, + &mut block_collisions, + initial_chunk_pos, + initial_chunk.as_deref(), + ); } block_collisions @@ -74,16 +60,73 @@ pub fn get_block_collisions(world: &Instance, aabb: AABB) -> Vec { pub struct BlockCollisionsState<'a> { pub world: &'a Instance, - pub aabb: AABB, + pub aabb: &'a AABB, pub entity_shape: VoxelShape, pub cursor: Cursor3d, + _context: EntityCollisionContext, + cached_sections: Vec<(ChunkSectionPos, azalea_world::Section)>, cached_block_shapes: Vec<(BlockState, &'static VoxelShape)>, } impl<'a> BlockCollisionsState<'a> { - pub fn new(world: &'a Instance, aabb: AABB) -> Self { + fn compute_next( + &mut self, + item: CursorIteration, + block_collisions: &mut Vec, + initial_chunk_pos: ChunkPos, + initial_chunk: Option<&Chunk>, + ) { + if item.iteration_type == CursorIterationType::Corner { + return; + } + + let item_chunk_pos = ChunkPos::from(item.pos); + let block_state: BlockState = if item_chunk_pos == initial_chunk_pos { + match &initial_chunk { + Some(initial_chunk) => initial_chunk + .get(&ChunkBlockPos::from(item.pos), self.world.chunks.min_y) + .unwrap_or(BlockState::AIR), + _ => BlockState::AIR, + } + } else { + self.get_block_state(item.pos) + }; + + if block_state.is_air() { + // fast path since we can't collide with air + return; + } + + // TODO: continue if self.only_suffocating_blocks and the block is not + // suffocating + + // if it's a full block do a faster collision check + if block_state.is_collision_shape_full() { + if !self.aabb.intersects_aabb(&AABB { + min: item.pos.to_vec3_floored(), + max: (item.pos + 1).to_vec3_floored(), + }) { + return; + } + + block_collisions.push(BLOCK_SHAPE.move_relative(item.pos.to_vec3_floored())); + return; + } + + let block_shape = self.get_block_shape(block_state); + + let block_shape = block_shape.move_relative(item.pos.to_vec3_floored()); + // if the entity shape and block shape don't collide, continue + if !Shapes::matches_anywhere(&block_shape, &self.entity_shape, |a, b| a && b) { + return; + } + + block_collisions.push(block_shape); + } + + pub fn new(world: &'a Instance, aabb: &'a AABB, context: EntityCollisionContext) -> Self { let origin = BlockPos { x: (aabb.min.x - EPSILON).floor() as i32 - 1, y: (aabb.min.y - EPSILON).floor() as i32 - 1, @@ -104,6 +147,8 @@ impl<'a> BlockCollisionsState<'a> { entity_shape: VoxelShape::from(aabb), cursor, + _context: context, + cached_sections: Vec::new(), cached_block_shapes: Vec::new(), } @@ -182,3 +227,78 @@ impl<'a> BlockCollisionsState<'a> { shape } } + +pub struct EntityCollisionContext { + pub descending: bool, + pub entity_bottom: f64, + pub held_item: ItemStack, + can_stand_on_fluid_predicate: CanStandOnFluidPredicate, + pub entity: Option, +} + +impl EntityCollisionContext { + pub fn of(entity: Option) -> Self { + Self { + descending: false, + entity_bottom: 0.0, + held_item: ItemStack::Empty, + can_stand_on_fluid_predicate: CanStandOnFluidPredicate::PassToEntity, + entity, + } + } + pub fn with_include_liquids(mut self, include_liquids: bool) -> Self { + self.can_stand_on_fluid_predicate = if include_liquids { + CanStandOnFluidPredicate::AlwaysTrue + } else { + CanStandOnFluidPredicate::PassToEntity + }; + self + } + + pub fn can_stand_on_fluid(&self, above: &FluidState, target: &FluidState) -> bool { + self.can_stand_on_fluid_predicate.matches(target) && !above.is_same_kind(target) + } +} + +enum CanStandOnFluidPredicate { + PassToEntity, + AlwaysTrue, +} +impl CanStandOnFluidPredicate { + pub fn matches(&self, _state: &FluidState) -> bool { + match self { + Self::AlwaysTrue => true, + // minecraft sometimes returns true for striders here, false for every other entity + // though + Self::PassToEntity => false, + } + } +} + +/// This basically gets all the chunks that an entity colliding with +/// that bounding box could be in. +/// +/// This is forEachAccessibleNonEmptySection in vanilla Minecraft because they +/// sort entities into sections instead of just chunks. In theory this might be +/// a performance loss for Azalea. If this ever turns out to be a bottleneck, +/// then maybe you should try having it do that instead. +pub fn for_entities_in_chunks_colliding_with( + world: &Instance, + aabb: &AABB, + mut consumer: impl FnMut(ChunkPos, &HashSet), +) { + let min_section = ChunkSectionPos::from(aabb.min - Vec3::new(2., 4., 2.)); + let max_section = ChunkSectionPos::from(aabb.max + Vec3::new(2., 0., 2.)); + + let min_chunk = ChunkPos::from(min_section); + let max_chunk = ChunkPos::from(max_section); + + for chunk_x in min_chunk.x..=max_chunk.x { + for chunk_z in min_chunk.z..=max_chunk.z { + let chunk_pos = ChunkPos::new(chunk_x, chunk_z); + if let Some(entities) = world.entities_by_chunk.get(&chunk_pos) { + consumer(chunk_pos, entities); + } + } + } +} diff --git a/azalea-physics/src/fluids.rs b/azalea-physics/src/fluids.rs index bbc044f6..f8643b9c 100644 --- a/azalea-physics/src/fluids.rs +++ b/azalea-physics/src/fluids.rs @@ -27,6 +27,8 @@ pub fn update_in_water_state_and_do_fluid_pushing( .expect("All entities with InLoadedChunk should be in a valid world"); let world = world_lock.read(); + // reset the heights since they're going to be set in + // update_in_water_state_and_do_water_current_pushing physics.water_fluid_height = 0.; physics.lava_fluid_height = 0.; @@ -110,9 +112,9 @@ fn update_fluid_height_and_do_fluid_pushing( let mut additional_player_delta = Vec3::default(); let mut num_fluids_being_touched = 0; - for cur_x in min_x..=max_x { - for cur_y in min_y..=max_y { - for cur_z in min_z..=max_z { + for cur_x in min_x..max_x { + for cur_y in min_y..max_y { + for cur_z in min_z..max_z { let cur_pos = BlockPos::new(cur_x, cur_y, cur_z); let Some(fluid_at_cur_pos) = world.get_fluid_state(&cur_pos) else { continue; @@ -184,42 +186,44 @@ pub fn get_fluid_flow(fluid: &FluidState, world: &Instance, pos: BlockPos) -> Ve let mut z_flow: f64 = 0.; let mut x_flow: f64 = 0.; + let cur_fluid_height = fluid.height(); + for direction in Direction::HORIZONTAL { let adjacent_block_pos = pos.offset_with_direction(direction); - let adjacent_fluid_state = world - .get_fluid_state(&adjacent_block_pos) + + let adjacent_block_state = world + .get_block_state(&adjacent_block_pos) .unwrap_or_default(); - if fluid.affects_flow(&adjacent_fluid_state) { - let mut adjacent_fluid_height = adjacent_fluid_state.height(); - let mut adjacent_height_difference: f32 = 0.; + let adjacent_fluid_state = FluidState::from(adjacent_block_state); - if adjacent_fluid_height == 0. { - if !legacy_blocks_motion( - world - .get_block_state(&adjacent_block_pos) - .unwrap_or_default(), - ) { - let block_pos_below_adjacent = adjacent_block_pos.down(1); - let fluid_below_adjacent = world - .get_fluid_state(&block_pos_below_adjacent) - .unwrap_or_default(); + if !fluid.affects_flow(&adjacent_fluid_state) { + continue; + }; + let mut adjacent_fluid_height = adjacent_fluid_state.height(); + let mut adjacent_height_difference: f32 = 0.; - if fluid.affects_flow(&fluid_below_adjacent) { - adjacent_fluid_height = fluid_below_adjacent.height(); - if adjacent_fluid_height > 0. { - adjacent_height_difference = - fluid.height() - (adjacent_fluid_height - 0.8888889); - } + if adjacent_fluid_height == 0. { + if !legacy_blocks_motion(adjacent_block_state) { + let block_pos_below_adjacent = adjacent_block_pos.down(1); + let fluid_below_adjacent = world + .get_fluid_state(&block_pos_below_adjacent) + .unwrap_or_default(); + + if fluid.affects_flow(&fluid_below_adjacent) { + adjacent_fluid_height = fluid_below_adjacent.height(); + if adjacent_fluid_height > 0. { + adjacent_height_difference = + cur_fluid_height - (adjacent_fluid_height - 0.8888889); } } - } else if adjacent_fluid_height > 0. { - adjacent_height_difference = fluid.height() - adjacent_fluid_height; } + } else if adjacent_fluid_height > 0. { + adjacent_height_difference = cur_fluid_height - adjacent_fluid_height; + } - if adjacent_height_difference != 0. { - x_flow += (direction.x() as f32 * adjacent_height_difference) as f64; - z_flow += (direction.z() as f32 * adjacent_height_difference) as f64; - } + if adjacent_height_difference != 0. { + x_flow += (direction.x() as f32 * adjacent_height_difference) as f64; + z_flow += (direction.z() as f32 * adjacent_height_difference) as f64; } } diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 0541042c..2e8132c8 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -90,44 +90,40 @@ pub fn ai_step( physics.velocity.z = 0.; } - if let Some(jumping) = jumping { - if **jumping { - // TODO: jumping in liquids and jump delay + if jumping == Some(&Jumping(true)) { + let fluid_height = if physics.is_in_lava() { + physics.lava_fluid_height + } else if physics.is_in_water() { + physics.water_fluid_height + } else { + 0. + }; - let fluid_height = if physics.is_in_lava() { - physics.lava_fluid_height - } else if physics.is_in_water() { - physics.water_fluid_height - } else { - 0. - }; + let in_water = physics.is_in_water() && fluid_height > 0.; + let fluid_jump_threshold = travel::fluid_jump_threshold(); - let in_water = physics.is_in_water() && fluid_height > 0.; - let fluid_jump_threshold = travel::fluid_jump_threshold(); - - if !in_water || physics.on_ground() && fluid_height <= fluid_jump_threshold { - if !physics.is_in_lava() - || physics.on_ground() && fluid_height <= fluid_jump_threshold + if !in_water || physics.on_ground() && fluid_height <= fluid_jump_threshold { + if !physics.is_in_lava() + || physics.on_ground() && fluid_height <= fluid_jump_threshold + { + if (physics.on_ground() || in_water && fluid_height <= fluid_jump_threshold) + && physics.no_jump_delay == 0 { - if (physics.on_ground() || in_water && fluid_height <= fluid_jump_threshold) - && physics.no_jump_delay == 0 - { - jump_from_ground( - &mut physics, - position, - look_direction, - sprinting, - instance_name, - &instance_container, - ); - physics.no_jump_delay = 10; - } - } else { - jump_in_liquid(&mut physics); + jump_from_ground( + &mut physics, + position, + look_direction, + sprinting, + instance_name, + &instance_container, + ); + physics.no_jump_delay = 10; } } else { jump_in_liquid(&mut physics); } + } else { + jump_in_liquid(&mut physics); } } else { physics.no_jump_delay = 0; @@ -417,7 +413,6 @@ fn handle_relative_friction_and_calculate_movement( .unwrap_or_default() .into(); - // TODO: powdered snow if **on_climbable || block_at_feet == azalea_registry::Block::PowderSnow { physics.velocity.y = 0.2; } diff --git a/azalea-physics/src/travel.rs b/azalea-physics/src/travel.rs index e6145c18..0ee39f73 100644 --- a/azalea-physics/src/travel.rs +++ b/azalea-physics/src/travel.rs @@ -1,5 +1,8 @@ -use azalea_block::{Block, BlockState}; -use azalea_core::{aabb::AABB, position::Vec3}; +use azalea_block::{Block, BlockState, fluid_state::FluidState}; +use azalea_core::{ + aabb::AABB, + position::{BlockPos, Vec3}, +}; use azalea_entity::{ Attributes, InLoadedChunk, Jumping, LocalEntity, LookDirection, OnClimbable, Physics, Pose, Position, metadata::Sprinting, move_relative, @@ -9,7 +12,11 @@ use bevy_ecs::prelude::*; use crate::{ HandleRelativeFrictionAndCalculateMovementOpts, - collision::{MoverType, move_colliding}, + collision::{ + MoverType, Shapes, + entity_collisions::{CollidableEntityQuery, PhysicsQuery, get_entity_collisions}, + move_colliding, + }, get_block_pos_below_that_affects_movement, handle_relative_friction_and_calculate_movement, }; @@ -19,6 +26,7 @@ use crate::{ pub fn travel( mut query: Query< ( + Entity, &mut Physics, &mut LookDirection, &mut Position, @@ -32,8 +40,11 @@ pub fn travel( (With, With), >, instance_container: Res, + physics_query: PhysicsQuery, + collidable_entity_query: CollidableEntityQuery, ) { for ( + entity, mut physics, direction, position, @@ -59,13 +70,16 @@ pub fn travel( // !this.canStandOnFluid(fluidAtBlock)` here but it doesn't matter // for players travel_in_fluid( + &world, + entity, &mut physics, &direction, position, attributes, sprinting, on_climbable, - &world, + &physics_query, + &collidable_entity_query, ); } else { travel_in_air( @@ -149,14 +163,18 @@ fn travel_in_air( } } +#[allow(clippy::too_many_arguments)] fn travel_in_fluid( + world: &Instance, + entity: Entity, physics: &mut Physics, direction: &LookDirection, mut position: Mut, attributes: &Attributes, sprinting: Sprinting, on_climbable: &OnClimbable, - world: &Instance, + physics_query: &PhysicsQuery, + collidable_entity_query: &CollidableEntityQuery, ) { let moving_down = physics.velocity.y <= 0.; let y = position.y; @@ -239,11 +257,13 @@ fn travel_in_fluid( let velocity = physics.velocity; if physics.horizontal_collision && is_free( - physics.bounding_box, world, - velocity.x, - velocity.y + 0.6 - position.y + y, - velocity.z, + entity, + physics_query, + collidable_entity_query, + physics, + physics.bounding_box, + velocity.up(0.6).down(position.y).up(y), ) { physics.velocity.y = 0.3; @@ -276,14 +296,97 @@ fn get_fluid_falling_adjusted_movement( } } -fn is_free(bounding_box: AABB, world: &Instance, x: f64, y: f64, z: f64) -> bool { - // let bounding_box = bounding_box.move_relative(Vec3::new(x, y, z)); +fn is_free( + world: &Instance, + source_entity: Entity, + physics_query: &PhysicsQuery, + collidable_entity_query: &CollidableEntityQuery, + entity_physics: &mut Physics, + bounding_box: AABB, + delta: Vec3, +) -> bool { + let bounding_box = bounding_box.move_relative(delta); - let _ = (bounding_box, world, x, y, z); + no_collision( + world, + Some(source_entity), + physics_query, + collidable_entity_query, + entity_physics, + &bounding_box, + false, + ) && !contains_any_liquid(world, bounding_box) +} - // TODO: implement this, see Entity.isFree +fn no_collision( + world: &Instance, + source_entity: Option, + physics_query: &PhysicsQuery, + collidable_entity_query: &CollidableEntityQuery, + entity_physics: &mut Physics, + aabb: &AABB, + include_liquid_collisions: bool, +) -> bool { + let collisions = if include_liquid_collisions { + crate::collision::world_collisions::get_block_and_liquid_collisions(world, aabb) + } else { + crate::collision::world_collisions::get_block_collisions(world, aabb) + }; - true + for collision in collisions { + if !collision.is_empty() { + return false; + } + } + + if !get_entity_collisions( + world, + aabb, + source_entity, + physics_query, + collidable_entity_query, + ) + .is_empty() + { + false + } else if source_entity.is_none() { + true + } else { + let collision = border_collision(entity_physics, aabb); + if let Some(collision) = collision { + // !Shapes.joinIsNotEmpty(collision, Shapes.create(aabb), BooleanOp.AND); + !Shapes::matches_anywhere(&collision.into(), &aabb.into(), |a, b| a && b) + } else { + true + } + } +} + +fn border_collision(_entity_physics: &Physics, _aabb: &AABB) -> Option { + // TODO: implement world border, see CollisionGetter.borderCollision + + None +} + +fn contains_any_liquid(world: &Instance, bounding_box: AABB) -> bool { + let min = bounding_box.min.to_block_pos_floor(); + let max = bounding_box.max.to_block_pos_ceil(); + + for x in min.x..max.x { + for y in min.y..max.y { + for z in min.z..max.z { + let block_state = world + .chunks + .get_block_state(&BlockPos::new(x, y, z)) + .unwrap_or_default(); + if !FluidState::from(block_state).is_empty() { + return true; + } + } + } + } + + false } fn get_effective_gravity() -> f64 { diff --git a/azalea-physics/tests/physics.rs b/azalea-physics/tests/physics.rs index c9fcdf97..396c34f9 100644 --- a/azalea-physics/tests/physics.rs +++ b/azalea-physics/tests/physics.rs @@ -1,5 +1,9 @@ use std::sync::Arc; +use azalea_block::{ + BlockState, block_state::BlockStateIntegerRepr, fluid_state::to_or_from_legacy_fluid_level, + properties::WaterLevel, +}; use azalea_core::{ position::{BlockPos, ChunkPos, Vec3}, registry_holder::RegistryHolder, @@ -409,3 +413,137 @@ fn spawn_and_unload_world() { app.world_mut().run_schedule(GameTick); app.update(); } + +#[test] +fn test_afk_pool() { + let mut app = make_test_app(); + let world_lock = insert_overworld(&mut app); + let mut partial_world = PartialInstance::default(); + + partial_world.chunks.set( + &ChunkPos { x: 0, z: 0 }, + Some(Chunk::default()), + &mut world_lock.write().chunks, + ); + let setblock = |x: i32, y: i32, z: i32, b: BlockState| { + world_lock + .write() + .chunks + .set_block_state(&BlockPos { x, y, z }, b); + }; + + let stone = azalea_block::blocks::Stone {}.into(); + let sign = azalea_block::blocks::OakSign { + rotation: azalea_block::properties::OakSignRotation::_0, + waterlogged: false, + } + .into(); + let water = |level: u8| { + BlockState::from(azalea_block::blocks::Water { + level: WaterLevel::from(to_or_from_legacy_fluid_level(level) as BlockStateIntegerRepr), + }) + }; + + let mut y = 69; + + // first layer + { + setblock(1, y, 1, stone); + setblock(2, y, 1, stone); + setblock(3, y, 1, stone); + setblock(3, y, 2, stone); + setblock(3, y, 3, stone); + setblock(2, y, 3, stone); + setblock(1, y, 3, stone); + setblock(1, y, 2, stone); + } + // second layer + y += 1; + { + setblock(1, y, 0, stone); + setblock(2, y, 0, stone); + setblock(3, y, 0, stone); + + setblock(0, y, 1, stone); + setblock(0, y, 2, stone); + setblock(0, y, 3, stone); + + setblock(1, y, 4, stone); + setblock(2, y, 4, stone); + setblock(3, y, 4, stone); + + setblock(4, y, 1, stone); + setblock(4, y, 2, stone); + setblock(4, y, 3, stone); + + // middle block + setblock(2, y, 2, stone); + + // sign + setblock(1, y, 1, sign); + + // water + setblock(1, y, 2, water(8)); + setblock(1, y, 3, water(7)); + setblock(2, y, 3, water(6)); + setblock(3, y, 3, water(5)); + setblock(3, y, 2, water(4)); + setblock(3, y, 1, water(3)); + setblock(2, y, 1, water(2)); + } + // third layer + y += 1; + { + setblock(1, y, 1, water(8)); + setblock(2, y, 1, sign); + } + + let entity = app + .world_mut() + .spawn(( + EntityBundle::new( + Uuid::nil(), + Vec3 { + x: 3.5, + y: 70., + z: 1.5, + }, + azalea_registry::EntityKind::Player, + ResourceLocation::new("minecraft:overworld"), + ), + MinecraftEntityId(0), + LocalEntity, + )) + .id(); + + let mut blocks_visited = Vec::new(); + let mut loops_done = 0; + + for _ in 0..300 { + app.world_mut().run_schedule(GameTick); + app.update(); + + let entity_pos = app.world_mut().get::(entity).unwrap(); + let entity_block_pos = BlockPos::from(entity_pos); + + if !blocks_visited.contains(&entity_block_pos) { + blocks_visited.push(entity_block_pos); + + if blocks_visited.len() == 8 { + loops_done += 1; + blocks_visited.clear(); + } + } + } + + assert_eq!( + blocks_visited.into_iter().collect::>(), + vec![ + BlockPos::new(3, 70, 2), + BlockPos::new(3, 70, 1), + BlockPos::new(2, 70, 1), + BlockPos::new(1, 70, 1), + ] + ); + assert_eq!(loops_done, 1); +} diff --git a/azalea-protocol/src/connect.rs b/azalea-protocol/src/connect.rs index a4c558a1..13a86ed8 100755 --- a/azalea-protocol/src/connect.rs +++ b/azalea-protocol/src/connect.rs @@ -296,7 +296,7 @@ impl Connection { let _ = socks5_impl::client::connect(&mut stream, address, proxy.auth) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + .map_err(io::Error::other)?; Self::new_from_stream(stream.into_inner()).await } diff --git a/azalea/src/accept_resource_packs.rs b/azalea/src/accept_resource_packs.rs index 807ad355..560140d0 100644 --- a/azalea/src/accept_resource_packs.rs +++ b/azalea/src/accept_resource_packs.rs @@ -1,7 +1,7 @@ use azalea_client::InConfigState; use azalea_client::chunks::handle_chunk_batch_finished_event; use azalea_client::inventory::InventorySet; -use azalea_client::packet::config::SendConfigPacketEvent; +use azalea_client::packet::config::{SendConfigPacketEvent, handle_send_packet_event}; use azalea_client::packet::game::SendPacketEvent; use azalea_client::packet::{death_event_on_0_health, game::ResourcePackEvent}; use azalea_client::respawn::perform_respawn; @@ -23,7 +23,9 @@ impl Plugin for AcceptResourcePacksPlugin { .before(perform_respawn) .after(death_event_on_0_health) .after(handle_chunk_batch_finished_event) - .after(InventorySet), + .after(InventorySet) + .before(handle_send_packet_event) + .after(azalea_client::brand::handle_end_login_state), ); } } diff --git a/codegen/genblocks.py b/codegen/genblocks.py index 1024072a..d0bea909 100755 --- a/codegen/genblocks.py +++ b/codegen/genblocks.py @@ -13,13 +13,14 @@ def generate(version_id): '1.20.3-pre4', 'shapes') pixlyzer_block_datas = lib.extract.get_pixlyzer_data( '1.20.3-pre4', 'blocks') + burger_data = lib.extract.get_burger_data_for_version(version_id) block_states_report = lib.extract.get_block_states_report(version_id) registries = lib.extract.get_registries_report(version_id) ordered_blocks = lib.code.blocks.get_ordered_blocks(registries) lib.code.blocks.generate_blocks( - block_states_report, pixlyzer_block_datas, ordered_blocks) + block_states_report, pixlyzer_block_datas, ordered_blocks, burger_data) lib.code.shapes.generate_block_shapes( pixlyzer_block_datas, shape_datas['shapes'], shape_datas['aabbs'], block_states_report) diff --git a/codegen/lib/code/blocks.py b/codegen/lib/code/blocks.py index 2733093b..181ce774 100755 --- a/codegen/lib/code/blocks.py +++ b/codegen/lib/code/blocks.py @@ -12,13 +12,15 @@ BLOCKS_RS_DIR = get_dir_location('../azalea-block/src/generated.rs') # - Block: Has properties and states. -def generate_blocks(blocks_report: dict, pixlyzer_block_datas: dict, ordered_blocks: list[str]): +def generate_blocks(blocks_report: dict, pixlyzer_block_datas: dict, ordered_blocks: list[str], burger_data: dict): with open(BLOCKS_RS_DIR, 'r') as f: existing_code = f.read().splitlines() new_make_block_states_macro_code = [] new_make_block_states_macro_code.append('make_block_states! {') + burger_block_datas = burger_data[0]['blocks']['block'] + # Find properties properties = {} @@ -77,6 +79,7 @@ def generate_blocks(blocks_report: dict, pixlyzer_block_datas: dict, ordered_blo for block_id in ordered_blocks: block_data_report = blocks_report['minecraft:' + block_id] block_data_pixlyzer = pixlyzer_block_datas.get(f'minecraft:{block_id}', {}) + block_data_burger = burger_block_datas.get(block_id, {}) default_property_variants: dict[str, str] = {} for state in block_data_report['states']: @@ -129,6 +132,14 @@ def generate_blocks(blocks_report: dict, pixlyzer_block_datas: dict, ordered_blo friction = block_data_pixlyzer.get('friction') if friction != None: behavior_constructor += f'.friction({friction})' + + force_solid = None + if block_data_burger.get('force_solid_on'): + force_solid = 'true' + elif block_data_burger.get('force_solid_off'): + force_solid = 'false' + if force_solid != None: + behavior_constructor += f'.force_solid({force_solid})' # TODO: use burger to generate the blockbehavior new_make_block_states_macro_code.append( diff --git a/codegen/lib/extract.py b/codegen/lib/extract.py index 4119ad55..c62b2b99 100755 --- a/codegen/lib/extract.py +++ b/codegen/lib/extract.py @@ -1,7 +1,7 @@ # Extracting data from the Minecraft jars from typing import TYPE_CHECKING -from lib.download import get_server_jar, get_burger, get_client_jar, get_pixlyzer, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions +from lib.download import get_mappings_for_version, get_server_jar, get_burger, get_client_jar, get_pixlyzer, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions from lib.utils import get_dir_location, to_camel_case, upper_first_letter from zipfile import ZipFile import subprocess @@ -53,19 +53,8 @@ python_command = None def determine_python_command(): - global python_command - if python_command: - return python_command - - def try_python_command(version): - return os.system(f'{version} --version') == 0 - - for version in (sys.executable, 'python3.9', 'python3.8', 'python3', 'python'): - if try_python_command(version): - python_command = version - return version - raise Exception( - 'Couldn\'t determine python command to use to run burger with!') + return 'venv/bin/python' + def run_python_command_and_download_deps(command): @@ -105,10 +94,14 @@ def get_burger_data_for_version(version_id: str): if not os.path.exists(get_dir_location(f'__cache__/burger-{version_id}.json')): get_burger() get_client_jar(version_id) + get_mappings_for_version(version_id) print('\033[92mRunning Burger...\033[m') run_python_command_and_download_deps( - f'cd {get_dir_location("__cache__/Burger")} && {determine_python_command()} munch.py {get_dir_location("__cache__")}/client-{version_id}.jar --output {get_dir_location("__cache__")}/burger-{version_id}.json' + f'cd {get_dir_location("__cache__/Burger")} && '\ + f'{determine_python_command()} munch.py {get_dir_location("__cache__")}/client-{version_id}.jar '\ + f'--output {get_dir_location("__cache__")}/burger-{version_id}.json '\ + f'--mappings {get_dir_location("__cache__")}/mappings-{version_id}.txt' ) with open(get_dir_location(f'__cache__/burger-{version_id}.json'), 'r') as f: return json.load(f) diff --git a/codegen/lib/mappings.py b/codegen/lib/mappings.py index 22624fac..9c39fc2b 100755 --- a/codegen/lib/mappings.py +++ b/codegen/lib/mappings.py @@ -78,7 +78,6 @@ class Mappings: return self.classes[obfuscated_class_name] def get_method(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature): - # print(obfuscated_class_name, self.methods[obfuscated_class_name]) return self.methods[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})'] def get_field_type(self, obfuscated_class_name, obfuscated_field_name) -> str: