From c2f8e9365bdf359b55f91056fd158d9d2c2a9f6b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 15 Mar 2025 20:53:49 +0000 Subject: [PATCH] BlockStateToObjectDeserializer: check that the returned state is actually registered if not, this will cause random crashes in core code, which assumes that state IDs found on runtime chunk memory are valid and registered. this problem exists in other places too, and probably requires a rethink of how we're dealing with this, but for now, this will do as a band-aid. --- src/block/RuntimeBlockStateRegistry.php | 4 ++++ .../convert/BlockStateToObjectDeserializer.php | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/block/RuntimeBlockStateRegistry.php b/src/block/RuntimeBlockStateRegistry.php index d13b942ba..a458b3368 100644 --- a/src/block/RuntimeBlockStateRegistry.php +++ b/src/block/RuntimeBlockStateRegistry.php @@ -209,6 +209,10 @@ class RuntimeBlockStateRegistry{ return $block; } + public function hasStateId(int $stateId) : bool{ + return isset($this->fullList[$stateId]); + } + /** * @return Block[] * @phpstan-return array diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php index 2ea2ecf8c..ed45a47d3 100644 --- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php +++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php @@ -33,6 +33,7 @@ use pocketmine\block\DoublePitcherCrop; use pocketmine\block\Opaque; use pocketmine\block\PinkPetals; use pocketmine\block\PitcherCrop; +use pocketmine\block\RuntimeBlockStateRegistry; use pocketmine\block\Slab; use pocketmine\block\Stair; use pocketmine\block\SweetBerryBush; @@ -97,11 +98,21 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ public function deserialize(BlockStateData $stateData) : int{ if(count($stateData->getStates()) === 0){ //if a block has zero properties, we can keep a map of string ID -> internal blockstate ID - return $this->simpleCache[$stateData->getName()] ??= $this->deserializeBlock($stateData)->getStateId(); + return $this->simpleCache[$stateData->getName()] ??= $this->deserializeToStateId($stateData); } //we can't cache blocks that have properties - go ahead and deserialize the slow way - return $this->deserializeBlock($stateData)->getStateId(); + return $this->deserializeToStateId($stateData); + } + + private function deserializeToStateId(BlockStateData $stateData) : int{ + $stateId = $this->deserializeBlock($stateData)->getStateId(); + //plugin devs seem to keep missing this and causing core crashes, so we need to verify this at the earliest + //available opportunity + if(!RuntimeBlockStateRegistry::getInstance()->hasStateId($stateId)){ + throw new \LogicException("State ID $stateId returned by deserializer for " . $stateData->getName() . " is not registered in RuntimeBlockStateRegistry"); + } + return $stateId; } /** @phpstan-param \Closure(Reader) : Block $c */