deserializer = new BlockStateToObjectDeserializer(); $this->serializer = new BlockObjectToStateSerializer(); $registrar = new BlockSerializerDeserializerRegistrar($this->deserializer, $this->serializer); VanillaBlockMappings::init($registrar); } public function testAllKnownBlockStatesSerializableAndDeserializable() : void{ foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $block){ try{ $blockStateData = $this->serializer->serializeBlock($block); }catch(BlockStateSerializeException $e){ self::fail("Failed to serialize " . $block->getName() . ": " . $e->getMessage()); } try{ $newBlock = $this->deserializer->deserializeBlock($blockStateData); }catch(BlockStateDeserializeException $e){ self::fail("Failed to deserialize " . $blockStateData->getName() . ": " . $e->getMessage() . " with data " . $blockStateData->toNbt()); } if(match ($block->getTypeId()) { BlockTypeIds::POTION_CAULDRON, BlockTypeIds::OMINOUS_BANNER, BlockTypeIds::OMINOUS_WALL_BANNER => true, default => false }){ //these pretend to be something else in the blockstate, and the variant switching is done via block entity data continue; } //The following are workarounds for differences in blockstate representation in Bedrock vs PM //In some cases, some properties are not stored in the blockstate (but rather in the block entity NBT), but //they do form part of the internal blockstate hash in PM. In other cases, PM allows representing states //that don't exist in Bedrock, such as the cave vines head without berries, which is a state that visually //exists in Bedrock, but doesn't have its own ID. //This leads to inconsistencies when serializing and deserializing blockstates which we need to correct for. if( ($block instanceof BaseBanner && $newBlock instanceof BaseBanner) || ($block instanceof Bed && $newBlock instanceof Bed) ){ $newBlock->setColor($block->getColor()); }elseif($block instanceof MobHead && $newBlock instanceof MobHead){ $newBlock->setMobHeadType($block->getMobHeadType()); }elseif($block instanceof CaveVines && $newBlock instanceof CaveVines && !$block->hasBerries()){ $newBlock->setHead($block->isHead()); }elseif($block instanceof Farmland && $newBlock instanceof Farmland){ $block->setWaterPositionIndex($newBlock->getWaterPositionIndex()); } self::assertSame($block->getStateId(), $newBlock->getStateId(), "Mismatch of blockstate for " . $block->getName() . ", " . print_r($block, true) . " vs " . print_r($newBlock, true)); } } }