PocketMine-MP 5.18.1 git-9381fc4172e5dce4cada1cb356050c8a2ab57b94
ItemSerializer.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\item;
25
35use function get_class;
36
37final class ItemSerializer{
45 private array $itemSerializers = [];
46
51 private array $blockItemSerializers = [];
52
53 public function __construct(
54 private BlockStateSerializer $blockStateSerializer
55 ){
56 $this->registerSpecialBlockSerializers();
58 }
59
65 public function map(Item $item, \Closure $serializer) : void{
66 $index = $item->getTypeId();
67 if(isset($this->itemSerializers[$index])){
68 throw new \InvalidArgumentException("Item type ID " . $index . " already has a serializer registered");
69 }
70 $this->itemSerializers[$index] = $serializer;
71 }
72
78 public function mapBlock(Block $block, \Closure $serializer) : void{
79 $index = $block->getTypeId();
80 if(isset($this->blockItemSerializers[$index])){
81 throw new \InvalidArgumentException("Block type ID " . $index . " already has a serializer registered");
82 }
83 $this->blockItemSerializers[$index] = $serializer;
84 }
85
92 public function serializeType(Item $item) : Data{
93 if($item->isNull()){
94 throw new \InvalidArgumentException("Cannot serialize a null itemstack");
95 }
96 if($item instanceof ItemBlock){
97 $data = $this->serializeBlockItem($item->getBlock());
98 }else{
99 $index = $item->getTypeId();
100
101 $locatedSerializer = $this->itemSerializers[$index] ?? null;
102 if($locatedSerializer === null){
103 throw new ItemTypeSerializeException("No serializer registered for " . get_class($item) . " ($index) " . $item->getName());
104 }
105
114 $serializer = $locatedSerializer;
115
117 $data = $serializer($item);
118 }
119
120 if($item->hasNamedTag()){
121 $resultTag = $item->getNamedTag();
122 $extraTag = $data->getTag();
123 if($extraTag !== null){
124 $resultTag = $resultTag->merge($extraTag);
125 }
126 $data = new Data($data->getName(), $data->getMeta(), $data->getBlock(), $resultTag);
127 }
128
129 return $data;
130 }
131
132 public function serializeStack(Item $item, ?int $slot = null) : SavedItemStackData{
133 return new SavedItemStackData(
134 $this->serializeType($item),
135 $item->getCount(),
136 $slot,
137 null,
138 [], //we currently represent canDestroy and canPlaceOn via NBT, like PC
139 []
140 );
141 }
142
149 private function serializeBlockItem(Block $block) : Data{
150 $index = $block->getTypeId();
151
152 $locatedSerializer = $this->blockItemSerializers[$index] ?? null;
153 if($locatedSerializer !== null){
161 $serializer = $locatedSerializer;
162 $data = $serializer($block);
163 }else{
164 $data = $this->standardBlock($block);
165 }
166
167 return $data;
168 }
169
173 private function standardBlock(Block $block) : Data{
174 try{
175 $blockStateData = $this->blockStateSerializer->serialize($block->getStateId());
176 }catch(BlockStateSerializeException $e){
177 throw new ItemTypeSerializeException($e->getMessage(), 0, $e);
178 }
179
180 //TODO: this really ought to throw if there's no blockitem ID
181 $itemNameId = BlockItemIdMap::getInstance()->lookupItemId($blockStateData->getName()) ?? $blockStateData->getName();
182
183 return new Data($itemNameId, 0, $blockStateData);
184 }
185
186 private function registerSpecialBlockSerializers() : void{
187 //these are encoded as regular blocks, but they have to be accounted for explicitly since they don't use ItemBlock
188 //Bamboo->getBlock() returns BambooSapling :(
189 $this->map(Items::BAMBOO(), fn() => $this->standardBlock(Blocks::BAMBOO()));
190 $this->map(Items::CORAL_FAN(), fn(CoralFan $item) => $this->standardBlock($item->getBlock()));
191 }
192}
mapBlock(Block $block, \Closure $serializer)
map(Item $item, \Closure $serializer)
getBlock(?int $clickedFace=null)
Definition: Item.php:491