From 755a1bd74934ecf06478ec7191e664d85d8f4a62 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 2 May 2026 22:04:26 +0200 Subject: [PATCH] chore: more entities taking sun damage instead of hardcoding, it now uses the tag::EntityType::MINECRAFT_BURN_IN_DAYLIGHT, will definitely be more future proof as well --- pumpkin/src/entity/mob/mod.rs | 128 +++++++++--------- pumpkin/src/entity/mob/skeleton/bogged.rs | 9 +- pumpkin/src/entity/mob/skeleton/skeleton.rs | 9 +- pumpkin/src/entity/mob/skeleton/stray.rs | 9 +- pumpkin/src/entity/mob/zombie/drowned.rs | 9 +- pumpkin/src/entity/mob/zombie/zombie.rs | 10 +- .../src/entity/mob/zombie/zombie_villager.rs | 10 +- 7 files changed, 72 insertions(+), 112 deletions(-) diff --git a/pumpkin/src/entity/mob/mod.rs b/pumpkin/src/entity/mob/mod.rs index 6c41c98f7..c79ca5734 100644 --- a/pumpkin/src/entity/mob/mod.rs +++ b/pumpkin/src/entity/mob/mod.rs @@ -8,9 +8,9 @@ use crate::world::World; use crossbeam::atomic::AtomicCell; use pumpkin_data::attributes::Attributes; use pumpkin_data::damage::DamageType; -use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::tag::{self, Taggable}; use pumpkin_data::tracked_data::TrackedData; use pumpkin_protocol::java::client::play::{CHeadRot, CUpdateEntityRot, Metadata}; use pumpkin_util::math::boundingbox::BoundingBox; @@ -240,6 +240,68 @@ impl MobEntity { base_box.expand(attack_range, 0.0, attack_range) } + + pub async fn tick_sun_burn(&self) { + if !self + .living_entity + .entity + .entity_type + .has_tag(&tag::EntityType::MINECRAFT_BURN_IN_DAYLIGHT) + { + return; + } + if !self.is_sun_burn_tick().await { + return; + } + self.apply_sun_burn(); + } + + async fn is_sun_burn_tick(&self) -> bool { + let entity = &self.living_entity.entity; + + let world_arc = entity.world.load(); + let world = world_arc.as_ref(); + + // TODO: gate behind EnvironmentAttributes::MONSTERS_BURN once implemented. + + // Vanilla: getLightLevelDependentMagicValue() — sky light at eye pos, scaled 0–1. + let eye_block_pos = entity.get_eye_pos(); + let brightness = world + .level + .light_engine + .get_sky_light_level(&world.level, &eye_block_pos.to_block_pos()) + .await as f32 + / 15.0; + + if brightness <= 0.5 { + return false; + } + + let is_in_non_burnable = entity.touching_water.load(Relaxed) + || world.weather.lock().await.raining + || entity.is_in_powder_snow() + || entity.was_in_powder_snow.load(Relaxed); + + if is_in_non_burnable { + return false; + } + + let pos = entity.pos.load(); + let top_y = world + .get_top_block(Vector2::new(pos.x as i32, pos.z as i32)) + .await; + if (entity.get_eye_y() as i32) < top_y { + return false; + } + + let mut rng = rand::rng(); + rng.random::() * 30.0 < (brightness - 0.4) * 2.0 + } + + fn apply_sun_burn(&self) { + let entity = &self.living_entity.entity; + entity.set_on_fire_for(8.0); + } } pub trait Mob: EntityBase + Send + Sync { @@ -348,6 +410,7 @@ impl EntityBase for T { ) -> EntityBaseFuture<'a, ()> { Box::pin(async move { let mob_entity = self.get_mob_entity(); + mob_entity.tick_sun_burn().await; if mob_entity.breeding_cooldown.load(Relaxed) > 0 { mob_entity.breeding_cooldown.fetch_sub(1, Relaxed); @@ -578,66 +641,3 @@ pub trait PathAwareEntity: Mob + Send + Sync { 1.0 } } - -pub trait SunSensitive: Mob + Send + Sync { - fn sun_sensitive_tick(&self) -> EntityBaseFuture<'_, ()> { - Box::pin(async { - let mob = self.get_mob_entity(); - let entity = &mob.living_entity.entity; - - if !entity.is_alive() - || entity.touching_water.load(Relaxed) - || entity.is_in_powder_snow() - { - return; - } - - let world_arc = entity.world.load(); - let world = world_arc.as_ref(); - - if world.level_time.lock().await.is_night() { - return; - } - if world.weather.lock().await.raining { - return; - } - - let pos = entity.pos.load(); - let top_y = world - .get_top_block(Vector2::new(pos.x as i32, pos.z as i32)) - .await; - if (entity.get_eye_y() as i32) < top_y { - return; - } - - let brightness = world - .level - .light_engine - .get_sky_light_level(&world.level, &pos.to_block_pos()) - .await as f32 - / 15.0; - - if brightness < 0.5 { - return; - } - - let damage_amount = { - let mut rng = self.get_random(); - if rng.random::() * 30.0 >= (brightness - 0.4) * 2.0 { - return; - } - rng.random_range(0..=1i32) - }; - - let equipment = mob.living_entity.entity_equipment.lock().await; - let head_slot = equipment.get(&EquipmentSlot::HEAD); - let mut head_item = head_slot.lock().await; - if head_item.is_empty() { - entity.set_on_fire_for(8.0); - } else { - // TODO: Handle DamageResult::Broken to broadcast item break and update player slot. - let _ = head_item.damage_item(damage_amount); - } - }) - } -} diff --git a/pumpkin/src/entity/mob/skeleton/bogged.rs b/pumpkin/src/entity/mob/skeleton/bogged.rs index 6b03c9322..56d89e4f9 100644 --- a/pumpkin/src/entity/mob/skeleton/bogged.rs +++ b/pumpkin/src/entity/mob/skeleton/bogged.rs @@ -1,6 +1,5 @@ -use crate::entity::mob::SunSensitive; use crate::entity::{ - Entity, EntityBase, EntityBaseFuture, NBTStorage, + Entity, NBTStorage, mob::{Mob, MobEntity, skeleton::SkeletonEntityBase}, }; use std::sync::Arc; @@ -23,10 +22,4 @@ impl Mob for BoggedSkeletonEntity { fn get_mob_entity(&self) -> &MobEntity { &self.entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for BoggedSkeletonEntity {} diff --git a/pumpkin/src/entity/mob/skeleton/skeleton.rs b/pumpkin/src/entity/mob/skeleton/skeleton.rs index b198d0006..8b1532f6c 100644 --- a/pumpkin/src/entity/mob/skeleton/skeleton.rs +++ b/pumpkin/src/entity/mob/skeleton/skeleton.rs @@ -1,8 +1,7 @@ use std::sync::Arc; -use crate::entity::mob::SunSensitive; use crate::entity::{ - Entity, EntityBase, EntityBaseFuture, NBTStorage, + Entity, NBTStorage, mob::{Mob, MobEntity, skeleton::SkeletonEntityBase}, }; @@ -24,10 +23,4 @@ impl Mob for SkeletonEntity { fn get_mob_entity(&self) -> &MobEntity { &self.entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for SkeletonEntity {} diff --git a/pumpkin/src/entity/mob/skeleton/stray.rs b/pumpkin/src/entity/mob/skeleton/stray.rs index bc3f2cab7..0c6014ef5 100644 --- a/pumpkin/src/entity/mob/skeleton/stray.rs +++ b/pumpkin/src/entity/mob/skeleton/stray.rs @@ -1,8 +1,7 @@ use std::sync::Arc; -use crate::entity::mob::SunSensitive; use crate::entity::{ - Entity, EntityBase, EntityBaseFuture, NBTStorage, + Entity, NBTStorage, mob::{Mob, MobEntity, skeleton::SkeletonEntityBase}, }; @@ -24,10 +23,4 @@ impl Mob for StraySkeletonEntity { fn get_mob_entity(&self) -> &MobEntity { &self.entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for StraySkeletonEntity {} diff --git a/pumpkin/src/entity/mob/zombie/drowned.rs b/pumpkin/src/entity/mob/zombie/drowned.rs index 64c7fedc9..da5b11de2 100644 --- a/pumpkin/src/entity/mob/zombie/drowned.rs +++ b/pumpkin/src/entity/mob/zombie/drowned.rs @@ -1,9 +1,8 @@ use std::sync::Arc; -use crate::entity::mob::SunSensitive; use crate::entity::mob::zombie::ZombieEntityBase; use crate::entity::{ - Entity, EntityBase, EntityBaseFuture, NBTStorage, + Entity, NBTStorage, mob::{Mob, MobEntity}, }; @@ -41,10 +40,4 @@ impl Mob for DrownedEntity { fn get_mob_entity(&self) -> &MobEntity { &self.entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for DrownedEntity {} diff --git a/pumpkin/src/entity/mob/zombie/zombie.rs b/pumpkin/src/entity/mob/zombie/zombie.rs index 625643207..1e992c06b 100644 --- a/pumpkin/src/entity/mob/zombie/zombie.rs +++ b/pumpkin/src/entity/mob/zombie/zombie.rs @@ -1,6 +1,6 @@ +use crate::entity::NBTStorage; use crate::entity::mob::zombie::ZombieEntityBase; -use crate::entity::mob::{Mob, MobEntity, SunSensitive}; -use crate::entity::{EntityBase, EntityBaseFuture, NBTStorage}; +use crate::entity::mob::{Mob, MobEntity}; use std::sync::Arc; pub struct ZombieEntity { @@ -21,10 +21,4 @@ impl Mob for ZombieEntity { fn get_mob_entity(&self) -> &MobEntity { &self.entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for ZombieEntity {} diff --git a/pumpkin/src/entity/mob/zombie/zombie_villager.rs b/pumpkin/src/entity/mob/zombie/zombie_villager.rs index 5e21159d5..e5597524f 100644 --- a/pumpkin/src/entity/mob/zombie/zombie_villager.rs +++ b/pumpkin/src/entity/mob/zombie/zombie_villager.rs @@ -1,6 +1,6 @@ use crate::entity::mob::zombie::ZombieEntityBase; -use crate::entity::mob::{Mob, MobEntity, SunSensitive}; -use crate::entity::{Entity, EntityBase, EntityBaseFuture, NBTStorage}; +use crate::entity::mob::{Mob, MobEntity}; +use crate::entity::{Entity, NBTStorage}; use std::sync::Arc; pub struct ZombieVillagerEntity { @@ -21,10 +21,4 @@ impl Mob for ZombieVillagerEntity { fn get_mob_entity(&self) -> &MobEntity { &self.mob_entity.mob_entity } - - fn mob_tick<'a>(&'a self, _caller: &'a Arc) -> EntityBaseFuture<'a, ()> { - self.sun_sensitive_tick() - } } - -impl SunSensitive for ZombieVillagerEntity {}