72    private function __construct(){
 
   77    public static function getString(ByteBufferReader $in) : string{
 
   78        return $in->readByteArray(VarInt::readUnsignedInt($in));
 
 
   81    public static function putString(ByteBufferWriter $out, 
string $v) : void{
 
   82        VarInt::writeUnsignedInt($out, strlen($v));
 
   83        $out->writeByteArray($v);
 
   87    public static function getBool(ByteBufferReader $in) : bool{
 
   88        return Byte::readUnsigned($in) !== 0;
 
 
   91    public static function putBool(ByteBufferWriter $out, 
bool $v) : void{
 
   92        Byte::writeUnsigned($out, $v ? 1 : 0);
 
   96    public static function getUUID(ByteBufferReader $in) : UuidInterface{
 
   98        $p1 = strrev($in->readByteArray(8));
 
   99        $p2 = strrev($in->readByteArray(8));
 
  100        return Uuid::fromBytes($p1 . $p2);
 
 
  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)));
 
  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);
 
  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);
 
  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);
 
  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);
 
  142        $pieceTintColorCount = LE::readUnsignedInt($in);
 
  143        $pieceTintColors = [];
 
  144        for($i = 0; $i < $pieceTintColorCount; ++$i){
 
  145            $pieceType = self::getString($in);
 
  146            $colorCount = LE::readUnsignedInt($in);
 
  148            for($j = 0; $j < $colorCount; ++$j){
 
  149                $colors[] = self::getString($in);
 
  151            $pieceTintColors[] = 
new PersonaPieceTintColor(
 
  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);
 
  171            $geometryDataVersion,
 
 
  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());
 
  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());
 
  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);
 
  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());
 
  232    private static function getSkinImage(ByteBufferReader $in) : SkinImage{
 
  233        $width = LE::readUnsignedInt($in);
 
  234        $height = LE::readUnsignedInt($in);
 
  235        $data = self::getString($in);
 
  237            return new SkinImage($height, $width, $data);
 
  238        }
catch(\InvalidArgumentException $e){
 
  239            throw new PacketDecodeException($e->getMessage(), 0, $e);
 
  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());
 
  254    private static function getItemStackHeader(ByteBufferReader $in) : array{
 
  255        $id = VarInt::readSignedInt($in);
 
  260        $count = LE::readUnsignedShort($in);
 
  261        $meta = VarInt::readUnsignedInt($in);
 
  263        return [$id, $count, $meta];
 
  266    private static function putItemStackHeader(ByteBufferWriter $out, ItemStack $itemStack) : bool{
 
  267        if($itemStack->getId() === 0){
 
  268            VarInt::writeSignedInt($out, 0);
 
  272        VarInt::writeSignedInt($out, $itemStack->getId());
 
  273        LE::writeUnsignedShort($out, $itemStack->getCount());
 
  274        VarInt::writeUnsignedInt($out, $itemStack->getMeta());
 
  280    private static function getItemStackFooter(ByteBufferReader $in, 
int $id, 
int $meta, 
int $count) : ItemStack{
 
  281        $blockRuntimeId = VarInt::readSignedInt($in);
 
  282        $rawExtraData = self::getString($in);
 
  284        return new ItemStack($id, $meta, $count, $blockRuntimeId, $rawExtraData);
 
  287    private static function putItemStackFooter(ByteBufferWriter $out, ItemStack $itemStack) : void{
 
  288        VarInt::writeSignedInt($out, $itemStack->getBlockRuntimeId());
 
  289        self::putString($out, $itemStack->getRawExtraData());
 
  297        [$id, $count, $meta] = self::getItemStackHeader($in);
 
  299        return $id !== 0 ? self::getItemStackFooter($in, $id, $meta, $count) : 
ItemStack::null();
 
 
  303    public static function putItemStackWithoutStackId(ByteBufferWriter $out, 
ItemStack $itemStack) : void{
 
  304        if(self::putItemStackHeader($out, $itemStack)){
 
  305            self::putItemStackFooter($out, $itemStack);
 
  311        [$id, $count, $meta] = self::getItemStackHeader($in);
 
  316        $hasNetId = self::getBool($in);
 
  317        $stackId = $hasNetId ? self::readServerItemStackId($in) : 0;
 
  319        $itemStack = self::getItemStackFooter($in, $id, $meta, $count);
 
 
  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);
 
  330                self::writeServerItemStackId($out, $itemStackWrapper->getStackId());
 
  333            self::putItemStackFooter($out, $itemStack);
 
  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),
 
  348        $count = VarInt::readSignedInt($in);
 
 
  353    public static function putRecipeIngredient(ByteBufferWriter $out, RecipeIngredient $ingredient) : void{
 
  354        $type = $ingredient->getDescriptor();
 
  356        Byte::writeUnsigned($out, $type?->getTypeId() ?? 0);
 
  359        VarInt::writeSignedInt($out, $ingredient->getCount());
 
  372        $count = VarInt::readUnsignedInt($in);
 
  374        for($i = 0; $i < $count; ++$i){
 
  375            $key = VarInt::readUnsignedInt($in);
 
  376            $type = VarInt::readUnsignedInt($in);
 
  378            $data[$key] = self::readMetadataProperty($in, $type);
 
 
  385    private static function readMetadataProperty(ByteBufferReader $in, 
int $type) : 
MetadataProperty{
 
  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),
 
  408        VarInt::writeUnsignedInt($out, count($metadata));
 
  409        foreach($metadata as $key => $d){
 
  410            VarInt::writeUnsignedInt($out, $key);
 
  411            VarInt::writeUnsignedInt($out, $d->getTypeId());
 
 
  418        return VarInt::readSignedLong($in);
 
 
  421    public static function putActorUniqueId(ByteBufferWriter $out, 
int $eid) : void{
 
  422        VarInt::writeSignedLong($out, $eid);
 
  427        return VarInt::readUnsignedLong($in);
 
 
  430    public static function putActorRuntimeId(ByteBufferWriter $out, 
int $eid) : void{
 
  431        VarInt::writeUnsignedLong($out, $eid);
 
  440        $x = VarInt::readSignedInt($in);
 
  441        $y = Binary::signInt(VarInt::readUnsignedInt($in)); 
 
  442        $z = VarInt::readSignedInt($in);
 
 
  450        VarInt::writeSignedInt($out, $blockPosition->getX());
 
  451        VarInt::writeUnsignedInt($out, Binary::unsignInt($blockPosition->getY())); 
 
  452        VarInt::writeSignedInt($out, $blockPosition->getZ());
 
 
  461        $x = VarInt::readSignedInt($in);
 
  462        $y = VarInt::readSignedInt($in);
 
  463        $z = VarInt::readSignedInt($in);
 
 
  471        VarInt::writeSignedInt($out, $blockPosition->getX());
 
  472        VarInt::writeSignedInt($out, $blockPosition->getY());
 
  473        VarInt::writeSignedInt($out, $blockPosition->getZ());
 
 
  482        $x = LE::readFloat($in);
 
  483        $y = LE::readFloat($in);
 
  484        $z = LE::readFloat($in);
 
  485        return new Vector3($x, $y, $z);
 
 
  494        $x = LE::readFloat($in);
 
  495        $y = LE::readFloat($in);
 
 
  508        if($vector !== null){
 
  509            self::putVector3($out, $vector);
 
  511            LE::writeFloat($out, 0.0);
 
  512            LE::writeFloat($out, 0.0);
 
  513            LE::writeFloat($out, 0.0);
 
 
  521        LE::writeFloat($out, $vector->x);
 
  522        LE::writeFloat($out, $vector->y);
 
  523        LE::writeFloat($out, $vector->z);
 
 
  530        LE::writeFloat($out, $vector2->x);
 
  531        LE::writeFloat($out, $vector2->y);
 
 
  536        return Byte::readUnsigned($in) * (360 / 256);
 
 
  539    public static function putRotationByte(ByteBufferWriter $out, 
float $rotation) : void{
 
  540        Byte::writeUnsigned($out, (int) ($rotation / (360 / 256)));
 
  544    private static function readGameRule(ByteBufferReader $in, 
int $type, 
bool $isPlayerModifiable, 
bool $isStartGame) : 
GameRule{
 
  546            BoolGameRule::ID => BoolGameRule::decode($in, $isPlayerModifiable),
 
  547            IntGameRule::ID => IntGameRule::decode($in, $isPlayerModifiable, $isStartGame),
 
  548            FloatGameRule::ID => FloatGameRule::decode($in, $isPlayerModifiable),
 
  562    public static function getGameRules(ByteBufferReader $in, 
bool $isStartGame) : array{
 
  563        $count = VarInt::readUnsignedInt($in);
 
  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);
 
 
  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);
 
 
  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);
 
 
  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);
 
  615        $result->type = VarInt::readUnsignedInt($in);
 
  616        $result->uuid = self::getUUID($in);
 
  617        $result->requestId = self::getString($in);
 
  619        if($result->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $result->type === CommandOriginData::ORIGIN_TEST){
 
  620            $result->playerActorUniqueId = VarInt::readSignedLong($in);
 
 
  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);
 
  631        if($data->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $data->type === CommandOriginData::ORIGIN_TEST){
 
  632            VarInt::writeSignedLong($out, $data->playerActorUniqueId);
 
  640        $result->paletteName = self::getString($in);
 
  642        $result->ignoreEntities = self::getBool($in);
 
  643        $result->ignoreBlocks = self::getBool($in);
 
  644        $result->allowNonTickingChunks = self::getBool($in);
 
  646        $result->dimensions = self::getBlockPosition($in);
 
  647        $result->offset = self::getBlockPosition($in);
 
  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);
 
 
  661    public static function putStructureSettings(ByteBufferWriter $out, 
StructureSettings $structureSettings) : void{
 
  662        self::putString($out, $structureSettings->paletteName);
 
  664        self::putBool($out, $structureSettings->ignoreEntities);
 
  665        self::putBool($out, $structureSettings->ignoreBlocks);
 
  666        self::putBool($out, $structureSettings->allowNonTickingChunks);
 
  668        self::putBlockPosition($out, $structureSettings->dimensions);
 
  669        self::putBlockPosition($out, $structureSettings->offset);
 
  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);
 
  685        $result->structureName = self::getString($in);
 
  686        $result->filteredStructureName = self::getString($in);
 
  687        $result->structureDataField = self::getString($in);
 
  689        $result->includePlayers = self::getBool($in);
 
  690        $result->showBoundingBox = self::getBool($in);
 
  692        $result->structureBlockType = VarInt::readSignedInt($in);
 
  693        $result->structureSettings = self::getStructureSettings($in);
 
  694        $result->structureRedstoneSaveMode = VarInt::readSignedInt($in);
 
 
  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);
 
  704        self::putBool($out, $structureEditorData->includePlayers);
 
  705        self::putBool($out, $structureEditorData->showBoundingBox);
 
  707        VarInt::writeSignedInt($out, $structureEditorData->structureBlockType);
 
  708        self::putStructureSettings($out, $structureEditorData->structureSettings);
 
  709        VarInt::writeSignedInt($out, $structureEditorData->structureRedstoneSaveMode);
 
  714        $offset = $in->getOffset();
 
  718            throw PacketDecodeException::wrap($e, 
"Failed decoding NBT root");
 
  720            $in->setOffset($offset);
 
 
  724    public static function getNbtCompoundRoot(ByteBufferReader $in) : 
CompoundTag{
 
  726            return self::getNbtRoot($in)->mustGetCompoundTag();
 
  727        }
catch(NbtDataException $e){
 
  728            throw PacketDecodeException::wrap($e, 
"Expected TAG_Compound NBT root");
 
  734        return VarInt::readUnsignedInt($in);
 
 
  737    public static function writeRecipeNetId(ByteBufferWriter $out, 
int $id) : void{
 
  738        VarInt::writeUnsignedInt($out, $id);
 
  743        return VarInt::readUnsignedInt($in);
 
 
  746    public static function writeCreativeItemNetId(ByteBufferWriter $out, 
int $id) : void{
 
  747        VarInt::writeUnsignedInt($out, $id);
 
  763        return VarInt::readSignedInt($in);
 
 
  772        VarInt::writeSignedInt($out, $id);
 
 
  777        return VarInt::readSignedInt($in);
 
 
  780    public static function writeItemStackRequestId(ByteBufferWriter $out, 
int $id) : void{
 
  781        VarInt::writeSignedInt($out, $id);
 
  786        return VarInt::readSignedInt($in);
 
 
  789    public static function writeLegacyItemStackRequestId(ByteBufferWriter $out, 
int $id) : void{
 
  790        VarInt::writeSignedInt($out, $id);
 
  795        return VarInt::readSignedInt($in);
 
 
  798    public static function writeServerItemStackId(ByteBufferWriter $out, 
int $id) : void{
 
  799        VarInt::writeSignedInt($out, $id);
 
  808    public static function readOptional(ByteBufferReader $in, \Closure $reader) : mixed{
 
  809        if(self::getBool($in)){
 
 
  820    public static function writeOptional(ByteBufferWriter $out, mixed $value, \Closure $writer) : void{
 
  822            self::putBool($out, 
true);
 
  823            $writer($out, $value);
 
  825            self::putBool($out, 
false);