From 5516d87b8f745d8e6c93ee89265dbe8ca7e306ab Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 5 Nov 2021 00:11:23 +0100 Subject: [PATCH 01/16] Update .poggit.yml --- .poggit.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.poggit.yml b/.poggit.yml index 0f178f9..c28dff3 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -4,4 +4,8 @@ projects: path: "" model: virion type: library + libs: + - src: thebigsmilexd/libblockstate/libblockstate + version: ^0.0.0 + branch: master ... From 844a48f24743959e62c964bb1b9664c84f182935 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 21 Nov 2021 04:46:11 +0100 Subject: [PATCH 02/16] Remove MagicWE2 dependency, use libblockstate virion, Update to API 4.0.0-BETA13 --- .poggit.yml | 2 +- .../libstructure/block/StructureBlock.php | 3 +- .../libstructure/format/MCStructure.php | 42 +++++++------ .../libstructure/format/NBTStructure.php | 61 ++++++++++++------- .../libstructure/tile/StructureBlockTile.php | 11 ++-- virion.yml | 2 +- 6 files changed, 71 insertions(+), 50 deletions(-) diff --git a/.poggit.yml b/.poggit.yml index c28dff3..7765e24 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -6,6 +6,6 @@ projects: type: library libs: - src: thebigsmilexd/libblockstate/libblockstate - version: ^0.0.0 + version: ^0.0.1 branch: master ... diff --git a/src/xenialdan/libstructure/block/StructureBlock.php b/src/xenialdan/libstructure/block/StructureBlock.php index 5732dbe..0955ffb 100644 --- a/src/xenialdan/libstructure/block/StructureBlock.php +++ b/src/xenialdan/libstructure/block/StructureBlock.php @@ -10,6 +10,7 @@ use pocketmine\item\Item; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\ContainerOpenPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; use pocketmine\network\mcpe\protocol\types\StructureEditorData; use pocketmine\player\Player; @@ -46,7 +47,7 @@ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player->setCurrentWindow($structureBlock->getInventory()); //TODO remove once PMMP allows injecting to InventoryManager::createContainerOpen $id = $player->getNetworkSession()->getInvManager()->getCurrentWindowId(); - $pk = ContainerOpenPacket::blockInvVec3($id, WindowTypes::STRUCTURE_EDITOR, $this->position->asVector3()); + $pk = ContainerOpenPacket::blockInv($id, WindowTypes::STRUCTURE_EDITOR, BlockPosition::fromVector3($this->position->asVector3())); $player->getNetworkSession()->sendDataPacket($pk); } } diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index b25867b..a19f445 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -22,16 +22,19 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\UnexpectedTagTypeException; +use pocketmine\Server; use pocketmine\utils\Filesystem; use pocketmine\utils\TextFormat; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\Position; use pocketmine\world\World; +use RuntimeException; use UnexpectedValueException; +use xenialdan\libblockstate\BlockState; +use xenialdan\libblockstate\BlockStatesParser; +use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; -use xenialdan\MagicWE2\helper\BlockStatesEntry; -use xenialdan\MagicWE2\helper\BlockStatesParser; class MCStructure { @@ -101,7 +104,7 @@ public function parse(string $path): void * @param string $tagName * @param bool $optional * @return Vector3 - * @throws UnexpectedValueException + * @throws UnexpectedValueException|UnexpectedTagTypeException */ private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional): Vector3 { @@ -135,6 +138,8 @@ private function parseStructure(CompoundTag $structure): void * @param ListTag>|null $blockIndicesList * @throws InvalidArgumentException * @throws OutOfRangeException + * @throws UnexpectedTagTypeException + * @throws RuntimeException */ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList): void { @@ -145,13 +150,17 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block $paletteBlocks = new PalettedBlockArray(BlockLegacyIds::AIR << 4); $paletteLiquids = new PalettedBlockArray(BlockLegacyIds::AIR << 4); $blockEntities = []; - /** @var BlockStatesEntry[] $paletteArray */ + /** @var BlockState[] $paletteArray */ $paletteArray = []; /** @var CompoundTag $blockCompoundTag */ foreach ($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag) { - $blockState = BlockStatesParser::getInstance()::getStateByCompound($blockCompoundTag); - if ($blockState instanceof BlockStatesEntry) $paletteArray[$paletteIndex] = $blockState; - else print TextFormat::RED . $blockCompoundTag . " is not BlockStatesEntry"; + try { + $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); + if ($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; + else print TextFormat::RED . $blockCompoundTag . " is not BlockState"; + } catch (BlockQueryParsingFailedException $e) { + Server::getInstance()->getLogger()->logException($e); + } } /** @var CompoundTag $blockPositionData */ $blockPositionData = $paletteDefaultTag->getCompoundTag(self::TAG_PALETTE_BLOCK_POSITION_DATA); @@ -173,6 +182,7 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block /** @var ListTag $tag */ if(!$tag instanceof ListTag) continue; + //TODO support more layers //block layer if($blockIndicesList->isset(0)){ $tag = $blockIndicesList->get(0); @@ -180,8 +190,7 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block if (($i = $blockLayer[$offset] ?? -1) !== -1) { if (($statesEntry = $paletteArray[$i] ?? null) !== null) { try { - $block = $statesEntry->toBlock(); - $paletteBlocks->set($x, $y, $z, $block->getFullId()); + $paletteBlocks->set($x, $y, $z, $statesEntry->getFullId()); } catch (Exception $e) { GlobalLogger::get()->logException($e); } @@ -194,8 +203,7 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block if (($i = $liquidLayer[$offset] ?? -1) !== -1) { if (($statesEntry = $paletteArray[$i] ?? null) !== null) { try { - $block = $statesEntry->toBlock(); - $paletteLiquids->set($x, $y, $z, $block->getFullId()); + $paletteLiquids->set($x, $y, $z, $statesEntry->getFullId()); } catch (Exception $e) { GlobalLogger::get()->logException($e); } @@ -275,6 +283,7 @@ public function translateBlockEntity(Position $position, Vector3 $origin): ?Tile // } // } + /** @noinspection PhpInternalEntityUsedInspection */ $tile = $instance->createFromData($position->getWorld(), $data); if ($tile === null) return null; return $tile; @@ -297,20 +306,19 @@ public static function &readAnyValue(object $object, string $property): mixed return $value; } - /** - * @return Vector3 - */ public function getSize(): Vector3 { return $this->size; } - /** - * @return Vector3 - */ public function getStructureWorldOrigin(): Vector3 { return $this->structure_world_origin; } + public function getFormatVersion(): int + { + return $this->format_version; + } + } \ No newline at end of file diff --git a/src/xenialdan/libstructure/format/NBTStructure.php b/src/xenialdan/libstructure/format/NBTStructure.php index be8ce54..a419ca2 100644 --- a/src/xenialdan/libstructure/format/NBTStructure.php +++ b/src/xenialdan/libstructure/format/NBTStructure.php @@ -8,6 +8,7 @@ use InvalidArgumentException; use OutOfRangeException; use pocketmine\block\Block; +use pocketmine\block\utils\InvalidBlockStateException; use pocketmine\math\Vector3; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NBT; @@ -16,21 +17,21 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; +use pocketmine\nbt\UnexpectedTagTypeException; +use pocketmine\Server; +use RuntimeException; +use xenialdan\libblockstate\BlockQuery; +use xenialdan\libblockstate\BlockStatesParser; +use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; +use xenialdan\libblockstate\exception\BlockStateNotFoundException; use xenialdan\libstructure\exception\StructureFileException; -use xenialdan\MagicWE2\exception\InvalidBlockStateException; -use xenialdan\MagicWE2\helper\BlockQuery; -use xenialdan\MagicWE2\helper\BlockStatesParser; -use xenialdan\MagicWE2\Loader; use function file_get_contents; use function zlib_decode; class NBTStructure { - /** @var int */ private int $version; - /** @var string */ private string $author; - /** @var Vector3 */ private Vector3 $size; /** @var ListTag */ private ListTag $palettes; @@ -66,6 +67,7 @@ public function save(string $file): void//TODO * @throws OutOfRangeException * @throws StructureFileException * @throws NbtDataException + * @throws UnexpectedTagTypeException */ public function parse(string $file): void { @@ -90,11 +92,15 @@ public function parse(string $file): void /** * @param ListTag $paletteList * @return Block[] - * @throws InvalidArgumentException - * @throws \pocketmine\block\utils\InvalidBlockStateException + * @throws RuntimeException + * @throws UnexpectedTagTypeException + * @throws BlockQueryParsingFailedException + * @throws BlockStateNotFoundException */ private function paletteToBlocks(ListTag $paletteList): array { + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); /** @var Block[] $blocks */ $blocks = []; /** @var CompoundTag $blockCompound */ @@ -129,27 +135,28 @@ private function paletteToBlocks(ListTag $paletteList): array $states[] = $name . '=' . $valueString; } try { - $fromString = BlockStatesParser::fromString(BlockQuery::fromString($id . '[' . implode(',', $states) . ']')); + $blocks[] = $blockStatesParser->parseQuery(BlockQuery::fromString($id . '[' . implode(',', $states) . ']'))->getBlock(); } catch (InvalidBlockStateException $e) { - Loader::getInstance()->getLogger()->logException($e); + Server::getInstance()->getLogger()->logException($e); } - $blocks[] = reset($fromString); } return $blocks; } /** * returns a generator of blocks found in the schematic opened. - * @param int $palette + * @param int $layer * @return Generator * @throws OutOfRangeException * @throws InvalidArgumentException - * @throws \pocketmine\block\utils\InvalidBlockStateException + * @throws InvalidBlockStateException + * @throws UnexpectedTagTypeException + * @throws RuntimeException */ - public function blocks(int $palette = 0): Generator + public function blocks(int $layer = 0): Generator { /** @var ListTag $paletteList */ - $paletteList = $this->palettes->get($palette); + $paletteList = $this->palettes->get($layer); $blockPalette = $this->paletteToBlocks($paletteList); /** @var CompoundTag $blockTag */ foreach ($this->blocks as $blockTag) { @@ -229,15 +236,23 @@ public function blocks(int $palette = 0): Generator // } // } - /** - * @param int $x - * @param int $y - * @param int $z - * - * @return int - */ protected function blockIndex(int $x, int $y, int $z): int { return ($y * $this->size->getZ() + $z) * $this->size->getX() + $x; } + + public function getVersion(): int + { + return $this->version; + } + + public function getAuthor(): string + { + return $this->author; + } + + public function getSize(): Vector3 + { + return $this->size; + } } diff --git a/src/xenialdan/libstructure/tile/StructureBlockTile.php b/src/xenialdan/libstructure/tile/StructureBlockTile.php index d4284c4..a84bf60 100644 --- a/src/xenialdan/libstructure/tile/StructureBlockTile.php +++ b/src/xenialdan/libstructure/tile/StructureBlockTile.php @@ -10,6 +10,7 @@ use pocketmine\inventory\InventoryHolder; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\StructureEditorData; use pocketmine\network\mcpe\protocol\types\StructureSettings; use pocketmine\world\World; @@ -276,15 +277,11 @@ private function getStructureSettings(Vector3 $size, Vector3 $origin): Structure $settings->paletteName = "default"; $settings->ignoreEntities = !$this->isShowEntities(); $settings->ignoreBlocks = !$this->isShowBlocks(); - $settings->structureSizeX = $size->getFloorX(); - $settings->structureSizeY = $size->getFloorY(); - $settings->structureSizeZ = $size->getFloorZ(); - $settings->structureOffsetX = 0; - $settings->structureOffsetY = 0; - $settings->structureOffsetZ = 0;//TODO position + $settings->dimensions = BlockPosition::fromVector3($size); + $settings->offset = new BlockPosition(0,0,0);//TODO position $settings->lastTouchedByPlayerID = -1; $settings->rotation = 0; - $settings->mirror = false; + $settings->mirror = 0; $settings->integrityValue = 1.0; $settings->integritySeed = 0; $settings->pivot = $origin; diff --git a/virion.yml b/virion.yml index 4b19379..65b5e4f 100644 --- a/virion.yml +++ b/virion.yml @@ -1,5 +1,5 @@ name: libstructure -version: 0.1.5 +version: 0.1.6 antigen: xenialdan\libstructure api: [4.0.0] php: [ 8.0 ] From c682b77bd7ee6b6d9f6a177b9682f8cc6985ad8b Mon Sep 17 00:00:00 2001 From: XenialDan Date: Thu, 7 Jul 2022 17:54:59 +0200 Subject: [PATCH 03/16] PMMP update & Reformat / cleanup --- .gitignore | 2 +- src/xenialdan/dump.md | 1 + src/xenialdan/libstructure/PacketListener.php | 79 ++++---- .../libstructure/block/StructureBlock.php | 25 ++- .../exception/StructureException.php | 3 +- .../exception/StructureFileException.php | 3 +- .../exception/StructureFormatException.php | 3 +- .../libstructure/format/MCStructure.php | 191 +++++++++--------- .../libstructure/format/NBTStructure.php | 46 ++--- .../libstructure/tile/StructureBlockTags.php | 19 +- .../libstructure/tile/StructureBlockTile.php | 114 +++++------ .../window/StructureBlockInventory.php | 7 +- virion.yml | 4 +- 13 files changed, 234 insertions(+), 263 deletions(-) diff --git a/.gitignore b/.gitignore index 723ef36..bc8a670 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.idea \ No newline at end of file +.idea/* \ No newline at end of file diff --git a/src/xenialdan/dump.md b/src/xenialdan/dump.md index 37095cf..2b7664a 100644 --- a/src/xenialdan/dump.md +++ b/src/xenialdan/dump.md @@ -1,4 +1,5 @@ # NBT format output of exported.mcstructure + ``` TAG_Compound({ 'structure_world_origin': TAG_List({ diff --git a/src/xenialdan/libstructure/PacketListener.php b/src/xenialdan/libstructure/PacketListener.php index 8a9fef0..d1b4bbf 100644 --- a/src/xenialdan/libstructure/PacketListener.php +++ b/src/xenialdan/libstructure/PacketListener.php @@ -10,8 +10,6 @@ use pocketmine\event\Listener; use pocketmine\event\server\DataPacketReceiveEvent; use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket; -use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket; -use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket; use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginException; use RuntimeException; @@ -20,55 +18,50 @@ use xenialdan\libstructure\tile\StructureBlockTile; use xenialdan\libstructure\window\StructureBlockInventory; -class PacketListener implements Listener -{ +class PacketListener implements Listener{ /** @var Plugin|null */ private static ?Plugin $registrant = null; - public static function isRegistered(): bool - { + public static function isRegistered() : bool{ return self::$registrant instanceof Plugin; } - public static function getRegistrant(): Plugin - { + public static function getRegistrant() : Plugin{ return self::$registrant; } - public static function unregister(): void - { + public static function unregister() : void{ self::$registrant = null; } /** * @param Plugin $plugin - * @throws PluginException|RuntimeException + * + * @throws PluginException|RuntimeException|InvalidArgumentException */ - public static function register(Plugin $plugin): void - { - if (self::isRegistered()) { + public static function register(Plugin $plugin) : void{ + if(self::isRegistered()){ return;//silent return } self::$registrant = $plugin; - try { - TileFactory::getInstance()->register(StructureBlockTile::class, [StructureBlockTags::TAG_ID, "minecraft:structure_block"]); - BlockFactory::getInstance()->register(new StructureBlock(new BlockIdentifier(BlockLegacyIds::STRUCTURE_BLOCK,0, null, StructureBlockTile::class), "Structure Block"), true); - } catch (InvalidArgumentException) { - } + /** @var TileFactory $tileFactory */ + $tileFactory = TileFactory::getInstance(); + $tileFactory->register(StructureBlockTile::class, [StructureBlockTags::TAG_ID, "minecraft:structure_block"]); + /** @var BlockFactory $blockFactory */ + $blockFactory = BlockFactory::getInstance(); + $blockFactory->register(new StructureBlock(new BlockIdentifier(BlockLegacyIds::STRUCTURE_BLOCK, 0, null, StructureBlockTile::class), "Structure Block"), true); $plugin->getServer()->getPluginManager()->registerEvents(new self, $plugin); } - public function onDataPacketReceiveEvent(DataPacketReceiveEvent $e) - { - if ($e->getPacket() instanceof StructureBlockUpdatePacket) $this->onStructureBlockUpdatePacket($e); + public function onDataPacketReceiveEvent(DataPacketReceiveEvent $e){ + if($e->getPacket() instanceof StructureBlockUpdatePacket) $this->onStructureBlockUpdatePacket($e); //if ($e->getPacket() instanceof StructureTemplateDataRequestPacket) $this->onStructureTemplateDataExportRequestPacket($e); //if ($e->getPacket() instanceof StructureTemplateDataResponsePacket) $this->onStructureTemplateDataExportResponsePacket($e); } - private function onStructureBlockUpdatePacket(DataPacketReceiveEvent $e) - { - if (!$e->getPacket() instanceof StructureBlockUpdatePacket) return; + private function onStructureBlockUpdatePacket(DataPacketReceiveEvent $e){ + if(!$e->getPacket() instanceof StructureBlockUpdatePacket) return; //** @var StructureBlockUpdatePacket $pk */ #var_dump($e->getPacket());//TODO remove $session = $e->getOrigin(); @@ -79,23 +72,21 @@ private function onStructureBlockUpdatePacket(DataPacketReceiveEvent $e) } } - private function onStructureTemplateDataExportRequestPacket(DataPacketReceiveEvent $e) - { - /** @var StructureTemplateDataRequestPacket $pk */ - $pk = $e->getPacket(); - #$player = $e->getOrigin()->getPlayer(); - if ($pk instanceof StructureTemplateDataRequestPacket) { - var_dump($pk);//TODO remove - } - } - - private function onStructureTemplateDataExportResponsePacket(DataPacketReceiveEvent $e) - { - /** @var StructureTemplateDataResponsePacket $pk */ - $pk = $e->getPacket(); - #$player = $e->getOrigin()->getPlayer(); - if ($pk instanceof StructureTemplateDataResponsePacket) { - var_dump($pk);//TODO remove - } - } +// private function onStructureTemplateDataExportRequestPacket(DataPacketReceiveEvent $e){ +// /** @var StructureTemplateDataRequestPacket $pk */ +// $pk = $e->getPacket(); +// #$player = $e->getOrigin()->getPlayer(); +// if($pk instanceof StructureTemplateDataRequestPacket){ +// var_dump($pk);//TODO remove +// } +// } +// +// private function onStructureTemplateDataExportResponsePacket(DataPacketReceiveEvent $e){ +// /** @var StructureTemplateDataResponsePacket $pk */ +// $pk = $e->getPacket(); +// #$player = $e->getOrigin()->getPlayer(); +// if($pk instanceof StructureTemplateDataResponsePacket){ +// var_dump($pk);//TODO remove +// } +// } } \ No newline at end of file diff --git a/src/xenialdan/libstructure/block/StructureBlock.php b/src/xenialdan/libstructure/block/StructureBlock.php index 0955ffb..3e61d7e 100644 --- a/src/xenialdan/libstructure/block/StructureBlock.php +++ b/src/xenialdan/libstructure/block/StructureBlock.php @@ -4,6 +4,8 @@ namespace xenialdan\libstructure\block; +use InvalidArgumentException; +use LogicException; use pocketmine\block\Block; use pocketmine\block\BlockBreakInfo; use pocketmine\block\BlockIdentifier; @@ -12,16 +14,17 @@ use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; -use pocketmine\network\mcpe\protocol\types\StructureEditorData; use pocketmine\player\Player; +use pocketmine\utils\AssumptionFailedError; use xenialdan\libstructure\tile\StructureBlockTile as TileStructureBlock; -class StructureBlock extends Block -{ - private int $mode = StructureEditorData::TYPE_SAVE;//TODO validate if correct +class StructureBlock extends Block{ + #private int $mode = StructureEditorData::TYPE_SAVE;//TODO validate if correct - public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null) - { + /** + * @throws InvalidArgumentException + */ + public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){ parent::__construct($idInfo, $name, $breakInfo ?? BlockBreakInfo::indestructible()); } @@ -39,11 +42,13 @@ public function getStateBitmask() : int{ return 0b101; } - public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null): bool - { - if ($player instanceof Player) { + /** + * @throws LogicException|InvalidArgumentException|AssumptionFailedError + */ + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($player instanceof Player){ $structureBlock = $this->position->getWorld()->getTile($this->position); - if ($structureBlock instanceof TileStructureBlock and $player->isCreative(true)) { + if($structureBlock instanceof TileStructureBlock and $player->isCreative(true)){ $player->setCurrentWindow($structureBlock->getInventory()); //TODO remove once PMMP allows injecting to InventoryManager::createContainerOpen $id = $player->getNetworkSession()->getInvManager()->getCurrentWindowId(); diff --git a/src/xenialdan/libstructure/exception/StructureException.php b/src/xenialdan/libstructure/exception/StructureException.php index 5314368..1915eb0 100644 --- a/src/xenialdan/libstructure/exception/StructureException.php +++ b/src/xenialdan/libstructure/exception/StructureException.php @@ -4,7 +4,6 @@ use Exception; -abstract class StructureException extends Exception -{ +abstract class StructureException extends Exception{ } \ No newline at end of file diff --git a/src/xenialdan/libstructure/exception/StructureFileException.php b/src/xenialdan/libstructure/exception/StructureFileException.php index a27df12..7dd1785 100644 --- a/src/xenialdan/libstructure/exception/StructureFileException.php +++ b/src/xenialdan/libstructure/exception/StructureFileException.php @@ -4,7 +4,6 @@ namespace xenialdan\libstructure\exception; -class StructureFileException extends StructureException -{ +class StructureFileException extends StructureException{ } \ No newline at end of file diff --git a/src/xenialdan/libstructure/exception/StructureFormatException.php b/src/xenialdan/libstructure/exception/StructureFormatException.php index 2110d56..d013120 100644 --- a/src/xenialdan/libstructure/exception/StructureFormatException.php +++ b/src/xenialdan/libstructure/exception/StructureFormatException.php @@ -6,7 +6,6 @@ use pocketmine\nbt\NbtDataException; -class StructureFormatException extends NbtDataException -{ +class StructureFormatException extends NbtDataException{ } \ No newline at end of file diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index a19f445..10e54b4 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -14,6 +14,7 @@ use pocketmine\block\tile\Container; use pocketmine\block\tile\Tile; use pocketmine\block\tile\TileFactory; +use pocketmine\data\SavedDataLoadingException; use pocketmine\math\Vector3; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NBT; @@ -22,22 +23,19 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\UnexpectedTagTypeException; -use pocketmine\Server; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; use pocketmine\utils\TextFormat; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\Position; use pocketmine\world\World; -use RuntimeException; use UnexpectedValueException; use xenialdan\libblockstate\BlockState; use xenialdan\libblockstate\BlockStatesParser; -use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; -class MCStructure -{ +class MCStructure{ //https://github.com/df-mc/structure/blob/651c5d323dbfb24991dafdb72129e2a8a478a81b/structure.go#L66-L91 public const TAG_STRUCTURE_WORLD_ORIGIN = 'structure_world_origin'; public const TAG_FORMAT_VERSION = 'format_version'; @@ -53,42 +51,35 @@ class MCStructure public const EXTENSION_MCSTRUCTURE = '.mcstructure'; public const LAYER_BLOCKS = 0; public const LAYER_LIQUIDS = 1; - /** @var Vector3 */ private Vector3 $structure_world_origin; - /** @var int */ private int $format_version; - /** @var Vector3 */ private Vector3 $size; /** @var PalettedBlockArray[] */ private array $blockLayers = []; - /** @var array|CompoundTag[] */ + /** @var CompoundTag[] */ private array $entities = []; - /** @var array|CompoundTag[] */ + /** @var CompoundTag[] */ private array $blockEntities = []; /** * Parses a *.mcstructure file + * * @param string $path path to the .mcstructure file - * @throws InvalidArgumentException - * @throws StructureFileException - * @throws StructureFormatException - * @throws UnexpectedTagTypeException - * @throws UnexpectedValueException - * @throws NbtDataException + * + * @throws InvalidArgumentException|StructureFileException|StructureFormatException|UnexpectedTagTypeException|UnexpectedValueException|NbtDataException|OutOfRangeException * @see MCStructure */ - public function parse(string $path): void - { + public function parse(string $path) : void{ $pathext = pathinfo($path, PATHINFO_EXTENSION); - if ('.' . strtolower($pathext) !== self::EXTENSION_MCSTRUCTURE) throw new InvalidArgumentException("File extension $pathext for file $path is not " . self::EXTENSION_MCSTRUCTURE); + if('.' . strtolower($pathext) !== self::EXTENSION_MCSTRUCTURE) throw new InvalidArgumentException("File extension $pathext for file $path is not " . self::EXTENSION_MCSTRUCTURE); $path = Filesystem::cleanPath(realpath($path)); $fread = file_get_contents($path); - if ($fread === false) throw new StructureFileException("Could not read file $path"); + if($fread === false) throw new StructureFileException("Could not read file $path"); $namedTag = (new LittleEndianNBTSerializer())->read($fread)->mustGetCompoundTag(); #Server::getInstance()->getLogger()->debug($namedTag->toString(2)); //version $version = $namedTag->getInt(self::TAG_FORMAT_VERSION); - if ($version === null) throw new StructureFormatException(self::TAG_FORMAT_VERSION . " must be present and valid integer"); + if($version === null) throw new StructureFormatException(self::TAG_FORMAT_VERSION . " must be present and valid integer"); $this->format_version = $version; //structure origin $structureWorldOrigin = self::parseVec3($namedTag, self::TAG_STRUCTURE_WORLD_ORIGIN, true);//TODO check if optional (makes it V3{0,0,0}) @@ -101,30 +92,32 @@ public function parse(string $path): void /** * @param CompoundTag $nbt - * @param string $tagName - * @param bool $optional + * @param string $tagName + * @param bool $optional + * * @return Vector3 * @throws UnexpectedValueException|UnexpectedTagTypeException */ - private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional): Vector3 - { + private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{ $pos = $nbt->getListTag($tagName); - if ($pos === null and $optional) { + if($pos === null and $optional){ return new Vector3(0, 0, 0); } - if (!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Int) { + if(!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Int){ throw new UnexpectedValueException("'$tagName' should be a List"); } /** @var IntTag[] $values */ $values = $pos->getValue(); - if (count($values) !== 3) { + if(count($values) !== 3){ throw new UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag"); } return new Vector3($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue()); } - private function parseStructure(CompoundTag $structure): void - { + /** + * @throws OutOfRangeException|UnexpectedTagTypeException|InvalidArgumentException + */ + private function parseStructure(CompoundTag $structure) : void{ $blockIndicesList = $structure->getListTag('block_indices');//list> #$entitiesList = $structure->getListTag('entities'); #var_dump($entitiesList->toString(2)); @@ -134,15 +127,12 @@ private function parseStructure(CompoundTag $structure): void } /** - * @param CompoundTag|null $paletteCompound + * @param CompoundTag|null $paletteCompound * @param ListTag>|null $blockIndicesList - * @throws InvalidArgumentException - * @throws OutOfRangeException - * @throws UnexpectedTagTypeException - * @throws RuntimeException + * + * @throws InvalidArgumentException|OutOfRangeException|UnexpectedTagTypeException */ - private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList): void - { + private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList) : void{ /*if($paletteCompound->count() > 1){ }*/ @@ -153,23 +143,19 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block /** @var BlockState[] $paletteArray */ $paletteArray = []; /** @var CompoundTag $blockCompoundTag */ - foreach ($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag) { - try { - $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); - if ($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; - else print TextFormat::RED . $blockCompoundTag . " is not BlockState"; - } catch (BlockQueryParsingFailedException $e) { - Server::getInstance()->getLogger()->logException($e); - } + foreach($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag){ + $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); + if($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; + else print TextFormat::RED . $blockCompoundTag . " is not BlockStatesEntry"; } /** @var CompoundTag $blockPositionData */ $blockPositionData = $paletteDefaultTag->getCompoundTag(self::TAG_PALETTE_BLOCK_POSITION_DATA); //positions $l = $this->size->getZ(); $h = $this->size->getY(); - foreach (range(0, $this->size->getZ() - 1) as $z) { - foreach (range(0, $this->size->getY() - 1) as $y) { - foreach (range(0, $this->size->getX() - 1) as $x) { + foreach(range(0, $this->size->getZ() - 1) as $z){ + foreach(range(0, $this->size->getY() - 1) as $y){ + foreach(range(0, $this->size->getX() - 1) as $x){ // foreach ($blockIndicesList as $layerIndex => $layer) { // $layer = reset($layer);//only default // /** @var ListTag $layer */ @@ -178,41 +164,42 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block // // } // } - $offset = (int)(($x * $l * $h) + ($y * $l) + $z); - /** @var ListTag $tag */ - if(!$tag instanceof ListTag) continue; + $offset = (int) (($x * $l * $h) + ($y * $l) + $z); - //TODO support more layers //block layer - if($blockIndicesList->isset(0)){ - $tag = $blockIndicesList->get(0); + /** @var ListTag $tag */ + $tag = $blockIndicesList->get(0); $blockLayer = $tag->getAllValues(); - if (($i = $blockLayer[$offset] ?? -1) !== -1) { - if (($statesEntry = $paletteArray[$i] ?? null) !== null) { - try { - $paletteBlocks->set($x, $y, $z, $statesEntry->getFullId()); - } catch (Exception $e) { + if(($i = $blockLayer[$offset] ?? -1) !== -1){ + if(($statesEntry = $paletteArray[$i] ?? null) !== null){ + try{ + $block = $statesEntry->getBlock(); + /** @noinspection PhpInternalEntityUsedInspection */ + $paletteBlocks->set($x, $y, $z, $block->getFullId()); + }catch(Exception $e){ GlobalLogger::get()->logException($e); } } - }} + } //liquid layer - if($blockIndicesList->isset(1)){ + /** @var ListTag $tag */ $tag = $blockIndicesList->get(1); $liquidLayer = $tag->getAllValues(); - if (($i = $liquidLayer[$offset] ?? -1) !== -1) { - if (($statesEntry = $paletteArray[$i] ?? null) !== null) { - try { - $paletteLiquids->set($x, $y, $z, $statesEntry->getFullId()); - } catch (Exception $e) { + if(($i = $liquidLayer[$offset] ?? -1) !== -1){ + if(($statesEntry = $paletteArray[$i] ?? null) !== null){ + try{ + $block = $statesEntry->getBlock(); + /** @noinspection PhpInternalEntityUsedInspection */ + $paletteLiquids->set($x, $y, $z, $block->getFullId()); + }catch(Exception $e){ GlobalLogger::get()->logException($e); } } - }} + } //nbt - if ($blockPositionData->getTag((string)$offset) !== null) { + if($blockPositionData->getTag((string) $offset) !== null){ /** @var CompoundTag $tag1 */ - $tag1 = $blockPositionData->getCompoundTag((string)$offset); + $tag1 = $blockPositionData->getCompoundTag((string) $offset); $blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(self::TAG_PALETTE_BLOCK_ENTITY_DATA); } } @@ -225,15 +212,15 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block /** * @param int $layer Zero = block layer, One = liquid layer + * * @return Generator * @throws OutOfBoundsException */ - public function blocks(int $layer = 0): Generator - { - if ($layer > count($this->blockLayers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->blockLayers)); - for ($x = 0; $x < $this->size->getX(); $x++) { - for ($y = 0; $y < $this->size->getY(); $y++) { - for ($z = 0; $z < $this->size->getZ(); $z++) { + public function blocks(int $layer = 0) : Generator{ + if($layer > count($this->blockLayers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->blockLayers)); + for($x = 0; $x < $this->size->getX(); $x++){ + for($y = 0; $y < $this->size->getY(); $y++){ + for($z = 0; $z < $this->size->getZ(); $z++){ $fullState = $this->blockLayers[$layer]->get($x, $y, $z); $block = BlockFactory::getInstance()->fromFullBlock($fullState); [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; @@ -243,26 +230,26 @@ public function blocks(int $layer = 0): Generator } } - public function translateBlockEntity(Position $position, Vector3 $origin): ?Tile - { + /** + * @throws UnexpectedTagTypeException|InvalidArgumentException|AssumptionFailedError|SavedDataLoadingException + */ + public function translateBlockEntity(Position $position, Vector3 $origin) : ?Tile{ $hash = World::blockHash($position->getFloorX(), $position->getFloorY(), $position->getFloorZ()); $data = $this->blockEntities[$hash] ?? null; - if ($data === null) return null; + if($data === null) return null; $instance = TileFactory::getInstance(); $data->setInt(Tile::TAG_X, $origin->getFloorX());//why do i have to manually change that before creation.. it won't work after creation $data->setInt(Tile::TAG_Y, $origin->getFloorY()); $data->setInt(Tile::TAG_Z, $origin->getFloorZ()); //hack to fix container items loading - if (($inventoryTag = $data->getTag(Container::TAG_ITEMS)) instanceof ListTag) { + if(($inventoryTag = $data->getTag(Container::TAG_ITEMS)) instanceof ListTag){ /** @var CompoundTag $itemNBT */ - foreach ($inventoryTag as $itemNBT) { + foreach($inventoryTag as $itemNBT){ $itemNBT->setString("id", $itemNBT->getString("Name", "minecraft:air")); $itemNBT->removeTag("Name"); - if ($itemNBT->getCompoundTag("tag") !== null) { - /** @var CompoundTag $tag */ - $tag = $itemNBT->getCompoundTag("tag"); - if ($tag->getTag("Damage") !== null) $tag->removeTag("Damage"); + if(($tag = $itemNBT->getCompoundTag("tag")) !== null){ + if($tag->getTag("Damage") !== null) $tag->removeTag("Damage"); } } } @@ -285,19 +272,20 @@ public function translateBlockEntity(Position $position, Vector3 $origin): ?Tile /** @noinspection PhpInternalEntityUsedInspection */ $tile = $instance->createFromData($position->getWorld(), $data); - if ($tile === null) return null; + if($tile === null) return null;//Might return null if the tile is not registered return $tile; } /** * Reads a value of an object, regardless of access modifiers + * * @param object $object * @param string $property + * * @return mixed */ - public static function &readAnyValue(object $object, string $property): mixed - { - $invoke = Closure::bind(function & () use ($property) { + public static function &readAnyValue(object $object, string $property) : mixed{ + $invoke = Closure::bind(function & () use ($property){ return $this->$property; }, $object, $object)->__invoke(); /** @noinspection PhpUnnecessaryLocalVariableInspection */ @@ -306,18 +294,33 @@ public static function &readAnyValue(object $object, string $property): mixed return $value; } - public function getSize(): Vector3 - { + public function getSize() : Vector3{ return $this->size; } - public function getStructureWorldOrigin(): Vector3 - { + public function getStructureWorldOrigin() : Vector3{ return $this->structure_world_origin; } - public function getFormatVersion(): int - { + /** + * @return CompoundTag[] + */ + public function getBlockEntitiesRaw() : array{ + return $this->blockEntities; + } + + /** + * @return CompoundTag[] + */ + public function getEntitiesRaw() : array{ + return $this->entities; + } + + public function getBlockLayersCount() : int{ + return count($this->blockLayers); + } + + public function getFormatVersion() : int{ return $this->format_version; } diff --git a/src/xenialdan/libstructure/format/NBTStructure.php b/src/xenialdan/libstructure/format/NBTStructure.php index a419ca2..c3de78a 100644 --- a/src/xenialdan/libstructure/format/NBTStructure.php +++ b/src/xenialdan/libstructure/format/NBTStructure.php @@ -28,8 +28,7 @@ use function file_get_contents; use function zlib_decode; -class NBTStructure -{ +class NBTStructure{ private int $version; private string $author; private Vector3 $size; @@ -45,7 +44,7 @@ class NBTStructure * * @param string $file the Schematic output file name */ - public function save(string $file): void//TODO + public function save(string $file) : void//TODO { // $nbt = new TreeRoot( // CompoundTag::create() @@ -64,13 +63,13 @@ public function save(string $file): void//TODO * parse parses a schematic from the file passed. * * @param string $file + * * @throws OutOfRangeException * @throws StructureFileException * @throws NbtDataException * @throws UnexpectedTagTypeException */ - public function parse(string $file): void - { + public function parse(string $file) : void{ $nbt = (new BigEndianNbtSerializer())->read(zlib_decode(file_get_contents($file))); $nbt = $nbt->getTag(); /** @var CompoundTag $nbt */ @@ -91,25 +90,25 @@ public function parse(string $file): void /** * @param ListTag $paletteList + * * @return Block[] * @throws RuntimeException * @throws UnexpectedTagTypeException * @throws BlockQueryParsingFailedException * @throws BlockStateNotFoundException */ - private function paletteToBlocks(ListTag $paletteList): array - { + private function paletteToBlocks(ListTag $paletteList) : array{ /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); /** @var Block[] $blocks */ $blocks = []; /** @var CompoundTag $blockCompound */ - foreach ($paletteList/*->getValue()*/ as $blockCompound) { + foreach($paletteList/*->getValue()*/ as $blockCompound){ $id = $blockCompound->getString('Name'); $states = []; /** @var CompoundTag $properties */ $properties = $blockCompound->getCompoundTag('Properties'); - if ($properties instanceof CompoundTag) + if($properties instanceof CompoundTag) //Java/legacy hack /*if($properties->getTag('dataID') !== null){ $legacyDataId = $properties->getInt('dataID'); @@ -127,16 +126,16 @@ private function paletteToBlocks(ListTag $paletteList): array }*///TODO java fixes /** - * @var string $name + * @var string $name * @var StringTag $value */ - foreach ($properties->getValue() as $name => $value) { - $valueString = (string)$value->getValue(); + foreach($properties->getValue() as $name => $value){ + $valueString = (string) $value->getValue(); $states[] = $name . '=' . $valueString; } - try { + try{ $blocks[] = $blockStatesParser->parseQuery(BlockQuery::fromString($id . '[' . implode(',', $states) . ']'))->getBlock(); - } catch (InvalidBlockStateException $e) { + }catch(InvalidBlockStateException $e){ Server::getInstance()->getLogger()->logException($e); } } @@ -145,7 +144,9 @@ private function paletteToBlocks(ListTag $paletteList): array /** * returns a generator of blocks found in the schematic opened. + * * @param int $layer + * * @return Generator * @throws OutOfRangeException * @throws InvalidArgumentException @@ -153,13 +154,12 @@ private function paletteToBlocks(ListTag $paletteList): array * @throws UnexpectedTagTypeException * @throws RuntimeException */ - public function blocks(int $layer = 0): Generator - { + public function blocks(int $layer = 0) : Generator{ /** @var ListTag $paletteList */ $paletteList = $this->palettes->get($layer); $blockPalette = $this->paletteToBlocks($paletteList); /** @var CompoundTag $blockTag */ - foreach ($this->blocks as $blockTag) { + foreach($this->blocks as $blockTag){ /** @var ListTag $pos */ $pos = $blockTag->getListTag("pos"); $block = $blockPalette[$blockTag->getInt('state')]; @@ -236,23 +236,19 @@ public function blocks(int $layer = 0): Generator // } // } - protected function blockIndex(int $x, int $y, int $z): int - { + protected function blockIndex(int $x, int $y, int $z) : int{ return ($y * $this->size->getZ() + $z) * $this->size->getX() + $x; } - public function getVersion(): int - { + public function getVersion() : int{ return $this->version; } - public function getAuthor(): string - { + public function getAuthor() : string{ return $this->author; } - public function getSize(): Vector3 - { + public function getSize() : Vector3{ return $this->size; } } diff --git a/src/xenialdan/libstructure/tile/StructureBlockTags.php b/src/xenialdan/libstructure/tile/StructureBlockTags.php index ea4b8c3..a1fac98 100644 --- a/src/xenialdan/libstructure/tile/StructureBlockTags.php +++ b/src/xenialdan/libstructure/tile/StructureBlockTags.php @@ -4,15 +4,14 @@ namespace xenialdan\libstructure\tile; -interface StructureBlockTags -{ - const TAG_ID = "StructureBlock"; - const TAG_DATA = "data"; - const TAG_DATA_INVENTORY_MODEL = 0; - const TAG_DATA_DATA = 1; - const TAG_DATA_SAVE = 2; - const TAG_DATA_LOAD = 3; - const TAG_DATA_CORNER = 4; - const TAG_DATA_EXPORT = 5; +interface StructureBlockTags{ + const TAG_ID = "StructureBlock"; + const TAG_DATA = "data"; + const TAG_DATA_INVENTORY_MODEL = 0; + const TAG_DATA_DATA = 1; + const TAG_DATA_SAVE = 2; + const TAG_DATA_LOAD = 3; + const TAG_DATA_CORNER = 4; + const TAG_DATA_EXPORT = 5; } \ No newline at end of file diff --git a/src/xenialdan/libstructure/tile/StructureBlockTile.php b/src/xenialdan/libstructure/tile/StructureBlockTile.php index a84bf60..cec2568 100644 --- a/src/xenialdan/libstructure/tile/StructureBlockTile.php +++ b/src/xenialdan/libstructure/tile/StructureBlockTile.php @@ -16,8 +16,7 @@ use pocketmine\world\World; use xenialdan\libstructure\window\StructureBlockInventory; -class StructureBlockTile extends Spawnable implements Nameable, InventoryHolder -{ +class StructureBlockTile extends Spawnable implements Nameable, InventoryHolder{ use NameableTrait { addAdditionalSpawnData as addNameSpawnData; } @@ -34,29 +33,25 @@ class StructureBlockTile extends Spawnable implements Nameable, InventoryHolder private Vector3 $toV3; private ?string $title = null; - public function __construct(World $world, Vector3 $pos) - { + public function __construct(World $world, Vector3 $pos){ parent::__construct($world, $pos); $this->fromV3 = $this->toV3 = $this->position->asVector3(); $this->inventory = new StructureBlockInventory($this->position); } - public function readSaveData(CompoundTag $nbt): void - { + public function readSaveData(CompoundTag $nbt) : void{ //todo read structure block data $this->loadName($nbt); } - protected function writeSaveData(CompoundTag $nbt): void - { + protected function writeSaveData(CompoundTag $nbt) : void{ //~todo~ write structure block data $this->addStructureBlockData($nbt); $nbt->setInt(StructureBlockTags::TAG_DATA, $this->mode); $this->saveName($nbt); } - protected function addAdditionalSpawnData(CompoundTag $nbt): void - { + protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ $this->addStructureBlockData($nbt); $this->addNameSpawnData($nbt); } @@ -64,30 +59,27 @@ protected function addAdditionalSpawnData(CompoundTag $nbt): void /** * @return StructureBlockInventory */ - public function getInventory(): StructureBlockInventory - { + public function getInventory() : StructureBlockInventory{ return $this->inventory; } - public function getDefaultName(): string - { + public function getDefaultName() : string{ return "Structure Block"; } /** * @return Vector3 */ - public function getFromV3(): Vector3 - { + public function getFromV3() : Vector3{ return $this->fromV3; } /** * @param Vector3 $fromV3 + * * @return StructureBlockTile */ - public function setFromV3(Vector3 $fromV3): self - { + public function setFromV3(Vector3 $fromV3) : self{ $this->fromV3 = $fromV3; return $this; } @@ -95,17 +87,16 @@ public function setFromV3(Vector3 $fromV3): self /** * @return Vector3 */ - public function getToV3(): Vector3 - { + public function getToV3() : Vector3{ return $this->toV3; } /** * @param Vector3 $toV3 + * * @return StructureBlockTile */ - public function setToV3(Vector3 $toV3): self - { + public function setToV3(Vector3 $toV3) : self{ $this->toV3 = $toV3; return $this; } @@ -113,83 +104,79 @@ public function setToV3(Vector3 $toV3): self /** * @return string */ - public function getTitle(): string - { + public function getTitle() : string{ return $this->title ?? $this->getName(); } /** * @param string $title + * * @return StructureBlockTile */ - public function setTitle(string $title): self - { + public function setTitle(string $title) : self{ $this->title = $title; return $this; } /** * @param bool $hideStructureBlock + * * @return StructureBlockTile */ - public function setHideStructureBlock(bool $hideStructureBlock): self - { + public function setHideStructureBlock(bool $hideStructureBlock) : self{ $this->hideStructureBlock = $hideStructureBlock; return $this; } /** * @param bool $showPlayers + * * @return StructureBlockTile */ - public function setShowPlayers(bool $showPlayers): self - { + public function setShowPlayers(bool $showPlayers) : self{ $this->showPlayers = $showPlayers; return $this; } /** * @param bool $showEntities + * * @return StructureBlockTile */ - public function setShowEntities(bool $showEntities): self - { + public function setShowEntities(bool $showEntities) : self{ $this->showEntities = $showEntities; return $this; } /** * @param bool $showBlocks + * * @return StructureBlockTile */ - public function setShowBlocks(bool $showBlocks): self - { + public function setShowBlocks(bool $showBlocks) : self{ $this->showBlocks = $showBlocks; return $this; } /** * @param bool $showBoundingBox + * * @return StructureBlockTile */ - public function setShowBoundingBox(bool $showBoundingBox): self - { + public function setShowBoundingBox(bool $showBoundingBox) : self{ $this->showBoundingBox = $showBoundingBox; return $this; } - public function calculateOffset(Vector3 $holderV3): Vector3 - { + public function calculateOffset(Vector3 $holderV3) : Vector3{ return $holderV3->subtractVector(Vector3::minComponents($this->fromV3, $this->toV3))->multiply(-1)->floor(); } - public function calculateSize(): Vector3 - { + public function calculateSize() : Vector3{ return $this->fromV3->subtractVector($this->toV3)->abs()->add(1, 1, 1); } - protected function addStructureBlockData(CompoundTag $nbt): void - { + protected function addStructureBlockData(CompoundTag $nbt) : void{ $pos = $this->getPosition(); $offset = $this->calculateOffset($pos->asVector3()); $size = $this->calculateSize(); @@ -207,78 +194,71 @@ protected function addStructureBlockData(CompoundTag $nbt): void $nbt->setLong("seed", 0); $nbt->setByte("showBoundingBox", $this->showBoundingBox ? 1 : 0); $nbt->setString("structureName", $this->getTitle()); - $nbt->setInt("x", (int)$pos->x); - $nbt->setInt("xStructureOffset", (int)$offset->x); - $nbt->setInt("xStructureSize", (int)$size->x); - $nbt->setInt("y", (int)$pos->y); - $nbt->setInt("yStructureOffset", (int)$offset->y/*+1*/);//TODO remove +1 hack - $nbt->setInt("yStructureSize", (int)$size->y); - $nbt->setInt("z", (int)$pos->z); - $nbt->setInt("zStructureOffset", (int)$offset->z); - $nbt->setInt("zStructureSize", (int)$size->z); + $nbt->setInt("x", (int) $pos->x); + $nbt->setInt("xStructureOffset", (int) $offset->x); + $nbt->setInt("xStructureSize", (int) $size->x); + $nbt->setInt("y", (int) $pos->y); + $nbt->setInt("yStructureOffset", (int) $offset->y/*+1*/);//TODO remove +1 hack + $nbt->setInt("yStructureSize", (int) $size->y); + $nbt->setInt("z", (int) $pos->z); + $nbt->setInt("zStructureOffset", (int) $offset->z); + $nbt->setInt("zStructureSize", (int) $size->z); } /** * @return bool */ - public function isShowPlayers(): bool - { + public function isShowPlayers() : bool{ return $this->showPlayers; } /** * @return bool */ - public function isShowEntities(): bool - { + public function isShowEntities() : bool{ return $this->showEntities; } /** * @return bool */ - public function isShowBlocks(): bool - { + public function isShowBlocks() : bool{ return $this->showBlocks; } /** * @return bool */ - public function isShowBoundingBox(): bool - { + public function isShowBoundingBox() : bool{ return $this->showBoundingBox; } /** * @return int */ - public function getMode(): int - { + public function getMode() : int{ return $this->mode; } - public function getStructureEditorData(string $structureName,Vector3 $size, Vector3 $origin): StructureEditorData - { + public function getStructureEditorData(string $structureName, Vector3 $size, Vector3 $origin) : StructureEditorData{ $data = new StructureEditorData(); $data->structureName = $structureName; $data->structureDataField = ""; $data->includePlayers = $this->isShowPlayers(); $data->showBoundingBox = $this->isShowBoundingBox(); $data->structureBlockType = $this->getMode(); - $data->structureSettings = $this->getStructureSettings($size,$origin); + $data->structureSettings = $this->getStructureSettings($size, $origin); $data->structureRedstoneSaveMove = 0; return $data; } - private function getStructureSettings(Vector3 $size, Vector3 $origin): StructureSettings - { + private function getStructureSettings(Vector3 $size, Vector3 $origin) : StructureSettings{ $settings = new StructureSettings(); $settings->paletteName = "default"; $settings->ignoreEntities = !$this->isShowEntities(); $settings->ignoreBlocks = !$this->isShowBlocks(); $settings->dimensions = BlockPosition::fromVector3($size); - $settings->offset = new BlockPosition(0,0,0);//TODO position + $settings->offset = new BlockPosition(0, 0, 0);//TODO position $settings->lastTouchedByPlayerID = -1; $settings->rotation = 0; $settings->mirror = 0; diff --git a/src/xenialdan/libstructure/window/StructureBlockInventory.php b/src/xenialdan/libstructure/window/StructureBlockInventory.php index 5a4ea11..e0e3d00 100644 --- a/src/xenialdan/libstructure/window/StructureBlockInventory.php +++ b/src/xenialdan/libstructure/window/StructureBlockInventory.php @@ -9,11 +9,10 @@ use pocketmine\inventory\SimpleInventory; use pocketmine\world\Position; -class StructureBlockInventory extends SimpleInventory implements BlockInventory -{ +class StructureBlockInventory extends SimpleInventory implements BlockInventory{ use BlockInventoryTrait; - public function __construct(Position $holder) - { + + public function __construct(Position $holder){ $this->holder = $holder; parent::__construct(0); } diff --git a/virion.yml b/virion.yml index 65b5e4f..80af43e 100644 --- a/virion.yml +++ b/virion.yml @@ -1,6 +1,6 @@ name: libstructure -version: 0.1.6 +version: 0.1.7 antigen: xenialdan\libstructure -api: [4.0.0] +api: [ 4.0.0 ] php: [ 8.0 ] author: XenialDan From c0fe3302af381c15d7598d46afe09c52e30852bf Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 14 Aug 2022 20:15:34 +0200 Subject: [PATCH 04/16] Cleaner&faster parsing,improved errors,inf layers - palette switch now possible - open up ways to write structure files - extract MCStructureData for raw file data parsing, i.e. palettes, nbt, blockIndices.. - added file validity checks - split parse into read() (raw file loading) and parse() (data converting) methods to allow lazy loading - Vector3s are BlockPosition instead now TODO remove blockEntity hack --- .../libstructure/format/MCStructure.php | 163 +++++++++++++----- .../libstructure/format/MCStructureData.php | 119 +++++++++++++ virion.yml | 2 +- 3 files changed, 239 insertions(+), 45 deletions(-) create mode 100644 src/xenialdan/libstructure/format/MCStructureData.php diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index 10e54b4..07a657e 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -23,6 +23,7 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\UnexpectedTagTypeException; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; use pocketmine\utils\TextFormat; @@ -34,9 +35,11 @@ use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; +use function count; class MCStructure{ //https://github.com/df-mc/structure/blob/651c5d323dbfb24991dafdb72129e2a8a478a81b/structure.go#L66-L91 + private const VERSION = 1; public const TAG_STRUCTURE_WORLD_ORIGIN = 'structure_world_origin'; public const TAG_FORMAT_VERSION = 'format_version'; public const TAG_SIZE = 'size'; @@ -49,17 +52,75 @@ class MCStructure{ public const TAG_PALETTE_BLOCK_POSITION_DATA = 'block_position_data'; public const TAG_PALETTE_BLOCK_ENTITY_DATA = 'block_entity_data'; public const EXTENSION_MCSTRUCTURE = '.mcstructure'; - public const LAYER_BLOCKS = 0; - public const LAYER_LIQUIDS = 1; - private Vector3 $structure_world_origin; - private int $format_version; - private Vector3 $size; - /** @var PalettedBlockArray[] */ - private array $blockLayers = []; - /** @var CompoundTag[] */ - private array $entities = []; - /** @var CompoundTag[] */ - private array $blockEntities = []; + + public int $formatVersion; + public BlockPosition $size; + public BlockPosition $origin; + public MCStructureData $structure; + + private string $paletteName; + /** @phpstan-var array> */ + private array $palette;//pointer + + /** + * @var PalettedBlockArray[] + */ + private array $layers; + public array $blockEntities; + + public function check() : bool{ + if($this->formatVersion !== self::VERSION) throw new StructureFileException("Unsupported format version: " . $this->formatVersion); + if(count($this->structure->blockIndices) === 0) throw new StructureFileException("Structure has no blocks in it"); + if(count($this->structure->palettes) === 0) throw new StructureFileException("Structure has no palettes in it"); + $size = $this->size->getX() * $this->size->getY() * $this->size->getZ(); + foreach($this->structure->blockIndices as $layer => $indices){ + if(count($indices) !== $size) throw new StructureFileException("Structure is " . $this->size->getX() . "x" . $this->size->getY() . "x" . $this->size->getZ() . " but has " . count($indices) . " blocks in layer " . $layer); + } + $paletteLen = -1; + foreach($this->structure->palettes as $name => $palette){ + if($paletteLen === -1){ + $paletteLen = count($palette); + continue; + } + if(count($palette) !== $paletteLen) throw new StructureFileException("Structure palette " . $name . " has " . count($palette) . " entries but previous palettes have " . $paletteLen); + } + return true; + } + + public function set(int $x, int $y, int $z, BlockState $blockState, ?CompoundTag $nbt = null){ + $ptr = $this->lookup($blockState); + if($ptr === -1){ + $ptr = count($this->palette[self::TAG_PALETTE_BLOCK_PALETTE]); + $this->palette[$ptr] = [ + self::TAG_PALETTE_BLOCK_PALETTE => $blockState, + self::TAG_PALETTE_BLOCK_POSITION_DATA => $nbt + ]; + } + $l = $this->size->getZ(); + $h = $this->size->getY(); + $offset = ($x * $l * $h) + ($y * $l) + $z; + $this->structure->blockIndices[0][$offset] = $ptr; + } + + //usePalette function + public function usePalette(string $name) : void{ + //FIXME add write mode + if(isset($this->structure->palettes[$name])){ + $this->paletteName = $name; + $this->palette = &$this->structure->palettes[$name]; + } + } + + public function lookup(BlockState $properties) : int{ + foreach($this->palette as $index => $entry){ + $blockState = $entry[self::TAG_PALETTE_BLOCK_PALETTE]; + if($blockState instanceof BlockState && $blockState->equals($properties)){ + return $index; + } + } + return -1; + } + /** * Parses a *.mcstructure file @@ -69,25 +130,32 @@ class MCStructure{ * @throws InvalidArgumentException|StructureFileException|StructureFormatException|UnexpectedTagTypeException|UnexpectedValueException|NbtDataException|OutOfRangeException * @see MCStructure */ - public function parse(string $path) : void{ + public static function read(string $path) : self{ $pathext = pathinfo($path, PATHINFO_EXTENSION); if('.' . strtolower($pathext) !== self::EXTENSION_MCSTRUCTURE) throw new InvalidArgumentException("File extension $pathext for file $path is not " . self::EXTENSION_MCSTRUCTURE); $path = Filesystem::cleanPath(realpath($path)); $fread = file_get_contents($path); if($fread === false) throw new StructureFileException("Could not read file $path"); $namedTag = (new LittleEndianNBTSerializer())->read($fread)->mustGetCompoundTag(); - #Server::getInstance()->getLogger()->debug($namedTag->toString(2)); - //version - $version = $namedTag->getInt(self::TAG_FORMAT_VERSION); - if($version === null) throw new StructureFormatException(self::TAG_FORMAT_VERSION . " must be present and valid integer"); - $this->format_version = $version; - //structure origin - $structureWorldOrigin = self::parseVec3($namedTag, self::TAG_STRUCTURE_WORLD_ORIGIN, true);//TODO check if optional (makes it V3{0,0,0}) - $this->structure_world_origin = $structureWorldOrigin; - //size - $size = self::parseVec3($namedTag, self::TAG_SIZE, false); - $this->size = $size; - $this->parseStructure($namedTag->getCompoundTag(self::TAG_STRUCTURE)); + + $structure = new self(); + + $structure->formatVersion = $namedTag->getInt(self::TAG_FORMAT_VERSION); + $structure->origin = self::parseBlockPosition($namedTag, self::TAG_STRUCTURE_WORLD_ORIGIN, true); + $structure->size = self::parseBlockPosition($namedTag, self::TAG_SIZE, false); + $structure->structure = MCStructureData::fromNBT($namedTag->getCompoundTag(self::TAG_STRUCTURE)); + + $structure->check(); + + return $structure; + + #$this->parseStructure($namedTag->getCompoundTag(self::TAG_STRUCTURE)); + } + + //parse method + public function parse() : self{ + $this->structure->parse($this); + return $this; } /** @@ -95,13 +163,14 @@ public function parse(string $path) : void{ * @param string $tagName * @param bool $optional * - * @return Vector3 - * @throws UnexpectedValueException|UnexpectedTagTypeException + * @return BlockPosition + * @throws UnexpectedTagTypeException + * @throws UnexpectedValueException */ - private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{ + private static function parseBlockPosition(CompoundTag $nbt, string $tagName, bool $optional) : BlockPosition{ $pos = $nbt->getListTag($tagName); if($pos === null and $optional){ - return new Vector3(0, 0, 0); + return new BlockPosition(0, 0, 0); } if(!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Int){ throw new UnexpectedValueException("'$tagName' should be a List"); @@ -111,19 +180,25 @@ private static function parseVec3(CompoundTag $nbt, string $tagName, bool $optio if(count($values) !== 3){ throw new UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag"); } - return new Vector3($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue()); + return new BlockPosition($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue()); + } + + public function getPaletteName() : string{ + return $this->paletteName; + } + + /** + * @param PalettedBlockArray[] $layers + */ + public function setLayers(array $layers) : void{ + $this->layers = $layers; } /** - * @throws OutOfRangeException|UnexpectedTagTypeException|InvalidArgumentException + * @return PalettedBlockArray[] */ - private function parseStructure(CompoundTag $structure) : void{ - $blockIndicesList = $structure->getListTag('block_indices');//list> - #$entitiesList = $structure->getListTag('entities'); - #var_dump($entitiesList->toString(2)); - $paletteCompound = $structure->getCompoundTag('palette'); - #$this->parseEntities($entitiesList);//TODO - $this->parseBlockLayers($paletteCompound, $blockIndicesList); + public function getLayers() : array{ + return $this->layers; } /** @@ -217,11 +292,11 @@ private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $block * @throws OutOfBoundsException */ public function blocks(int $layer = 0) : Generator{ - if($layer > count($this->blockLayers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->blockLayers)); + if($layer > count($this->layers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->layers)); for($x = 0; $x < $this->size->getX(); $x++){ for($y = 0; $y < $this->size->getY(); $y++){ for($z = 0; $z < $this->size->getZ(); $z++){ - $fullState = $this->blockLayers[$layer]->get($x, $y, $z); + $fullState = $this->layers[$layer]->get($x, $y, $z); $block = BlockFactory::getInstance()->fromFullBlock($fullState); [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; yield $block; @@ -294,12 +369,12 @@ public static function &readAnyValue(object $object, string $property) : mixed{ return $value; } - public function getSize() : Vector3{ + public function getSize() : BlockPosition{ return $this->size; } - public function getStructureWorldOrigin() : Vector3{ - return $this->structure_world_origin; + public function getStructureWorldOrigin() : BlockPosition{ + return $this->origin; } /** @@ -317,11 +392,11 @@ public function getEntitiesRaw() : array{ } public function getBlockLayersCount() : int{ - return count($this->blockLayers); + return count($this->layers); } public function getFormatVersion() : int{ - return $this->format_version; + return $this->formatVersion; } } \ No newline at end of file diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php new file mode 100644 index 0000000..4566795 --- /dev/null +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -0,0 +1,119 @@ +> + * layer => index + */ + public array $blockIndices = []; + public array $entities = []; + /** + * @phpstan-var array> + */ + public array $palettes = []; + public array $blockEntity = []; + + private array $layers = []; + private $blockPositionData; + + public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ + $data = new MCStructureData(); + $blockIndices = $compoundTag->getListTag(MCStructure::TAG_BLOCK_INDICES); + /** + * @var int $layer + * @var ListTag $list + */ + foreach($blockIndices as $layer => $list){ + $data->blockIndices[$layer] = $list->getAllValues(); + } + $palettes = $compoundTag->getCompoundTag(MCStructure::TAG_PALETTE); + foreach($palettes as $paletteName => $paletteData){ + $data->palettes[$paletteName] = $paletteData->getListTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE)?->getValue(); + /** @var CompoundTag $blockPositionData */ + $data->blockPositionData = $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA); + } + return $data; + } + + //toNBT + + public function parse(MCStructure $structure) : MCStructure{//TODO layer or palette parameter? + $structure->usePalette(MCStructure::TAG_PALETTE_DEFAULT);//TODO + $paletteName = $structure->getPaletteName();//TODO check if empty/not set + //TODO check if palette was already parsed + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + /** @var PalettedBlockArray[] $layers */ + $layers = []; + + $palette = $this->parsePalette($paletteName); + + foreach($this->blockIndices as $layer => $indices){ + $layers[$layer] = new PalettedBlockArray(BlockLegacyIds::AIR << 4);//TODO structure void block id? + + //positions + $l = $structure->size->getZ(); + $h = $structure->size->getY(); + foreach(range(0, $structure->size->getZ() - 1) as $z){ + foreach(range(0, $structure->size->getY() - 1) as $y){ + foreach(range(0, $structure->size->getX() - 1) as $x){ + $offset = (int) (($x * $l * $h) + ($y * $l) + $z); + + if(($i = $this->blockIndices[$layer][$offset] ?? -1) !== -1){ + if(($statesEntry = $palette[$i] ?? null) !== null){ + try{ + $layers[$layer]->set($x, $y, $z, $statesEntry->getFullId()); + }catch(Exception $e){ + GlobalLogger::get()->logException($e); + } + } + } + //nbt + if($this->blockPositionData->getTag((string) $offset) !== null){ + /** @var CompoundTag $tag1 */ + $tag1 = $this->blockPositionData->getCompoundTag((string) $offset); + $structure->blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_ENTITY_DATA); + } + } + } + } + } + + $structure->setLayers($layers); + + return $structure; + } + + /** @phpstan-return array */ + private function parsePalette(string $paletteName) : array{ + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + $palette = []; + foreach($this->palettes[$paletteName] as $index => $blockStateTag){ + $blockState = $blockStatesParser->getFromCompound($blockStateTag); + $palette[$index] = $blockState; + } + return $palette; + } + + //writePalette + //writeNBT + + +} \ No newline at end of file diff --git a/virion.yml b/virion.yml index 80af43e..318e297 100644 --- a/virion.yml +++ b/virion.yml @@ -1,5 +1,5 @@ name: libstructure -version: 0.1.7 +version: 0.2.0 antigen: xenialdan\libstructure api: [ 4.0.0 ] php: [ 8.0 ] From b52721f97f33dd27cd886a11c0a4bba672d9de76 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Tue, 30 Aug 2022 14:38:48 +0200 Subject: [PATCH 05/16] Return fullId instead of BlockStates in MCStructureData::parsePalette() --- src/xenialdan/libstructure/format/MCStructureData.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index 4566795..cdae804 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -11,7 +11,6 @@ use pocketmine\nbt\tag\ListTag; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\World; -use xenialdan\libblockstate\BlockState; use xenialdan\libblockstate\BlockStatesParser; use function range; @@ -57,8 +56,6 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale $structure->usePalette(MCStructure::TAG_PALETTE_DEFAULT);//TODO $paletteName = $structure->getPaletteName();//TODO check if empty/not set //TODO check if palette was already parsed - /** @var BlockStatesParser $blockStatesParser */ - $blockStatesParser = BlockStatesParser::getInstance(); /** @var PalettedBlockArray[] $layers */ $layers = []; @@ -76,9 +73,9 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale $offset = (int) (($x * $l * $h) + ($y * $l) + $z); if(($i = $this->blockIndices[$layer][$offset] ?? -1) !== -1){ - if(($statesEntry = $palette[$i] ?? null) !== null){ + if(($fullId = $palette[$i] ?? null) !== null){ try{ - $layers[$layer]->set($x, $y, $z, $statesEntry->getFullId()); + $layers[$layer]->set($x, $y, $z, $fullId); }catch(Exception $e){ GlobalLogger::get()->logException($e); } @@ -100,14 +97,14 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale return $structure; } - /** @phpstan-return array */ + /** @phpstan-return array */ private function parsePalette(string $paletteName) : array{ /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); $palette = []; foreach($this->palettes[$paletteName] as $index => $blockStateTag){ $blockState = $blockStatesParser->getFromCompound($blockStateTag); - $palette[$index] = $blockState; + $palette[$index] = $blockState->getFullId(); } return $palette; } From 1aeb6fe294cff13c3d7d74f9c7fb1777896ef3f5 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 31 Aug 2022 03:38:30 +0200 Subject: [PATCH 06/16] Implement palette filters, closes #4 --- .../libstructure/format/MCStructure.php | 190 +++++++++-------- .../format/filter/MCStructureFilter.php | 198 ++++++++++++++++++ 2 files changed, 297 insertions(+), 91 deletions(-) create mode 100644 src/xenialdan/libstructure/format/filter/MCStructureFilter.php diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index 07a657e..6c11a09 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -3,14 +3,11 @@ namespace xenialdan\libstructure\format; use Closure; -use Exception; use Generator; -use GlobalLogger; use InvalidArgumentException; use OutOfBoundsException; use OutOfRangeException; use pocketmine\block\BlockFactory; -use pocketmine\block\BlockLegacyIds; use pocketmine\block\tile\Container; use pocketmine\block\tile\Tile; use pocketmine\block\tile\TileFactory; @@ -26,15 +23,14 @@ use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; -use pocketmine\utils\TextFormat; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\Position; use pocketmine\world\World; use UnexpectedValueException; use xenialdan\libblockstate\BlockState; -use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; +use xenialdan\libstructure\format\filter\MCStructureFilter; use function count; class MCStructure{ @@ -61,11 +57,10 @@ class MCStructure{ private string $paletteName; /** @phpstan-var array> */ private array $palette;//pointer - - /** - * @var PalettedBlockArray[] - */ + /** @var PalettedBlockArray[] */ private array $layers; + private int $activeLayer = 0; + public array $blockEntities; public function check() : bool{ @@ -202,102 +197,115 @@ public function getLayers() : array{ } /** - * @param CompoundTag|null $paletteCompound - * @param ListTag>|null $blockIndicesList - * - * @throws InvalidArgumentException|OutOfRangeException|UnexpectedTagTypeException + * @throws OutOfBoundsException */ - private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList) : void{ - /*if($paletteCompound->count() > 1){ - - }*/ - $paletteDefaultTag = $paletteCompound->getCompoundTag(self::TAG_PALETTE_DEFAULT); - $paletteBlocks = new PalettedBlockArray(BlockLegacyIds::AIR << 4); - $paletteLiquids = new PalettedBlockArray(BlockLegacyIds::AIR << 4); - $blockEntities = []; - /** @var BlockState[] $paletteArray */ - $paletteArray = []; - /** @var CompoundTag $blockCompoundTag */ - foreach($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag){ - $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); - if($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; - else print TextFormat::RED . $blockCompoundTag . " is not BlockStatesEntry"; - } - /** @var CompoundTag $blockPositionData */ - $blockPositionData = $paletteDefaultTag->getCompoundTag(self::TAG_PALETTE_BLOCK_POSITION_DATA); - //positions - $l = $this->size->getZ(); - $h = $this->size->getY(); - foreach(range(0, $this->size->getZ() - 1) as $z){ - foreach(range(0, $this->size->getY() - 1) as $y){ - foreach(range(0, $this->size->getX() - 1) as $x){ -// foreach ($blockIndicesList as $layerIndex => $layer) { -// $layer = reset($layer);//only default -// /** @var ListTag $layer */ -// foreach ($layer as $i => $paletteId) { -// /** @var IntTag $paletteId */ + public function setActiveLayer(int $layer) : self{ + if($layer > count($this->layers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->layers)); + $this->activeLayer = $layer; + return $this; + } + +// /** +// * @param CompoundTag|null $paletteCompound +// * @param ListTag>|null $blockIndicesList +// * +// * @throws InvalidArgumentException|OutOfRangeException|UnexpectedTagTypeException +// */ +// private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList) : void{ +// /*if($paletteCompound->count() > 1){ // +// }*/ +// $paletteDefaultTag = $paletteCompound->getCompoundTag(self::TAG_PALETTE_DEFAULT); +// $paletteBlocks = new PalettedBlockArray(BlockLegacyIds::AIR << 4); +// $paletteLiquids = new PalettedBlockArray(BlockLegacyIds::AIR << 4); +// $blockEntities = []; +// /** @var BlockState[] $paletteArray */ +// $paletteArray = []; +// /** @var CompoundTag $blockCompoundTag */ +// foreach($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag){ +// $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); +// if($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; +// else print TextFormat::RED . $blockCompoundTag . " is not BlockStatesEntry"; +// } +// /** @var CompoundTag $blockPositionData */ +// $blockPositionData = $paletteDefaultTag->getCompoundTag(self::TAG_PALETTE_BLOCK_POSITION_DATA); +// //positions +// $l = $this->size->getZ(); +// $h = $this->size->getY(); +// foreach(range(0, $this->size->getZ() - 1) as $z){ +// foreach(range(0, $this->size->getY() - 1) as $y){ +// foreach(range(0, $this->size->getX() - 1) as $x){ +//// foreach ($blockIndicesList as $layerIndex => $layer) { +//// $layer = reset($layer);//only default +//// /** @var ListTag $layer */ +//// foreach ($layer as $i => $paletteId) { +//// /** @var IntTag $paletteId */ +//// +//// } +//// } +// $offset = (int) (($x * $l * $h) + ($y * $l) + $z); +// +// //block layer +// /** @var ListTag $tag */ +// $tag = $blockIndicesList->get(0); +// $blockLayer = $tag->getAllValues(); +// if(($i = $blockLayer[$offset] ?? -1) !== -1){ +// if(($statesEntry = $paletteArray[$i] ?? null) !== null){ +// try{ +// $block = $statesEntry->getBlock(); +// /** @noinspection PhpInternalEntityUsedInspection */ +// $paletteBlocks->set($x, $y, $z, $block->getFullId()); +// }catch(Exception $e){ +// GlobalLogger::get()->logException($e); +// } // } // } - $offset = (int) (($x * $l * $h) + ($y * $l) + $z); - - //block layer - /** @var ListTag $tag */ - $tag = $blockIndicesList->get(0); - $blockLayer = $tag->getAllValues(); - if(($i = $blockLayer[$offset] ?? -1) !== -1){ - if(($statesEntry = $paletteArray[$i] ?? null) !== null){ - try{ - $block = $statesEntry->getBlock(); - /** @noinspection PhpInternalEntityUsedInspection */ - $paletteBlocks->set($x, $y, $z, $block->getFullId()); - }catch(Exception $e){ - GlobalLogger::get()->logException($e); - } - } - } - //liquid layer - /** @var ListTag $tag */ - $tag = $blockIndicesList->get(1); - $liquidLayer = $tag->getAllValues(); - if(($i = $liquidLayer[$offset] ?? -1) !== -1){ - if(($statesEntry = $paletteArray[$i] ?? null) !== null){ - try{ - $block = $statesEntry->getBlock(); - /** @noinspection PhpInternalEntityUsedInspection */ - $paletteLiquids->set($x, $y, $z, $block->getFullId()); - }catch(Exception $e){ - GlobalLogger::get()->logException($e); - } - } - } - //nbt - if($blockPositionData->getTag((string) $offset) !== null){ - /** @var CompoundTag $tag1 */ - $tag1 = $blockPositionData->getCompoundTag((string) $offset); - $blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(self::TAG_PALETTE_BLOCK_ENTITY_DATA); - } - } - } - } +// //liquid layer +// /** @var ListTag $tag */ +// $tag = $blockIndicesList->get(1); +// $liquidLayer = $tag->getAllValues(); +// if(($i = $liquidLayer[$offset] ?? -1) !== -1){ +// if(($statesEntry = $paletteArray[$i] ?? null) !== null){ +// try{ +// $block = $statesEntry->getBlock(); +// /** @noinspection PhpInternalEntityUsedInspection */ +// $paletteLiquids->set($x, $y, $z, $block->getFullId()); +// }catch(Exception $e){ +// GlobalLogger::get()->logException($e); +// } +// } +// } +// //nbt +// if($blockPositionData->getTag((string) $offset) !== null){ +// /** @var CompoundTag $tag1 */ +// $tag1 = $blockPositionData->getCompoundTag((string) $offset); +// $blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(self::TAG_PALETTE_BLOCK_ENTITY_DATA); +// } +// } +// } +// } +// +// $this->blockLayers = [$paletteBlocks, $paletteLiquids]; +// $this->blockEntities = $blockEntities; +// } - $this->blockLayers = [$paletteBlocks, $paletteLiquids]; - $this->blockEntities = $blockEntities; + public function getPalettedBlockArray(?int $layer = null) : PalettedBlockArray{ + $this->activeLayer = $layer ?? $this->activeLayer; + return $this->layers[$this->activeLayer]; } /** - * @param int $layer Zero = block layer, One = liquid layer + * @param PalettedBlockArray|null $palettedBlockArray can be filtered or modified using {@link MCStructureFilter} methods. If null is passed, the current layer will be used. * * @return Generator - * @throws OutOfBoundsException */ - public function blocks(int $layer = 0) : Generator{ - if($layer > count($this->layers) || $layer < 0) throw new OutOfBoundsException('Layers must be in range 0...' . count($this->layers)); + public function blocks(?PalettedBlockArray $palettedBlockArray = null) : Generator{ + $palettedBlockArray ??= $this->getPalettedBlockArray(); for($x = 0; $x < $this->size->getX(); $x++){ for($y = 0; $y < $this->size->getY(); $y++){ for($z = 0; $z < $this->size->getZ(); $z++){ - $fullState = $this->layers[$layer]->get($x, $y, $z); - $block = BlockFactory::getInstance()->fromFullBlock($fullState); + $fullId = $palettedBlockArray->get($x, $y, $z); + $block = BlockFactory::getInstance()->fromFullBlock($fullId); [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; yield $block; } diff --git a/src/xenialdan/libstructure/format/filter/MCStructureFilter.php b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php new file mode 100644 index 0000000..0904582 --- /dev/null +++ b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php @@ -0,0 +1,198 @@ + $fullIds + * + * @return PalettedBlockArray + */ + public static function with(PalettedBlockArray $layer, array $fullIds = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + foreach($palette as $id){ + if(!in_array($id, $fullIds, true)){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + return $layer; + } + + /** + * Returns all blocks except those contained in $fullIds + * + * @param PalettedBlockArray $layer + * @param array $fullIds + * + * @phpstan-param list $fullIds + * + * @return PalettedBlockArray + */ + public static function except(PalettedBlockArray $layer, array $fullIds = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + foreach($palette as $id){ + if(in_array($id, $fullIds, true)){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + return $layer; + } + + /** + * Returns only blocks that have the same string ID as any contained in $blockIds + * + * @param PalettedBlockArray $layer + * @param string[] $blockIds + * + * @phpstan-param list $blockIds + * + * @return PalettedBlockArray + */ + public static function withBlockIds(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + foreach($palette as $id){ + $blockState = $blockStatesParser->getFullId($id); + if(!in_array($blockState->state->getId(), $blockIds, true)){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + return $layer; + } + + /** + * Returns all blocks except those that have the same string ID as any contained in $blockIds + * + * @param PalettedBlockArray $layer + * @param string[] $blockIds + * + * @phpstan-param list $blockIds + * + * @return PalettedBlockArray + */ + public static function exceptBlockIds(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + foreach($palette as $id){ + $blockState = $blockStatesParser->getFullId($id); + if(in_array($blockState->state->getId(), $blockIds, true)){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + return $layer; + } + + /** + * Returns only blocks that have any blockstates contained in $blockStates + * + * @param PalettedBlockArray $layer + * @param string[] $blockStates + * + * @phpstan-param list $blockStates + * + * @return PalettedBlockArray + */ + public static function withBlockStates(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + foreach($palette as $id){ + $blockState = $blockStatesParser->getFullId($id); + $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); + foreach($blockStates as $blockState){ + if($compoundTag->getTag($blockState) === null){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + } + return $layer; + } + + /** + * Returns only blocks that have any blockstates contained in $blockStates and their values match + * + * @param PalettedBlockArray $layer + * @param string[] $blockStates + * + * @phpstan-param array $blockStates + * + * @return PalettedBlockArray + */ + public static function withBlockStatesAndValues(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + foreach($palette as $id){ + $blockState = $blockStatesParser->getFullId($id); + $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); + foreach($blockStates as $stateName => $stateValue){ + if(!(($state = $compoundTag->getTag($stateName)) !== null && $state->getValue() === $stateValue)){ + $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + } + } + } + return $layer; + } + + /** + * Replaces the $data keys with the $blockIds values + * + * @param PalettedBlockArray $layer + * @param array $blockIds full ids + * + * @phpstan-param array $blockIds full ids + * + * @return PalettedBlockArray + */ + public static function replace(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + var_dump($layer->getPalette()); + foreach($blockIds as $from => $to){ + $layer->replaceAll($from, $to); + } + var_dump($layer->getPalette()); + return $layer; + } + + /** + * Replaces all blockstates with new values from $blockStates if the blockstate exits + * + * @param PalettedBlockArray $layer + * @param array[] $blockStates keys are blockstates, values are the new values + * + * @phpstan-param array $blockStates keys are blockstates, values are the new values + * @return PalettedBlockArray + * @throws NoSuchTagException Technically impossible to throw + */ + public static function replaceBlockStates(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $palette = $layer->getPalette(); + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + foreach($palette as $id){ + $blockState = $blockStatesParser->getFullId($id); + try{ + $newBlockState = $blockState->replaceBlockStateValues($blockStates, false);//automatically skips if no changes are made + $layer->replaceAll($blockState->getFullId(), $newBlockState->getFullId()); + }catch(UnexpectedTagTypeException | BlockQueryParsingFailedException){ + } + } + return $layer; + } +} \ No newline at end of file From 2df5a28a2c85091a98f7927df6dc9ebfbae67359 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 31 Aug 2022 04:11:18 +0200 Subject: [PATCH 07/16] Use -1 instead of AIR to init palettes --- .../libstructure/format/MCStructure.php | 4 ++-- .../libstructure/format/MCStructureData.php | 3 +-- .../format/filter/MCStructureFilter.php | 16 ++++++---------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index 6c11a09..138780f 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -216,8 +216,8 @@ public function setActiveLayer(int $layer) : self{ // // }*/ // $paletteDefaultTag = $paletteCompound->getCompoundTag(self::TAG_PALETTE_DEFAULT); -// $paletteBlocks = new PalettedBlockArray(BlockLegacyIds::AIR << 4); -// $paletteLiquids = new PalettedBlockArray(BlockLegacyIds::AIR << 4); +// $paletteBlocks = new PalettedBlockArray(-1); +// $paletteLiquids = new PalettedBlockArray(-1); // $blockEntities = []; // /** @var BlockState[] $paletteArray */ // $paletteArray = []; diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index cdae804..d9e5dee 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -6,7 +6,6 @@ use Exception; use GlobalLogger; -use pocketmine\block\BlockLegacyIds; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; use pocketmine\world\format\PalettedBlockArray; @@ -62,7 +61,7 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale $palette = $this->parsePalette($paletteName); foreach($this->blockIndices as $layer => $indices){ - $layers[$layer] = new PalettedBlockArray(BlockLegacyIds::AIR << 4);//TODO structure void block id? + $layers[$layer] = new PalettedBlockArray(-1); //positions $l = $structure->size->getZ(); diff --git a/src/xenialdan/libstructure/format/filter/MCStructureFilter.php b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php index 0904582..099003d 100644 --- a/src/xenialdan/libstructure/format/filter/MCStructureFilter.php +++ b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php @@ -4,13 +4,11 @@ namespace xenialdan\libstructure\format\filter; -use pocketmine\block\BlockLegacyIds; use pocketmine\nbt\NoSuchTagException; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\world\format\PalettedBlockArray; use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libblockstate\exception\BlockQueryParsingFailedException; -use function var_dump; class MCStructureFilter{ @@ -28,7 +26,7 @@ public static function with(PalettedBlockArray $layer, array $fullIds = []) : Pa $palette = $layer->getPalette(); foreach($palette as $id){ if(!in_array($id, $fullIds, true)){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } return $layer; @@ -48,7 +46,7 @@ public static function except(PalettedBlockArray $layer, array $fullIds = []) : $palette = $layer->getPalette(); foreach($palette as $id){ if(in_array($id, $fullIds, true)){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } return $layer; @@ -71,7 +69,7 @@ public static function withBlockIds(PalettedBlockArray $layer, array $blockIds = foreach($palette as $id){ $blockState = $blockStatesParser->getFullId($id); if(!in_array($blockState->state->getId(), $blockIds, true)){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } return $layer; @@ -94,7 +92,7 @@ public static function exceptBlockIds(PalettedBlockArray $layer, array $blockIds foreach($palette as $id){ $blockState = $blockStatesParser->getFullId($id); if(in_array($blockState->state->getId(), $blockIds, true)){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } return $layer; @@ -119,7 +117,7 @@ public static function withBlockStates(PalettedBlockArray $layer, array $blockSt $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); foreach($blockStates as $blockState){ if($compoundTag->getTag($blockState) === null){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } } @@ -145,7 +143,7 @@ public static function withBlockStatesAndValues(PalettedBlockArray $layer, array $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); foreach($blockStates as $stateName => $stateValue){ if(!(($state = $compoundTag->getTag($stateName)) !== null && $state->getValue() === $stateValue)){ - $layer->replaceAll($id, BlockLegacyIds::AIR << 4);//TODO figure out a way to skip the block instead of replacing it with air + $layer->replaceAll($id, -1); } } } @@ -163,11 +161,9 @@ public static function withBlockStatesAndValues(PalettedBlockArray $layer, array * @return PalettedBlockArray */ public static function replace(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ - var_dump($layer->getPalette()); foreach($blockIds as $from => $to){ $layer->replaceAll($from, $to); } - var_dump($layer->getPalette()); return $layer; } From 45877211707f81dfa796fbb45620bf4dcffe8e18 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Wed, 31 Aug 2022 04:14:44 +0200 Subject: [PATCH 08/16] Update required libblockstate version --- .poggit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.poggit.yml b/.poggit.yml index 7765e24..a7c7c1a 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -6,6 +6,6 @@ projects: type: library libs: - src: thebigsmilexd/libblockstate/libblockstate - version: ^0.0.1 + version: ^0.1.2 branch: master ... From a052ad9da10a31ad86f05df28f57e6ae999ab838 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 01:43:39 +0200 Subject: [PATCH 09/16] Change dump to file with tiles (nbt) --- src/xenialdan/dump.md | 173 ++++++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 74 deletions(-) diff --git a/src/xenialdan/dump.md b/src/xenialdan/dump.md index 2b7664a..8fe6fb8 100644 --- a/src/xenialdan/dump.md +++ b/src/xenialdan/dump.md @@ -1,76 +1,101 @@ -# NBT format output of exported.mcstructure +# NBT format output of room_1.mcstructure ``` -TAG_Compound({ - 'structure_world_origin': TAG_List({ - 1, - 4, - 0, - }), - 'format_version': TAG_Int(1), - 'size': TAG_List({ - 1, - 1, - 14, - }), - 'structure': TAG_Compound({ - 'block_indices': TAG_List>({ - { - 0, - 1, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - }, - { - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - }, - }), - 'entities': TAG_List({ - }), - 'palette': TAG_Compound({ - 'default': TAG_Compound({ - 'block_palette': TAG_List({ - { - 'name': TAG_String(minecraft:air), - 'states': TAG_Compound({ - }), - 'version': TAG_Int(17760256), - }, - { - 'name': TAG_String(minecraft:stained_glass), - 'states': TAG_Compound({ - 'color': TAG_String(white), - }), - 'version': TAG_Int(17760256), - }, - }), - 'block_position_data': TAG_Compound({ - }), - }), - }), - }), -}) -``` +TAG_Compound={ + "format_version" => TAG_Int=1 + "size" => TAG_List={ + TAG_Int=2 + TAG_Int=2 + TAG_Int=2 + } + "structure" => TAG_Compound={ + "block_indices" => TAG_List={ + TAG_List={ + TAG_Int=0 + TAG_Int=0 + TAG_Int=1 + TAG_Int=2 + TAG_Int=2 + TAG_Int=2 + TAG_Int=3 + TAG_Int=4 + } + TAG_List={ + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + TAG_Int=-1 + } + } + "entities" => TAG_List={ + } + "palette" => TAG_Compound={ + "default" => TAG_Compound={ + "block_palette" => TAG_List={ + TAG_Compound={ + "name" => TAG_String="minecraft:planks" + "states" => TAG_Compound={ + "wood_type" => TAG_String="oak" + } + "version" => TAG_Int=17959425 + } + TAG_Compound={ + "name" => TAG_String="minecraft:log" + "states" => TAG_Compound={ + "old_log_type" => TAG_String="oak" + "pillar_axis" => TAG_String="y" + } + "version" => TAG_Int=17959425 + } + TAG_Compound={ + "name" => TAG_String="minecraft:stonebrick" + "states" => TAG_Compound={ + "stone_brick_type" => TAG_String="default" + } + "version" => TAG_Int=17959425 + } + TAG_Compound={ + "name" => TAG_String="minecraft:air" + "states" => TAG_Compound={ + } + "version" => TAG_Int=17959425 + } + TAG_Compound={ + "name" => TAG_String="minecraft:jigsaw" + "states" => TAG_Compound={ + "facing_direction" => TAG_Int=4 + "rotation" => TAG_Int=0 + } + "version" => TAG_Int=17959425 + } + } + "block_position_data" => TAG_Compound={ + "1072" => TAG_Compound={ + "block_entity_data" => TAG_Compound={ + "final_state" => TAG_String="minecraft:air" + "id" => TAG_String="JigsawBlock" + "isMovable" => TAG_Byte=1 + "joint" => TAG_String="aligned" + "name" => TAG_String="test:connector" + "target" => TAG_String="test:connector" + "target_pool" => TAG_String="test:tunnel" + "x" => TAG_Int=-18 + "y" => TAG_Int=4 + "z" => TAG_Int=103 + } + } + } + } + } + } + "structure_world_origin" => TAG_List={ + TAG_Int=-32 + TAG_Int=3 + TAG_Int=96 + } +} +``` \ No newline at end of file From df7ba514e28d5ead33fcaf39a79279c11c369897 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 01:45:38 +0200 Subject: [PATCH 10/16] Use "0xff_ff_ff_ff" as "filler block" for palettes --- src/xenialdan/libstructure/format/MCStructure.php | 4 ++-- src/xenialdan/libstructure/format/MCStructureData.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index 138780f..c53061f 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -216,8 +216,8 @@ public function setActiveLayer(int $layer) : self{ // // }*/ // $paletteDefaultTag = $paletteCompound->getCompoundTag(self::TAG_PALETTE_DEFAULT); -// $paletteBlocks = new PalettedBlockArray(-1); -// $paletteLiquids = new PalettedBlockArray(-1); +// $paletteBlocks = new PalettedBlockArray(0xff_ff_ff_ff); +// $paletteLiquids = new PalettedBlockArray(0xff_ff_ff_ff); // $blockEntities = []; // /** @var BlockState[] $paletteArray */ // $paletteArray = []; diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index d9e5dee..32e3c19 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -61,7 +61,7 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale $palette = $this->parsePalette($paletteName); foreach($this->blockIndices as $layer => $indices){ - $layers[$layer] = new PalettedBlockArray(-1); + $layers[$layer] = new PalettedBlockArray(0xff_ff_ff_ff); //positions $l = $structure->size->getZ(); From 0b60650ef2434c205b756e3f0097db94a049962b Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 01:47:51 +0200 Subject: [PATCH 11/16] Support per-palettename tiles in palettes --- .../libstructure/format/MCStructureData.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index 32e3c19..f891dc0 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -6,12 +6,15 @@ use Exception; use GlobalLogger; +use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\World; use xenialdan\libblockstate\BlockStatesParser; use function range; +use function var_dump; class MCStructureData{ /** @@ -21,14 +24,13 @@ class MCStructureData{ */ public array $blockIndices = []; public array $entities = []; - /** - * @phpstan-var array> - */ + /** @phpstan-var array> */ public array $palettes = []; public array $blockEntity = []; private array $layers = []; - private $blockPositionData; + /** @phpstan-var array */ + private array $blockPositionData = []; public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ $data = new MCStructureData(); @@ -43,8 +45,7 @@ public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ $palettes = $compoundTag->getCompoundTag(MCStructure::TAG_PALETTE); foreach($palettes as $paletteName => $paletteData){ $data->palettes[$paletteName] = $paletteData->getListTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE)?->getValue(); - /** @var CompoundTag $blockPositionData */ - $data->blockPositionData = $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA); + $data->blockPositionData[$paletteName] = $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA); } return $data; } @@ -81,9 +82,9 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale } } //nbt - if($this->blockPositionData->getTag((string) $offset) !== null){ + if($this->blockPositionData[$paletteName]->getTag((string) $offset) !== null){ /** @var CompoundTag $tag1 */ - $tag1 = $this->blockPositionData->getCompoundTag((string) $offset); + $tag1 = $this->blockPositionData[$paletteName]->getCompoundTag((string) $offset); $structure->blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_ENTITY_DATA); } } From a1ae075357cda2474e2aa6bd9002f0583bdbc7d1 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 01:51:17 +0200 Subject: [PATCH 12/16] Add MCStructureData::toNBT() and ::fromStructure() methods Also ::writePalette() used by fromStructure() --- .../libstructure/format/MCStructureData.php | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index f891dc0..6771e0d 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -51,6 +51,27 @@ public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ } //toNBT + public function toNBT() : CompoundTag{ + $blockIndices = new ListTag(); + foreach($this->blockIndices as $indices){ + $walk = $indices; + array_walk($walk, static function(&$value, $key){ + $value = new IntTag($value); + }); + /** @var ListTag[] $walk */ + $blockIndices->push(new ListTag($walk, NBT::TAG_Int)); + } + $compoundTag = (new CompoundTag())->setTag(MCStructure::TAG_BLOCK_INDICES, $blockIndices); + $palettes = new CompoundTag(); + foreach($this->palettes as $paletteName => $paletteData){ + $palette = (new CompoundTag()) + ->setTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE, new ListTag($paletteData)) + ->setTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA, $this->blockPositionData[$paletteName]); + $palettes->setTag($paletteName, $palette); + } + $compoundTag->setTag(MCStructure::TAG_PALETTE, $palettes); + return $compoundTag; + } public function parse(MCStructure $structure) : MCStructure{//TODO layer or palette parameter? $structure->usePalette(MCStructure::TAG_PALETTE_DEFAULT);//TODO @@ -97,6 +118,18 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale return $structure; } + //create MCStructureData from MCStructure + public static function fromStructure(MCStructure $structure) : MCStructureData{ + $data = new MCStructureData(); + foreach($structure->getLayers() as $layer => $palettedBlockArray){ + $palettedBlockArray = $structure->getPalettedBlockArray($layer); + $paletteName = $structure->getPaletteName(); + $data->writePalette($paletteName, $palettedBlockArray); + } + + return $data; + } + /** @phpstan-return array */ private function parsePalette(string $paletteName) : array{ /** @var BlockStatesParser $blockStatesParser */ @@ -109,8 +142,24 @@ private function parsePalette(string $paletteName) : array{ return $palette; } - //writePalette - //writeNBT + /** @phpstan-param array $palette */ + private function writePalette(string $paletteName, PalettedBlockArray $palette) : void{ + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + #$this->palettes[$paletteName] = []; + $index = 0; + var_dump($palette->getPalette()); + $palette->collectGarbage(); + var_dump($palette->getPalette()); + foreach($palette->getPalette() as $fullId){ + if($fullId !== 0xff_ff_ff_ff){ + $blockState = $blockStatesParser->getFullId($fullId); + var_dump((string) $blockState, $blockState->state->getBlockState()); + $this->palettes[$paletteName][$index] = $blockState->state->getBlockState(); + $index++; + } + } + } } \ No newline at end of file From 93e471c150a19bb247562caffbfa4fc4251c2b53 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 04:07:48 +0200 Subject: [PATCH 13/16] Combine block_position_data and block_palette into one palette array --- .../libstructure/format/MCStructure.php | 12 +++--- .../libstructure/format/MCStructureData.php | 39 +++++++++++-------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index c53061f..bb09205 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -55,7 +55,7 @@ class MCStructure{ public MCStructureData $structure; private string $paletteName; - /** @phpstan-var array> */ + /** @phpstan-var array|CompoundTag */ private array $palette;//pointer /** @var PalettedBlockArray[] */ private array $layers; @@ -74,10 +74,10 @@ public function check() : bool{ $paletteLen = -1; foreach($this->structure->palettes as $name => $palette){ if($paletteLen === -1){ - $paletteLen = count($palette); + $paletteLen = count($palette[MCStructure::TAG_PALETTE_BLOCK_PALETTE]); continue; } - if(count($palette) !== $paletteLen) throw new StructureFileException("Structure palette " . $name . " has " . count($palette) . " entries but previous palettes have " . $paletteLen); + if(count($palette[MCStructure::TAG_PALETTE_BLOCK_PALETTE]) !== $paletteLen) throw new StructureFileException("Structure palette " . $name . " has " . count($palette[MCStructure::TAG_PALETTE_BLOCK_PALETTE]) . " entries but previous palettes have " . $paletteLen); } return true; } @@ -100,14 +100,14 @@ public function set(int $x, int $y, int $z, BlockState $blockState, ?CompoundTag //usePalette function public function usePalette(string $name) : void{ //FIXME add write mode - if(isset($this->structure->palettes[$name])){ + if(isset($this->structure->palettes[$name])){//array_key_exists? $this->paletteName = $name; $this->palette = &$this->structure->palettes[$name]; } } public function lookup(BlockState $properties) : int{ - foreach($this->palette as $index => $entry){ + foreach($this->palette[MCStructure::TAG_PALETTE_BLOCK_PALETTE] as $index => $entry){ $blockState = $entry[self::TAG_PALETTE_BLOCK_PALETTE]; if($blockState instanceof BlockState && $blockState->equals($properties)){ return $index; @@ -396,7 +396,7 @@ public function getBlockEntitiesRaw() : array{ * @return CompoundTag[] */ public function getEntitiesRaw() : array{ - return $this->entities; + return $this->structure->entities; } public function getBlockLayersCount() : int{ diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index 6771e0d..6a86682 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -24,13 +24,9 @@ class MCStructureData{ */ public array $blockIndices = []; public array $entities = []; - /** @phpstan-var array> */ + //TODO palettename tagName + /** @phpstan-var array|CompoundTag> */ public array $palettes = []; - public array $blockEntity = []; - - private array $layers = []; - /** @phpstan-var array */ - private array $blockPositionData = []; public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ $data = new MCStructureData(); @@ -44,8 +40,11 @@ public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ } $palettes = $compoundTag->getCompoundTag(MCStructure::TAG_PALETTE); foreach($palettes as $paletteName => $paletteData){ - $data->palettes[$paletteName] = $paletteData->getListTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE)?->getValue(); - $data->blockPositionData[$paletteName] = $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA); + $data->palettes[$paletteName] = [ + MCStructure::TAG_PALETTE_BLOCK_PALETTE => $paletteData->getListTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE)?->getValue(), + //compound -> int => compound data + MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA => $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA) + ]; } return $data; } @@ -65,8 +64,8 @@ public function toNBT() : CompoundTag{ $palettes = new CompoundTag(); foreach($this->palettes as $paletteName => $paletteData){ $palette = (new CompoundTag()) - ->setTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE, new ListTag($paletteData)) - ->setTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA, $this->blockPositionData[$paletteName]); + ->setTag(MCStructure::TAG_PALETTE_BLOCK_PALETTE, new ListTag($paletteData[MCStructure::TAG_PALETTE_BLOCK_PALETTE])) + ->setTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA, $paletteData[MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]); $palettes->setTag($paletteName, $palette); } $compoundTag->setTag(MCStructure::TAG_PALETTE, $palettes); @@ -103,9 +102,8 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale } } //nbt - if($this->blockPositionData[$paletteName]->getTag((string) $offset) !== null){ - /** @var CompoundTag $tag1 */ - $tag1 = $this->blockPositionData[$paletteName]->getCompoundTag((string) $offset); + if($this->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]->getTag((string) $offset) !== null){ + $tag1 = $this->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]->getCompoundTag((string) $offset); $structure->blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_ENTITY_DATA); } } @@ -121,12 +119,21 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale //create MCStructureData from MCStructure public static function fromStructure(MCStructure $structure) : MCStructureData{ $data = new MCStructureData(); + $paletteName = $structure->getPaletteName(); foreach($structure->getLayers() as $layer => $palettedBlockArray){ $palettedBlockArray = $structure->getPalettedBlockArray($layer); - $paletteName = $structure->getPaletteName(); $data->writePalette($paletteName, $palettedBlockArray); } + foreach($structure->blockEntities as $hash => $blockEntity){ + World::getBlockXYZ($hash, $x, $y, $z); + $offset = (int) (($x * $structure->size->getZ() * $structure->size->getY()) + ($y * $structure->size->getZ()) + $z); + if(!isset($data->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA])){ + $data->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA] = new CompoundTag(); + } + $data->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]->setTag((string) $offset, (new CompoundTag())->setTag(MCStructure::TAG_PALETTE_BLOCK_ENTITY_DATA, $blockEntity)); + } + return $data; } @@ -135,7 +142,7 @@ private function parsePalette(string $paletteName) : array{ /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); $palette = []; - foreach($this->palettes[$paletteName] as $index => $blockStateTag){ + foreach($this->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_PALETTE] as $index => $blockStateTag){ $blockState = $blockStatesParser->getFromCompound($blockStateTag); $palette[$index] = $blockState->getFullId(); } @@ -155,7 +162,7 @@ private function writePalette(string $paletteName, PalettedBlockArray $palette) if($fullId !== 0xff_ff_ff_ff){ $blockState = $blockStatesParser->getFullId($fullId); var_dump((string) $blockState, $blockState->state->getBlockState()); - $this->palettes[$paletteName][$index] = $blockState->state->getBlockState(); + $this->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_PALETTE][$index] = $blockState->state->getBlockState(); $index++; } } From e63285cc128c26a940286ecd428077d50fb2ebf6 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 11 Sep 2022 07:02:19 +0200 Subject: [PATCH 14/16] v0.3.0: Implemented writing MCStructure to file Example: ```php (new MCStructure(MCStructureData::fromStructure($structure),$structure->getSize(),$structure->getStructureWorldOrigin()))->write("structure".MCStructure::EXTENSION_MCSTRUCTURE); ``` --- .../libstructure/format/MCStructure.php | 190 ++++++------------ .../libstructure/format/MCStructureData.php | 42 +++- virion.yml | 2 +- 3 files changed, 102 insertions(+), 132 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index bb09205..b13cf4f 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -2,11 +2,11 @@ namespace xenialdan\libstructure\format; -use Closure; use Generator; use InvalidArgumentException; use OutOfBoundsException; use OutOfRangeException; +use pocketmine\block\Block; use pocketmine\block\BlockFactory; use pocketmine\block\tile\Container; use pocketmine\block\tile\Tile; @@ -19,6 +19,7 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; +use pocketmine\nbt\TreeRoot; use pocketmine\nbt\UnexpectedTagTypeException; use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\utils\AssumptionFailedError; @@ -31,6 +32,7 @@ use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; use xenialdan\libstructure\format\filter\MCStructureFilter; +use function array_key_exists; use function count; class MCStructure{ @@ -58,10 +60,19 @@ class MCStructure{ /** @phpstan-var array|CompoundTag */ private array $palette;//pointer /** @var PalettedBlockArray[] */ - private array $layers; + private array $layers = []; private int $activeLayer = 0; - - public array $blockEntities; + /** @phpstan-var array blockHash => data */ + public array $blockEntities = []; + + public function __construct(MCStructureData $structure, BlockPosition $size, BlockPosition $origin, string $paletteName = self::TAG_PALETTE_DEFAULT){ + $this->formatVersion = self::VERSION; + $this->structure = $structure; + $this->size = $size; + $this->origin = $origin; + $this->paletteName = $paletteName; + $this->palette = []; + } public function check() : bool{ if($this->formatVersion !== self::VERSION) throw new StructureFileException("Unsupported format version: " . $this->formatVersion); @@ -97,13 +108,16 @@ public function set(int $x, int $y, int $z, BlockState $blockState, ?CompoundTag $this->structure->blockIndices[0][$offset] = $ptr; } - //usePalette function public function usePalette(string $name) : void{ //FIXME add write mode - if(isset($this->structure->palettes[$name])){//array_key_exists? - $this->paletteName = $name; - $this->palette = &$this->structure->palettes[$name]; + $this->paletteName = $name; + if(!array_key_exists($name, $this->structure->palettes)){ + $this->structure->palettes[$name] = [ + self::TAG_PALETTE_BLOCK_PALETTE => [], + self::TAG_PALETTE_BLOCK_POSITION_DATA => new CompoundTag() + ]; } + $this->palette = &$this->structure->palettes[$name]; } public function lookup(BlockState $properties) : int{ @@ -133,18 +147,39 @@ public static function read(string $path) : self{ if($fread === false) throw new StructureFileException("Could not read file $path"); $namedTag = (new LittleEndianNBTSerializer())->read($fread)->mustGetCompoundTag(); - $structure = new self(); - + $structure = new self( + MCStructureData::fromNBT($namedTag->getCompoundTag(self::TAG_STRUCTURE)), + self::parseBlockPosition($namedTag, self::TAG_SIZE, false), + self::parseBlockPosition($namedTag, self::TAG_STRUCTURE_WORLD_ORIGIN, true) + ); $structure->formatVersion = $namedTag->getInt(self::TAG_FORMAT_VERSION); - $structure->origin = self::parseBlockPosition($namedTag, self::TAG_STRUCTURE_WORLD_ORIGIN, true); - $structure->size = self::parseBlockPosition($namedTag, self::TAG_SIZE, false); - $structure->structure = MCStructureData::fromNBT($namedTag->getCompoundTag(self::TAG_STRUCTURE)); $structure->check(); return $structure; + } - #$this->parseStructure($namedTag->getCompoundTag(self::TAG_STRUCTURE)); + //write file + public function write(string $path, ?MCStructureData $data = null) : void{ + $this->structure ??= $data; + $pathext = pathinfo($path, PATHINFO_EXTENSION); + if('.' . strtolower($pathext) !== self::EXTENSION_MCSTRUCTURE) throw new InvalidArgumentException("File extension $pathext for file $path is not " . self::EXTENSION_MCSTRUCTURE); + $path = Filesystem::cleanPath($path); + $namedTag = new TreeRoot((new CompoundTag()) + ->setInt(self::TAG_FORMAT_VERSION, self::VERSION) + ->setTag(self::TAG_SIZE, new ListTag([ + new IntTag($this->size->getX()), + new IntTag($this->size->getY()), + new IntTag($this->size->getZ()) + ], NBT::TAG_Int)) + ->setTag(self::TAG_STRUCTURE, $this->structure->toNBT()) + ->setTag(self::TAG_STRUCTURE_WORLD_ORIGIN, new ListTag([ + new IntTag($this->origin->getX()), + new IntTag($this->origin->getY()), + new IntTag($this->origin->getZ()) + ], NBT::TAG_Int))); + $serialized = (new LittleEndianNBTSerializer())->write($namedTag); + file_put_contents($path, $serialized); } //parse method @@ -205,90 +240,6 @@ public function setActiveLayer(int $layer) : self{ return $this; } -// /** -// * @param CompoundTag|null $paletteCompound -// * @param ListTag>|null $blockIndicesList -// * -// * @throws InvalidArgumentException|OutOfRangeException|UnexpectedTagTypeException -// */ -// private function parseBlockLayers(?CompoundTag $paletteCompound, ?ListTag $blockIndicesList) : void{ -// /*if($paletteCompound->count() > 1){ -// -// }*/ -// $paletteDefaultTag = $paletteCompound->getCompoundTag(self::TAG_PALETTE_DEFAULT); -// $paletteBlocks = new PalettedBlockArray(0xff_ff_ff_ff); -// $paletteLiquids = new PalettedBlockArray(0xff_ff_ff_ff); -// $blockEntities = []; -// /** @var BlockState[] $paletteArray */ -// $paletteArray = []; -// /** @var CompoundTag $blockCompoundTag */ -// foreach($paletteDefaultTag->getListTag(self::TAG_PALETTE_BLOCK_PALETTE) as $paletteIndex => $blockCompoundTag){ -// $blockState = BlockStatesParser::getInstance()->getFromCompound($blockCompoundTag); -// if($blockState instanceof BlockState) $paletteArray[$paletteIndex] = $blockState; -// else print TextFormat::RED . $blockCompoundTag . " is not BlockStatesEntry"; -// } -// /** @var CompoundTag $blockPositionData */ -// $blockPositionData = $paletteDefaultTag->getCompoundTag(self::TAG_PALETTE_BLOCK_POSITION_DATA); -// //positions -// $l = $this->size->getZ(); -// $h = $this->size->getY(); -// foreach(range(0, $this->size->getZ() - 1) as $z){ -// foreach(range(0, $this->size->getY() - 1) as $y){ -// foreach(range(0, $this->size->getX() - 1) as $x){ -//// foreach ($blockIndicesList as $layerIndex => $layer) { -//// $layer = reset($layer);//only default -//// /** @var ListTag $layer */ -//// foreach ($layer as $i => $paletteId) { -//// /** @var IntTag $paletteId */ -//// -//// } -//// } -// $offset = (int) (($x * $l * $h) + ($y * $l) + $z); -// -// //block layer -// /** @var ListTag $tag */ -// $tag = $blockIndicesList->get(0); -// $blockLayer = $tag->getAllValues(); -// if(($i = $blockLayer[$offset] ?? -1) !== -1){ -// if(($statesEntry = $paletteArray[$i] ?? null) !== null){ -// try{ -// $block = $statesEntry->getBlock(); -// /** @noinspection PhpInternalEntityUsedInspection */ -// $paletteBlocks->set($x, $y, $z, $block->getFullId()); -// }catch(Exception $e){ -// GlobalLogger::get()->logException($e); -// } -// } -// } -// //liquid layer -// /** @var ListTag $tag */ -// $tag = $blockIndicesList->get(1); -// $liquidLayer = $tag->getAllValues(); -// if(($i = $liquidLayer[$offset] ?? -1) !== -1){ -// if(($statesEntry = $paletteArray[$i] ?? null) !== null){ -// try{ -// $block = $statesEntry->getBlock(); -// /** @noinspection PhpInternalEntityUsedInspection */ -// $paletteLiquids->set($x, $y, $z, $block->getFullId()); -// }catch(Exception $e){ -// GlobalLogger::get()->logException($e); -// } -// } -// } -// //nbt -// if($blockPositionData->getTag((string) $offset) !== null){ -// /** @var CompoundTag $tag1 */ -// $tag1 = $blockPositionData->getCompoundTag((string) $offset); -// $blockEntities[World::blockHash($x, $y, $z)] = $tag1->getCompoundTag(self::TAG_PALETTE_BLOCK_ENTITY_DATA); -// } -// } -// } -// } -// -// $this->blockLayers = [$paletteBlocks, $paletteLiquids]; -// $this->blockEntities = $blockEntities; -// } - public function getPalettedBlockArray(?int $layer = null) : PalettedBlockArray{ $this->activeLayer = $layer ?? $this->activeLayer; return $this->layers[$this->activeLayer]; @@ -299,20 +250,29 @@ public function getPalettedBlockArray(?int $layer = null) : PalettedBlockArray{ * * @return Generator */ - public function blocks(?PalettedBlockArray $palettedBlockArray = null) : Generator{ - $palettedBlockArray ??= $this->getPalettedBlockArray(); + public function blocks(?PalettedBlockArray $palettedBlockArray = null) : Generator{//TODO offset for($x = 0; $x < $this->size->getX(); $x++){ for($y = 0; $y < $this->size->getY(); $y++){ for($z = 0; $z < $this->size->getZ(); $z++){ - $fullId = $palettedBlockArray->get($x, $y, $z); - $block = BlockFactory::getInstance()->fromFullBlock($fullId); - [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; - yield $block; + yield $this->get($x, $y, $z, $palettedBlockArray); } } } } + /** + * Get block at position. + * + * @param PalettedBlockArray|null $palettedBlockArray can be filtered or modified using {@link MCStructureFilter} methods. If null is passed, the current layer will be used. + */ + public function get(int $x, int $y, int $z, ?PalettedBlockArray $palettedBlockArray = null) : Block{//TODO offset + $palettedBlockArray ??= $this->getPalettedBlockArray(); + $fullId = $palettedBlockArray->get($x, $y, $z); + $block = BlockFactory::getInstance()->fromFullBlock($fullId); + [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; + return $block; + } + /** * @throws UnexpectedTagTypeException|InvalidArgumentException|AssumptionFailedError|SavedDataLoadingException */ @@ -359,24 +319,6 @@ public function translateBlockEntity(Position $position, Vector3 $origin) : ?Til return $tile; } - /** - * Reads a value of an object, regardless of access modifiers - * - * @param object $object - * @param string $property - * - * @return mixed - */ - public static function &readAnyValue(object $object, string $property) : mixed{ - $invoke = Closure::bind(function & () use ($property){ - return $this->$property; - }, $object, $object)->__invoke(); - /** @noinspection PhpUnnecessaryLocalVariableInspection */ - $value = &$invoke; - - return $value; - } - public function getSize() : BlockPosition{ return $this->size; } @@ -385,15 +327,13 @@ public function getStructureWorldOrigin() : BlockPosition{ return $this->origin; } - /** - * @return CompoundTag[] - */ public function getBlockEntitiesRaw() : array{ return $this->blockEntities; } /** * @return CompoundTag[] + * @phpstan-return list */ public function getEntitiesRaw() : array{ return $this->structure->entities; diff --git a/src/xenialdan/libstructure/format/MCStructureData.php b/src/xenialdan/libstructure/format/MCStructureData.php index 6a86682..6baf76d 100644 --- a/src/xenialdan/libstructure/format/MCStructureData.php +++ b/src/xenialdan/libstructure/format/MCStructureData.php @@ -13,16 +13,21 @@ use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\World; use xenialdan\libblockstate\BlockStatesParser; +use function array_search; +use function count; use function range; -use function var_dump; class MCStructureData{ /** * @var int[] - * @phpstan-var array> + * @phpstan-var array> * layer => index */ public array $blockIndices = []; + /** + * @var CompoundTag[] + * @phpstan-var list + */ public array $entities = []; //TODO palettename tagName /** @phpstan-var array|CompoundTag> */ @@ -46,6 +51,7 @@ public static function fromNBT(?CompoundTag $compoundTag) : MCStructureData{ MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA => $paletteData->getCompoundTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA) ]; } + $data->entities = $compoundTag->getListTag(MCStructure::TAG_ENTITIES)->getValue(); return $data; } @@ -68,6 +74,7 @@ public function toNBT() : CompoundTag{ ->setTag(MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA, $paletteData[MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]); $palettes->setTag($paletteName, $palette); } + $compoundTag->setTag(MCStructure::TAG_ENTITIES, new ListTag($this->entities, NBT::TAG_Compound)); $compoundTag->setTag(MCStructure::TAG_PALETTE, $palettes); return $compoundTag; } @@ -92,7 +99,8 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale foreach(range(0, $structure->size->getX() - 1) as $x){ $offset = (int) (($x * $l * $h) + ($y * $l) + $z); - if(($i = $this->blockIndices[$layer][$offset] ?? -1) !== -1){ +// if(($i = $this->blockIndices[$layer][$offset] ?? -1) !== -1){ + if(($i = $indices[$offset] ?? -1) !== -1){ if(($fullId = $palette[$i] ?? null) !== null){ try{ $layers[$layer]->set($x, $y, $z, $fullId); @@ -120,9 +128,32 @@ public function parse(MCStructure $structure) : MCStructure{//TODO layer or pale public static function fromStructure(MCStructure $structure) : MCStructureData{ $data = new MCStructureData(); $paletteName = $structure->getPaletteName(); + /** @phpstan-var list $indices */ + $indices = []; foreach($structure->getLayers() as $layer => $palettedBlockArray){ $palettedBlockArray = $structure->getPalettedBlockArray($layer); $data->writePalette($paletteName, $palettedBlockArray); + + //write block indices + for($x = 0; $x < $structure->size->getX(); $x++){ + for($y = 0; $y < $structure->size->getY(); $y++){ + for($z = 0; $z < $structure->size->getZ(); $z++){ + $fullId = $palettedBlockArray->get($x, $y, $z); + $offset = (int) (($x * $structure->size->getZ() * $structure->size->getY()) + ($y * $structure->size->getZ()) + $z); + if($fullId === 0xff_ff_ff_ff){ + $data->blockIndices[$layer][$offset] = -1; + continue; + } + + $index = array_search($fullId, $indices, true); + if($index === false){ + $index = count($indices); + $indices[$index] = $fullId; + } + $data->blockIndices[$layer][$offset] = $index; + } + } + } } foreach($structure->blockEntities as $hash => $blockEntity){ @@ -134,6 +165,8 @@ public static function fromStructure(MCStructure $structure) : MCStructureData{ $data->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_POSITION_DATA]->setTag((string) $offset, (new CompoundTag())->setTag(MCStructure::TAG_PALETTE_BLOCK_ENTITY_DATA, $blockEntity)); } + $data->entities = $structure->getEntitiesRaw(); + return $data; } @@ -155,13 +188,10 @@ private function writePalette(string $paletteName, PalettedBlockArray $palette) $blockStatesParser = BlockStatesParser::getInstance(); #$this->palettes[$paletteName] = []; $index = 0; - var_dump($palette->getPalette()); $palette->collectGarbage(); - var_dump($palette->getPalette()); foreach($palette->getPalette() as $fullId){ if($fullId !== 0xff_ff_ff_ff){ $blockState = $blockStatesParser->getFullId($fullId); - var_dump((string) $blockState, $blockState->state->getBlockState()); $this->palettes[$paletteName][MCStructure::TAG_PALETTE_BLOCK_PALETTE][$index] = $blockState->state->getBlockState(); $index++; } diff --git a/virion.yml b/virion.yml index 318e297..ffe590c 100644 --- a/virion.yml +++ b/virion.yml @@ -1,5 +1,5 @@ name: libstructure -version: 0.2.0 +version: 0.3.0 antigen: xenialdan\libstructure api: [ 4.0.0 ] php: [ 8.0 ] From f73dc5e2c9d222d2fddd5591993121bac93c90c0 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 14 Oct 2022 23:11:46 +0200 Subject: [PATCH 15/16] Patch filters (clone layer) --- .../format/filter/MCStructureFilter.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/xenialdan/libstructure/format/filter/MCStructureFilter.php b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php index 099003d..3e17acb 100644 --- a/src/xenialdan/libstructure/format/filter/MCStructureFilter.php +++ b/src/xenialdan/libstructure/format/filter/MCStructureFilter.php @@ -23,8 +23,10 @@ class MCStructureFilter{ * @return PalettedBlockArray */ public static function with(PalettedBlockArray $layer, array $fullIds = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; if(!in_array($id, $fullIds, true)){ $layer->replaceAll($id, -1); } @@ -43,8 +45,10 @@ public static function with(PalettedBlockArray $layer, array $fullIds = []) : Pa * @return PalettedBlockArray */ public static function except(PalettedBlockArray $layer, array $fullIds = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; if(in_array($id, $fullIds, true)){ $layer->replaceAll($id, -1); } @@ -63,10 +67,12 @@ public static function except(PalettedBlockArray $layer, array $fullIds = []) : * @return PalettedBlockArray */ public static function withBlockIds(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; $blockState = $blockStatesParser->getFullId($id); if(!in_array($blockState->state->getId(), $blockIds, true)){ $layer->replaceAll($id, -1); @@ -86,10 +92,12 @@ public static function withBlockIds(PalettedBlockArray $layer, array $blockIds = * @return PalettedBlockArray */ public static function exceptBlockIds(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; $blockState = $blockStatesParser->getFullId($id); if(in_array($blockState->state->getId(), $blockIds, true)){ $layer->replaceAll($id, -1); @@ -109,10 +117,12 @@ public static function exceptBlockIds(PalettedBlockArray $layer, array $blockIds * @return PalettedBlockArray */ public static function withBlockStates(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; $blockState = $blockStatesParser->getFullId($id); $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); foreach($blockStates as $blockState){ @@ -135,10 +145,12 @@ public static function withBlockStates(PalettedBlockArray $layer, array $blockSt * @return PalettedBlockArray */ public static function withBlockStatesAndValues(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; $blockState = $blockStatesParser->getFullId($id); $compoundTag = $blockState->state->getBlockState()->getCompoundTag("states"); foreach($blockStates as $stateName => $stateValue){ @@ -161,6 +173,7 @@ public static function withBlockStatesAndValues(PalettedBlockArray $layer, array * @return PalettedBlockArray */ public static function replace(PalettedBlockArray $layer, array $blockIds = []) : PalettedBlockArray{ + $layer = clone $layer; foreach($blockIds as $from => $to){ $layer->replaceAll($from, $to); } @@ -178,10 +191,12 @@ public static function replace(PalettedBlockArray $layer, array $blockIds = []) * @throws NoSuchTagException Technically impossible to throw */ public static function replaceBlockStates(PalettedBlockArray $layer, array $blockStates = []) : PalettedBlockArray{ + $layer = clone $layer; $palette = $layer->getPalette(); /** @var BlockStatesParser $blockStatesParser */ $blockStatesParser = BlockStatesParser::getInstance(); foreach($palette as $id){ + if($id === 0xff_ff_ff_ff) continue; $blockState = $blockStatesParser->getFullId($id); try{ $newBlockState = $blockState->replaceBlockStateValues($blockStates, false);//automatically skips if no changes are made From 453958834c703a9f94566d968f4933f8cc6da6a3 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Fri, 14 Oct 2022 23:20:45 +0200 Subject: [PATCH 16/16] Add MCStructure::set(), fix crash on getting "no" block, fix Doc TODO: Tiles --- .../libstructure/format/MCStructure.php | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/xenialdan/libstructure/format/MCStructure.php b/src/xenialdan/libstructure/format/MCStructure.php index b13cf4f..d916a9c 100644 --- a/src/xenialdan/libstructure/format/MCStructure.php +++ b/src/xenialdan/libstructure/format/MCStructure.php @@ -29,6 +29,7 @@ use pocketmine\world\World; use UnexpectedValueException; use xenialdan\libblockstate\BlockState; +use xenialdan\libblockstate\BlockStatesParser; use xenialdan\libstructure\exception\StructureFileException; use xenialdan\libstructure\exception\StructureFormatException; use xenialdan\libstructure\format\filter\MCStructureFilter; @@ -67,7 +68,7 @@ class MCStructure{ public function __construct(MCStructureData $structure, BlockPosition $size, BlockPosition $origin, string $paletteName = self::TAG_PALETTE_DEFAULT){ $this->formatVersion = self::VERSION; - $this->structure = $structure; + $this->structure = &$structure; $this->size = $size; $this->origin = $origin; $this->paletteName = $paletteName; @@ -93,20 +94,6 @@ public function check() : bool{ return true; } - public function set(int $x, int $y, int $z, BlockState $blockState, ?CompoundTag $nbt = null){ - $ptr = $this->lookup($blockState); - if($ptr === -1){ - $ptr = count($this->palette[self::TAG_PALETTE_BLOCK_PALETTE]); - $this->palette[$ptr] = [ - self::TAG_PALETTE_BLOCK_PALETTE => $blockState, - self::TAG_PALETTE_BLOCK_POSITION_DATA => $nbt - ]; - } - $l = $this->size->getZ(); - $h = $this->size->getY(); - $offset = ($x * $l * $h) + ($y * $l) + $z; - $this->structure->blockIndices[0][$offset] = $ptr; - } public function usePalette(string $name) : void{ //FIXME add write mode @@ -122,7 +109,9 @@ public function usePalette(string $name) : void{ public function lookup(BlockState $properties) : int{ foreach($this->palette[MCStructure::TAG_PALETTE_BLOCK_PALETTE] as $index => $entry){ - $blockState = $entry[self::TAG_PALETTE_BLOCK_PALETTE]; + /** @var BlockStatesParser $blockStatesParser */ + $blockStatesParser = BlockStatesParser::getInstance(); + $blockState = $blockStatesParser->getFromCompound($entry); if($blockState instanceof BlockState && $blockState->equals($properties)){ return $index; } @@ -249,6 +238,7 @@ public function getPalettedBlockArray(?int $layer = null) : PalettedBlockArray{ * @param PalettedBlockArray|null $palettedBlockArray can be filtered or modified using {@link MCStructureFilter} methods. If null is passed, the current layer will be used. * * @return Generator + * @phpstan-return Generator */ public function blocks(?PalettedBlockArray $palettedBlockArray = null) : Generator{//TODO offset for($x = 0; $x < $this->size->getX(); $x++){ @@ -265,14 +255,35 @@ public function blocks(?PalettedBlockArray $palettedBlockArray = null) : Generat * * @param PalettedBlockArray|null $palettedBlockArray can be filtered or modified using {@link MCStructureFilter} methods. If null is passed, the current layer will be used. */ - public function get(int $x, int $y, int $z, ?PalettedBlockArray $palettedBlockArray = null) : Block{//TODO offset + public function get(int $x, int $y, int $z, ?PalettedBlockArray $palettedBlockArray = null) : ?Block{//TODO offset $palettedBlockArray ??= $this->getPalettedBlockArray(); $fullId = $palettedBlockArray->get($x, $y, $z); + if($fullId === 0xff_ff_ff_ff) return null; $block = BlockFactory::getInstance()->fromFullBlock($fullId); [$block->getPosition()->x, $block->getPosition()->y, $block->getPosition()->z] = [$x, $y, $z]; return $block; } + public function set(int $x, int $y, int $z, ?BlockState $blockState, ?CompoundTag $nbt = null){ + if($blockState === null){ + $this->getPalettedBlockArray()->set($x, $y, $z, 0xff_ff_ff_ff); + return; + } + $this->getPalettedBlockArray()->set($x, $y, $z, $blockState->getFullId()); +// $ptr = $this->lookup($blockState); +// if($ptr === -1){ +// $ptr = count($this->palette[self::TAG_PALETTE_BLOCK_PALETTE]); +// $this->palette[$ptr] = [ +// self::TAG_PALETTE_BLOCK_PALETTE => $blockState, +// self::TAG_PALETTE_BLOCK_POSITION_DATA => $nbt +// ]; +// } +// $l = $this->size->getZ(); +// $h = $this->size->getY(); +// $offset = ($x * $l * $h) + ($y * $l) + $z; +// $this->structure->blockIndices[0][$offset] = $ptr; + } + /** * @throws UnexpectedTagTypeException|InvalidArgumentException|AssumptionFailedError|SavedDataLoadingException */