*/ private array $serializers = []; /** * @var BlockStateData[] * @phpstan-var array */ private array $cache = []; public function serialize(int $stateId) : BlockStateData{ //TODO: singleton usage not ideal //TODO: we may want to deduplicate cache entries to avoid wasting memory return $this->cache[$stateId] ??= $this->serializeBlock(RuntimeBlockStateRegistry::getInstance()->fromStateId($stateId)); } public function isRegistered(Block $block) : bool{ return isset($this->serializers[$block->getTypeId()]); } /** * @phpstan-template TBlockType of Block * @phpstan-param TBlockType $block * @phpstan-param \Closure(TBlockType) : (Writer|BlockStateData)|Writer|BlockStateData $serializer */ public function map(Block $block, \Closure|Writer|BlockStateData $serializer) : void{ if(isset($this->serializers[$block->getTypeId()])){ throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " (" . $block->getName() . ") already has a serializer registered"); } //writer accepted for convenience only $this->serializers[$block->getTypeId()] = $serializer instanceof Writer ? $serializer->getBlockStateData() : $serializer; } /** * @deprecated */ public function mapSimple(Block $block, string $id) : void{ $this->map($block, BlockStateData::current($id, [])); } /** * @deprecated */ public function mapSlab(Slab $block, string $singleId, string $doubleId) : void{ $this->map($block, fn(Slab $block) => Helper::encodeSlab($block, $singleId, $doubleId)); } /** * @deprecated */ public function mapStairs(Stair $block, string $id) : void{ $this->map($block, fn(Stair $block) => Helper::encodeStairs($block, Writer::create($id))); } /** * @deprecated */ public function mapLog(Wood $block, string $unstrippedId, string $strippedId) : void{ $this->map($block, fn(Wood $block) => Helper::encodeLog($block, $unstrippedId, $strippedId)); } /** * @phpstan-template TBlockType of Block * @phpstan-param TBlockType $blockState * * @throws BlockStateSerializeException */ public function serializeBlock(Block $blockState) : BlockStateData{ $typeId = $blockState->getTypeId(); $locatedSerializer = $this->serializers[$typeId] ?? null; if($locatedSerializer === null){ throw new BlockStateSerializeException("No serializer registered for " . get_class($blockState) . " with type ID $typeId"); } if($locatedSerializer instanceof BlockStateData){ //static data, not dependent on state return $locatedSerializer; } /** * TODO: there is no guarantee that this type actually matches that of $blockState - a plugin may have stolen * the type ID of the block (which never makes sense, even in a world where overriding block types is a thing). * In the future we'll need some way to guarantee that type IDs are never reused (perhaps spl_object_id()?) * * @var \Closure $locatedSerializer * @phpstan-var \Closure(TBlockType) : (Writer|BlockStateData) $locatedSerializer */ $result = $locatedSerializer($blockState); return $result instanceof Writer ? $result->getBlockStateData() : $result; } }