Add runtime support for wall connections

this doesn't match the 1.16+ behaviour yet, but it at least recognizes walls that are already in the post-1.16 way and doesn't break them if not interacted with.
This commit is contained in:
Dylan K. Taylor
2022-06-25 15:59:38 +01:00
parent b9542b4908
commit 1da4c45979
9 changed files with 149 additions and 25 deletions

View File

@ -49,7 +49,7 @@ use function count;
use const PHP_INT_MAX;
class Block{
public const INTERNAL_STATE_DATA_BITS = 6;
public const INTERNAL_STATE_DATA_BITS = 9;
public const INTERNAL_STATE_DATA_MASK = ~(~0 << self::INTERNAL_STATE_DATA_BITS);
protected BlockIdentifier $idInfo;

View File

@ -23,30 +23,93 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataReader;
use pocketmine\block\utils\BlockDataWriter;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
/**
* @phpstan-type WallConnectionSet array<Facing::NORTH|Facing::EAST|Facing::SOUTH|Facing::WEST, WallConnectionType>
*/
class Wall extends Transparent{
/** @var int[] facing => facing */
/**
* @var WallConnectionType[]
* @phpstan-var WallConnectionSet
*/
protected array $connections = [];
protected bool $up = false;
protected bool $post = false;
public function readStateFromWorld() : void{
parent::readStateFromWorld();
protected function decodeState(BlockDataReader $r) : void{
$this->connections = $r->readWallConnections();
$this->post = $r->readBool();
}
$this->recalculateConnections();
protected function encodeState(BlockDataWriter $w) : void{
$w->writeWallConnections($this->connections);
$w->writeBool($this->post);
}
public function onNearbyBlockChange() : void{
if($this->recalculateConnections()){
$this->position->getWorld()->setBlock($this->position, $this);
}
}
/**
* @return WallConnectionType[]
* @phpstan-return WallConnectionSet
*/
public function getConnections() : array{ return $this->connections; }
public function getConnection(int $face) : ?WallConnectionType{
return $this->connections[$face] ?? null;
}
/**
* @param WallConnectionType[] $connections
* @phpstan-param WallConnectionSet $connections
* @return $this
*/
public function setConnections(array $connections) : self{
$this->connections = $connections;
return $this;
}
/** @return $this */
public function setConnection(int $face, ?WallConnectionType $type) : self{
if($face !== Facing::NORTH && $face !== Facing::SOUTH && $face !== Facing::WEST && $face !== Facing::EAST){
throw new \InvalidArgumentException("Facing can only be north, east, south or west");
}
if($type !== null){
$this->connections[$face] = $type;
}else{
unset($this->connections[$face]);
}
return $this;
}
public function isPost() : bool{ return $this->post; }
/** @return $this */
public function setPost(bool $post) : self{
$this->post = $post;
return $this;
}
protected function recalculateConnections() : bool{
$changed = 0;
//TODO: implement tall/short connections - right now we only support short as per pre-1.16
foreach(Facing::HORIZONTAL as $facing){
$block = $this->getSide($facing);
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
if(!isset($this->connections[$facing])){
$this->connections[$facing] = $facing;
$this->connections[$facing] = WallConnectionType::SHORT();
$changed++;
}
}elseif(isset($this->connections[$facing])){
@ -56,8 +119,8 @@ class Wall extends Transparent{
}
$up = $this->getSide(Facing::UP)->getTypeId() !== BlockTypeIds::AIR;
if($up !== $this->up){
$this->up = $up;
if($up !== $this->post){
$this->post = $up;
$changed++;
}
@ -74,7 +137,7 @@ class Wall extends Transparent{
$inset = 0.25;
if(
!$this->up && //if there is a block on top, it stays as a post
!$this->post && //if there is a block on top, it stays as a post
(
($north && $south && !$west && !$east) ||
(!$north && !$south && $west && $east)

View File

@ -97,4 +97,25 @@ final class BlockDataReader{
default => throw new AssumptionFailedError("Unreachable")
};
}
/**
* @return WallConnectionType[]
* @phpstan-return array<Facing::NORTH|Facing::EAST|Facing::SOUTH|Facing::WEST, WallConnectionType>
*/
public function readWallConnections() : array{
$connections = [];
//TODO: we can pack this into 7 bits instead of 8
foreach(Facing::HORIZONTAL as $facing){
$type = $this->readBoundedInt(2, 0, 2);
if($type !== 0){
$connections[$facing] = match($type){
1 => WallConnectionType::SHORT(),
2 => WallConnectionType::TALL(),
default => throw new AssumptionFailedError("Unreachable")
};
}
}
return $connections;
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block\utils;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\utils\AssumptionFailedError;
final class BlockDataWriter{
@ -95,6 +96,24 @@ final class BlockDataWriter{
});
}
/**
* @param WallConnectionType[] $connections
* @phpstan-param array<Facing::NORTH|Facing::EAST|Facing::SOUTH|Facing::WEST, WallConnectionType> $connections
*/
public function writeWallConnections(array $connections) : self{
//TODO: we can pack this into 7 bits instead of 8
foreach(Facing::HORIZONTAL as $facing){
$this->writeInt(2, match($connections[$facing] ?? null){
null => 0,
WallConnectionType::SHORT() => 1,
WallConnectionType::TALL() => 2,
default => throw new AssumptionFailedError("Unreachable")
});
}
return $this;
}
public function getValue() : int{ return $this->value; }
public function getOffset() : int{ return $this->offset; }

View File

@ -31,7 +31,6 @@ use pocketmine\utils\EnumTrait;
* @see build/generate-registry-annotations.php
* @generate-registry-docblock
*
* @method static WallConnectionType NONE()
* @method static WallConnectionType SHORT()
* @method static WallConnectionType TALL()
*/
@ -40,7 +39,6 @@ final class WallConnectionType{
protected static function setup() : void{
self::registerAll(
new self("none"),
new self("short"),
new self("tall")
);