From 3ec3be6b20522c641b305fef14b1d63498cedf10 Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 Date: Sat, 10 Aug 2024 21:00:38 +0200 Subject: [PATCH] base system --- src/block/Block.php | 9 ++++- src/block/Stair.php | 14 +++++++- src/block/utils/Waterloggable.php | 32 +++++++++++++++++ src/block/utils/WaterloggableTrait.php | 40 +++++++++++++++++++++ src/world/SimpleChunkManager.php | 12 +++++-- src/world/World.php | 5 +-- src/world/format/Chunk.php | 9 +++++ src/world/format/SubChunk.php | 14 ++++++++ src/world/utils/BlockChunkReader.php | 48 ++++++++++++++++++++++++++ 9 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 src/block/utils/Waterloggable.php create mode 100644 src/block/utils/WaterloggableTrait.php create mode 100644 src/world/utils/BlockChunkReader.php diff --git a/src/block/Block.php b/src/block/Block.php index dbc269c63..820aadb33 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -29,6 +29,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Spawnable; use pocketmine\block\tile\Tile; use pocketmine\block\utils\SupportType; +use pocketmine\block\utils\Waterloggable; use pocketmine\data\runtime\InvalidSerializedRuntimeDataException; use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\runtime\RuntimeDataReader; @@ -379,7 +380,13 @@ class Block{ if($chunk === null){ throw new AssumptionFailedError("World::setBlock() should have loaded the chunk before calling this method"); } - $chunk->setBlockStateId($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getStateId()); + $x = $this->position->x & Chunk::COORD_MASK; + $z = $this->position->z & Chunk::COORD_MASK; + $stateId = $this->getStateId(); + $chunk->setBlockStateId($x, $this->position->y, $z, $stateId); + if($this instanceof Waterloggable){ + $chunk->setWaterStateId($x, $this->position->y, $z, $this->getWaterState()?->getStateId()); + } $tileType = $this->idInfo->getTileClass(); $oldTile = $world->getTile($this->position); diff --git a/src/block/Stair.php b/src/block/Stair.php index d66a9ce5c..49084f673 100644 --- a/src/block/Stair.php +++ b/src/block/Stair.php @@ -26,8 +26,11 @@ namespace pocketmine\block; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\StairShape; use pocketmine\block\utils\SupportType; +use pocketmine\block\utils\Waterloggable; +use pocketmine\block\utils\WaterloggableTrait; use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\item\Item; +use pocketmine\item\LiquidBucket; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -35,8 +38,9 @@ use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; -class Stair extends Transparent{ +class Stair extends Transparent implements Waterloggable{ use HorizontalFacingTrait; + use WaterloggableTrait; protected bool $upsideDown = false; protected StairShape $shape = StairShape::STRAIGHT; @@ -134,4 +138,12 @@ class Stair extends Transparent{ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } + + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ + if($item instanceof LiquidBucket && $item->getLiquid() instanceof Water){ + $this->position->getWorld()->setBlock($this->position, $this->setWaterState($item->getLiquid())); + } + + return parent::onInteract($item, $face, $clickVector, $player, $returnedItems); + } } diff --git a/src/block/utils/Waterloggable.php b/src/block/utils/Waterloggable.php new file mode 100644 index 000000000..e45bff219 --- /dev/null +++ b/src/block/utils/Waterloggable.php @@ -0,0 +1,32 @@ +waterState; + } + + public function setWaterState(?Water $state) : self{ + $this->waterState = $state; + + return $this; + } +} diff --git a/src/world/SimpleChunkManager.php b/src/world/SimpleChunkManager.php index 221adbe89..36e1c1739 100644 --- a/src/world/SimpleChunkManager.php +++ b/src/world/SimpleChunkManager.php @@ -24,10 +24,11 @@ declare(strict_types=1); namespace pocketmine\world; use pocketmine\block\Block; -use pocketmine\block\RuntimeBlockStateRegistry; +use pocketmine\block\utils\Waterloggable; use pocketmine\block\VanillaBlocks; use pocketmine\utils\Limits; use pocketmine\world\format\Chunk; +use pocketmine\world\utils\BlockChunkReader; class SimpleChunkManager implements ChunkManager{ @@ -41,14 +42,19 @@ class SimpleChunkManager implements ChunkManager{ public function getBlockAt(int $x, int $y, int $z) : Block{ if($this->isInWorld($x, $y, $z) && ($chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)) !== null){ - return RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK)); + return BlockChunkReader::getBlock($chunk, $x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK); } return VanillaBlocks::AIR(); } public function setBlockAt(int $x, int $y, int $z, Block $block) : void{ if(($chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)) !== null){ - $chunk->setBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK, $block->getStateId()); + $xMasked = $x & Chunk::COORD_MASK; + $zMasked = $z & Chunk::COORD_MASK; + $chunk->setBlockStateId($xMasked, $y, $zMasked, $block->getStateId()); + if($block instanceof Waterloggable){ + $chunk->setWaterStateId($xMasked, $y, $zMasked, $block->getWaterState()?->getStateId()); + } }else{ throw new \InvalidArgumentException("Cannot set block at coordinates x=$x,y=$y,z=$z, terrain is not loaded or out of bounds"); } diff --git a/src/world/World.php b/src/world/World.php index fbfa05b71..2a8d91c8a 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -103,6 +103,7 @@ use pocketmine\world\particle\BlockBreakParticle; use pocketmine\world\particle\Particle; use pocketmine\world\sound\BlockPlaceSound; use pocketmine\world\sound\Sound; +use pocketmine\world\utils\BlockChunkReader; use pocketmine\world\utils\SubChunkExplorer; use pocketmine\YmlServerProperties; use function abs; @@ -1893,7 +1894,7 @@ class World implements ChunkManager{ $chunk = $this->chunks[$chunkHash] ?? null; if($chunk !== null){ - $block = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK)); + $block = BlockChunkReader::getBlock($chunk, $x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK); }else{ $addToCache = false; $block = VanillaBlocks::AIR(); @@ -2542,7 +2543,7 @@ class World implements ChunkManager{ $localY = $tilePosition->getFloorY(); $localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK; - $newBlock = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($localX, $localY, $localZ)); + $newBlock = BlockChunkReader::getBlock($chunk, $localX, $localY, $localZ);; $expectedTileClass = $newBlock->getIdInfo()->getTileClass(); if( $expectedTileClass === null || //new block doesn't expect a tile diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index e4c877dc9..2913b1f03 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -107,6 +107,15 @@ class Chunk{ $this->terrainDirtyFlags |= self::DIRTY_FLAG_BLOCKS; } + public function getWaterStateId(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)->getWaterStateId($x, $y & SubChunk::COORD_MASK, $z); + } + + public function setWaterStateId(int $x, int $y, int $z, ?int $block) : void{ + $this->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)->setWaterStateId($x, $y & SubChunk::COORD_MASK, $z, $block ?? Block::EMPTY_STATE_ID); + $this->terrainDirtyFlags |= self::DIRTY_FLAG_BLOCKS; + } + /** * Returns the Y coordinate of the highest non-air block at the specified X/Z chunk block coordinates * diff --git a/src/world/format/SubChunk.php b/src/world/format/SubChunk.php index 3f7e943e3..b7460dd62 100644 --- a/src/world/format/SubChunk.php +++ b/src/world/format/SubChunk.php @@ -83,6 +83,20 @@ class SubChunk{ $this->blockLayers[0]->set($x, $y, $z, $block); } + public function getWaterStateId(int $x, int $y, int $z) : int{ + if(count($this->blockLayers) < 2){ + return $this->emptyBlockId; + } + return $this->blockLayers[1]->get($x, $y, $z); + } + + public function setWaterStateId(int $x, int $y, int $z, int $block) : void{ + if(count($this->blockLayers) < 2){ + $this->blockLayers[1] = new PalettedBlockArray($this->emptyBlockId); + } + $this->blockLayers[1]->set($x, $y, $z, $block); + } + /** * @return PalettedBlockArray[] */ diff --git a/src/world/utils/BlockChunkReader.php b/src/world/utils/BlockChunkReader.php new file mode 100644 index 000000000..fbadef59b --- /dev/null +++ b/src/world/utils/BlockChunkReader.php @@ -0,0 +1,48 @@ +fromStateId($chunk->getBlockStateId($x, $y, $z)); + if($block instanceof Waterloggable){ + $waterState = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getWaterStateId($x, $y, $z)); + if($waterState instanceof Water){ + $block->setWaterState($waterState); + } + } + + return $block; + } +}