feat(block): implement calibrated sculk sensor resonance logic

This commit is contained in:
Alexander Medvedev
2026-08-12 20:32:22 +02:00
parent e9958f5d64
commit 3fcbf9ba3d
2 changed files with 90 additions and 17 deletions

View File

@@ -1,10 +1,10 @@
use std::sync::Arc;
use pumpkin_data::BlockStateId;
use pumpkin_data::block_properties::{BlockProperties, DecoratedPotLikeProperties};
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::BlockStateId;
use pumpkin_macros::pumpkin_block;
use crate::block::entities::decorated_pot::DecoratedPotBlockEntity;
@@ -20,10 +20,8 @@ pub struct DecoratedPotBlock;
impl BlockBehaviour for DecoratedPotBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let mut props = DecoratedPotLikeProperties::from_state_id(
args.block.default_state.id,
args.block,
);
let mut props =
DecoratedPotLikeProperties::from_state_id(args.block.default_state.id, args.block);
props.facing = args
.player
.living_entity
@@ -60,8 +58,9 @@ impl BlockBehaviour for DecoratedPotBlock {
}
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
&& let Some(pot_entity) = block_entity
.as_any()
.downcast_ref::<DecoratedPotBlockEntity>()
{
if pot_entity.try_insert_item(args.item_stack, 1).await {
args.world.play_sound(
@@ -97,8 +96,9 @@ impl BlockBehaviour for DecoratedPotBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
&& let Some(pot_entity) = block_entity
.as_any()
.downcast_ref::<DecoratedPotBlockEntity>()
&& let Some(contained) = pot_entity.take_item().await
{
args.world.drop_stack(args.position, contained).await;
@@ -109,7 +109,9 @@ impl BlockBehaviour for DecoratedPotBlock {
SoundCategory::Blocks,
&args.position.to_f64(),
);
args.world.drop_stack(args.position, ItemStack::new(4, &Item::BRICK)).await;
args.world
.drop_stack(args.position, ItemStack::new(4, &Item::BRICK))
.await;
})
}
@@ -119,8 +121,9 @@ impl BlockBehaviour for DecoratedPotBlock {
) -> BlockFuture<'a, Option<u8>> {
Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
&& let Some(pot_entity) = block_entity
.as_any()
.downcast_ref::<DecoratedPotBlockEntity>()
{
Some(pot_entity.get_comparator_output().await)
} else {

View File

@@ -1,15 +1,17 @@
use std::sync::Arc;
use crate::block::entities::calibrated_sculk_sensor::CalibratedSculkSensorBlockEntity;
use crate::block::entities::sculk_sensor::SculkSensorBlockEntity;
use crate::block::{
BlockBehaviour, BlockFuture, BlockMetadata, EmitsRedstonePowerArgs, GetRedstonePowerArgs,
OnPlaceArgs, OnScheduledTickArgs,
BlockBehaviour, BlockFuture, BlockMetadata, EmitsRedstonePowerArgs, GetComparatorOutputArgs,
GetRedstonePowerArgs, OnPlaceArgs, OnScheduledTickArgs, PlacedArgs,
};
use crate::world::World;
use pumpkin_data::block_properties::{
BlockProperties, CalibratedSculkSensorLikeProperties, SculkSensorLikeProperties,
SculkSensorPhase,
BlockProperties, CalibratedSculkSensorLikeProperties, HorizontalFacing,
SculkSensorLikeProperties, SculkSensorPhase,
};
use pumpkin_data::{Block, BlockId, BlockStateId};
use pumpkin_data::{Block, BlockDirection, BlockId, BlockStateId};
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::tick::TickPriority;
use pumpkin_world::world::BlockFlags;
@@ -22,12 +24,27 @@ impl BlockMetadata for SculkSensorBlock {
}
}
const fn horizontal_facing_to_dir(facing: HorizontalFacing) -> BlockDirection {
match facing {
HorizontalFacing::North => BlockDirection::North,
HorizontalFacing::South => BlockDirection::South,
HorizontalFacing::West => BlockDirection::West,
HorizontalFacing::East => BlockDirection::East,
}
}
impl SculkSensorBlock {
pub async fn trigger(world: &Arc<World>, pos: &BlockPos, block: &Block, power: u8) {
if block.id == BlockId::SCULK_SENSOR {
let state = world.get_block_state(pos);
let mut props = SculkSensorLikeProperties::from_state_id(state.id, block);
if props.sculk_sensor_phase == SculkSensorPhase::Inactive {
if let Some(be) = world.get_block_entity(pos)
&& let Some(sensor_be) = be.as_any().downcast_ref::<SculkSensorBlockEntity>()
{
*sensor_be.last_vibration_frequency.lock().await = power as i32;
}
props.sculk_sensor_phase = SculkSensorPhase::Active;
props.power = power;
world
@@ -40,6 +57,28 @@ impl SculkSensorBlock {
let state = world.get_block_state(pos);
let mut props = CalibratedSculkSensorLikeProperties::from_state_id(state.id, block);
if props.sculk_sensor_phase == SculkSensorPhase::Inactive {
let back_dir = horizontal_facing_to_dir(props.facing).opposite();
let back_pos = pos.offset(back_dir.to_offset());
let back_state = world.get_block_state(&back_pos);
let back_block = Block::from_state_id(back_state.id);
let calibrated_freq = world
.block_registry
.get_weak_redstone_power(back_block, world, &back_pos, back_state, back_dir)
.await;
if calibrated_freq > 0 && calibrated_freq != power {
return;
}
if let Some(be) = world.get_block_entity(pos)
&& let Some(cal_be) = be
.as_any()
.downcast_ref::<CalibratedSculkSensorBlockEntity>()
{
*cal_be.last_vibration_frequency.lock().await = power as i32;
}
props.sculk_sensor_phase = SculkSensorPhase::Active;
props.power = power;
world
@@ -66,6 +105,18 @@ impl BlockBehaviour for SculkSensorBlock {
})
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
if args.block.id == BlockId::CALIBRATED_SCULK_SENSOR {
let entity = CalibratedSculkSensorBlockEntity::new(*args.position);
args.world.add_block_entity(Arc::new(entity));
} else if args.block.id == BlockId::SCULK_SENSOR {
let entity = SculkSensorBlockEntity::new(*args.position);
args.world.add_block_entity(Arc::new(entity));
}
})
}
fn emits_redstone_power<'a>(
&'a self,
_args: EmitsRedstonePowerArgs<'a>,
@@ -99,6 +150,25 @@ impl BlockBehaviour for SculkSensorBlock {
})
}
fn get_comparator_output<'a>(
&'a self,
args: GetComparatorOutputArgs<'a>,
) -> BlockFuture<'a, Option<u8>> {
Box::pin(async move {
let be = args.world.get_block_entity(args.position)?;
if let Some(sensor_be) = be.as_any().downcast_ref::<SculkSensorBlockEntity>() {
return Some(*sensor_be.last_vibration_frequency.lock().await as u8);
}
if let Some(cal_be) = be
.as_any()
.downcast_ref::<CalibratedSculkSensorBlockEntity>()
{
return Some(*cal_be.last_vibration_frequency.lock().await as u8);
}
None
})
}
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let state = args.world.get_block_state(args.position);