feat(block): implement sniffer egg hatching logic

This commit is contained in:
Alexander Medvedev
2026-08-12 20:40:08 +02:00
parent c64d6cca70
commit 75200d79ae
3 changed files with 110 additions and 0 deletions

View File

@@ -112,5 +112,6 @@ pub mod abstract_wall_mounting;
pub mod beacon;
pub mod creaking_heart;
pub mod decorated_pot;
pub mod sniffer_egg;
pub mod trial_spawner;
pub mod vault;

View File

@@ -0,0 +1,107 @@
use pumpkin_data::block_properties::{BlockProperties, SnifferEggLikeProperties};
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::{Block, BlockStateId};
use pumpkin_macros::pumpkin_block;
use pumpkin_world::tick::TickPriority;
use pumpkin_world::world::BlockFlags;
use crate::block::{
BlockBehaviour, BlockFuture, BrokenArgs, OnPlaceArgs, OnScheduledTickArgs, PlacedArgs,
};
#[pumpkin_block("minecraft:sniffer_egg")]
pub struct SnifferEggBlock;
impl SnifferEggBlock {
fn is_on_moss(
world: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos,
) -> bool {
let below_pos = pos.down();
let state = world.get_block_state(&below_pos);
let block = Block::from_state_id(state.id);
block.name == "moss_block"
}
const fn get_hatch_delay(on_moss: bool) -> u8 {
if on_moss { 100 } else { 200 }
}
}
impl BlockBehaviour for SnifferEggBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let props = SnifferEggLikeProperties::default(args.block);
props.to_state_id(args.block)
})
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
args.world.play_sound(
Sound::BlockSnifferEggPlop,
SoundCategory::Blocks,
&args.position.to_f64(),
);
let on_moss = Self::is_on_moss(args.world.as_ref(), args.position);
let delay = Self::get_hatch_delay(on_moss);
args.world
.schedule_block_tick(args.block, *args.position, delay, TickPriority::Normal);
})
}
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position);
let mut props = SnifferEggLikeProperties::from_state_id(state_id, args.block);
if props.hatch < 2 {
props.hatch += 1;
args.world
.set_block_state(
args.position,
props.to_state_id(args.block),
BlockFlags::NOTIFY_ALL,
)
.await;
args.world.play_sound(
Sound::BlockSnifferEggCrack,
SoundCategory::Blocks,
&args.position.to_f64(),
);
let on_moss = Self::is_on_moss(args.world.as_ref(), args.position);
let delay = Self::get_hatch_delay(on_moss);
args.world
.schedule_block_tick(args.block, *args.position, delay, TickPriority::Normal);
} else {
args.world
.break_block(args.position, None, BlockFlags::SKIP_DROPS)
.await;
args.world.play_sound(
Sound::BlockSnifferEggHatch,
SoundCategory::Blocks,
&args.position.to_f64(),
);
}
})
}
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
args.world.play_sound(
Sound::BlockSnifferEggCrack,
SoundCategory::Blocks,
&args.position.to_f64(),
);
args.world
.drop_stack(args.position, ItemStack::new(1, &Item::SNIFFER_EGG))
.await;
})
}
}

View File

@@ -129,6 +129,7 @@ use crate::block::blocks::signs::SignBlock;
use crate::block::blocks::slabs::SlabBlock;
use crate::block::blocks::slime::SlimeBlock;
use crate::block::blocks::snow::LayeredSnowBlock;
use crate::block::blocks::sniffer_egg::SnifferEggBlock;
use crate::block::blocks::spawner::SpawnerBlock;
use crate::block::blocks::sponge::{SpongeBlock, WetSpongeBlock};
use crate::block::blocks::stairs::StairBlock;
@@ -256,6 +257,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
manager.register(VaultBlock);
manager.register(DecoratedPotBlock);
manager.register(CreakingHeartBlock);
manager.register(SnifferEggBlock);
manager.register(BushBlock);
manager.register(FlowerBlock);
manager.register(PotatoBlock);