From 0d443944a73bd9027e5e9ce1dcd2923c7313f8b7 Mon Sep 17 00:00:00 2001 From: Afalinx <107479966+afalinx@users.noreply.github.com> Date: Fri, 24 Jul 2026 20:22:19 +0300 Subject: [PATCH] fix(redstone): use vanilla pressure plate detection bounds (#2439) Replace full-block entity queries with vanilla's centered 14x4x14 pressure plate detection box. Share the bounds between normal and weighted pressure plates and cover the geometry with unit tests. --- .../blocks/redstone/pressure_plate/mod.rs | 15 +++++- .../blocks/redstone/pressure_plate/plate.rs | 7 ++- .../blocks/redstone/pressure_plate/tests.rs | 51 +++++++++++++++++++ .../redstone/pressure_plate/weighted.rs | 7 ++- 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 pumpkin/src/block/blocks/redstone/pressure_plate/tests.rs diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/mod.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/mod.rs index 5aa009a14..b260f3839 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/mod.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/mod.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use pumpkin_data::{Block, BlockDirection, BlockState, BlockStateId}; -use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos}; use pumpkin_world::{tick::TickPriority, world::BlockFlags}; use crate::{ @@ -12,6 +12,19 @@ use crate::{ pub mod plate; pub mod weighted; +#[cfg(test)] +mod tests; + +// Vanilla pressure plates detect entities in a centered 14x4x14-pixel volume. +const PRESSURE_PLATE_DETECTION_BOX: BoundingBox = BoundingBox::new_array( + [1.0 / 16.0, 0.0, 1.0 / 16.0], + [15.0 / 16.0, 4.0 / 16.0, 15.0 / 16.0], +); + +fn detection_box_at(pos: &BlockPos) -> BoundingBox { + PRESSURE_PLATE_DETECTION_BOX.at_pos(*pos) +} + pub(crate) trait PressurePlate { async fn on_entity_collision_pp(&self, args: OnEntityCollisionArgs<'_>) { let output = self.get_redstone_output(args.block, args.state.id); diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs index ebee4d7be..908aaf5e4 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs @@ -3,7 +3,7 @@ use pumpkin_data::{ block_properties::BlockProperties, tag::{self}, }; -use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos}; +use pumpkin_util::math::position::BlockPos; use pumpkin_world::world::BlockFlags; use crate::{ @@ -15,7 +15,7 @@ use crate::{ world::World, }; -use super::PressurePlate; +use super::{PressurePlate, detection_box_at}; /// This is for Normal Pressure plates, so not Gold or Iron pub struct PressurePlateBlock; @@ -99,8 +99,7 @@ impl PressurePlate for PressurePlateBlock { } async fn calculate_redstone_output(&self, world: &World, _block: &Block, pos: &BlockPos) -> u8 { - // TODO: this is bad use real box - let aabb = BoundingBox::from_block(pos); + let aabb = detection_box_at(pos); if !world.get_entities_at_box(&aabb).is_empty() || !world.get_players_at_box(&aabb).is_empty() { diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/tests.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/tests.rs new file mode 100644 index 000000000..c1cb7e2f6 --- /dev/null +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/tests.rs @@ -0,0 +1,51 @@ +use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos, vector3::Vector3}; + +use super::*; + +#[test] +fn detection_box_is_offset_to_block_position() { + let bounding_box = detection_box_at(&BlockPos::new(10, 64, -5)); + + assert_eq!(bounding_box.min, Vector3::new(10.0625, 64.0, -4.9375)); + assert_eq!(bounding_box.max, Vector3::new(10.9375, 64.25, -4.0625)); +} + +#[test] +fn entity_at_plate_center_intersects_detection_box() { + let detection_box = detection_box_at(&BlockPos::new(0, 0, 0)); + let entity_box = BoundingBox::new_array([0.4, 0.0, 0.4], [0.6, 1.8, 0.6]); + + assert!(detection_box.intersects(&entity_box)); +} + +#[test] +fn entity_outside_horizontal_bounds_does_not_intersect_detection_box() { + let detection_box = detection_box_at(&BlockPos::new(0, 0, 0)); + let entity_box = BoundingBox::new_array([0.95, 0.0, 0.4], [1.0, 0.2, 0.6]); + + assert!(!detection_box.intersects(&entity_box)); +} + +#[test] +fn entity_above_detection_height_does_not_intersect_detection_box() { + let detection_box = detection_box_at(&BlockPos::new(0, 0, 0)); + let entity_box = BoundingBox::new_array([0.4, 0.3, 0.4], [0.6, 0.6, 0.6]); + + assert!(!detection_box.intersects(&entity_box)); +} + +#[test] +fn entity_partially_overlapping_detection_box_intersects() { + let detection_box = detection_box_at(&BlockPos::new(0, 0, 0)); + let entity_box = BoundingBox::new_array([0.9, 0.2, 0.4], [0.95, 0.3, 0.6]); + + assert!(detection_box.intersects(&entity_box)); +} + +#[test] +fn entity_touching_detection_box_boundary_does_not_intersect() { + let detection_box = detection_box_at(&BlockPos::new(0, 0, 0)); + let entity_box = BoundingBox::new_array([0.9375, 0.0, 0.4], [1.0, 0.2, 0.6]); + + assert!(!detection_box.intersects(&entity_box)); +} diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs index d3021190e..b318169a3 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs @@ -1,7 +1,7 @@ use pumpkin_data::{ Block, BlockDirection, BlockId, BlockState, BlockStateId, block_properties::BlockProperties, }; -use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos}; +use pumpkin_util::math::position::BlockPos; use pumpkin_world::world::BlockFlags; use crate::{ @@ -13,7 +13,7 @@ use crate::{ world::World, }; -use super::PressurePlate; +use super::{PressurePlate, detection_box_at}; /// This is for Gold and Iron Pressure Plate pub struct WeightedPressurePlateBlock; @@ -109,8 +109,7 @@ impl PressurePlate for WeightedPressurePlateBlock { // Iron 150 }; - // TODO: this is bad use real box - let aabb = BoundingBox::from_block(pos); + let aabb = detection_box_at(pos); let len = world.get_entities_at_box(&aabb).len() + world.get_players_at_box(&aabb).len(); let len = len.min(weight); if len > 0 {