Added a mechanism for blocks to detect dynamic state properties from surroundings

This commit is contained in:
Dylan K. Taylor 2018-10-26 15:57:32 +01:00
parent b2201c8c59
commit 3af293f024
6 changed files with 63 additions and 37 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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