diff --git a/pumpkin/src/block/blocks/bed.rs b/pumpkin/src/block/blocks/bed.rs index b77f4c911..b8c21a87a 100644 --- a/pumpkin/src/block/blocks/bed.rs +++ b/pumpkin/src/block/blocks/bed.rs @@ -15,6 +15,7 @@ use pumpkin_world::block::entities::bed::BedBlockEntity; use pumpkin_world::world::BlockFlags; use crate::block::BlockFuture; +use crate::block::OnLandedUponArgs; use crate::block::registry::BlockActionResult; use crate::block::{ BlockBehaviour, BrokenArgs, CanPlaceAtArgs, NormalUseArgs, OnPlaceArgs, OnStateReplacedArgs, @@ -86,6 +87,16 @@ impl BlockBehaviour for BedBlock { }) } + fn on_landed_upon<'a>(&'a self, args: OnLandedUponArgs<'a>) -> BlockFuture<'a, ()> { + Box::pin(async move { + if let Some(living) = args.entity.get_living_entity() { + living + .handle_fall_damage(args.fall_distance * 0.5, 1.0) + .await; + } + }) + } + fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { Box::pin(async move { let mut bed_props = BedProperties::default(args.block); diff --git a/pumpkin/src/block/blocks/hay.rs b/pumpkin/src/block/blocks/hay.rs new file mode 100644 index 000000000..bc1fb20ad --- /dev/null +++ b/pumpkin/src/block/blocks/hay.rs @@ -0,0 +1,16 @@ +use pumpkin_macros::pumpkin_block; + +use crate::block::{BlockBehaviour, BlockFuture, OnLandedUponArgs}; + +#[pumpkin_block("minecraft:hay_block")] +pub struct HayBlock; + +impl BlockBehaviour for HayBlock { + fn on_landed_upon<'a>(&'a self, args: OnLandedUponArgs<'a>) -> BlockFuture<'a, ()> { + Box::pin(async move { + if let Some(living) = args.entity.get_living_entity() { + living.handle_fall_damage(args.fall_distance, 0.2).await; + } + }) + } +} diff --git a/pumpkin/src/block/blocks/mod.rs b/pumpkin/src/block/blocks/mod.rs index c9fdd23b7..7358f0e7a 100644 --- a/pumpkin/src/block/blocks/mod.rs +++ b/pumpkin/src/block/blocks/mod.rs @@ -29,6 +29,7 @@ pub mod furnace; pub mod glass_panes; pub mod glazed_terracotta; pub mod grindstone; +pub mod hay; pub mod iron_bars; pub mod jukebox; pub mod ladder; diff --git a/pumpkin/src/block/blocks/redstone/comparator.rs b/pumpkin/src/block/blocks/redstone/comparator.rs index 012d32867..fc077a28a 100644 --- a/pumpkin/src/block/blocks/redstone/comparator.rs +++ b/pumpkin/src/block/blocks/redstone/comparator.rs @@ -254,7 +254,7 @@ impl RedstoneGateBlock for ComparatorBlock { let (source_block, source_state) = world.get_block_and_state(&source_pos).await; // Note: .get_comparator_output is assumed to be an async method returning Option - if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block) + if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block.id) && let Some(level) = pumpkin_block .get_comparator_output(GetComparatorOutputArgs { world, @@ -276,7 +276,7 @@ impl RedstoneGateBlock for ComparatorBlock { .get_attached_itemframe_level(world, facing, source_pos) .await; let block_level = if let Some(pumpkin_block) = - world.block_registry.get_pumpkin_block(source_block) + world.block_registry.get_pumpkin_block(source_block.id) { pumpkin_block .get_comparator_output(GetComparatorOutputArgs { diff --git a/pumpkin/src/block/mod.rs b/pumpkin/src/block/mod.rs index b2a370a90..fcb6bd5ba 100644 --- a/pumpkin/src/block/mod.rs +++ b/pumpkin/src/block/mod.rs @@ -99,6 +99,14 @@ pub trait BlockBehaviour: Send + Sync { Box::pin(async {}) } + fn on_landed_upon<'a>(&'a self, args: OnLandedUponArgs<'a>) -> BlockFuture<'a, ()> { + Box::pin(async move { + if let Some(living) = args.entity.get_living_entity() { + living.handle_fall_damage(args.fall_distance, 1.0).await; + } + }) + } + fn broken<'a>(&'a self, _args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async {}) } @@ -264,6 +272,12 @@ pub struct PlayerPlacedArgs<'a> { pub player: &'a Player, } +pub struct OnLandedUponArgs<'a> { + pub world: &'a Arc, + pub fall_distance: f32, + pub entity: &'a dyn EntityBase, +} + pub struct BrokenArgs<'a> { pub block: &'a Block, pub player: &'a Arc, diff --git a/pumpkin/src/block/registry.rs b/pumpkin/src/block/registry.rs index 8d5065c30..b4fa62fca 100644 --- a/pumpkin/src/block/registry.rs +++ b/pumpkin/src/block/registry.rs @@ -21,6 +21,7 @@ use crate::block::blocks::fire::soul_fire::SoulFireBlock; use crate::block::blocks::furnace::FurnaceBlock; use crate::block::blocks::glass_panes::GlassPaneBlock; use crate::block::blocks::grindstone::GrindstoneBlock; +use crate::block::blocks::hay::HayBlock; use crate::block::blocks::iron_bars::IronBarsBlock; use crate::block::blocks::logs::LogBlock; use crate::block::blocks::mangrove_roots::MangroveRootsBlock; @@ -77,7 +78,9 @@ use crate::block::blocks::vine::VineBlock; use crate::block::blocks::walls::WallBlock; use crate::block::fluid::lava::FlowingLava; use crate::block::fluid::water::FlowingWater; -use crate::block::{BlockBehaviour, BlockHitResult, BlockMetadata, OnEntityCollisionArgs}; +use crate::block::{ + BlockBehaviour, BlockHitResult, BlockMetadata, OnEntityCollisionArgs, OnLandedUponArgs, +}; use crate::entity::EntityBase; use crate::entity::player::Player; use crate::server::Server; @@ -167,6 +170,7 @@ pub fn default_registry() -> Arc { manager.register(SmokerBlock); manager.register(GlassPaneBlock); manager.register(GlazedTerracottaBlock); + manager.register(HayBlock); manager.register(GrindstoneBlock); manager.register(IronBarsBlock); manager.register(JukeboxBlock); @@ -298,8 +302,8 @@ impl BlockActionResult { #[derive(Default)] pub struct BlockRegistry { - blocks: HashMap<&'static Block, Arc>, - fluids: HashMap<&'static Fluid, Arc>, + blocks: HashMap>, + fluids: HashMap>, } impl BlockRegistryExt for BlockRegistry { @@ -333,7 +337,7 @@ impl BlockRegistry { self.blocks.reserve(names.len()); for i in names { self.blocks - .insert(Block::from_name(i.as_str()).unwrap(), val.clone()); + .insert(Block::from_name(i.as_str()).unwrap().id, val.clone()); } } @@ -343,7 +347,7 @@ impl BlockRegistry { self.fluids.reserve(names.len()); for i in names { self.fluids - .insert(fluid::get_fluid(i.as_str()).unwrap(), val.clone()); + .insert(fluid::get_fluid(i.as_str()).unwrap().id, val.clone()); } } @@ -355,7 +359,7 @@ impl BlockRegistry { r#type: u8, data: u8, ) -> bool { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .on_synced_block_event(OnSyncedBlockEventArgs { @@ -379,7 +383,7 @@ impl BlockRegistry { state: &BlockState, server: &Server, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .on_entity_collision(OnEntityCollisionArgs { @@ -395,7 +399,7 @@ impl BlockRegistry { } pub async fn on_entity_collision_fluid(&self, fluid: &Fluid, entity: &dyn EntityBase) { - let pumpkin_fluid = self.get_pumpkin_fluid(fluid); + let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id); if let Some(pumpkin_fluid) = pumpkin_fluid { pumpkin_fluid.on_entity_collision(entity).await; } @@ -410,7 +414,7 @@ impl BlockRegistry { server: &Server, world: &Arc, ) -> BlockActionResult { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .normal_use(NormalUseArgs { @@ -427,7 +431,7 @@ impl BlockRegistry { } pub async fn explode(&self, block: &Block, world: &Arc, position: &BlockPos) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .explode(ExplodeArgs { @@ -450,7 +454,7 @@ impl BlockRegistry { server: &Server, world: &Arc, ) -> BlockActionResult { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .use_with_item(UseWithItemArgs { @@ -476,7 +480,7 @@ impl BlockRegistry { server: &Server, world: &Arc, ) -> BlockActionResult { - let pumpkin_fluid = self.get_pumpkin_fluid(fluid); + let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id); if let Some(pumpkin_fluid) = pumpkin_fluid { return pumpkin_fluid .use_with_item(fluid, player, position, item, server, world) @@ -497,7 +501,7 @@ impl BlockRegistry { position: &BlockPos, use_item_on: Option<&SUseItemOn>, ) -> bool { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .can_place_at(CanPlaceAtArgs { @@ -526,7 +530,7 @@ impl BlockRegistry { use_item_on: &SUseItemOn, player: &Player, ) -> bool { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .can_update_at(CanUpdateAtArgs { @@ -555,7 +559,7 @@ impl BlockRegistry { replacing: BlockIsReplacing, use_item_on: &SUseItemOn, ) -> BlockStateId { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .on_place(OnPlaceArgs { @@ -582,7 +586,7 @@ impl BlockRegistry { direction: BlockDirection, player: &Player, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .player_placed(PlayerPlacedArgs { @@ -606,7 +610,7 @@ impl BlockRegistry { old_state_id: BlockStateId, notify: bool, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .placed(PlacedArgs { @@ -630,7 +634,7 @@ impl BlockRegistry { old_state_id: BlockStateId, notify: bool, ) { - let pumpkin_fluid = self.get_pumpkin_fluid(fluid); + let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id); if let Some(pumpkin_fluid) = pumpkin_fluid { pumpkin_fluid .placed(world, fluid, state_id, position, old_state_id, notify) @@ -638,6 +642,25 @@ impl BlockRegistry { } } + pub async fn on_landed_upon( + &self, + block: &Block, + world: &Arc, + fall_distance: f32, + entity: &dyn EntityBase, + ) { + let pumpkin_block = self.get_pumpkin_block(block.id); + if let Some(pumpkin_block) = pumpkin_block { + pumpkin_block + .on_landed_upon(OnLandedUponArgs { + world, + fall_distance, + entity, + }) + .await; + } + } + pub async fn broken( &self, world: &Arc, @@ -647,7 +670,7 @@ impl BlockRegistry { server: &Server, state: &BlockState, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .broken(BrokenArgs { @@ -670,7 +693,7 @@ impl BlockRegistry { old_state_id: BlockStateId, moved: bool, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .on_state_replaced(OnStateReplacedArgs { @@ -696,7 +719,7 @@ impl BlockRegistry { for direction in BlockDirection::all() { let neighbor_pos = position.offset(direction.to_offset()); let neighbor_state_id = world.get_block_state_id(&neighbor_pos).await; - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { let new_state = pumpkin_block .get_state_for_neighbor_update(GetStateForNeighborUpdateArgs { @@ -722,7 +745,7 @@ impl BlockRegistry { state_id: BlockStateId, flags: BlockFlags, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .prepare(PrepareArgs { @@ -747,7 +770,7 @@ impl BlockRegistry { neighbor_location: &BlockPos, neighbor_state_id: BlockStateId, ) -> BlockStateId { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .get_state_for_neighbor_update(GetStateForNeighborUpdateArgs { @@ -791,7 +814,7 @@ impl BlockRegistry { source_block: &Block, notify: bool, ) { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { pumpkin_block .on_neighbor_update(OnNeighborUpdateArgs { @@ -806,13 +829,13 @@ impl BlockRegistry { } #[must_use] - pub fn get_pumpkin_block(&self, block: &Block) -> Option<&Arc> { - self.blocks.get(block) + pub fn get_pumpkin_block(&self, block: u16) -> Option<&Arc> { + self.blocks.get(&block) } #[must_use] - pub fn get_pumpkin_fluid(&self, fluid: &Fluid) -> Option<&Arc> { - self.fluids.get(fluid) + pub fn get_pumpkin_fluid(&self, fluid: u16) -> Option<&Arc> { + self.fluids.get(&fluid) } pub async fn emits_redstone_power( @@ -821,7 +844,7 @@ impl BlockRegistry { state: &BlockState, direction: BlockDirection, ) -> bool { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .emits_redstone_power(EmitsRedstonePowerArgs { @@ -842,7 +865,7 @@ impl BlockRegistry { state: &BlockState, direction: BlockDirection, ) -> u8 { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .get_weak_redstone_power(GetRedstonePowerArgs { @@ -865,7 +888,7 @@ impl BlockRegistry { state: &BlockState, direction: BlockDirection, ) -> u8 { - let pumpkin_block = self.get_pumpkin_block(block); + let pumpkin_block = self.get_pumpkin_block(block.id); if let Some(pumpkin_block) = pumpkin_block { return pumpkin_block .get_strong_redstone_power(GetRedstonePowerArgs { diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index 877aa97b2..d2cbb042c 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -16,6 +16,7 @@ use std::{collections::HashMap, sync::atomic::AtomicI32}; use super::{Entity, NBTStorage}; use super::{EntityBase, NBTStorageInit}; +use crate::block::OnLandedUponArgs; use crate::entity::{EntityBaseFuture, NbtFuture}; use crate::server::Server; use crate::world::loot::{LootContextParameters, LootTableExt}; @@ -685,7 +686,7 @@ impl LivingEntity { strength } - pub async fn update_fall_distance( + pub async fn fall( &self, caller: Arc, height_difference: f64, @@ -701,19 +702,21 @@ impl LivingEntity { { return; } - - let safe_fall_distance = 3.0; - let mut damage = fall_distance - safe_fall_distance; - damage = damage.ceil(); - - // TODO: Play block fall sound - if damage > 0.0 { - let check_damage = self.damage(&*caller, damage, DamageType::FALL).await; // Fall - if check_damage { - self.entity - .play_sound(Self::get_fall_sound(fall_distance as i32)) - .await; - } + let world = &self.entity.world; + let block = world + .get_block(&self.entity.get_pos_with_y_offset(0.2).await.0) + .await; + let pumpkin_block = world.block_registry.get_pumpkin_block(block.id); + if let Some(pumpkin_block) = pumpkin_block { + pumpkin_block + .on_landed_upon(OnLandedUponArgs { + world, + fall_distance, + entity: caller.as_ref(), + }) + .await; + } else { + self.handle_fall_damage(fall_distance, 1.0).await; } } else if height_difference < 0.0 { let new_fall_distance = if !self.is_in_water().await && !self.is_in_powder_snow().await @@ -723,12 +726,26 @@ impl LivingEntity { } else { 0f32 }; - - // Reset fall distance if is in water or powder_snow self.fall_distance.store(new_fall_distance); } } + pub async fn handle_fall_damage(&self, fall_distance: f32, damage_per_distance: f32) { + // TODO: use attributes + let safe_fall_distance = 3.0; + let unsafe_fall_distance = fall_distance + 1.0E-6 - safe_fall_distance; + + let damage = (unsafe_fall_distance * damage_per_distance).floor(); + if damage > 0.0 { + let check_damage = self.damage(self, damage, DamageType::FALL).await; // Fall + if check_damage { + self.entity + .play_sound(Self::get_fall_sound(fall_distance as i32)) + .await; + } + } + } + fn get_fall_sound(distance: i32) -> Sound { if distance > 4 { Sound::EntityGenericBigFall diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 13f1cf552..61dee6703 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1243,7 +1243,7 @@ impl Entity { if let Some(living) = caller.get_living_entity() { living - .update_fall_distance( + .fall( caller.clone(), final_move.y, self.on_ground.load(Ordering::SeqCst), diff --git a/pumpkin/src/net/java/play.rs b/pumpkin/src/net/java/play.rs index a70c98fd7..f6661fcd5 100644 --- a/pumpkin/src/net/java/play.rs +++ b/pumpkin/src/net/java/play.rs @@ -324,7 +324,7 @@ impl JavaClient { if !player.abilities.lock().await.flying { player.living_entity - .update_fall_distance( + .fall( player.clone(), height_difference, packet.collision & FLAG_ON_GROUND != 0, @@ -449,7 +449,7 @@ impl JavaClient { .await; if !player.abilities.lock().await.flying { player.living_entity - .update_fall_distance( + .fall( player.clone(), height_difference, (packet.collision & FLAG_ON_GROUND) != 0, diff --git a/pumpkin/src/world/explosion.rs b/pumpkin/src/world/explosion.rs index dad0c1930..bacd99ecd 100644 --- a/pumpkin/src/world/explosion.rs +++ b/pumpkin/src/world/explosion.rs @@ -81,7 +81,7 @@ impl Explosion { if state.is_air() { continue; } - let pumpkin_block = world.block_registry.get_pumpkin_block(block); + let pumpkin_block = world.block_registry.get_pumpkin_block(block.id); world.set_block_state(pos, 0, BlockFlags::NOTIFY_ALL).await; diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 569570773..34812c8b3 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -606,7 +606,7 @@ impl World { // 5. Detailed Slow Tick Logging let total_elapsed = start.elapsed(); if total_elapsed.as_millis() > 50 { - log::warn!( + log::debug!( "Slow Tick [{}ms]: Chunks: {:?} | Players({}): {:?} | Entities({}): {:?}", total_elapsed.as_millis(), chunk_elapsed, @@ -695,7 +695,7 @@ impl World { let tick_data = self.level.get_tick_data().await; for scheduled_tick in tick_data.block_ticks { let block = self.get_block(&scheduled_tick.position).await; - if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block) { + if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block.id) { pumpkin_block .on_scheduled_tick(OnScheduledTickArgs { world: self, @@ -707,7 +707,7 @@ impl World { } for scheduled_tick in tick_data.fluid_ticks { let fluid = self.get_fluid(&scheduled_tick.position).await; - if let Some(pumpkin_fluid) = self.block_registry.get_pumpkin_fluid(fluid) { + if let Some(pumpkin_fluid) = self.block_registry.get_pumpkin_fluid(fluid.id) { pumpkin_fluid .on_scheduled_tick(self, fluid, &scheduled_tick.position) .await; @@ -718,7 +718,7 @@ impl World { // TODO: ^ find this deadlock ^ for scheduled_tick in tick_data.random_ticks { let block = self.get_block(&scheduled_tick.position).await; - if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block) { + if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block.id) { pumpkin_block .random_tick(RandomTickArgs { world: self, @@ -2981,7 +2981,7 @@ impl World { let (neighbor_block, neighbor_fluid) = self.get_block_and_fluid(&neighbor_pos).await; if let Some(neighbor_pumpkin_block) = - self.block_registry.get_pumpkin_block(neighbor_block) + self.block_registry.get_pumpkin_block(neighbor_block.id) { neighbor_pumpkin_block .on_neighbor_update(OnNeighborUpdateArgs { @@ -2995,7 +2995,7 @@ impl World { } if let Some(neighbor_pumpkin_fluid) = - self.block_registry.get_pumpkin_fluid(neighbor_fluid) + self.block_registry.get_pumpkin_fluid(neighbor_fluid.id) { neighbor_pumpkin_fluid .on_neighbor_update(self, neighbor_fluid, &neighbor_pos, false) @@ -3011,7 +3011,8 @@ impl World { ) { let neighbor_block = self.get_block(neighbor_block_pos).await; - if let Some(neighbor_pumpkin_block) = self.block_registry.get_pumpkin_block(neighbor_block) + if let Some(neighbor_pumpkin_block) = + self.block_registry.get_pumpkin_block(neighbor_block.id) { neighbor_pumpkin_block .on_neighbor_update(OnNeighborUpdateArgs {