PocketMine-MP 5.35.1 git-e32e836dad793a3a3c8ddd8927c00e112b1e576a
Loading...
Searching...
No Matches
CommonTypes.php
1<?php
2
3/*
4 * This file is part of BedrockProtocol.
5 * Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
6 *
7 * BedrockProtocol is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13declare(strict_types=1);
14
15namespace pocketmine\network\mcpe\protocol\serializer;
16
17use pmmp\encoding\Byte;
18use pmmp\encoding\ByteBufferReader;
19use pmmp\encoding\ByteBufferWriter;
20use pmmp\encoding\DataDecodeException;
21use pmmp\encoding\LE;
22use pmmp\encoding\VarInt;
63use Ramsey\Uuid\Uuid;
64use Ramsey\Uuid\UuidInterface;
65use function count;
66use function strlen;
67use function strrev;
68use function substr;
69
70final class CommonTypes{
71
72 private function __construct(){
73 //NOOP
74 }
75
77 public static function getString(ByteBufferReader $in) : string{
78 return $in->readByteArray(VarInt::readUnsignedInt($in));
79 }
80
81 public static function putString(ByteBufferWriter $out, string $v) : void{
82 VarInt::writeUnsignedInt($out, strlen($v));
83 $out->writeByteArray($v);
84 }
85
87 public static function getBool(ByteBufferReader $in) : bool{
88 return Byte::readUnsigned($in) !== 0;
89 }
90
91 public static function putBool(ByteBufferWriter $out, bool $v) : void{
92 Byte::writeUnsigned($out, $v ? 1 : 0);
93 }
94
96 public static function getUUID(ByteBufferReader $in) : UuidInterface{
97 //This is two little-endian longs: bytes 7-0 followed by bytes 15-8
98 $p1 = strrev($in->readByteArray(8));
99 $p2 = strrev($in->readByteArray(8));
100 return Uuid::fromBytes($p1 . $p2);
101 }
102
103 public static function putUUID(ByteBufferWriter $out, UuidInterface $uuid) : void{
104 $bytes = $uuid->getBytes();
105 $out->writeByteArray(strrev(substr($bytes, 0, 8)));
106 $out->writeByteArray(strrev(substr($bytes, 8, 8)));
107 }
108
110 public static function getSkin(ByteBufferReader $in) : SkinData{
111 $skinId = self::getString($in);
112 $skinPlayFabId = self::getString($in);
113 $skinResourcePatch = self::getString($in);
114 $skinData = self::getSkinImage($in);
115 $animationCount = LE::readUnsignedInt($in);
116 $animations = [];
117 for($i = 0; $i < $animationCount; ++$i){
118 $skinImage = self::getSkinImage($in);
119 $animationType = LE::readUnsignedInt($in);
120 $animationFrames = LE::readFloat($in);
121 $expressionType = LE::readUnsignedInt($in);
122 $animations[] = new SkinAnimation($skinImage, $animationType, $animationFrames, $expressionType);
123 }
124 $capeData = self::getSkinImage($in);
125 $geometryData = self::getString($in);
126 $geometryDataVersion = self::getString($in);
127 $animationData = self::getString($in);
128 $capeId = self::getString($in);
129 $fullSkinId = self::getString($in);
130 $armSize = self::getString($in);
131 $skinColor = self::getString($in);
132 $personaPieceCount = LE::readUnsignedInt($in);
133 $personaPieces = [];
134 for($i = 0; $i < $personaPieceCount; ++$i){
135 $pieceId = self::getString($in);
136 $pieceType = self::getString($in);
137 $packId = self::getString($in);
138 $isDefaultPiece = self::getBool($in);
139 $productId = self::getString($in);
140 $personaPieces[] = new PersonaSkinPiece($pieceId, $pieceType, $packId, $isDefaultPiece, $productId);
141 }
142 $pieceTintColorCount = LE::readUnsignedInt($in);
143 $pieceTintColors = [];
144 for($i = 0; $i < $pieceTintColorCount; ++$i){
145 $pieceType = self::getString($in);
146 $colorCount = LE::readUnsignedInt($in);
147 $colors = [];
148 for($j = 0; $j < $colorCount; ++$j){
149 $colors[] = self::getString($in);
150 }
151 $pieceTintColors[] = new PersonaPieceTintColor(
152 $pieceType,
153 $colors
154 );
155 }
156
157 $premium = self::getBool($in);
158 $persona = self::getBool($in);
159 $capeOnClassic = self::getBool($in);
160 $isPrimaryUser = self::getBool($in);
161 $override = self::getBool($in);
162
163 return new SkinData(
164 $skinId,
165 $skinPlayFabId,
166 $skinResourcePatch,
167 $skinData,
168 $animations,
169 $capeData,
170 $geometryData,
171 $geometryDataVersion,
172 $animationData,
173 $capeId,
174 $fullSkinId,
175 $armSize,
176 $skinColor,
177 $personaPieces,
178 $pieceTintColors,
179 true,
180 $premium,
181 $persona,
182 $capeOnClassic,
183 $isPrimaryUser,
184 $override,
185 );
186 }
187
188 public static function putSkin(ByteBufferWriter $out, SkinData $skin) : void{
189 self::putString($out, $skin->getSkinId());
190 self::putString($out, $skin->getPlayFabId());
191 self::putString($out, $skin->getResourcePatch());
192 self::putSkinImage($out, $skin->getSkinImage());
193 LE::writeUnsignedInt($out, count($skin->getAnimations()));
194 foreach($skin->getAnimations() as $animation){
195 self::putSkinImage($out, $animation->getImage());
196 LE::writeUnsignedInt($out, $animation->getType());
197 LE::writeFloat($out, $animation->getFrames());
198 LE::writeUnsignedInt($out, $animation->getExpressionType());
199 }
200 self::putSkinImage($out, $skin->getCapeImage());
201 self::putString($out, $skin->getGeometryData());
202 self::putString($out, $skin->getGeometryDataEngineVersion());
203 self::putString($out, $skin->getAnimationData());
204 self::putString($out, $skin->getCapeId());
205 self::putString($out, $skin->getFullSkinId());
206 self::putString($out, $skin->getArmSize());
207 self::putString($out, $skin->getSkinColor());
208 LE::writeUnsignedInt($out, count($skin->getPersonaPieces()));
209 foreach($skin->getPersonaPieces() as $piece){
210 self::putString($out, $piece->getPieceId());
211 self::putString($out, $piece->getPieceType());
212 self::putString($out, $piece->getPackId());
213 self::putBool($out, $piece->isDefaultPiece());
214 self::putString($out, $piece->getProductId());
215 }
216 LE::writeUnsignedInt($out, count($skin->getPieceTintColors()));
217 foreach($skin->getPieceTintColors() as $tint){
218 self::putString($out, $tint->getPieceType());
219 LE::writeUnsignedInt($out, count($tint->getColors()));
220 foreach($tint->getColors() as $color){
221 self::putString($out, $color);
222 }
223 }
224 self::putBool($out, $skin->isPremium());
225 self::putBool($out, $skin->isPersona());
226 self::putBool($out, $skin->isPersonaCapeOnClassic());
227 self::putBool($out, $skin->isPrimaryUser());
228 self::putBool($out, $skin->isOverride());
229 }
230
232 private static function getSkinImage(ByteBufferReader $in) : SkinImage{
233 $width = LE::readUnsignedInt($in);
234 $height = LE::readUnsignedInt($in);
235 $data = self::getString($in);
236 try{
237 return new SkinImage($height, $width, $data);
238 }catch(\InvalidArgumentException $e){
239 throw new PacketDecodeException($e->getMessage(), 0, $e);
240 }
241 }
242
243 private static function putSkinImage(ByteBufferWriter $out, SkinImage $image) : void{
244 LE::writeUnsignedInt($out, $image->getWidth());
245 LE::writeUnsignedInt($out, $image->getHeight());
246 self::putString($out, $image->getData());
247 }
248
254 private static function getItemStackHeader(ByteBufferReader $in) : array{
255 $id = VarInt::readSignedInt($in);
256 if($id === 0){
257 return [0, 0, 0];
258 }
259
260 $count = LE::readUnsignedShort($in);
261 $meta = VarInt::readUnsignedInt($in);
262
263 return [$id, $count, $meta];
264 }
265
266 private static function putItemStackHeader(ByteBufferWriter $out, ItemStack $itemStack) : bool{
267 if($itemStack->getId() === 0){
268 VarInt::writeSignedInt($out, 0);
269 return false;
270 }
271
272 VarInt::writeSignedInt($out, $itemStack->getId());
273 LE::writeUnsignedShort($out, $itemStack->getCount());
274 VarInt::writeUnsignedInt($out, $itemStack->getMeta());
275
276 return true;
277 }
278
280 private static function getItemStackFooter(ByteBufferReader $in, int $id, int $meta, int $count) : ItemStack{
281 $blockRuntimeId = VarInt::readSignedInt($in);
282 $rawExtraData = self::getString($in);
283
284 return new ItemStack($id, $meta, $count, $blockRuntimeId, $rawExtraData);
285 }
286
287 private static function putItemStackFooter(ByteBufferWriter $out, ItemStack $itemStack) : void{
288 VarInt::writeSignedInt($out, $itemStack->getBlockRuntimeId());
289 self::putString($out, $itemStack->getRawExtraData());
290 }
291
296 public static function getItemStackWithoutStackId(ByteBufferReader $in) : ItemStack{
297 [$id, $count, $meta] = self::getItemStackHeader($in);
298
299 return $id !== 0 ? self::getItemStackFooter($in, $id, $meta, $count) : ItemStack::null();
300
301 }
302
303 public static function putItemStackWithoutStackId(ByteBufferWriter $out, ItemStack $itemStack) : void{
304 if(self::putItemStackHeader($out, $itemStack)){
305 self::putItemStackFooter($out, $itemStack);
306 }
307 }
308
310 public static function getItemStackWrapper(ByteBufferReader $in) : ItemStackWrapper{
311 [$id, $count, $meta] = self::getItemStackHeader($in);
312 if($id === 0){
313 return new ItemStackWrapper(0, ItemStack::null());
314 }
315
316 $hasNetId = self::getBool($in);
317 $stackId = $hasNetId ? self::readServerItemStackId($in) : 0;
318
319 $itemStack = self::getItemStackFooter($in, $id, $meta, $count);
320
321 return new ItemStackWrapper($stackId, $itemStack);
322 }
323
324 public static function putItemStackWrapper(ByteBufferWriter $out, ItemStackWrapper $itemStackWrapper) : void{
325 $itemStack = $itemStackWrapper->getItemStack();
326 if(self::putItemStackHeader($out, $itemStack)){
327 $hasNetId = $itemStackWrapper->getStackId() !== 0;
328 self::putBool($out, $hasNetId);
329 if($hasNetId){
330 self::writeServerItemStackId($out, $itemStackWrapper->getStackId());
331 }
332
333 self::putItemStackFooter($out, $itemStack);
334 }
335 }
336
338 public static function getRecipeIngredient(ByteBufferReader $in) : RecipeIngredient{
339 $descriptorType = Byte::readUnsigned($in);
340 $descriptor = match($descriptorType){
341 ItemDescriptorType::INT_ID_META => IntIdMetaItemDescriptor::read($in),
342 ItemDescriptorType::STRING_ID_META => StringIdMetaItemDescriptor::read($in),
343 ItemDescriptorType::TAG => TagItemDescriptor::read($in),
344 ItemDescriptorType::MOLANG => MolangItemDescriptor::read($in),
345 ItemDescriptorType::COMPLEX_ALIAS => ComplexAliasItemDescriptor::read($in),
346 default => null
347 };
348 $count = VarInt::readSignedInt($in);
349
350 return new RecipeIngredient($descriptor, $count);
351 }
352
353 public static function putRecipeIngredient(ByteBufferWriter $out, RecipeIngredient $ingredient) : void{
354 $type = $ingredient->getDescriptor();
355
356 Byte::writeUnsigned($out, $type?->getTypeId() ?? 0);
357 $type?->write($out);
358
359 VarInt::writeSignedInt($out, $ingredient->getCount());
360 }
361
371 public static function getEntityMetadata(ByteBufferReader $in) : array{
372 $count = VarInt::readUnsignedInt($in);
373 $data = [];
374 for($i = 0; $i < $count; ++$i){
375 $key = VarInt::readUnsignedInt($in);
376 $type = VarInt::readUnsignedInt($in);
377
378 $data[$key] = self::readMetadataProperty($in, $type);
379 }
380
381 return $data;
382 }
383
385 private static function readMetadataProperty(ByteBufferReader $in, int $type) : MetadataProperty{
386 return match($type){
387 ByteMetadataProperty::ID => ByteMetadataProperty::read($in),
388 ShortMetadataProperty::ID => ShortMetadataProperty::read($in),
389 IntMetadataProperty::ID => IntMetadataProperty::read($in),
390 FloatMetadataProperty::ID => FloatMetadataProperty::read($in),
391 StringMetadataProperty::ID => StringMetadataProperty::read($in),
392 CompoundTagMetadataProperty::ID => CompoundTagMetadataProperty::read($in),
393 BlockPosMetadataProperty::ID => BlockPosMetadataProperty::read($in),
394 LongMetadataProperty::ID => LongMetadataProperty::read($in),
395 Vec3MetadataProperty::ID => Vec3MetadataProperty::read($in),
396 default => throw new PacketDecodeException("Unknown entity metadata type " . $type),
397 };
398 }
399
407 public static function putEntityMetadata(ByteBufferWriter $out, array $metadata) : void{
408 VarInt::writeUnsignedInt($out, count($metadata));
409 foreach($metadata as $key => $d){
410 VarInt::writeUnsignedInt($out, $key);
411 VarInt::writeUnsignedInt($out, $d->getTypeId());
412 $d->write($out);
413 }
414 }
415
417 public static function getActorUniqueId(ByteBufferReader $in) : int{
418 return VarInt::readSignedLong($in);
419 }
420
421 public static function putActorUniqueId(ByteBufferWriter $out, int $eid) : void{
422 VarInt::writeSignedLong($out, $eid);
423 }
424
426 public static function getActorRuntimeId(ByteBufferReader $in) : int{
427 return VarInt::readUnsignedLong($in);
428 }
429
430 public static function putActorRuntimeId(ByteBufferWriter $out, int $eid) : void{
431 VarInt::writeUnsignedLong($out, $eid);
432 }
433
439 public static function getBlockPosition(ByteBufferReader $in) : BlockPosition{
440 $x = VarInt::readSignedInt($in);
441 $y = Binary::signInt(VarInt::readUnsignedInt($in)); //Y coordinate may be signed, but it's written unsigned :<
442 $z = VarInt::readSignedInt($in);
443 return new BlockPosition($x, $y, $z);
444 }
445
449 public static function putBlockPosition(ByteBufferWriter $out, BlockPosition $blockPosition) : void{
450 VarInt::writeSignedInt($out, $blockPosition->getX());
451 VarInt::writeUnsignedInt($out, Binary::unsignInt($blockPosition->getY())); //Y coordinate may be signed, but it's written unsigned :<
452 VarInt::writeSignedInt($out, $blockPosition->getZ());
453 }
454
460 public static function getSignedBlockPosition(ByteBufferReader $in) : BlockPosition{
461 $x = VarInt::readSignedInt($in);
462 $y = VarInt::readSignedInt($in);
463 $z = VarInt::readSignedInt($in);
464 return new BlockPosition($x, $y, $z);
465 }
466
470 public static function putSignedBlockPosition(ByteBufferWriter $out, BlockPosition $blockPosition) : void{
471 VarInt::writeSignedInt($out, $blockPosition->getX());
472 VarInt::writeSignedInt($out, $blockPosition->getY());
473 VarInt::writeSignedInt($out, $blockPosition->getZ());
474 }
475
481 public static function getVector3(ByteBufferReader $in) : Vector3{
482 $x = LE::readFloat($in);
483 $y = LE::readFloat($in);
484 $z = LE::readFloat($in);
485 return new Vector3($x, $y, $z);
486 }
487
493 public static function getVector2(ByteBufferReader $in) : Vector2{
494 $x = LE::readFloat($in);
495 $y = LE::readFloat($in);
496 return new Vector2($x, $y);
497 }
498
507 public static function putVector3Nullable(ByteBufferWriter $out, ?Vector3 $vector) : void{
508 if($vector !== null){
509 self::putVector3($out, $vector);
510 }else{
511 LE::writeFloat($out, 0.0);
512 LE::writeFloat($out, 0.0);
513 LE::writeFloat($out, 0.0);
514 }
515 }
516
520 public static function putVector3(ByteBufferWriter $out, Vector3 $vector) : void{
521 LE::writeFloat($out, $vector->x);
522 LE::writeFloat($out, $vector->y);
523 LE::writeFloat($out, $vector->z);
524 }
525
529 public static function putVector2(ByteBufferWriter $out, Vector2 $vector2) : void{
530 LE::writeFloat($out, $vector2->x);
531 LE::writeFloat($out, $vector2->y);
532 }
533
535 public static function getRotationByte(ByteBufferReader $in) : float{
536 return Byte::readUnsigned($in) * (360 / 256);
537 }
538
539 public static function putRotationByte(ByteBufferWriter $out, float $rotation) : void{
540 Byte::writeUnsigned($out, (int) ($rotation / (360 / 256)));
541 }
542
544 private static function readGameRule(ByteBufferReader $in, int $type, bool $isPlayerModifiable, bool $isStartGame) : GameRule{
545 return match($type){
546 BoolGameRule::ID => BoolGameRule::decode($in, $isPlayerModifiable),
547 IntGameRule::ID => IntGameRule::decode($in, $isPlayerModifiable, $isStartGame),
548 FloatGameRule::ID => FloatGameRule::decode($in, $isPlayerModifiable),
549 default => throw new PacketDecodeException("Unknown gamerule type $type"),
550 };
551 }
552
562 public static function getGameRules(ByteBufferReader $in, bool $isStartGame) : array{
563 $count = VarInt::readUnsignedInt($in);
564 $rules = [];
565 for($i = 0; $i < $count; ++$i){
566 $name = self::getString($in);
567 $isPlayerModifiable = self::getBool($in);
568 $type = VarInt::readUnsignedInt($in);
569 $rules[$name] = self::readGameRule($in, $type, $isPlayerModifiable, $isStartGame);
570 }
571
572 return $rules;
573 }
574
581 public static function putGameRules(ByteBufferWriter $out, array $rules, bool $isStartGame) : void{
582 VarInt::writeUnsignedInt($out, count($rules));
583 foreach($rules as $name => $rule){
584 self::putString($out, $name);
585 self::putBool($out, $rule->isPlayerModifiable());
586 VarInt::writeUnsignedInt($out, $rule->getTypeId());
587 $rule->encode($out, $isStartGame);
588 }
589 }
590
592 public static function getEntityLink(ByteBufferReader $in) : EntityLink{
593 $fromActorUniqueId = self::getActorUniqueId($in);
594 $toActorUniqueId = self::getActorUniqueId($in);
595 $type = Byte::readUnsigned($in);
596 $immediate = self::getBool($in);
597 $causedByRider = self::getBool($in);
598 $vehicleAngularVelocity = LE::readFloat($in);
599 return new EntityLink($fromActorUniqueId, $toActorUniqueId, $type, $immediate, $causedByRider, $vehicleAngularVelocity);
600 }
601
602 public static function putEntityLink(ByteBufferWriter $out, EntityLink $link) : void{
603 self::putActorUniqueId($out, $link->fromActorUniqueId);
604 self::putActorUniqueId($out, $link->toActorUniqueId);
605 Byte::writeUnsigned($out, $link->type);
606 self::putBool($out, $link->immediate);
607 self::putBool($out, $link->causedByRider);
608 LE::writeFloat($out, $link->vehicleAngularVelocity);
609 }
610
612 public static function getCommandOriginData(ByteBufferReader $in) : CommandOriginData{
613 $result = new CommandOriginData();
614
615 $result->type = VarInt::readUnsignedInt($in);
616 $result->uuid = self::getUUID($in);
617 $result->requestId = self::getString($in);
618
619 if($result->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $result->type === CommandOriginData::ORIGIN_TEST){
620 $result->playerActorUniqueId = VarInt::readSignedLong($in);
621 }
622
623 return $result;
624 }
625
626 public static function putCommandOriginData(ByteBufferWriter $out, CommandOriginData $data) : void{
627 VarInt::writeUnsignedInt($out, $data->type);
628 self::putUUID($out, $data->uuid);
629 self::putString($out, $data->requestId);
630
631 if($data->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $data->type === CommandOriginData::ORIGIN_TEST){
632 VarInt::writeSignedLong($out, $data->playerActorUniqueId);
633 }
634 }
635
637 public static function getStructureSettings(ByteBufferReader $in) : StructureSettings{
638 $result = new StructureSettings();
639
640 $result->paletteName = self::getString($in);
641
642 $result->ignoreEntities = self::getBool($in);
643 $result->ignoreBlocks = self::getBool($in);
644 $result->allowNonTickingChunks = self::getBool($in);
645
646 $result->dimensions = self::getBlockPosition($in);
647 $result->offset = self::getBlockPosition($in);
648
649 $result->lastTouchedByPlayerID = self::getActorUniqueId($in);
650 $result->rotation = Byte::readUnsigned($in);
651 $result->mirror = Byte::readUnsigned($in);
652 $result->animationMode = Byte::readUnsigned($in);
653 $result->animationSeconds = LE::readFloat($in);
654 $result->integrityValue = LE::readFloat($in);
655 $result->integritySeed = LE::readUnsignedInt($in);
656 $result->pivot = self::getVector3($in);
657
658 return $result;
659 }
660
661 public static function putStructureSettings(ByteBufferWriter $out, StructureSettings $structureSettings) : void{
662 self::putString($out, $structureSettings->paletteName);
663
664 self::putBool($out, $structureSettings->ignoreEntities);
665 self::putBool($out, $structureSettings->ignoreBlocks);
666 self::putBool($out, $structureSettings->allowNonTickingChunks);
667
668 self::putBlockPosition($out, $structureSettings->dimensions);
669 self::putBlockPosition($out, $structureSettings->offset);
670
671 self::putActorUniqueId($out, $structureSettings->lastTouchedByPlayerID);
672 Byte::writeUnsigned($out, $structureSettings->rotation);
673 Byte::writeUnsigned($out, $structureSettings->mirror);
674 Byte::writeUnsigned($out, $structureSettings->animationMode);
675 LE::writeFloat($out, $structureSettings->animationSeconds);
676 LE::writeFloat($out, $structureSettings->integrityValue);
677 LE::writeUnsignedInt($out, $structureSettings->integritySeed);
678 self::putVector3($out, $structureSettings->pivot);
679 }
680
682 public static function getStructureEditorData(ByteBufferReader $in) : StructureEditorData{
683 $result = new StructureEditorData();
684
685 $result->structureName = self::getString($in);
686 $result->filteredStructureName = self::getString($in);
687 $result->structureDataField = self::getString($in);
688
689 $result->includePlayers = self::getBool($in);
690 $result->showBoundingBox = self::getBool($in);
691
692 $result->structureBlockType = VarInt::readSignedInt($in);
693 $result->structureSettings = self::getStructureSettings($in);
694 $result->structureRedstoneSaveMode = VarInt::readSignedInt($in);
695
696 return $result;
697 }
698
699 public static function putStructureEditorData(ByteBufferWriter $out, StructureEditorData $structureEditorData) : void{
700 self::putString($out, $structureEditorData->structureName);
701 self::putString($out, $structureEditorData->filteredStructureName);
702 self::putString($out, $structureEditorData->structureDataField);
703
704 self::putBool($out, $structureEditorData->includePlayers);
705 self::putBool($out, $structureEditorData->showBoundingBox);
706
707 VarInt::writeSignedInt($out, $structureEditorData->structureBlockType);
708 self::putStructureSettings($out, $structureEditorData->structureSettings);
709 VarInt::writeSignedInt($out, $structureEditorData->structureRedstoneSaveMode);
710 }
711
713 public static function getNbtRoot(ByteBufferReader $in) : TreeRoot{
714 $offset = $in->getOffset();
715 try{
716 return (new NetworkNbtSerializer())->read($in->getData(), $offset, 512);
717 }catch(NbtDataException $e){
718 throw PacketDecodeException::wrap($e, "Failed decoding NBT root");
719 }finally{
720 $in->setOffset($offset);
721 }
722 }
723
724 public static function getNbtCompoundRoot(ByteBufferReader $in) : CompoundTag{
725 try{
726 return self::getNbtRoot($in)->mustGetCompoundTag();
727 }catch(NbtDataException $e){
728 throw PacketDecodeException::wrap($e, "Expected TAG_Compound NBT root");
729 }
730 }
731
733 public static function readRecipeNetId(ByteBufferReader $in) : int{
734 return VarInt::readUnsignedInt($in);
735 }
736
737 public static function writeRecipeNetId(ByteBufferWriter $out, int $id) : void{
738 VarInt::writeUnsignedInt($out, $id);
739 }
740
742 public static function readCreativeItemNetId(ByteBufferReader $in) : int{
743 return VarInt::readUnsignedInt($in);
744 }
745
746 public static function writeCreativeItemNetId(ByteBufferWriter $out, int $id) : void{
747 VarInt::writeUnsignedInt($out, $id);
748 }
749
762 public static function readItemStackNetIdVariant(ByteBufferReader $in) : int{
763 return VarInt::readSignedInt($in);
764 }
765
771 public static function writeItemStackNetIdVariant(ByteBufferWriter $out, int $id) : void{
772 VarInt::writeSignedInt($out, $id);
773 }
774
776 public static function readItemStackRequestId(ByteBufferReader $in) : int{
777 return VarInt::readSignedInt($in);
778 }
779
780 public static function writeItemStackRequestId(ByteBufferWriter $out, int $id) : void{
781 VarInt::writeSignedInt($out, $id);
782 }
783
785 public static function readLegacyItemStackRequestId(ByteBufferReader $in) : int{
786 return VarInt::readSignedInt($in);
787 }
788
789 public static function writeLegacyItemStackRequestId(ByteBufferWriter $out, int $id) : void{
790 VarInt::writeSignedInt($out, $id);
791 }
792
794 public static function readServerItemStackId(ByteBufferReader $in) : int{
795 return VarInt::readSignedInt($in);
796 }
797
798 public static function writeServerItemStackId(ByteBufferWriter $out, int $id) : void{
799 VarInt::writeSignedInt($out, $id);
800 }
801
808 public static function readOptional(ByteBufferReader $in, \Closure $reader) : mixed{
809 if(self::getBool($in)){
810 return $reader($in);
811 }
812 return null;
813 }
814
820 public static function writeOptional(ByteBufferWriter $out, mixed $value, \Closure $writer) : void{
821 if($value !== null){
822 self::putBool($out, true);
823 $writer($out, $value);
824 }else{
825 self::putBool($out, false);
826 }
827 }
828}
static putVector3Nullable(ByteBufferWriter $out, ?Vector3 $vector)
static readOptional(ByteBufferReader $in, \Closure $reader)
static writeItemStackNetIdVariant(ByteBufferWriter $out, int $id)
static putGameRules(ByteBufferWriter $out, array $rules, bool $isStartGame)
static putSignedBlockPosition(ByteBufferWriter $out, BlockPosition $blockPosition)
static putVector2(ByteBufferWriter $out, Vector2 $vector2)
static getGameRules(ByteBufferReader $in, bool $isStartGame)
static writeOptional(ByteBufferWriter $out, mixed $value, \Closure $writer)
static putEntityMetadata(ByteBufferWriter $out, array $metadata)
static putBlockPosition(ByteBufferWriter $out, BlockPosition $blockPosition)
static putVector3(ByteBufferWriter $out, Vector3 $vector)