aternos / nbt
PHP库,用于解析、修改和创建NBT对象
Requires
- php: >=8.1
- php-64bit: *
- ext-json: *
- ext-mbstring: *
- ext-zlib: *
- pocketmine/binaryutils: ^0.2.1
README
Minecraft的命名二进制标签(NBT)格式的完整PHP实现。
与其他实现相比,此库支持64位类型,包括相对较新的TAG_Long_Array
。
此外,NBT格式的三个版本(Java版本、基岩版/小端和基岩版/VarInt)都得到了支持。
安装
composer require aternos/nbt
用法
读取NBT数据
要读取现有的NBT数据,需要一个Reader对象。此库实现了不同的读者,用于从字符串中读取NBT数据。
//Read uncompressed NBT data $reader = new \Aternos\Nbt\IO\Reader\StringReader("...nbtData...", \Aternos\Nbt\NbtFormat::BEDROCK_EDITION); //Read gzip compressed NBT data $gzipReader = new \Aternos\Nbt\IO\Reader\GZipCompressedStringReader("...compressedNbtData...", \Aternos\Nbt\NbtFormat::JAVA_EDITION); //Read zlib compressed NBT data $zlibReader = new \Aternos\Nbt\IO\Reader\ZLibCompressedStringReader("...compressedNbtData...", \Aternos\Nbt\NbtFormat::BEDROCK_EDITION_NETWORK);
请注意,读者对象也用于指定NBT格式版本。可用的有\Aternos\Nbt\NbtFormat::JAVA_EDITION
、\Aternos\Nbt\NbtFormat::BEDROCK_EDITION
和\Aternos\Nbt\NbtFormat::BEDROCK_EDITION_NETWORK
。
可以通过实现\Aternos\Nbt\IO\Reader\Reader
接口或扩展\Aternos\Nbt\IO\Reader\AbstractReader
类来创建更高级的读者。
读者对象可以用来加载NBT标签。
$reader = new \Aternos\Nbt\IO\Reader\StringReader("...nbtData...", \Aternos\Nbt\NbtFormat::BEDROCK_EDITION); $tag = \Aternos\Nbt\Tag\Tag::load($reader);
理论上,任何类型的NBT标签都可能被返回,但在现实中,所有NBT文件都是以复合标签或列表标签开始的。
操作NBT结构
类型为TAG_Byte
、TAG_Short
、TAG_Int
、TAG_Long
、TAG_Float
、TAG_Double
、TAG_String
的标签值可以通过它们的getValue()
和setValue()
函数访问。
$myInt new \Aternos\Nbt\Tag\IntTag(); $myInt->setValue(42); echo $myInt->getValue(); // 42
对于字符串标签,getValue()
和setValue()
使用UTF-8编码,并在序列化时根据所选的NBT版本进行字符串转换。
复合标签、列表标签和数组标签实现了ArrayAccess
、Countable
和Iterator
接口,因此可以像数组一样访问。
$myCompound = new \Aternos\Nbt\Tag\CompoundTag(); $myCompound["myInt"] = (new \Aternos\Nbt\Tag\IntTag())->setValue(42); $myCompound["myFloat"] = (new \Aternos\Nbt\Tag\IntTag())->setValue(42.42); echo count($myCompound); // 2 //Manually setting a list's type is not strictly necessary, //since it's type will be set automatically when the first element is added $myList = (new \Aternos\Nbt\Tag\ListTag())->setContentTag(\Aternos\Nbt\Tag\TagType::TAG_String); $myList[] = (new \Aternos\Nbt\Tag\StringTag())->setValue("Hello"); $myList[] = (new \Aternos\Nbt\Tag\StringTag())->setValue("World");
也可以通过getter/setter函数访问复合标签。这在使用新的PHP null安全操作符时特别有用。
/** @var \Aternos\Nbt\Tag\CompoundTag $playerDat */ $playerDat = \Aternos\Nbt\Tag\Tag::load($reader); $playerDat->set("foo", (new \Aternos\Nbt\Tag\StringTag())->setValue("bar")); //Set a value $playerDat->delete("foo"); //Delete a value $playerName = $playerDat->getCompound("bukkit")?->getString("lastKnownName")?->getValue(); echo $playerName ?? "Unknown player name";
序列化NBT结构
与读取NBT数据的读者对象类似,需要一个写入对象来写入NBT数据。
//Write uncompressed NBT data $writer = (new \Aternos\Nbt\IO\Writer\StringWriter())->setFormat(\Aternos\Nbt\NbtFormat::BEDROCK_EDITION); //Write gzip compressed NBT data $gzipWriter = (new \Aternos\Nbt\IO\Writer\GZipCompressedStringWriter())->setFormat(\Aternos\Nbt\NbtFormat::JAVA_EDITION); //Write zlib compressed NBT data $gzipWriter = (new \Aternos\Nbt\IO\Writer\ZLibCompressedStringWriter())->setFormat(\Aternos\Nbt\NbtFormat::BEDROCK_EDITION_NETWORK);
写入对象使用的NBT版本可能与最初用于读取NBT结构的读者对象使用的版本不同。因此,可以使用此库在不同格式之间转换NBT结构。
可以通过实现\Aternos\Nbt\IO\Writer\Writer
接口或扩展\Aternos\Nbt\IO\Writer\AbstractWriter
类来创建更高级的写入对象。
写入对象可以用来写入/序列化NBT结构。
$writer = (new \Aternos\Nbt\IO\Writer\StringWriter())->setFormat(\Aternos\Nbt\NbtFormat::BEDROCK_EDITION); $tag->write($writer); file_put_contents("data.nbt", $writer->getStringData());
基岩版level.dat
虽然基岩版的level.dat文件是一个未压缩的NBT文件,但其NBT数据前面有两个32位小端整数。
第一个似乎是基岩版存储工具的版本,它也存储在NBT结构的StorageVersion
标签中。
第二个数字是文件NBT结构的大小(不包括前面的两个整数)。
基岩版level.dat文件可以这样读取:
$data = file_get_contents("level.dat"); $version = unpack("V", $data)[1]; $dataLength = unpack("V", $data, 4)[1]; if($dataLength !== strlen($data) - 8) { throw new Exception("Invalid level.dat data length"); } $tag = \Aternos\Nbt\Tag\Tag::load(new \Aternos\Nbt\IO\Reader\StringReader(substr($data, 8), \Aternos\Nbt\NbtFormat::BEDROCK_EDITION));