mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-08-21 02:41:17 +00:00
Added a mechanism for blocks to detect dynamic state properties from surroundings
This commit is contained in:
parent
b2201c8c59
commit
3af293f024
@ -448,7 +448,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
$this->level = $v->level;
|
||||
$this->boundingBox = null;
|
||||
$this->updateState();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -718,10 +718,13 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any cached precomputed objects, such as bounding boxes. This is called on block neighbour update and when
|
||||
* the block is set into the world to remove any outdated precomputed things such as AABBs and force recalculation.
|
||||
* Called when this block is created, set, or has a neighbouring block update, to re-detect dynamic properties which
|
||||
* are not saved on the world.
|
||||
*
|
||||
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
|
||||
* AABBs and force recalculation.
|
||||
*/
|
||||
public function clearCaches() : void{
|
||||
public function updateState() : void{
|
||||
$this->boundingBox = null;
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
@ -31,6 +31,11 @@ class CobblestoneWall extends Transparent{
|
||||
public const NONE_MOSSY_WALL = 0;
|
||||
public const MOSSY_WALL = 1;
|
||||
|
||||
/** @var bool[] facing => dummy */
|
||||
protected $connections = [];
|
||||
/** @var bool */
|
||||
protected $up = false;
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
@ -43,17 +48,32 @@ class CobblestoneWall extends Transparent{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function updateState() : void{
|
||||
parent::updateState();
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent())){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->up = $this->getSide(Facing::UP)->getId() !== Block::AIR;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
//walls don't have any special collision boxes like fences do
|
||||
|
||||
$north = $this->canConnect($this->getSide(Facing::NORTH));
|
||||
$south = $this->canConnect($this->getSide(Facing::SOUTH));
|
||||
$west = $this->canConnect($this->getSide(Facing::WEST));
|
||||
$east = $this->canConnect($this->getSide(Facing::EAST));
|
||||
$north = isset($this->connections[Facing::NORTH]);
|
||||
$south = isset($this->connections[Facing::SOUTH]);
|
||||
$west = isset($this->connections[Facing::WEST]);
|
||||
$east = isset($this->connections[Facing::EAST]);
|
||||
|
||||
$inset = 0.25;
|
||||
if(
|
||||
$this->getSide(Facing::UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
|
||||
!$this->up and //if there is a block on top, it stays as a post
|
||||
(
|
||||
($north and $south and !$west and !$east) or
|
||||
(!$north and !$south and $west and $east)
|
||||
@ -72,8 +92,4 @@ class CobblestoneWall extends Transparent{
|
||||
1 - ($south ? 0 : $inset)
|
||||
);
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
}
|
||||
|
@ -69,11 +69,10 @@ abstract class Door extends Transparent{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies door properties from the other half of the door, since metadata is split between the two halves.
|
||||
* TODO: the blockstate should be updated directly on creation so these properties can be detected in advance.
|
||||
*/
|
||||
private function updateStateFromOtherHalf() : void{
|
||||
public function updateState() : void{
|
||||
parent::updateState();
|
||||
|
||||
//copy door properties from other half
|
||||
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
|
||||
if($other instanceof Door and $other->isSameType($this)){
|
||||
if($this->top){
|
||||
@ -91,8 +90,6 @@ abstract class Door extends Transparent{
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$this->updateStateFromOtherHalf();
|
||||
|
||||
return AxisAlignedBB::one()
|
||||
->extend(Facing::UP, 1)
|
||||
->trim($this->open ? Facing::rotate($this->facing, Facing::AXIS_Y, !$this->hingeRight) : $this->facing, 13 / 16);
|
||||
@ -135,7 +132,6 @@ abstract class Door extends Transparent{
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$this->updateStateFromOtherHalf();
|
||||
$this->open = !$this->open;
|
||||
|
||||
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
|
||||
|
@ -27,21 +27,36 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
abstract class Fence extends Transparent{
|
||||
/** @var bool[] facing => dummy */
|
||||
protected $connections = [];
|
||||
|
||||
public function getThickness() : float{
|
||||
return 0.25;
|
||||
}
|
||||
|
||||
public function updateState() : void{
|
||||
parent::updateState();
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent())){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$width = 0.5 - $this->getThickness() / 2;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
($this->canConnect($this->getSide(Facing::WEST)) ? 0 : $width),
|
||||
(isset($this->connections[Facing::WEST]) ? 0 : $width),
|
||||
0,
|
||||
($this->canConnect($this->getSide(Facing::NORTH)) ? 0 : $width),
|
||||
1 - ($this->canConnect($this->getSide(Facing::EAST)) ? 0 : $width),
|
||||
(isset($this->connections[Facing::NORTH]) ? 0 : $width),
|
||||
1 - (isset($this->connections[Facing::EAST]) ? 0 : $width),
|
||||
1.5,
|
||||
1 - ($this->canConnect($this->getSide(Facing::SOUTH)) ? 0 : $width)
|
||||
1 - (isset($this->connections[Facing::WEST]) ? 0 : $width)
|
||||
);
|
||||
}
|
||||
|
||||
@ -51,8 +66,8 @@ abstract class Fence extends Transparent{
|
||||
/** @var AxisAlignedBB[] $bbs */
|
||||
$bbs = [];
|
||||
|
||||
$connectWest = $this->canConnect($this->getSide(Facing::WEST));
|
||||
$connectEast = $this->canConnect($this->getSide(Facing::EAST));
|
||||
$connectWest = isset($this->connections[Facing::WEST]);
|
||||
$connectEast = isset($this->connections[Facing::EAST]);
|
||||
|
||||
if($connectWest or $connectEast){
|
||||
//X axis (west/east)
|
||||
@ -66,8 +81,8 @@ abstract class Fence extends Transparent{
|
||||
);
|
||||
}
|
||||
|
||||
$connectNorth = $this->canConnect($this->getSide(Facing::NORTH));
|
||||
$connectSouth = $this->canConnect($this->getSide(Facing::SOUTH));
|
||||
$connectNorth = isset($this->connections[Facing::NORTH]);
|
||||
$connectSouth = isset($this->connections[Facing::SOUTH]);
|
||||
|
||||
if($connectNorth or $connectSouth){
|
||||
//Z axis (north/south)
|
||||
@ -97,8 +112,4 @@ abstract class Fence extends Transparent{
|
||||
|
||||
return $bbs;
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
}
|
||||
|
@ -118,8 +118,8 @@ abstract class Liquid extends Transparent{
|
||||
return $block->falling ? 0 : $block->decay;
|
||||
}
|
||||
|
||||
public function clearCaches() : void{
|
||||
parent::clearCaches();
|
||||
public function updateState() : void{
|
||||
parent::updateState();
|
||||
$this->flowVector = null;
|
||||
}
|
||||
|
||||
|
@ -762,7 +762,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
Level::getBlockXYZ($index, $x, $y, $z);
|
||||
|
||||
$block = $this->getBlockAt($x, $y, $z);
|
||||
$block->clearCaches(); //for blocks like fences, force recalculation of connected AABBs
|
||||
$block->updateState(); //for blocks like fences, force recalculation of connected AABBs
|
||||
|
||||
$ev = new BlockUpdateEvent($block);
|
||||
$ev->call();
|
||||
@ -1372,6 +1372,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$block->y = $y;
|
||||
$block->z = $z;
|
||||
$block->level = $this;
|
||||
$block->updateState();
|
||||
|
||||
if($addToCache and $blockHash !== null){
|
||||
$this->blockCache[$chunkHash][$blockHash] = $block;
|
||||
@ -1524,7 +1525,6 @@ class Level implements ChunkManager, Metadatable{
|
||||
$block = clone $block;
|
||||
|
||||
$block->position($pos);
|
||||
$block->clearCaches();
|
||||
|
||||
$chunkHash = Level::chunkHash($pos->x >> 4, $pos->z >> 4);
|
||||
$blockHash = Level::blockHash($pos->x, $pos->y, $pos->z);
|
||||
|
Loading…
x
Reference in New Issue
Block a user