Merge PR #1775: NBT streams refactor

This commit is contained in:
Dylan K. Taylor 2017-12-30 15:53:47 +00:00 committed by GitHub
commit 3ea72a0bf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 606 additions and 344 deletions

View File

@ -91,7 +91,7 @@ use pocketmine\level\WeakPosition;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\metadata\MetadataValue; use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\NBT; use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\DoubleTag;
@ -2834,8 +2834,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$t = $this->level->getTile($pos); $t = $this->level->getTile($pos);
if($t instanceof Spawnable){ if($t instanceof Spawnable){
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new NetworkLittleEndianNBTStream();
$nbt->read($packet->namedtag, false, true); $nbt->read($packet->namedtag);
$nbt = $nbt->getData(); $nbt = $nbt->getData();
if(!$t->updateCompoundTag($nbt, $this)){ if(!$t->updateCompoundTag($nbt, $this)){
$t->spawnTo($this); $t->spawnTo($this);

View File

@ -67,6 +67,7 @@ use pocketmine\level\LevelException;
use pocketmine\metadata\EntityMetadataStore; use pocketmine\metadata\EntityMetadataStore;
use pocketmine\metadata\LevelMetadataStore; use pocketmine\metadata\LevelMetadataStore;
use pocketmine\metadata\PlayerMetadataStore; use pocketmine\metadata\PlayerMetadataStore;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -749,7 +750,7 @@ class Server{
if($this->shouldSavePlayerData()){ if($this->shouldSavePlayerData()){
if(file_exists($path . "$name.dat")){ if(file_exists($path . "$name.dat")){
try{ try{
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
$nbt->readCompressed(file_get_contents($path . "$name.dat")); $nbt->readCompressed(file_get_contents($path . "$name.dat"));
return $nbt->getData(); return $nbt->getData();
@ -815,7 +816,7 @@ class Server{
$this->pluginManager->callEvent($ev); $this->pluginManager->callEvent($ev);
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
try{ try{
$nbt->setData($ev->getSaveData()); $nbt->setData($ev->getSaveData());

View File

@ -34,6 +34,7 @@ use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -64,7 +65,7 @@ class Item implements ItemIds, \JsonSerializable{
} }
if(self::$cachedParser === null){ if(self::$cachedParser === null){
self::$cachedParser = new NBT(NBT::LITTLE_ENDIAN); self::$cachedParser = new LittleEndianNBTStream();
} }
self::$cachedParser->read($tag); self::$cachedParser->read($tag);
@ -79,7 +80,7 @@ class Item implements ItemIds, \JsonSerializable{
private static function writeCompoundTag(CompoundTag $tag) : string{ private static function writeCompoundTag(CompoundTag $tag) : string{
if(self::$cachedParser === null){ if(self::$cachedParser === null){
self::$cachedParser = new NBT(NBT::LITTLE_ENDIAN); self::$cachedParser = new LittleEndianNBTStream();
} }
self::$cachedParser->setData($tag); self::$cachedParser->setData($tag);

View File

@ -29,7 +29,7 @@ use pocketmine\level\generator\Generator;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\LevelException; use pocketmine\level\LevelException;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\NBT; use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\scheduler\AsyncTask; use pocketmine\scheduler\AsyncTask;
@ -48,7 +48,7 @@ abstract class BaseLevelProvider implements LevelProvider{
if(!file_exists($this->path)){ if(!file_exists($this->path)){
mkdir($this->path, 0777, true); mkdir($this->path, 0777, true);
} }
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
$nbt->readCompressed(file_get_contents($this->getPath() . "level.dat")); $nbt->readCompressed(file_get_contents($this->getPath() . "level.dat"));
$levelData = $nbt->getData()->getCompoundTag("Data"); $levelData = $nbt->getData()->getCompoundTag("Data");
if($levelData !== null){ if($levelData !== null){
@ -120,7 +120,7 @@ abstract class BaseLevelProvider implements LevelProvider{
} }
public function saveLevelData(){ public function saveLevelData(){
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
$nbt->setData(new CompoundTag("", [ $nbt->setData(new CompoundTag("", [
$this->levelData $this->levelData
])); ]));

View File

@ -32,7 +32,7 @@ use pocketmine\level\generator\Flat;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\LevelException; use pocketmine\level\LevelException;
use pocketmine\nbt\NBT; use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\tag\{ use pocketmine\nbt\tag\{
ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag
}; };
@ -94,7 +94,7 @@ class LevelDB extends BaseLevelProvider{
if(!file_exists($this->path)){ if(!file_exists($this->path)){
mkdir($this->path, 0777, true); mkdir($this->path, 0777, true);
} }
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new LittleEndianNBTStream();
$nbt->read(substr(file_get_contents($this->getPath() . "level.dat"), 8)); $nbt->read(substr(file_get_contents($this->getPath() . "level.dat"), 8));
$levelData = $nbt->getData(); $levelData = $nbt->getData();
if($levelData instanceof CompoundTag){ if($levelData instanceof CompoundTag){
@ -217,7 +217,7 @@ class LevelDB extends BaseLevelProvider{
new StringTag("generatorOptions", $options["preset"] ?? "") new StringTag("generatorOptions", $options["preset"] ?? "")
]); ]);
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new LittleEndianNBTStream();
$nbt->setData($levelData); $nbt->setData($levelData);
$buffer = $nbt->write(); $buffer = $nbt->write();
file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
@ -247,7 +247,7 @@ class LevelDB extends BaseLevelProvider{
$this->levelData->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL); $this->levelData->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL);
$this->levelData->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION); $this->levelData->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION);
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new LittleEndianNBTStream();
$nbt->setData($this->levelData); $nbt->setData($this->levelData);
$buffer = $nbt->write(); $buffer = $nbt->write();
file_put_contents($this->getPath() . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); file_put_contents($this->getPath() . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer);
@ -416,7 +416,7 @@ class LevelDB extends BaseLevelProvider{
throw new UnsupportedChunkFormatException("don't know how to decode chunk format version $chunkVersion"); throw new UnsupportedChunkFormatException("don't know how to decode chunk format version $chunkVersion");
} }
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new LittleEndianNBTStream();
$entities = []; $entities = [];
if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and strlen($entityData) > 0){ if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and strlen($entityData) > 0){
@ -553,7 +553,7 @@ class LevelDB extends BaseLevelProvider{
*/ */
private function writeTags(array $targets, string $index){ private function writeTags(array $targets, string $index){
if(!empty($targets)){ if(!empty($targets)){
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new LittleEndianNBTStream();
$nbt->setData($targets); $nbt->setData($targets);
$this->db->put($index, $nbt->write()); $this->db->put($index, $nbt->write());
}else{ }else{

View File

@ -27,6 +27,7 @@ use pocketmine\level\format\Chunk;
use pocketmine\level\format\ChunkException; use pocketmine\level\format\ChunkException;
use pocketmine\level\format\io\ChunkUtils; use pocketmine\level\format\io\ChunkUtils;
use pocketmine\level\format\SubChunk; use pocketmine\level\format\SubChunk;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag; use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -83,7 +84,7 @@ class Anvil extends McRegion{
//TODO: TileTicks //TODO: TileTicks
$writer = new NBT(NBT::BIG_ENDIAN); $writer = new BigEndianNBTStream();
$nbt->setName("Level"); $nbt->setName("Level");
$writer->setData(new CompoundTag("", [$nbt])); $writer->setData(new CompoundTag("", [$nbt]));
@ -100,7 +101,7 @@ class Anvil extends McRegion{
} }
public function nbtDeserialize(string $data){ public function nbtDeserialize(string $data){
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
try{ try{
$nbt->readCompressed($data); $nbt->readCompressed($data);

View File

@ -30,6 +30,7 @@ use pocketmine\level\format\io\ChunkUtils;
use pocketmine\level\format\SubChunk; use pocketmine\level\format\SubChunk;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\{ use pocketmine\nbt\tag\{
ByteArrayTag, ByteTag, CompoundTag, IntArrayTag, IntTag, ListTag, LongTag, StringTag ByteArrayTag, ByteTag, CompoundTag, IntArrayTag, IntTag, ListTag, LongTag, StringTag
@ -102,7 +103,7 @@ class McRegion extends BaseLevelProvider{
$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound)); $nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));
$writer = new NBT(NBT::BIG_ENDIAN); $writer = new BigEndianNBTStream();
$nbt->setName("Level"); $nbt->setName("Level");
$writer->setData(new CompoundTag("", [$nbt])); $writer->setData(new CompoundTag("", [$nbt]));
@ -115,7 +116,7 @@ class McRegion extends BaseLevelProvider{
* @return Chunk|null * @return Chunk|null
*/ */
public function nbtDeserialize(string $data){ public function nbtDeserialize(string $data){
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
try{ try{
$nbt->readCompressed($data); $nbt->readCompressed($data);
@ -258,7 +259,7 @@ class McRegion extends BaseLevelProvider{
new StringTag("LevelName", $name), new StringTag("LevelName", $name),
new CompoundTag("GameRules", []) new CompoundTag("GameRules", [])
]); ]);
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new BigEndianNBTStream();
$nbt->setData(new CompoundTag("", [ $nbt->setData(new CompoundTag("", [
$levelData $levelData
])); ]));

View File

@ -0,0 +1,87 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\nbt;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
#include <rules/NBT.h>
class BigEndianNBTStream extends NBTStream{
public function getShort() : int{
return Binary::readShort($this->get(2));
}
public function getSignedShort() : int{
return Binary::readSignedShort($this->get(2));
}
public function putShort(int $v) : void{
$this->buffer .= Binary::writeShort($v);
}
public function getInt() : int{
return Binary::readInt($this->get(4));
}
public function putInt(int $v) : void{
$this->buffer .= Binary::writeInt($v);
}
public function getLong() : int{
return Binary::readLong($this->get(8));
}
public function putLong(int $v) : void{
$this->buffer .= Binary::writeLong($v);
}
public function getFloat() : float{
return Binary::readFloat($this->get(4));
}
public function putFloat(float $v) : void{
$this->buffer .= Binary::writeFloat($v);
}
public function getDouble() : float{
return Binary::readDouble($this->get(8));
}
public function putDouble(float $v) : void{
$this->buffer .= Binary::writeDouble($v);
}
public function getIntArray() : array{
$len = $this->getInt();
return array_values(unpack("N*", $this->get($len * 4)));
}
public function putIntArray(array $array) : void{
$this->putInt(count($array));
$this->put(pack("N*", ...$array));
}
}

View File

@ -0,0 +1,87 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\nbt;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
#include <rules/NBT.h>
class LittleEndianNBTStream extends NBTStream{
public function getShort() : int{
return Binary::readLShort($this->get(2));
}
public function getSignedShort() : int{
return Binary::readSignedLShort($this->get(2));
}
public function putShort(int $v) : void{
$this->put(Binary::writeLShort($v));
}
public function getInt() : int{
return Binary::readLInt($this->get(4));
}
public function putInt(int $v) : void{
$this->put(Binary::writeLInt($v));
}
public function getLong() : int{
return Binary::readLLong($this->get(8));
}
public function putLong(int $v) : void{
$this->put(Binary::writeLLong($v));
}
public function getFloat() : float{
return Binary::readLFloat($this->get(4));
}
public function putFloat(float $v) : void{
$this->put(Binary::writeLFloat($v));
}
public function getDouble() : float{
return Binary::readLDouble($this->get(8));
}
public function putDouble(float $v) : void{
$this->put(Binary::writeLDouble($v));
}
public function getIntArray() : array{
$len = $this->getInt();
return array_values(unpack("V*", $this->get($len * 4)));
}
public function putIntArray(array $array) : void{
$this->putInt(count($array));
$this->put(pack("V*", ...$array));
}
}

View File

@ -36,22 +36,11 @@ use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\LongTag; use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\Tag; use pocketmine\nbt\tag\Tag;
#ifndef COMPILE abstract class NBT{
use pocketmine\utils\Binary;
#endif
#include <rules/NBT.h>
/**
* Named Binary Tag encoder/decoder
*/
class NBT{
public const LITTLE_ENDIAN = 0; public const LITTLE_ENDIAN = 0;
public const BIG_ENDIAN = 1; public const BIG_ENDIAN = 1;
@ -68,17 +57,12 @@ class NBT{
public const TAG_Compound = 10; public const TAG_Compound = 10;
public const TAG_IntArray = 11; public const TAG_IntArray = 11;
public $buffer;
public $offset;
public $endianness;
private $data;
/** /**
* @param int $type * @param int $type
* *
* @return Tag * @return Tag
*/ */
public static function createTag(int $type){ public static function createTag(int $type) : Tag{
switch($type){ switch($type){
case self::TAG_End: case self::TAG_End:
return new EndTag(); return new EndTag();
@ -172,260 +156,4 @@ class NBT{
return true; return true;
} }
public function get($len){
if($len < 0){
$this->offset = strlen($this->buffer) - 1;
return "";
}elseif($len === true){
return substr($this->buffer, $this->offset);
}
return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len);
}
public function put($v){
$this->buffer .= $v;
}
public function feof() : bool{
return !isset($this->buffer{$this->offset});
}
public function __construct($endianness = self::LITTLE_ENDIAN){
$this->offset = 0;
$this->endianness = $endianness & 0x01;
}
public function read($buffer, $doMultiple = false, bool $network = false){
$this->offset = 0;
$this->buffer = $buffer;
$this->data = $this->readTag($network);
if($doMultiple and $this->offset < strlen($this->buffer)){
$this->data = [$this->data];
do{
$this->data[] = $this->readTag($network);
}while($this->offset < strlen($this->buffer));
}
$this->buffer = "";
}
public function readCompressed($buffer){
$this->read(zlib_decode($buffer));
}
/**
* @param bool $network
*
* @return string|bool
*/
public function write(bool $network = false){
$this->offset = 0;
$this->buffer = "";
if($this->data instanceof CompoundTag){
$this->writeTag($this->data, $network);
return $this->buffer;
}elseif(is_array($this->data)){
foreach($this->data as $tag){
$this->writeTag($tag, $network);
}
return $this->buffer;
}
return false;
}
public function writeCompressed($compression = ZLIB_ENCODING_GZIP, $level = 7){
if(($write = $this->write()) !== false){
return zlib_encode($write, $compression, $level);
}
return false;
}
public function readTag(bool $network = false){
if($this->feof()){
return new EndTag();
}
$tagType = $this->getByte();
$tag = self::createTag($tagType);
if($tag instanceof NamedTag){
$tag->setName($this->getString($network));
$tag->read($this, $network);
}
return $tag;
}
public function writeTag(Tag $tag, bool $network = false){
$this->putByte($tag->getType());
if($tag instanceof NamedTag){
$this->putString($tag->getName(), $network);
}
$tag->write($this, $network);
}
public function getByte() : int{
return Binary::readByte($this->get(1));
}
public function getSignedByte() : int{
return Binary::readSignedByte($this->get(1));
}
public function putByte($v){
$this->buffer .= Binary::writeByte($v);
}
public function getShort() : int{
return $this->endianness === self::BIG_ENDIAN ? Binary::readShort($this->get(2)) : Binary::readLShort($this->get(2));
}
public function getSignedShort() : int{
return $this->endianness === self::BIG_ENDIAN ? Binary::readSignedShort($this->get(2)) : Binary::readSignedLShort($this->get(2));
}
public function putShort($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeShort($v) : Binary::writeLShort($v);
}
public function getInt(bool $network = false) : int{
if($network === true){
return Binary::readVarInt($this->buffer, $this->offset);
}
return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4));
}
public function putInt($v, bool $network = false){
if($network === true){
$this->buffer .= Binary::writeVarInt($v);
}else{
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v);
}
}
public function getLong(bool $network = false) : int{
if($network){
return Binary::readVarLong($this->buffer, $this->offset);
}
return $this->endianness === self::BIG_ENDIAN ? Binary::readLong($this->get(8)) : Binary::readLLong($this->get(8));
}
public function putLong($v, bool $network = false){
if($network){
$this->buffer .= Binary::writeVarLong($v);
}else{
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeLong($v) : Binary::writeLLong($v);
}
}
public function getFloat() : float{
return $this->endianness === self::BIG_ENDIAN ? Binary::readFloat($this->get(4)) : Binary::readLFloat($this->get(4));
}
public function putFloat($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeFloat($v) : Binary::writeLFloat($v);
}
public function getDouble() : float{
return $this->endianness === self::BIG_ENDIAN ? Binary::readDouble($this->get(8)) : Binary::readLDouble($this->get(8));
}
public function putDouble($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeDouble($v) : Binary::writeLDouble($v);
}
public function getString(bool $network = false){
$len = $network ? Binary::readUnsignedVarInt($this->buffer, $this->offset) : $this->getShort();
return $this->get($len);
}
public function putString($v, bool $network = false){
if($network === true){
$this->put(Binary::writeUnsignedVarInt(strlen($v)));
}else{
$this->putShort(strlen($v));
}
$this->buffer .= $v;
}
public function getArray() : array{
$data = [];
self::toArray($data, $this->data);
return $data;
}
private static function toArray(array &$data, Tag $tag){
/** @var CompoundTag[]|ListTag[]|IntArrayTag[] $tag */
foreach($tag as $key => $value){
if($value instanceof CompoundTag or $value instanceof ListTag or $value instanceof IntArrayTag){
$data[$key] = [];
self::toArray($data[$key], $value);
}else{
$data[$key] = $value->getValue();
}
}
}
public static function fromArrayGuesser($key, $value){
if(is_int($value)){
return new IntTag($key, $value);
}elseif(is_float($value)){
return new FloatTag($key, $value);
}elseif(is_string($value)){
return new StringTag($key, $value);
}elseif(is_bool($value)){
return new ByteTag($key, $value ? 1 : 0);
}
return null;
}
private static function fromArray(Tag $tag, array $data, callable $guesser){
foreach($data as $key => $value){
if(is_array($value)){
$isNumeric = true;
$isIntArray = true;
foreach($value as $k => $v){
if(!is_numeric($k)){
$isNumeric = false;
break;
}elseif(!is_int($v)){
$isIntArray = false;
}
}
$tag{$key} = $isNumeric ? ($isIntArray ? new IntArrayTag($key, []) : new ListTag($key, [])) : new CompoundTag($key, []);
self::fromArray($tag->{$key}, $value, $guesser);
}else{
$v = call_user_func($guesser, $key, $value);
if($v instanceof Tag){
$tag{$key} = $v;
}
}
}
}
public function setArray(array $data, callable $guesser = null){
$this->data = new CompoundTag("", []);
self::fromArray($this->data, $data, $guesser ?? [self::class, "fromArrayGuesser"]);
}
/**
* @return CompoundTag|array
*/
public function getData(){
return $this->data;
}
/**
* @param CompoundTag|array $data
*/
public function setData($data){
$this->data = $data;
}
} }

View File

@ -0,0 +1,271 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\nbt;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\EndTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\Tag;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
#include <rules/NBT.h>
/**
* Base Named Binary Tag encoder/decoder
*/
abstract class NBTStream{
public $buffer;
public $offset;
private $data;
public function get($len) : string{
if($len < 0){
$this->offset = strlen($this->buffer) - 1;
return "";
}elseif($len === true){
return substr($this->buffer, $this->offset);
}
return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len);
}
public function put(string $v) : void{
$this->buffer .= $v;
}
public function feof() : bool{
return !isset($this->buffer{$this->offset});
}
public function __construct(){
$this->offset = 0;
$this->buffer = "";
}
public function read(string $buffer, bool $doMultiple = false) : void{
$this->offset = 0;
$this->buffer = $buffer;
$this->data = $this->readTag();
if($doMultiple and $this->offset < strlen($this->buffer)){
$this->data = [$this->data];
do{
$this->data[] = $this->readTag();
}while($this->offset < strlen($this->buffer));
}
$this->buffer = "";
}
public function readCompressed(string $buffer) : void{
$this->read(zlib_decode($buffer));
}
/**
* @return bool|string
*/
public function write(){
$this->offset = 0;
$this->buffer = "";
if($this->data instanceof CompoundTag){
$this->writeTag($this->data);
return $this->buffer;
}elseif(is_array($this->data)){
foreach($this->data as $tag){
$this->writeTag($tag);
}
return $this->buffer;
}
return false;
}
public function writeCompressed(int $compression = ZLIB_ENCODING_GZIP, int $level = 7){
if(($write = $this->write()) !== false){
return zlib_encode($write, $compression, $level);
}
return false;
}
public function readTag() : Tag{
if($this->feof()){
return new EndTag();
}
$tagType = $this->getByte();
$tag = NBT::createTag($tagType);
if($tag instanceof NamedTag){
$tag->setName($this->getString());
$tag->read($this);
}
return $tag;
}
public function writeTag(Tag $tag) : void{
$this->putByte($tag->getType());
if($tag instanceof NamedTag){
$this->putString($tag->getName());
}
$tag->write($this);
}
public function getByte() : int{
return Binary::readByte($this->get(1));
}
public function getSignedByte() : int{
return Binary::readSignedByte($this->get(1));
}
public function putByte(int $v) : void{
$this->buffer .= Binary::writeByte($v);
}
abstract public function getShort() : int;
abstract public function getSignedShort() : int;
abstract public function putShort(int $v) : void;
abstract public function getInt() : int;
abstract public function putInt(int $v) : void;
abstract public function getLong() : int;
abstract public function putLong(int $v) : void;
abstract public function getFloat() : float;
abstract public function putFloat(float $v) : void;
abstract public function getDouble() : float;
abstract public function putDouble(float $v) : void;
public function getString() : string{
return $this->get($this->getShort());
}
public function putString(string $v) : void{
$this->putShort(strlen($v));
$this->put($v);
}
abstract public function getIntArray() : array;
abstract public function putIntArray(array $array) : void;
public function getArray() : array{
$data = [];
self::toArray($data, $this->data);
return $data;
}
private static function toArray(array &$data, Tag $tag) : void{
/** @var CompoundTag[]|ListTag[]|IntArrayTag[] $tag */
foreach($tag as $key => $value){
if($value instanceof CompoundTag or $value instanceof ListTag or $value instanceof IntArrayTag){
$data[$key] = [];
self::toArray($data[$key], $value);
}else{
$data[$key] = $value->getValue();
}
}
}
public static function fromArrayGuesser(string $key, $value) : ?NamedTag{
if(is_int($value)){
return new IntTag($key, $value);
}elseif(is_float($value)){
return new FloatTag($key, $value);
}elseif(is_string($value)){
return new StringTag($key, $value);
}elseif(is_bool($value)){
return new ByteTag($key, $value ? 1 : 0);
}
return null;
}
private static function fromArray(Tag $tag, array $data, callable $guesser) : void{
foreach($data as $key => $value){
if(is_array($value)){
$isNumeric = true;
$isIntArray = true;
foreach($value as $k => $v){
if(!is_numeric($k)){
$isNumeric = false;
break;
}elseif(!is_int($v)){
$isIntArray = false;
}
}
$tag{$key} = $isNumeric ? ($isIntArray ? new IntArrayTag($key, []) : new ListTag($key, [])) : new CompoundTag($key, []);
self::fromArray($tag->{$key}, $value, $guesser);
}else{
$v = call_user_func($guesser, $key, $value);
if($v instanceof Tag){
$tag{$key} = $v;
}
}
}
}
public function setArray(array $data, callable $guesser = null) : void{
$this->data = new CompoundTag("", []);
self::fromArray($this->data, $data, $guesser ?? [self::class, "fromArrayGuesser"]);
}
/**
* @return CompoundTag|array
*/
public function getData(){
return $this->data;
}
/**
* @param CompoundTag|array $data
*/
public function setData($data) : void{
$this->data = $data;
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\nbt;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
#include <rules/NBT.h>
class NetworkLittleEndianNBTStream extends LittleEndianNBTStream{
public function getInt() : int{
return Binary::readVarInt($this->buffer, $this->offset);
}
public function putInt(int $v) : void{
$this->put(Binary::writeVarInt($v));
}
public function getLong() : int{
return Binary::readVarLong($this->buffer, $this->offset);
}
public function putLong(int $v) : void{
$this->put(Binary::writeVarLong($v));
}
public function getString() : string{
return $this->get(Binary::readUnsignedVarInt($this->buffer, $this->offset));
}
public function putString(string $v) : void{
$this->put(Binary::writeUnsignedVarInt(strlen($v)) . $v);
}
public function getIntArray() : array{
$len = $this->getInt(); //varint
$ret = [];
for($i = 0; $i < $len; ++$i){
$ret[] = $this->getInt(); //varint
}
return $ret;
}
public function putIntArray(array $array) : void{
$this->putInt(count($array)); //varint
foreach($array as $v){
$this->putInt($v); //varint
}
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,12 +44,12 @@ class ByteArrayTag extends NamedTag{
return NBT::TAG_ByteArray; return NBT::TAG_ByteArray;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->get($nbt->getInt($network)); $this->value = $nbt->get($nbt->getInt());
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putInt(strlen($this->value), $network); $nbt->putInt(strlen($this->value));
$nbt->put($this->value); $nbt->put($this->value);
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,11 +44,11 @@ class ByteTag extends NamedTag{
return NBT::TAG_Byte; return NBT::TAG_Byte;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getSignedByte(); $this->value = $nbt->getSignedByte();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putByte($this->value); $nbt->putByte($this->value);
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -427,23 +428,23 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
return NBT::TAG_Compound; return NBT::TAG_Compound;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = []; $this->value = [];
do{ do{
$tag = $nbt->readTag($network); $tag = $nbt->readTag();
if($tag instanceof NamedTag and $tag->__name !== ""){ if($tag instanceof NamedTag and $tag->__name !== ""){
$this->{$tag->__name} = $tag; $this->{$tag->__name} = $tag;
} }
}while(!($tag instanceof EndTag) and !$nbt->feof()); }while(!($tag instanceof EndTag) and !$nbt->feof());
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
foreach($this as $tag){ foreach($this as $tag){
if($tag instanceof Tag and !($tag instanceof EndTag)){ if($tag instanceof Tag and !($tag instanceof EndTag)){
$nbt->writeTag($tag, $network); $nbt->writeTag($tag);
} }
} }
$nbt->writeTag(new EndTag, $network); $nbt->writeTag(new EndTag);
} }
public function __toString(){ public function __toString(){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,11 +44,11 @@ class DoubleTag extends NamedTag{
return NBT::TAG_Double; return NBT::TAG_Double;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getDouble(); $this->value = $nbt->getDouble();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putDouble($this->value); $nbt->putDouble($this->value);
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
class EndTag extends Tag{ class EndTag extends Tag{
@ -31,11 +32,11 @@ class EndTag extends Tag{
return NBT::TAG_End; return NBT::TAG_End;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
} }
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,11 +44,11 @@ class FloatTag extends NamedTag{
return NBT::TAG_Float; return NBT::TAG_Float;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getFloat(); $this->value = $nbt->getFloat();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putFloat($this->value); $nbt->putFloat($this->value);
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,14 +44,12 @@ class IntArrayTag extends NamedTag{
return NBT::TAG_IntArray; return NBT::TAG_IntArray;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$size = $nbt->getInt($network); $this->value = $nbt->getIntArray();
$this->value = array_values(unpack($nbt->endianness === NBT::LITTLE_ENDIAN ? "V*" : "N*", $nbt->get($size * 4)));
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putInt(count($this->value), $network); $nbt->putIntArray($this->value);
$nbt->put(pack($nbt->endianness === NBT::LITTLE_ENDIAN ? "V*" : "N*", ...$this->value));
} }
public function __toString(){ public function __toString(){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -41,12 +42,12 @@ class IntTag extends NamedTag{
return NBT::TAG_Int; return NBT::TAG_Int;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getInt($network); $this->value = $nbt->getInt();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putInt($this->value, $network); $nbt->putInt($this->value);
} }
/** /**

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -163,20 +164,20 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{
return $this->tagType; return $this->tagType;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = []; $this->value = [];
$this->tagType = $nbt->getByte(); $this->tagType = $nbt->getByte();
$size = $nbt->getInt($network); $size = $nbt->getInt();
$tagBase = NBT::createTag($this->tagType); $tagBase = NBT::createTag($this->tagType);
for($i = 0; $i < $size and !$nbt->feof(); ++$i){ for($i = 0; $i < $size and !$nbt->feof(); ++$i){
$tag = clone $tagBase; $tag = clone $tagBase;
$tag->read($nbt, $network); $tag->read($nbt);
$this->{$i} = $tag; $this->{$i} = $tag;
} }
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
if($this->tagType === NBT::TAG_End){ //previously empty list, try detecting type from tag children if($this->tagType === NBT::TAG_End){ //previously empty list, try detecting type from tag children
$id = NBT::TAG_End; $id = NBT::TAG_End;
foreach($this as $tag){ foreach($this as $tag){
@ -200,9 +201,9 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{
$tags[] = $tag; $tags[] = $tag;
} }
} }
$nbt->putInt(count($tags), $network); $nbt->putInt(count($tags));
foreach($tags as $tag){ foreach($tags as $tag){
$tag->write($nbt, $network); $tag->write($nbt);
} }
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,12 +44,12 @@ class LongTag extends NamedTag{
return NBT::TAG_Long; return NBT::TAG_Long;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getLong($network); $this->value = $nbt->getLong();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putLong($this->value, $network); $nbt->putLong($this->value);
} }
/** /**

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,11 +44,11 @@ class ShortTag extends NamedTag{
return NBT::TAG_Short; return NBT::TAG_Short;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getSignedShort(); $this->value = $nbt->getSignedShort();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putShort($this->value); $nbt->putShort($this->value);
} }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
#include <rules/NBT.h> #include <rules/NBT.h>
@ -43,12 +44,12 @@ class StringTag extends NamedTag{
return NBT::TAG_String; return NBT::TAG_String;
} }
public function read(NBT $nbt, bool $network = false) : void{ public function read(NBTStream $nbt) : void{
$this->value = $nbt->getString($network); $this->value = $nbt->getString();
} }
public function write(NBT $nbt, bool $network = false) : void{ public function write(NBTStream $nbt) : void{
$nbt->putString($this->value, $network); $nbt->putString($this->value);
} }
/** /**

View File

@ -26,7 +26,7 @@ declare(strict_types=1);
*/ */
namespace pocketmine\nbt\tag; namespace pocketmine\nbt\tag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBTStream;
abstract class Tag extends \stdClass{ abstract class Tag extends \stdClass{
@ -42,9 +42,9 @@ abstract class Tag extends \stdClass{
$this->value = $value; $this->value = $value;
} }
abstract public function write(NBT $nbt, bool $network = false) : void; abstract public function write(NBTStream $nbt) : void;
abstract public function read(NBT $nbt, bool $network = false) : void; abstract public function read(NBTStream $nbt) : void;
public function __toString(){ public function __toString(){
return (string) $this->value; return (string) $this->value;

View File

@ -25,6 +25,7 @@ namespace pocketmine\tile;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket; use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\Player; use pocketmine\Player;
@ -92,11 +93,11 @@ abstract class Spawnable extends Tile{
final public function getSerializedSpawnCompound() : string{ final public function getSerializedSpawnCompound() : string{
if($this->spawnCompoundCache === null){ if($this->spawnCompoundCache === null){
if(self::$nbtWriter === null){ if(self::$nbtWriter === null){
self::$nbtWriter = new NBT(NBT::LITTLE_ENDIAN); self::$nbtWriter = new NetworkLittleEndianNBTStream();
} }
self::$nbtWriter->setData($this->getSpawnCompound()); self::$nbtWriter->setData($this->getSpawnCompound());
$this->spawnCompoundCache = self::$nbtWriter->write(true); $this->spawnCompoundCache = self::$nbtWriter->write();
} }
return $this->spawnCompoundCache; return $this->spawnCompoundCache;

@ -1 +1 @@
Subproject commit 86961f81970a49f8c25e18d0d414961d7142a84d Subproject commit 316fd5606fef1191e7f228d3156dd1518c33aba4