Cactus hurts now

This commit is contained in:
Alexander Medvedev
2025-05-15 18:35:41 +02:00
parent 81c45b7c78
commit 4b9c92dff0
13 changed files with 59 additions and 37 deletions

View File

@@ -1,11 +1,12 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::block_properties::{
BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15,
};
use pumpkin_data::damage::DamageType;
use pumpkin_data::tag::Tagable;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
@@ -15,6 +16,7 @@ use pumpkin_world::chunk::TickPriority;
use pumpkin_world::world::BlockFlags;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::EntityBase;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
@@ -59,6 +61,17 @@ impl PumpkinBlock for CactusBlock {
}
}
async fn on_entity_collision(
&self,
_world: &Arc<World>,
entity: &dyn EntityBase,
_pos: BlockPos,
_block: Block,
_state: BlockState,
) {
entity.damage(1.0, DamageType::CACTUS).await;
}
async fn get_state_for_neighbor_update(
&self,
world: &World,

View File

@@ -11,7 +11,7 @@ use pumpkin_world::{BlockStateId, block::BlockDirection};
use crate::{
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
entity::Entity,
entity::EntityBase,
world::World,
};
@@ -44,7 +44,7 @@ impl PumpkinBlock for PressurePlateBlock {
async fn on_entity_collision(
&self,
world: &Arc<World>,
_entity: &Entity,
_entity: &dyn EntityBase,
pos: BlockPos,
block: Block,
state: BlockState,

View File

@@ -10,7 +10,7 @@ use pumpkin_world::{BlockStateId, block::BlockDirection};
use crate::{
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
entity::Entity,
entity::EntityBase,
world::World,
};
@@ -41,7 +41,7 @@ impl PumpkinBlock for WeightedPressurePlateBlock {
async fn on_entity_collision(
&self,
world: &Arc<World>,
_entity: &Entity,
_entity: &dyn EntityBase,
pos: BlockPos,
block: Block,
state: BlockState,

View File

@@ -1,5 +1,5 @@
use crate::block::registry::BlockActionResult;
use crate::entity::Entity;
use crate::entity::EntityBase;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
@@ -53,7 +53,7 @@ pub trait PumpkinBlock: Send + Sync {
async fn on_entity_collision(
&self,
_world: &Arc<World>,
_entity: &Entity,
_entity: &dyn EntityBase,
_pos: BlockPos,
_block: Block,
_state: BlockState,

View File

@@ -1,5 +1,5 @@
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
use crate::entity::Entity;
use crate::entity::EntityBase;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
@@ -60,7 +60,7 @@ impl BlockRegistry {
&self,
block: Block,
world: &Arc<World>,
entity: &Entity,
entity: &dyn EntityBase,
pos: BlockPos,
state: BlockState,
) {

View File

@@ -64,8 +64,8 @@ impl ExperienceOrbEntity {
#[async_trait]
impl EntityBase for ExperienceOrbEntity {
async fn tick(&self, server: &Server) {
self.entity.tick(server).await;
async fn tick(&self, caller: &dyn EntityBase, server: &Server) {
self.entity.tick(caller, server).await;
let age = self
.orb_age
@@ -79,7 +79,7 @@ impl EntityBase for ExperienceOrbEntity {
&self.entity
}
async fn on_player_collision(&self, player: Arc<Player>) {
async fn on_player_collision(&self, player: &Arc<Player>) {
let mut delay = player.experience_pick_up_delay.lock().await;
if *delay == 0 {
*delay = 2;

View File

@@ -63,9 +63,9 @@ impl ItemEntity {
#[async_trait]
impl EntityBase for ItemEntity {
async fn tick(&self, server: &Server) {
async fn tick(&self, caller: &dyn EntityBase, server: &Server) {
let entity = &self.entity;
entity.tick(server).await;
entity.tick(caller, server).await;
{
let mut delay = self.pickup_delay.lock().await;
*delay = delay.saturating_sub(1);
@@ -91,7 +91,7 @@ impl EntityBase for ItemEntity {
false
}
async fn on_player_collision(&self, player: Arc<Player>) {
async fn on_player_collision(&self, player: &Arc<Player>) {
let can_pickup = {
let delay = self.pickup_delay.lock().await;
*delay == 0

View File

@@ -262,7 +262,7 @@ impl LivingEntity {
.await;
}
async fn tick_move(&self) {
async fn tick_move(&self, entity: &dyn EntityBase) {
let velo = self.entity.velocity.load();
let pos = self.entity.pos.load();
self.entity
@@ -272,7 +272,7 @@ impl LivingEntity {
self.entity
.velocity
.store(velo.multiply(multiplier, 1.0, multiplier));
self.entity.check_block_collision().await;
Entity::check_block_collision(entity).await;
}
async fn tick_effects(&self) {
@@ -296,9 +296,9 @@ impl LivingEntity {
#[async_trait]
impl EntityBase for LivingEntity {
async fn tick(&self, server: &Server) {
self.entity.tick(server).await;
self.tick_move().await;
async fn tick(&self, caller: &dyn EntityBase, server: &Server) {
self.entity.tick(caller, server).await;
self.tick_move(caller).await;
self.tick_effects().await;
if self.time_until_regen.load(Relaxed) > 0 {
self.time_until_regen.fetch_sub(1, Relaxed);

View File

@@ -24,8 +24,8 @@ pub struct MobEntity {
#[async_trait]
impl EntityBase for MobEntity {
async fn tick(&self, server: &Server) {
self.living_entity.tick(server).await;
async fn tick(&self, caller: &dyn EntityBase, server: &Server) {
self.living_entity.tick(caller, server).await;
let mut goals = self.goals.lock().await;
for (goal, running) in goals.iter_mut() {
if *running {

View File

@@ -57,12 +57,18 @@ pub type EntityId = i32;
#[async_trait]
pub trait EntityBase: Send + Sync {
/// Gets Called every tick
async fn tick(&self, server: &Server) {
/// Called every tick for this entity.
///
/// The `caller` parameter is a reference to the entity that initiated the tick.
/// This can be the same entity the method is being called on (`self`),
/// but in some scenarios (e.g., interactions or events), it might be a different entity.
///
/// The `server` parameter provides access to the game server instance.
async fn tick(&self, caller: &dyn EntityBase, server: &Server) {
if let Some(living) = self.get_living_entity() {
living.tick(server).await;
living.tick(caller, server).await;
} else {
self.get_entity().tick(server).await;
self.get_entity().tick(caller, server).await;
}
}
@@ -78,7 +84,7 @@ pub trait EntityBase: Send + Sync {
}
/// Called when a player collides with a entity
async fn on_player_collision(&self, _player: Arc<Player>) {}
async fn on_player_collision(&self, _player: &Arc<Player>) {}
fn get_entity(&self) -> &Entity;
fn get_living_entity(&self) -> Option<&LivingEntity>;
}
@@ -485,8 +491,8 @@ impl Entity {
// }
}
pub async fn check_block_collision(&self) {
let aabb = self.bounding_box.load();
pub async fn check_block_collision(entity: &dyn EntityBase) {
let aabb = entity.get_entity().bounding_box.load();
let blockpos = BlockPos::new(
(aabb.min.x + 0.001).floor() as i32,
(aabb.min.y + 0.001).floor() as i32,
@@ -497,7 +503,7 @@ impl Entity {
(aabb.max.y - 0.001).floor() as i32,
(aabb.max.z - 0.001).floor() as i32,
);
let world = self.world.read().await;
let world = entity.get_entity().world.read().await;
for x in blockpos.0.x..=blockpos1.0.x {
for y in blockpos.0.y..=blockpos1.0.y {
@@ -506,7 +512,7 @@ impl Entity {
let (block, state) = world.get_block_and_block_state(&pos).await.unwrap();
world
.block_registry
.on_entity_collision(block, &world, self, pos, state)
.on_entity_collision(block, &world, entity, pos, state)
.await;
}
}
@@ -520,8 +526,8 @@ impl EntityBase for Entity {
false
}
async fn tick(&self, _: &Server) {
//Todo! Tick
async fn tick(&self, _caller: &dyn EntityBase, _: &Server) {
// TODO: Tick
}
fn get_entity(&self) -> &Entity {

View File

@@ -663,7 +663,7 @@ impl Player {
self.last_attacked_ticks.fetch_add(1, Relaxed);
self.living_entity.tick(server).await;
self.living_entity.tick(self, server).await;
self.hunger_manager.tick(self).await;
// experience handling
@@ -1797,6 +1797,9 @@ impl NBTStorage for PlayerInventory {
#[async_trait]
impl EntityBase for Player {
async fn damage(&self, amount: f32, damage_type: DamageType) -> bool {
if self.abilities.lock().await.invulnerable {
return false;
}
self.world()
.await
.play_sound(

View File

@@ -31,7 +31,7 @@ impl TNTEntity {
#[async_trait]
impl EntityBase for TNTEntity {
async fn tick(&self, server: &Server) {
async fn tick(&self, _caller: &dyn EntityBase, server: &Server) {
let fuse = self.fuse.fetch_sub(1, Relaxed);
if fuse == 0 {
self.entity.remove().await;

View File

@@ -400,7 +400,7 @@ impl World {
// Entity ticks
for entity in entities_to_tick {
entity.tick(server).await;
entity.tick(entity.as_ref(), server).await;
for player in self.players.read().await.values() {
if player
.living_entity
@@ -411,7 +411,7 @@ impl World {
.expand(1.0, 0.5, 1.0)
.intersects(&entity.get_entity().bounding_box.load())
{
entity.on_player_collision(player.clone()).await;
entity.on_player_collision(player).await;
break;
}
}