PocketMine-MP 5.32.2 git-1ebd7d3960d713d56f77f610fe0c15cdee201069
Loading...
Searching...
No Matches
BlockSerializerDeserializerRegistrar.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\data\bedrock\block\convert;
25
35use function array_map;
36use function count;
37use function implode;
38use function is_string;
39
45
46 public function __construct(
47 public readonly BlockStateToObjectDeserializer $deserializer,
48 public readonly BlockObjectToStateSerializer $serializer
49 ){}
50
59 private static function compileFlattenedIdPartMatrix(array $components) : array{
60 $result = [];
61 foreach($components as $component){
62 $column = is_string($component) ? [$component] : $component->getPossibleValues();
63
64 if(count($result) === 0){
65 $result = array_map(fn($value) => [$value], $column);
66 }else{
67 $stepResult = [];
68 foreach($result as $parts){
69 foreach($column as $value){
70 $stepPart = $parts;
71 $stepPart[] = $value;
72 $stepResult[] = $stepPart;
73 }
74 }
75
76 $result = $stepResult;
77 }
78 }
79
80 return $result;
81 }
82
91 private static function serializeFlattenedId(Block $block, array $idComponents) : string{
92 $id = "";
93 foreach($idComponents as $infix){
94 $id .= is_string($infix) ? $infix : $infix->serializePlain($block);
95 }
96 return $id;
97 }
98
111 private static function deserializeFlattenedId(Block $baseBlock, array $idComponents, array $idPropertyValues) : Block{
112 $preparedBlock = clone $baseBlock;
113 foreach($idComponents as $k => $component){
114 if($component instanceof StringProperty){
115 $fakeValue = $idPropertyValues[$k];
116 $component->deserializePlain($preparedBlock, $fakeValue);
117 }
118 }
119
120 return $preparedBlock;
121 }
122
123 public function mapSimple(Block $block, string $id) : void{
124 $this->deserializer->map($id, fn() => clone $block);
125 $this->serializer->map($block, BlockStateData::current($id, []));
126 }
127
132 public function mapFlattenedId(FlattenedIdModel $model) : void{
133 $block = $model->getBlock();
134
135 $idComponents = $model->getIdComponents();
136 if(count($idComponents) === 0){
137 throw new \InvalidArgumentException("No ID components provided");
138 }
139 $properties = $model->getProperties();
140
141 //This is a really cursed hack that lets us essentially write flattened properties as blockstate properties, and
142 //then pull them out to compile an ID :D
143 //This works surprisingly well and is much more elegant than I would've expected
144
145 if(count($properties) > 0){
146 $this->serializer->map($block, function(Block $block) use ($idComponents, $properties) : Writer{
147 $id = self::serializeFlattenedId($block, $idComponents);
148
149 $writer = new Writer($id);
150 foreach($properties as $property){
151 $property->serialize($block, $writer);
152 }
153
154 return $writer;
155 });
156 }else{
157 $this->serializer->map($block, function(Block $block) use ($idComponents) : BlockStateData{
158 //fast path for blocks with no state properties
159 $id = self::serializeFlattenedId($block, $idComponents);
160 return BlockStateData::current($id, []);
161 });
162 }
163
164 $idPermutations = self::compileFlattenedIdPartMatrix($idComponents);
165 foreach($idPermutations as $idParts){
166 //deconstruct the ID into a partial state
167 //we can do this at registration time since there will be multiple deserializers
168 $preparedBlock = self::deserializeFlattenedId($block, $idComponents, $idParts);
169 $id = implode("", $idParts);
170
171 if(count($properties) > 0){
172 $this->deserializer->map($id, function(Reader $reader) use ($preparedBlock, $properties) : Block{
173 $block = clone $preparedBlock;
174
175 foreach($properties as $property){
176 $property->deserialize($block, $reader);
177 }
178 return $block;
179 });
180 }else{
181 //fast path for blocks with no state properties
182 $this->deserializer->map($id, fn() => clone $preparedBlock);
183 }
184 }
185 }
186
191 public function mapColored(Block $block, string $idPrefix, string $idSuffix) : void{
192 $this->mapFlattenedId(FlattenedIdModel::create($block)
193 ->idComponents([
194 $idPrefix,
195 CommonProperties::getInstance()->dyeColorIdInfix,
196 $idSuffix
197 ])
198 );
199 }
200
201 public function mapSlab(Slab $block, string $type) : void{
202 $commonProperties = CommonProperties::getInstance();
203 $this->mapFlattenedId(FlattenedIdModel::create($block)
204 ->idComponents(["minecraft:", $type, "_", $commonProperties->slabIdInfix, "slab"])
205 ->properties([$commonProperties->slabPositionProperty])
206 );
207 }
208
209 public function mapStairs(Stair $block, string $id) : void{
210 $this->mapModel(Model::create($block, $id)->properties(CommonProperties::getInstance()->stairProperties));
211 }
212
217 public function mapModel(Model $model) : void{
218 $id = $model->getId();
219 $block = $model->getBlock();
220 $propertyDescriptors = $model->getProperties();
221
222 $this->deserializer->map($id, static function(Reader $in) use ($block, $propertyDescriptors) : Block{
223 $newBlock = clone $block;
224 foreach($propertyDescriptors as $descriptor){
225 $descriptor->deserialize($newBlock, $in);
226 }
227 return $newBlock;
228 });
229 $this->serializer->map($block, static function(Block $block) use ($id, $propertyDescriptors) : Writer{
230 $writer = new Writer($id);
231 foreach($propertyDescriptors as $descriptor){
232 $descriptor->serialize($block, $writer);
233 }
234 return $writer;
235 });
236 }
237}
static current(string $name, array $states)