From 0acb91377512e63c63b0cdc101b990e14d8b649f Mon Sep 17 00:00:00 2001 From: Mikhail Reznichenko Date: Fri, 13 Feb 2026 13:57:51 +0300 Subject: [PATCH] fix: sweet berry bush collision (#1547) * fix berry bush collision * fix format * fix fall distance * rename function --- .../blocks/plant/crop/sweet_berry_bush.rs | 56 +++++++++++-------- pumpkin/src/entity/living.rs | 9 +++ pumpkin/src/entity/mod.rs | 31 +++++++++- 3 files changed, 73 insertions(+), 23 deletions(-) diff --git a/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs b/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs index d709989d4..4400e2ed9 100644 --- a/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs +++ b/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs @@ -1,22 +1,5 @@ use std::sync::Arc; -use pumpkin_data::{ - Block, - block_properties::{BlockProperties, EnumVariants, Integer0To3, NetherWartLikeProperties}, - damage::DamageType, - entity::EntityType, - item::Item, - tag::{self, Taggable}, -}; -use pumpkin_macros::pumpkin_block; -use pumpkin_util::math::position::BlockPos; -use pumpkin_world::{ - BlockStateId, - item::ItemStack, - world::{BlockAccessor, BlockFlags}, -}; -use rand::RngExt; - use crate::{ block::{ BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, NormalUseArgs, @@ -26,6 +9,23 @@ use crate::{ }, world::World, }; +use pumpkin_data::{ + Block, + block_properties::{BlockProperties, EnumVariants, Integer0To3, NetherWartLikeProperties}, + damage::DamageType, + entity::EntityType, + item::Item, + tag::{self, Taggable}, +}; +use pumpkin_macros::pumpkin_block; +use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; +use pumpkin_world::{ + BlockStateId, + item::ItemStack, + world::{BlockAccessor, BlockFlags}, +}; +use rand::RngExt; #[pumpkin_block("minecraft:sweet_berry_bush")] pub struct SweetBerryBushBlock; @@ -104,20 +104,32 @@ impl BlockBehaviour for SweetBerryBushBlock { Box::pin(async move { let entity = args.entity.get_entity(); - if entity.entity_type == &EntityType::FOX || entity.entity_type == &EntityType::BEE { + let living_entity_opt = args.entity.get_living_entity(); + if living_entity_opt.is_none() + || entity.entity_type == &EntityType::FOX + || entity.entity_type == &EntityType::BEE + { return; } + let living_entity = living_entity_opt.expect("Living entity should exist"); + entity + .slow_movement(args.state, Vector3::new(0.8, 0.75, 0.8)) + .await; + let mov = if living_entity.is_player() { + living_entity.get_movement() + } else { + entity.last_pos.load() - entity.pos.load() + }; + let state_id = args.world.get_block_state_id(args.position).await; let props = NetherWartLikeProperties::from_state_id(state_id, args.block); if props.age == Integer0To3::L0 { return; } - let velocity = entity.velocity.load(); // FIXME: velocity != momentum/movement - - if velocity.horizontal_length_squared() <= 0.0 - || (velocity.x.abs() < 0.003 && velocity.z.abs() < 0.003) + if mov.horizontal_length_squared() <= 0.0 + || (mov.x.abs() < 0.003 && mov.z.abs() < 0.003) { return; } diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index dc04288bb..d1a773a43 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -1142,6 +1142,15 @@ impl LivingEntity { self.dead.store(false, Relaxed); } + + pub fn is_player(&self) -> bool { + let world = self.entity.world.load(); + world.get_player_by_id(self.entity.entity_id).is_some() + } + + pub fn get_movement(&self) -> Vector3 { + self.entity.movement.load() + } } impl NBTStorage for LivingEntity { diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 6da3c7ab8..acdf0b4a4 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -326,6 +326,8 @@ pub struct Entity { pub pos: AtomicCell>, /// The last known position of the entity. pub last_pos: AtomicCell>, + /// The last movement vector + pub movement: AtomicCell>, /// The entity's position rounded to the nearest block coordinates pub block_pos: AtomicCell, /// The block supporting the entity @@ -443,6 +445,7 @@ impl Entity { horizontal_collision: AtomicBool::new(false), pos: AtomicCell::new(position), last_pos: AtomicCell::new(position), + movement: AtomicCell::new(Vector3::default()), block_pos: AtomicCell::new(BlockPos(Vector3::new(floor_x, floor_y, floor_z))), supporting_block_pos: AtomicCell::new(None), chunk_pos: AtomicCell::new(Vector2::new( @@ -968,7 +971,7 @@ impl Entity { pub fn update_last_pos(&self) -> Vector3 { let pos = self.pos.load(); let old = self.last_pos.load(); - + self.movement.store(pos - old); self.last_pos.store(pos); old } @@ -2074,6 +2077,31 @@ impl Entity { self.extinguish(); self.set_on_fire(false).await; } + + pub async fn slow_movement(&self, state: &BlockState, multiplier: Vector3) { + match self.entity_type.id { + v if v == EntityType::PLAYER.id => { + if let Some(player_entity) = self.get_player() + && player_entity.is_flying().await + { + return; + } + } + v if v == EntityType::SPIDER.id || v == EntityType::CAVE_SPIDER.id => { + if Block::from_state_id(state.id).id == Block::COBWEB.id { + return; + } + } + v if v == EntityType::WITHER.id => { + return; + } + _ => {} + } + if let Some(living) = self.get_living_entity() { + living.fall_distance.store(0f32); + } + self.movement_multiplier.store(multiplier); + } } impl NBTStorage for Entity { @@ -2168,6 +2196,7 @@ impl EntityBase for Entity { _server: &'a Server, ) -> EntityBaseFuture<'a, ()> { Box::pin(async move { + self.update_last_pos(); self.tick_portal(&caller).await; self.update_fluid_state(&caller).await; self.check_out_of_world(&*caller).await;