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.
This commit is contained in:
Afalinx
2026-07-24 20:22:19 +03:00
committed by GitHub
parent 6263b894ff
commit 0d443944a7
4 changed files with 71 additions and 9 deletions

View File

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

View File

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

View File

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

View File

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