diff --git a/pumpkin-util/src/math/boundingbox.rs b/pumpkin-util/src/math/boundingbox.rs index 2f64ac63f..9c65feb32 100644 --- a/pumpkin-util/src/math/boundingbox.rs +++ b/pumpkin-util/src/math/boundingbox.rs @@ -61,6 +61,14 @@ impl BoundingBox { } } + pub fn expand_all(&self, value: f64) -> Self { + self.expand(value, value, value) + } + + pub fn contract_all(&self, value: f64) -> Self { + self.expand_all(-value) + } + pub fn offset(&self, other: Self) -> Self { Self { min: self.min.add(&other.min), @@ -207,4 +215,15 @@ impl BoundingBox { pub struct EntityDimensions { pub width: f32, pub height: f32, + pub eye_height: f32, +} + +impl EntityDimensions { + pub fn new(width: f32, height: f32, eye_height: f32) -> Self { + Self { + width, + height, + eye_height, + } + } } diff --git a/pumpkin-world/src/block/entities/mob_spawner.rs b/pumpkin-world/src/block/entities/mob_spawner.rs index 75c0d55f2..5022f66a7 100644 --- a/pumpkin-world/src/block/entities/mob_spawner.rs +++ b/pumpkin-world/src/block/entities/mob_spawner.rs @@ -113,6 +113,7 @@ impl BlockEntity for MobSpawnerBlockEntity { &EntityDimensions { width: entity_type.dimension[0], height: entity_type.dimension[1], + eye_height: entity_type.eye_height, }, )) .await diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index 250618efb..95f010642 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -638,7 +638,7 @@ impl LivingEntity { } pub fn get_swim_height(&self) -> f64 { - let eye_height = self.entity.standing_eye_height; + let eye_height = self.entity.entity_dimension.load().eye_height; if self.entity.entity_type == &EntityType::BREEZE { f64::from(eye_height) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index f6de0a861..35c5ada63 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -321,14 +321,12 @@ pub struct Entity { pub body_yaw: AtomicCell, /// The entity's pitch rotation (vertical rotation) ↑ ↓ pub pitch: AtomicCell, - /// The height of the entity's eyes from the ground. - pub standing_eye_height: f32, /// The entity's current pose (e.g., standing, sitting, swimming). pub pose: AtomicCell, /// The bounding box of an entity (hitbox) pub bounding_box: AtomicCell, ///The size (width and height) of the bounding box - pub bounding_box_size: AtomicCell, + pub entity_dimension: AtomicCell, /// Whether this entity is invulnerable to all damage pub invulnerable: AtomicBool, /// List of damage types this entity is immune to @@ -378,6 +376,7 @@ impl Entity { let bounding_box_size = EntityDimensions { width: entity_type.dimension[0], height: entity_type.dimension[1], + eye_height: entity_type.eye_height, }; Self { @@ -408,7 +407,6 @@ impl Entity { body_yaw: AtomicCell::new(0.0), pitch: AtomicCell::new(0.0), velocity: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)), - standing_eye_height: entity_type.eye_height, pose: AtomicCell::new(EntityPose::Standing), first_loaded_chunk_position: AtomicCell::new(None), bounding_box: AtomicCell::new(BoundingBox::new_from_pos( @@ -417,7 +415,7 @@ impl Entity { position.z, &bounding_box_size, )), - bounding_box_size: AtomicCell::new(bounding_box_size), + entity_dimension: AtomicCell::new(bounding_box_size), invulnerable: AtomicBool::new(invulnerable), damage_immunities: Vec::new(), data: AtomicI32::new(0), @@ -460,6 +458,19 @@ impl Entity { .await; } + #[must_use] + pub fn get_entity_dimensions(pose: EntityPose) -> EntityDimensions { + match pose { + EntityPose::Sleeping => EntityDimensions::new(0.2, 0.2, 0.2), + EntityPose::FallFlying | EntityPose::Swimming | EntityPose::SpinAttack => { + EntityDimensions::new(0.6, 0.6, 0.4) + } + EntityPose::Crouching => EntityDimensions::new(0.6, 1.5, 1.27), + EntityPose::Dying => EntityDimensions::new(0.2, 0.2, 1.62), + _ => EntityDimensions::new(0.6, 1.8, 1.62), + } + } + /// Updates the entity's position, block position, and chunk position. /// /// This function calculates the new position, block position, and chunk position based on the provided coordinates. If any of these values change, the corresponding fields are updated. @@ -471,7 +482,7 @@ impl Entity { new_position.x, new_position.y, new_position.z, - &self.bounding_box_size.load(), + &self.entity_dimension.load(), )); let floor_x = new_position.x.floor() as i32; @@ -806,7 +817,7 @@ impl Entity { let mut eye_level_box = aabb; - let eye_height = f64::from(self.standing_eye_height); + let eye_height = f64::from(self.entity_dimension.load().eye_height); eye_level_box.min.y += eye_height; @@ -1400,11 +1411,11 @@ impl Entity { ) } pub fn width(&self) -> f32 { - self.bounding_box_size.load().width + self.entity_dimension.load().width } pub fn height(&self) -> f32 { - self.bounding_box_size.load().height + self.entity_dimension.load().height } /// Applies knockback to the entity, following vanilla Minecraft's mechanics. @@ -1634,14 +1645,22 @@ impl Entity { } pub async fn set_pose(&self, pose: EntityPose) { - self.pose.store(pose); - let pose = pose as i32; - self.send_meta_data(&[Metadata::new( - TrackedData::DATA_POSE, - MetaDataType::EntityPose, - VarInt(pose), - )]) - .await; + let dimension = Self::get_entity_dimensions(pose); + let position = self.pos.load(); + let aabb = BoundingBox::new_from_pos(position.x, position.y, position.z, &dimension); + if self.world.is_space_empty(aabb.contract_all(1.0E-7)).await { + self.pose.store(pose); + let dimension = Self::get_entity_dimensions(pose); + self.bounding_box.store(aabb); + self.entity_dimension.store(dimension); + let pose = pose as i32; + self.send_meta_data(&[Metadata::new( + TrackedData::DATA_POSE, + MetaDataType::EntityPose, + VarInt(pose), + )]) + .await; + } } pub fn is_invulnerable_to(&self, damage_type: &DamageType) -> bool { @@ -1735,7 +1754,7 @@ impl Entity { } pub fn get_eye_y(&self) -> f64 { - self.pos.load().y + f64::from(self.standing_eye_height) + self.pos.load().y + f64::from(self.entity_dimension.load().eye_height) } pub fn is_removed(&self) -> bool { diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index fad5615c7..91f073061 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1081,11 +1081,7 @@ impl Player { } pub fn eye_position(&self) -> Vector3 { - let eye_height = if self.living_entity.entity.pose.load() == EntityPose::Crouching { - 1.27 - } else { - f64::from(self.living_entity.entity.standing_eye_height) - }; + let eye_height = f64::from(self.living_entity.entity.entity_dimension.load().eye_height); Vector3::new( self.living_entity.entity.pos.load().x, self.living_entity.entity.pos.load().y + eye_height, @@ -1388,7 +1384,7 @@ impl Player { let d = self.block_interaction_range() + additional_range; let box_pos = BoundingBox::from_block(position); let entity_pos = self.living_entity.entity.pos.load(); - let standing_eye_height = self.living_entity.entity.standing_eye_height; + let standing_eye_height = self.living_entity.entity.entity_dimension.load().eye_height; box_pos.squared_magnitude(Vector3 { x: entity_pos.x, y: entity_pos.y + f64::from(standing_eye_height), diff --git a/pumpkin/src/entity/projectile/mod.rs b/pumpkin/src/entity/projectile/mod.rs index 5c2c96d85..64a9ffd97 100644 --- a/pumpkin/src/entity/projectile/mod.rs +++ b/pumpkin/src/entity/projectile/mod.rs @@ -16,7 +16,7 @@ pub struct ThrownItemEntity { impl ThrownItemEntity { pub fn new(entity: Entity, owner: &Entity) -> Self { let mut owner_pos = owner.pos.load(); - owner_pos.y = (owner_pos.y + f64::from(owner.standing_eye_height)) - 0.1; + owner_pos.y = (owner_pos.y + f64::from(owner.entity_dimension.load().eye_height)) - 0.1; entity.pos.store(owner_pos); Self { entity } } diff --git a/pumpkin/src/world/natural_spawner.rs b/pumpkin/src/world/natural_spawner.rs index 497cdb9de..9e62ef5f7 100644 --- a/pumpkin/src/world/natural_spawner.rs +++ b/pumpkin/src/world/natural_spawner.rs @@ -567,6 +567,7 @@ pub async fn is_valid_spawn_position_for_type( &EntityDimensions { width: entity_type.dimension[0], height: entity_type.dimension[1], + eye_height: entity_type.eye_height, }, )) .await