Alexander Medvedev 2026-01-17 10:52:34 +01:00
parent 6f18d16581
commit 16abf08de3
11 changed files with 143 additions and 60 deletions

View File

@ -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);

View File

@ -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;
}
})
}
}

View File

@ -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;

View File

@ -254,7 +254,7 @@ impl RedstoneGateBlock<ComparatorLikeProperties> 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<u8>
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<ComparatorLikeProperties> 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 {

View File

@ -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<World>,
pub fall_distance: f32,
pub entity: &'a dyn EntityBase,
}
pub struct BrokenArgs<'a> {
pub block: &'a Block,
pub player: &'a Arc<Player>,

View File

@ -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<BlockRegistry> {
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<dyn BlockBehaviour>>,
fluids: HashMap<&'static Fluid, Arc<dyn FluidBehaviour>>,
blocks: HashMap<u16, Arc<dyn BlockBehaviour>>,
fluids: HashMap<u16, Arc<dyn FluidBehaviour>>,
}
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<World>,
) -> 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<World>, 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<World>,
) -> 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<World>,
) -> 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<World>,
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<World>,
@ -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<dyn BlockBehaviour>> {
self.blocks.get(block)
pub fn get_pumpkin_block(&self, block: u16) -> Option<&Arc<dyn BlockBehaviour>> {
self.blocks.get(&block)
}
#[must_use]
pub fn get_pumpkin_fluid(&self, fluid: &Fluid) -> Option<&Arc<dyn FluidBehaviour>> {
self.fluids.get(fluid)
pub fn get_pumpkin_fluid(&self, fluid: u16) -> Option<&Arc<dyn FluidBehaviour>> {
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 {

View File

@ -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<dyn EntityBase>,
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

View File

@ -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),

View File

@ -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,

View File

@ -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;

View File

@ -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 {