Skip to content

Commit 89d5d60

Browse files
committed
[sync] Update embedded LibSerializer from standalone
1 parent 356353f commit 89d5d60

6 files changed

Lines changed: 370 additions & 0 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
use pocketmine\block\utils\DyeColor;
8+
use pocketmine\block\utils\ColoredTrait;
9+
use pocketmine\item\Dye;
10+
use pocketmine\item\Item;
11+
use pocketmine\item\ItemBlock;
12+
use pocketmine\item\StringToItemParser;
13+
use pocketmine\item\LegacyStringToItemParser;
14+
use pocketmine\nbt\TreeRoot;
15+
use pocketmine\nbt\tag\CompoundTag;
16+
use pocketmine\nbt\LittleEndianNbtSerializer;
17+
18+
use function json_decode;
19+
use function str_replace;
20+
use function strtolower;
21+
22+
/**
23+
* Class ItemSerializable
24+
* @package imperazim\serializer
25+
*/
26+
final class ItemSerializable {
27+
28+
private static function hasColoredTrait(object $object): bool {
29+
$class = get_class($object);
30+
$traits = [];
31+
do {
32+
$classTraits = class_uses($class);
33+
if ($classTraits !== false) {
34+
$traits = array_merge($traits, $classTraits);
35+
}
36+
$class = get_parent_class($class);
37+
} while ($class !== false);
38+
return in_array(ColoredTrait::class, $traits, true);
39+
}
40+
41+
public static function jsonDeserialize(string $data): ?Item {
42+
try {
43+
$decodedData = json_decode($data);
44+
if (json_last_error() !== JSON_ERROR_NONE) {
45+
throw new \RuntimeException("JSON error: " . json_last_error_msg());
46+
}
47+
48+
$typeId = $decodedData->typeId ?? null;
49+
$vanillaName = $decodedData->vanillaName ?? null;
50+
51+
if ($vanillaName !== null) {
52+
$item = StringToItemParser::getInstance()->parse($vanillaName)
53+
?? LegacyStringToItemParser::getInstance()->parse($vanillaName);
54+
} else {
55+
throw new \RuntimeException("Neither typeId nor vanillaName found.");
56+
}
57+
58+
if ($item === null || $item->isNull()) {
59+
throw new \RuntimeException("Item not found: typeId=$typeId, vanillaName=$vanillaName");
60+
}
61+
62+
$item->setCount($decodedData->count ?? 1);
63+
64+
// Handle Dye items color restoration
65+
if ($item instanceof Dye && isset($decodedData->color)) {
66+
$colorName = mb_strtoupper($decodedData->color);
67+
$dyeColor = DyeColor::getAll()[$colorName] ?? null;
68+
if ($dyeColor !== null) {
69+
$item->setColor($dyeColor);
70+
}
71+
}
72+
// Handle colored blocks color restoration
73+
elseif ($item instanceof ItemBlock && self::hasColoredTrait($item->getBlock())) {
74+
if (isset($decodedData->color)) {
75+
$colorName = mb_strtoupper($decodedData->color);
76+
$dyeColor = DyeColor::getAll()[$colorName] ?? null;
77+
if ($dyeColor !== null) {
78+
$block = $item->getBlock();
79+
if (method_exists($block, 'setColor')) {
80+
$block->setColor($dyeColor);
81+
$item = $block->asItem();
82+
}
83+
}
84+
}
85+
}
86+
87+
if (!empty($decodedData->nbt)) {
88+
$nbtData = base64_decode($decodedData->nbt, true);
89+
if ($nbtData === false) {
90+
throw new \RuntimeException("Invalid base64 NBT");
91+
}
92+
$nbt = (new LittleEndianNbtSerializer())->read($nbtData)->getTag();
93+
if (!$nbt instanceof CompoundTag) {
94+
throw new \RuntimeException("NBT is not CompoundTag");
95+
}
96+
$item->setNamedTag($nbt);
97+
}
98+
99+
return $item;
100+
} catch (\RuntimeException $e) {
101+
return null;
102+
}
103+
}
104+
105+
public static function jsonSerialize(Item $item): ?string {
106+
try {
107+
$data = [
108+
"vanillaName" => strtolower(str_replace(' ', '_', $item->getVanillaName())),
109+
"typeId" => $item->getTypeId()
110+
];
111+
112+
if ($item->getCount() !== 1) {
113+
$data["count"] = $item->getCount();
114+
}
115+
116+
// Handle Dye items (has color but not ItemBlock)
117+
if ($item instanceof Dye) {
118+
$color = $item->getColor();
119+
if ($color !== null) {
120+
$data["color"] = $color->name;
121+
}
122+
}
123+
// Handle colored blocks (wool, concrete, etc)
124+
elseif ($item instanceof ItemBlock && self::hasColoredTrait($item->getBlock())) {
125+
$block = $item->getBlock();
126+
$color = $block->getColor();
127+
if ($color !== null) {
128+
$data["color"] = $color->name;
129+
}
130+
}
131+
132+
if ($item->hasNamedTag()) {
133+
$nbtSerializer = new LittleEndianNbtSerializer();
134+
$data["nbt"] = base64_encode($nbtSerializer->write(new TreeRoot($item->getNamedTag())));
135+
}
136+
137+
return json_encode($data);
138+
} catch (\RuntimeException $e) {
139+
return null;
140+
}
141+
}
142+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
/**
8+
* Interface JsonSerializable
9+
* @package imperazim\serializer
10+
*/
11+
interface JsonSerializable {
12+
13+
/**
14+
* Deserialize a JSON string to an object.
15+
* @param string $jsonString The JSON string to deserialize.
16+
* @return object|null The deserialized object or null on failure.
17+
*/
18+
public static function jsonDeserialize(string $jsonString): ?object;
19+
20+
/**
21+
* Serialize the object to a JSON string.
22+
* @param object $object The object to serialize.
23+
* @return string The serialized JSON string.
24+
*/
25+
public static function jsonSerialize(object $object): string;
26+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
use GlobalLogger;
8+
use pocketmine\Server;
9+
use pocketmine\entity\Location;
10+
11+
/**
12+
* Class LocationSerializable
13+
* @package imperazim\serializer
14+
*/
15+
class LocationSerializable implements JsonSerializable {
16+
17+
/**
18+
* Deserialize a JSON string to a Location object.
19+
* @param string $jsonString The JSON string to deserialize.
20+
* @return Location|null The deserialized object or null on failure.
21+
*/
22+
public static function jsonDeserialize(string $jsonString): ?Location {
23+
try {
24+
$data = json_decode($jsonString, true);
25+
if (isset($data['x'], $data['y'], $data['z'], $data['yaw'], $data['pitch'], $data['world'])) {
26+
$world = Server::getInstance()->getWorldManager()->getWorldByName($data['world']);
27+
return new Location((float)$data['x'], (float)$data['y'], (float)$data['z'], $world, (float)$data['yaw'], (float)$data['pitch']);
28+
}
29+
} catch (\RuntimeException $e) {
30+
GlobalLogger::get()->logException($e);
31+
}
32+
return null;
33+
}
34+
35+
/**
36+
* Serialize a Location object to a JSON string.
37+
* @param object $object The object to serialize.
38+
* @return string The serialized JSON string.
39+
* @throws \InvalidArgumentException If the object is not an instance of Location.
40+
*/
41+
public static function jsonSerialize(object $object): string {
42+
if (!$object instanceof Location) {
43+
throw new \InvalidArgumentException("Object must be an instance of Location");
44+
}
45+
$data = [
46+
'x' => $object->getX(),
47+
'y' => $object->getY(),
48+
'z' => $object->getZ(),
49+
'yaw' => $object->getYaw(),
50+
'pitch' => $object->getPitch(),
51+
'world' => $object->isValid() ? $object->getWorld()->getDisplayName() : "null"
52+
];
53+
return json_encode($data);
54+
}
55+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
use GlobalLogger;
8+
use pocketmine\Server;
9+
use pocketmine\world\Position;
10+
11+
/**
12+
* Class PositionSerializable
13+
* @package imperazim\serializer
14+
*/
15+
class PositionSerializable implements JsonSerializable {
16+
17+
/**
18+
* Deserialize a JSON string to a Position object.
19+
* @param string $jsonString The JSON string to deserialize.
20+
* @return Position|null The deserialized object or null on failure.
21+
*/
22+
public static function jsonDeserialize(string $jsonString): ?Position {
23+
try {
24+
$data = json_decode($jsonString, true);
25+
if (isset($data['x'], $data['y'], $data['z'], $data['world'])) {
26+
$world = Server::getInstance()->getWorldManager()->getWorldByName($data['world']);
27+
return new Position((float)$data['x'], (float)$data['y'], (float)$data['z'], $world);
28+
}
29+
} catch (\RuntimeException $e) {
30+
GlobalLogger::get()->logException($e);
31+
}
32+
return null;
33+
}
34+
35+
/**
36+
* Serialize a Position object to a JSON string.
37+
* @param object $object The object to serialize.
38+
* @return string The serialized JSON string.
39+
* @throws \InvalidArgumentException If the object is not an instance of Position.
40+
*/
41+
public static function jsonSerialize(object $object): string {
42+
if (!$object instanceof Position) {
43+
throw new \InvalidArgumentException("Object must be an instance of Position");
44+
}
45+
$data = [
46+
'x' => $object->getX(),
47+
'y' => $object->getY(),
48+
'z' => $object->getZ(),
49+
'world' => $object->isValid() ? $object->getWorld()->getDisplayName() : "null"
50+
];
51+
return json_encode($data);
52+
}
53+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
use pocketmine\entity\Skin;
8+
9+
/**
10+
* Class SkinSerializable
11+
* @package imperazim\serializer
12+
*/
13+
final class SkinSerializable {
14+
15+
/**
16+
* Serializes the Skin object into an associative array.
17+
* @param Skin $skin The skin containing the data to serialize.
18+
* @return array The array containing the serialized data of the Skin.
19+
*/
20+
public static function jsonSerialize(Skin $skin): array {
21+
return [
22+
'skinId' => $skin->getSkinId(),
23+
'skinData' => base64_encode($skin->getSkinData()),
24+
'capeData' => $skin->getCapeData(),
25+
'geometryName' => $skin->getGeometryName(),
26+
'geometryData' => $skin->getGeometryData(),
27+
];
28+
}
29+
30+
/**
31+
* Deserializes data from an associative array to create a new instance of Skin.
32+
* @param array $data The array containing the data to deserialize.
33+
* @return Skin The new instance of Skin created based on the provided data.
34+
*/
35+
public static function jsonDeserialize(array $data): Skin {
36+
return new Skin(
37+
$data['skinId'],
38+
base64_decode($data['skinData']),
39+
$data['capeData'] ?? "",
40+
$data['geometryName'] ?? "",
41+
$data['geometryData'] ?? ""
42+
);
43+
}
44+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\serializer;
6+
7+
use GlobalLogger;
8+
use pocketmine\math\Vector3;
9+
10+
/**
11+
* Class Vector3Serializable
12+
* @package imperazim\serializer
13+
*/
14+
class Vector3Serializable implements JsonSerializable {
15+
16+
/**
17+
* Deserialize a JSON string to a Vector3 object.
18+
* @param string $jsonString The JSON string to deserialize.
19+
* @return Vector3|null The deserialized object or null on failure.
20+
*/
21+
public static function jsonDeserialize(string $jsonString): ?Vector3 {
22+
try {
23+
$data = json_decode($jsonString, true);
24+
if (isset($data['x'], $data['y'], $data['z'])) {
25+
return new Vector3((float)$data['x'], (float)$data['y'], (float)$data['z']);
26+
}
27+
} catch (\RuntimeException $e) {
28+
GlobalLogger::get()->logException($e);
29+
}
30+
return null;
31+
}
32+
33+
/**
34+
* Serialize a Vector3 object to a JSON string.
35+
* @param object $object The object to serialize.
36+
* @return string The serialized JSON string.
37+
* @throws \InvalidArgumentException If the object is not an instance of Vector3.
38+
*/
39+
public static function jsonSerialize(object $object): string {
40+
if (!$object instanceof Vector3) {
41+
throw new \InvalidArgumentException("Object must be an instance of Vector3");
42+
}
43+
$data = [
44+
'x' => $object->getX(),
45+
'y' => $object->getY(),
46+
'z' => $object->getZ()
47+
];
48+
return json_encode($data);
49+
}
50+
}

0 commit comments

Comments
 (0)