Skip to content

Releases: m-stilling/snbt-parser-php

v1.2.0

Choose a tag to compare

@m-stilling m-stilling released this 27 Sep 09:53

Behavior changes

  • Numbers outside the range of their type now throw SNBTParseException, for example 300b, 1.5b and 1e400.
  • Tag constructors and intsToUuid() now throw SNBTInvalidArgumentException for values outside the range, and for INF and NaN.
  • Unquoted values such as 0x1F, 0b101 and 1_000 are now numbers, not strings.
  • CompoundTag::getIterator() returns \Iterator, not \ArrayIterator. All keys are strings.
  • Classes that extend Tag must add the bool $escapeControlCharacters parameter to render(). They must also add it to quote(), serializeKey() and toSnbt() if they override them.

Added

  • Typed getters on CompoundTag and ListTag: getString(), getInt(), getFloat(), getBool(), getCompound(), getList() and getAs().
  • SNBTParser::parseCompound() returns a CompoundTag.
  • Tag::fromPhp() makes tags from PHP values.
  • with(), without() and withAppended() return a changed copy of a compound or a list.
  • SNBTParseException has position, lineNumber and columnNumber.
  • The parser reads the Minecraft 1.21.5 syntax: hexadecimal and binary numbers, _ in numbers, the new string escapes, trailing commas, and bool() and uuid().
  • toSnbt(escapeControlCharacters: true) writes control characters as escapes.
  • MIN and MAX constants on the integer tags, and NumberArrayTag::elementType().

Fixed

  • toSnbt() output with a line feed, a carriage return or a tab now parses on Minecraft 1.21.4 and earlier.
  • Every exception that the package throws implements SNBTException.
  • Iterating a CompoundTag gives string keys, also for numeric keys.

Package

  • The package archive does not contain composer.lock.
  • composer.json suggests ext-intl.

Full Changelog: v1.1.0...v1.2.0

v1.1.0

Choose a tag to compare

@m-stilling m-stilling released this 25 Sep 09:55

This release adds three helpers that convert between UUID strings and the four-integer arrays Minecraft stores them as. It completes the round trip that intsToUuid() started. No existing behavior changes.

Added

  • SNBTParser::uuidToInts(string $uuid): array returns the four signed 32-bit integers for a UUID. It accepts the hyphenated form or 32 bare hex digits, in either case, and throws InvalidArgumentException for any other input.
  • SNBTParser::uuidToSnbt(string $uuid, SNBTFormat $format = SNBTFormat::Compact): string returns the same integers as a ready-made SNBT int array, for example [I;110787060,1156138790,-1514210135,238594805]. The format argument works the same as on toSnbt().
  • IntArrayTag::toUuid(): string reads a parsed int array as a UUID string. It throws InvalidArgumentException unless the array holds exactly four integers.

Example

use Stilling\SNBTParser\SNBTParser;

SNBTParser::uuidToInts("069a79f4-44e9-4726-a5be-fca90e38aaf5");
// [110787060, 1156138790, -1514210135, 238594805]

SNBTParser::uuidToSnbt("069a79f4-44e9-4726-a5be-fca90e38aaf5");
// "[I;110787060,1156138790,-1514210135,238594805]"

SNBTParser::parseTyped('{UUID: [I; 110787060, 1156138790, -1514210135, 238594805]}')->get("UUID")->toUuid();
// "069a79f4-44e9-4726-a5be-fca90e38aaf5"

Full Changelog: v1.0.0...v1.1.0

v1.0.0

Choose a tag to compare

@m-stilling m-stilling released this 25 Sep 09:06
ed7e828

This release replaces the JSON round-trip with a direct parser. parse() keeps its return values. A new parseTyped() returns a tag tree that keeps the NBT types and can serialize back to SNBT.

What's Changed

Added

  • SNBTParser::parseTyped(string $input): Tag parses SNBT into a typed tag tree. Every value is a Tag subclass under Stilling\SNBTParser\Tag: ByteTag, ShortTag, IntTag, LongTag, FloatTag, DoubleTag, BooleanTag, StringTag, ByteArrayTag, IntArrayTag, LongArrayTag, ListTag and CompoundTag. The tree tells 0b, 0s, 0 and 0L apart.
  • Tag::toPhp() returns the native PHP value. This is the same value that parse() returns.
  • Tag::toSnbt(SNBTFormat $format = SNBTFormat::Compact) serializes the tag back to SNBT and keeps the NBT types. A compact data get blob round-trips byte for byte.
  • SNBTFormat selects the layout of toSnbt(). Compact gives {a:1,b:[1,2]}. Spaced gives { a: 1, b: [ 1, 2 ] }. Pretty puts compounds and lists on multiple lines with four-space indentation, and keeps typed number arrays on one line.
  • CompoundTag::get(string $key): ?Tag and CompoundTag::has(string $key): bool read compound entries. ListTag::get(int $index): ?Tag reads list items.
  • CompoundTag, ListTag and the three number array tags implement Countable and IteratorAggregate. count($tag) and foreach ($tag as $key => $value) work on them. The readonly entries, items and values properties expose the contents as arrays.
  • examples/parse-typed.php dumps a typed tree, its toPhp() value and its toSnbt() output.

Changed

  • parse() now delegates to parseTyped()->toPhp(). The return values do not change: every integer type becomes int, every floating-point type becomes float, true and false become bool.
  • Unquoted string values parse. { id: stone } returns [ "id" => "stone" ]. Earlier versions threw on this input.
  • The escape sequences \n, \r and \t decode to the control characters. toSnbt() writes them back as escape sequences.
  • [B; true, false] parses to the bytes 1 and 0. Earlier versions returned 0 for both.
  • Invalid typed-array elements throw SNBTParseException. This covers [I; foo], [I; 1.5], [I; 1f] and boolean keywords outside a byte array. Earlier versions returned 0 for these elements. Any integer suffix is still accepted in any array type, so [I; 1b, 2s] parses.
  • Parse errors report the byte position and the text near it. Example: Expected ',' or '}' at position 6 near "x: 1}".

Removed

  • The ext-mbstring requirement. The package needs no PHP extensions.
  • The internal Stilling\SNBTParser\Tokens namespace. It was not part of the public API.

Compatibility

  • PHP 8.3, 8.4 and 8.5 are supported. The CI matrix tests all three with the lowest and the highest dependency versions.
  • SNBTParser::parse() and SNBTParser::intsToUuid() keep their signatures. The declared return type of parse() no longer lists object, which it never returned.

Upgrading from 0.3

No code changes are needed for parse() and intsToUuid(). Check these points:

  • If your input relied on invalid typed-array elements parsing as 0, it now throws. Fix the input, or catch SNBTParseException.
  • If your input contained \n, \r or \t escape sequences, the values now contain the control characters instead of the two-character sequences.
  • If you catch parse errors by message text, update the patterns. The messages changed.

Full Changelog: v0.3.0...v1.0.0

v0.3.0

Choose a tag to compare

@m-stilling m-stilling released this 13 Jun 22:00

What's Changed

This release focuses on parser correctness, fixing several string and number edge cases, and broadens SNBT compatibility, alongside stricter internal typing.

Fixes

  • Strings: spaces inside quoted strings are no longer stripped
  • Strings: values are now escaped via json_encode, fixing malformed output for strings containing quotes, backslashes, tabs, or newlines
  • Strings: correctly terminate strings ending in an escaped backslash (e.g. "C:\\")
  • Arrays: empty typed arrays ([I;], [B;], [L;]) now parse to [] instead of [0]
  • Numbers: full float/double precision is preserved instead of being rounded to 14 significant digits (e.g. 0.10000000149011612d)

Features

  • Allow dots, dashes, and plus signs in unquoted compound keys
  • Tolerate tabs and newlines between tokens, so pretty-printed SNBT parses
  • Malformed input now throws a dedicated SNBTParseException (implements SNBTException, extends RuntimeException) instead of a bare Exception (still catchable as \Exception)

Tooling

  • Static analysis with PHPStan at level 8 across src and tests, enforced in CI
  • Development-only files are trimmed from the distributed package via .gitattributes

Full Changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@m-stilling m-stilling released this 20 Jan 11:31

What's Changed

  • Removed PHP 8.3 support
    It only ever actually worked due to unintentional polyfills for mb_* functions, and I rather avoid an explicit dependency. If you require this to work on PHP 8.3, install v0.1.2 alongside symfony/polyfill-mbstring.
  • Added tests against PHP 8.5

Full Changelog: v0.1.2...v0.2.0

v0.1.2

Choose a tag to compare

@m-stilling m-stilling released this 18 Sep 17:12

What's Changed

Full Changelog: v0.1.1...v0.1.2

v0.1.1

Choose a tag to compare

@m-stilling m-stilling released this 29 Aug 14:46

What's Changed

  • Added intsToUuid() helper 6d32d89

Full Changelog: v0.1.0...v0.1.1

v0.1.0

Choose a tag to compare

@m-stilling m-stilling released this 27 Aug 07:05

Initial release 🥳🎉