Skip to content

Commit

Permalink
Stop using closures to process itemstack extra data
Browse files Browse the repository at this point in the history
closes #223
  • Loading branch information
dktapps committed Feb 16, 2024
1 parent bd21347 commit d38eb07
Showing 1 changed file with 80 additions and 69 deletions.
149 changes: 80 additions & 69 deletions src/serializer/PacketSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,86 +280,97 @@ private function putItemStackHeader(ItemStack $itemStack) : bool{
return true;
}

private function getItemStackFooter(int $id, int $meta, int $count) : ItemStack{
$blockRuntimeId = $this->getVarInt();
$extraData = self::decoder($this->getString(), 0, $this->context);
return (static function() use ($extraData, $id, $meta, $count, $blockRuntimeId) : ItemStack{
$nbtLen = $extraData->getLShort();

/** @var CompoundTag|null $compound */
$compound = null;
if($nbtLen === 0xffff){
$nbtDataVersion = $extraData->getByte();
if($nbtDataVersion !== 1){
throw new PacketDecodeException("Unexpected NBT data version $nbtDataVersion");
}
$offset = $extraData->getOffset();
try{
$compound = (new LittleEndianNbtSerializer())->read($extraData->getBuffer(), $offset, 512)->mustGetCompoundTag();
}catch(NbtDataException $e){
throw PacketDecodeException::wrap($e, "Failed decoding NBT root");
}finally{
$extraData->setOffset($offset);
}
}elseif($nbtLen !== 0){
throw new PacketDecodeException("Unexpected fake NBT length $nbtLen");
/**
* @return CompoundTag[]|string[][]|int[]|null[]
*
* @phpstan-return array{?CompoundTag, string[], string[], ?int}
*/
private function deserializeItemStackExtraData(int $id) : array{
$nbtLen = $this->getLShort();

/** @var CompoundTag|null $compound */
$compound = null;
if($nbtLen === 0xffff){
$nbtDataVersion = $this->getByte();
if($nbtDataVersion !== 1){
throw new PacketDecodeException("Unexpected NBT data version $nbtDataVersion");
}

$canPlaceOn = [];
for($i = 0, $canPlaceOnCount = $extraData->getLInt(); $i < $canPlaceOnCount; ++$i){
$canPlaceOn[] = $extraData->get($extraData->getLShort());
$offset = $this->getOffset();
try{
$compound = (new LittleEndianNbtSerializer())->read($this->getBuffer(), $offset, 512)->mustGetCompoundTag();
}catch(NbtDataException $e){
throw PacketDecodeException::wrap($e, "Failed decoding NBT root");
}finally{
$this->setOffset($offset);
}
}elseif($nbtLen !== 0){
throw new PacketDecodeException("Unexpected fake NBT length $nbtLen");
}

$canDestroy = [];
for($i = 0, $canDestroyCount = $extraData->getLInt(); $i < $canDestroyCount; ++$i){
$canDestroy[] = $extraData->get($extraData->getLShort());
}
$canPlaceOn = [];
for($i = 0, $canPlaceOnCount = $this->getLInt(); $i < $canPlaceOnCount; ++$i){
$canPlaceOn[] = $this->get($this->getLShort());
}

$shieldBlockingTick = null;
if($id === $extraData->shieldItemRuntimeId){
$shieldBlockingTick = $extraData->getLLong();
}
$canDestroy = [];
for($i = 0, $canDestroyCount = $this->getLInt(); $i < $canDestroyCount; ++$i){
$canDestroy[] = $this->get($this->getLShort());
}

if(!$extraData->feof()){
throw new PacketDecodeException("Unexpected trailing extradata for network item $id");
}
$shieldBlockingTick = null;
if($id === $this->shieldItemRuntimeId){
$shieldBlockingTick = $this->getLLong();
}

return new ItemStack($id, $meta, $count, $blockRuntimeId, $compound, $canPlaceOn, $canDestroy, $shieldBlockingTick);
})();
if(!$this->feof()){
throw new PacketDecodeException("Unexpected trailing extradata for network item $id");
}

return [$compound, $canPlaceOn, $canDestroy, $shieldBlockingTick];
}

private function serializeItemStackExtraData(ItemStack $itemStack) : void{
$nbt = $itemStack->getNbt();
if($nbt !== null){
$this->putLShort(0xffff);
$this->putByte(1); //TODO: NBT data version (?)
$this->put((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)));
}else{
$this->putLShort(0);
}

$this->putLInt(count($itemStack->getCanPlaceOn()));
foreach($itemStack->getCanPlaceOn() as $entry){
$this->putLShort(strlen($entry));
$this->put($entry);
}
$this->putLInt(count($itemStack->getCanDestroy()));
foreach($itemStack->getCanDestroy() as $entry){
$this->putLShort(strlen($entry));
$this->put($entry);
}

$blockingTick = $itemStack->getShieldBlockingTick();
if($itemStack->getId() === $this->shieldItemRuntimeId){
$this->putLLong($blockingTick ?? 0);
}
}

private function getItemStackFooter(int $id, int $meta, int $count) : ItemStack{
$blockRuntimeId = $this->getVarInt();

$extraDataReader = self::decoder($this->getString(), 0, $this->context);
[$nbt, $canPlaceOn, $canDestroy, $shieldBlockingTick] = $extraDataReader->deserializeItemStackExtraData($id);

return new ItemStack($id, $meta, $count, $blockRuntimeId, $nbt, $canPlaceOn, $canDestroy, $shieldBlockingTick);
}

private function putItemStackFooter(ItemStack $itemStack) : void{
$this->putVarInt($itemStack->getBlockRuntimeId());
$context = $this->context;
$this->putString((static function() use ($itemStack, $context) : string{
$extraData = PacketSerializer::encoder($context);

$nbt = $itemStack->getNbt();
if($nbt !== null){
$extraData->putLShort(0xffff);
$extraData->putByte(1); //TODO: NBT data version (?)
$extraData->put((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)));
}else{
$extraData->putLShort(0);
}

$extraData->putLInt(count($itemStack->getCanPlaceOn()));
foreach($itemStack->getCanPlaceOn() as $entry){
$extraData->putLShort(strlen($entry));
$extraData->put($entry);
}
$extraData->putLInt(count($itemStack->getCanDestroy()));
foreach($itemStack->getCanDestroy() as $entry){
$extraData->putLShort(strlen($entry));
$extraData->put($entry);
}

$blockingTick = $itemStack->getShieldBlockingTick();
if($itemStack->getId() === $extraData->shieldItemRuntimeId){
$extraData->putLLong($blockingTick ?? 0);
}
return $extraData->getBuffer();
})());
$extraDataWriter = self::encoder($this->context);
$extraDataWriter->serializeItemStackExtraData($itemStack);
$this->putString($extraDataWriter->getBuffer());
}

/**
Expand Down

0 comments on commit d38eb07

Please sign in to comment.