mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 10:53:05 +00:00
Implement pressure plate activation logic and events (#5991)
closes #5936 This implements all of the basic activation logic for pressure plates. It also introduces a PressurePlateUpdateEvent, which is called in pulses when entities are standing on top of the plate and when it deactivates. Deactivation can be detected by checking if the list of activating entities is empty. --------- Co-authored-by: Javier León <58715544+JavierLeon9966@users.noreply.github.com>
This commit is contained in:
@ -24,14 +24,33 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\PressurePlateUpdateEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\PressurePlateActivateSound;
|
||||
use pocketmine\world\sound\PressurePlateDeactivateSound;
|
||||
use function count;
|
||||
|
||||
abstract class PressurePlate extends Transparent{
|
||||
|
||||
private readonly int $deactivationDelayTicks;
|
||||
|
||||
public function __construct(
|
||||
BlockIdentifier $idInfo,
|
||||
string $name,
|
||||
BlockTypeInfo $typeInfo,
|
||||
int $deactivationDelayTicks = 20 //TODO: make this mandatory in PM6
|
||||
){
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
$this->deactivationDelayTicks = $deactivationDelayTicks;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
@ -61,5 +80,89 @@ abstract class PressurePlate extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
if(!$this->hasOutputSignal()){
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AABB that entities must intersect to activate the pressure plate.
|
||||
* Note that this is not the same as the collision box (pressure plate doesn't have one), nor the visual bounding
|
||||
* box. The activation area has a height of 0.25 blocks.
|
||||
*/
|
||||
protected function getActivationBox() : AxisAlignedBB{
|
||||
return AxisAlignedBB::one()
|
||||
->squash(Axis::X, 1 / 8)
|
||||
->squash(Axis::Z, 1 / 8)
|
||||
->trim(Facing::UP, 3 / 4)
|
||||
->offset($this->position->x, $this->position->y, $this->position->z);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this abstract in PM6
|
||||
*/
|
||||
protected function hasOutputSignal() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this abstract in PM6
|
||||
*
|
||||
* @param Entity[] $entities
|
||||
*
|
||||
* @return mixed[]
|
||||
* @phpstan-return array{Block, ?bool}
|
||||
*/
|
||||
protected function calculatePlateState(array $entities) : array{
|
||||
return [$this, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters entities which don't affect the pressure plate state from the given list.
|
||||
*
|
||||
* @param Entity[] $entities
|
||||
* @return Entity[]
|
||||
*/
|
||||
protected function filterIrrelevantEntities(array $entities) : array{
|
||||
return $entities;
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$intersectionAABB = $this->getActivationBox();
|
||||
$activatingEntities = $this->filterIrrelevantEntities($world->getNearbyEntities($intersectionAABB));
|
||||
|
||||
//if an irrelevant entity is inside the full cube space of the pressure plate but not activating the plate,
|
||||
//it will cause scheduled updates on the plate every tick. We don't want to fire events in this case if the
|
||||
//plate is already deactivated.
|
||||
if(count($activatingEntities) > 0 || $this->hasOutputSignal()){
|
||||
[$newState, $pressedChange] = $this->calculatePlateState($activatingEntities);
|
||||
|
||||
//always call this, in case there are new entities on the plate
|
||||
if(PressurePlateUpdateEvent::hasHandlers()){
|
||||
$ev = new PressurePlateUpdateEvent($this, $newState, $activatingEntities);
|
||||
$ev->call();
|
||||
$newState = $ev->isCancelled() ? null : $ev->getNewState();
|
||||
}
|
||||
if($newState !== null){
|
||||
$world->setBlock($this->position, $newState);
|
||||
if($pressedChange !== null){
|
||||
$world->addSound($this->position, $pressedChange ?
|
||||
new PressurePlateActivateSound($this) :
|
||||
new PressurePlateDeactivateSound($this)
|
||||
);
|
||||
}
|
||||
}
|
||||
if($pressedChange ?? $this->hasOutputSignal()){
|
||||
$world->scheduleDelayedBlockUpdate($this->position, $this->deactivationDelayTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user