A small SNBT (stringified NBT) parser and writer for the Java NBT implementation by CloudburstMC.
Sigil accepts everything Mojang's SNBT spec accepts, plus a few ergonomic extensions:
- Trailing commas in compounds and lists
//line and/* */block comments- Single-quoted strings (
'...') in addition to"..." - Hex (
0xFF), binary (0b1010) and octal (0o755) integer literals - Unsigned integer suffixes (
ub,us,ui,ul) - Named float literals (
Infinity,NaN) with optional+/-andf/d - Explicit
i/Isuffix forint
String values must always be quoted. Compound keys may be bareword
identifiers ([A-Za-z_][A-Za-z0-9_]*); anything else (spaces, leading digit,
punctuation) must be quoted.
Maven:
<dependency>
<groupId>net.craftersmc</groupId>
<artifactId>sigil</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>Sigil depends on org.cloudburstmc:nbt:3.0.4.Final (transitive).
import net.craftersmc.sigil.Sigil;
import org.cloudburstmc.nbt.NbtMap;
NbtMap player = Sigil.parseCompound("""
{
name: "Steve",
level: 42,
pos: [0.5d, 64d, -12.3d],
inventory: [
{id: "minecraft:stone", count: 64b},
{id: "minecraft:torch", count: 16b},
]
}
""");
String compact = Sigil.write(player);
String pretty = Sigil.writePretty(player);// Parse any value (compound, list, primitive, ...)
Object value = Sigil.parse("42L");
// Parse and require a compound at the root
NbtMap map = Sigil.parseCompound("{ a: 1, b: 2 }");Errors throw SnbtParseException with line and column:
try {
Sigil.parse("{name: bare}"); // unquoted value strings are rejected
} catch (SnbtParseException e) {
System.out.println(e.getMessage());
// -> unquoted string 'bare' is not allowed; wrap it in quotes (at line 1, column 8)
}NbtMap map = NbtMap.builder()
.putString("name", "Steve")
.putInt("level", 42)
.putByteArray("data", new byte[]{1, 2, 3})
.build();
Sigil.write(map);
// {name:"Steve",level:42,data:[B;1b,2b,3b]}
Sigil.writePretty(map);
// {
// name: "Steve",
// level: 42,
// data: [B; 1b, 2b, 3b]
// }Customizing the output format:
import net.craftersmc.sigil.writer.SnbtFormat;
SnbtFormat fourSpace = SnbtFormat.PRETTY.withIndent(" ");
SnbtFormat singleQuotes = SnbtFormat.COMPACT.withQuote('\'');
Sigil.write(map, fourSpace);
Sigil.write(map, singleQuotes);| Form | Type | Notes |
|---|---|---|
42 |
int |
default for integer literals |
42b, 42B |
byte |
|
42s, 42S |
short |
|
42i, 42I |
int |
explicit |
42L, 42l |
long |
|
1.5 |
double |
default for fractional literals |
1.5f, 1.5F |
float |
|
1.5d, 1.5D |
double |
explicit |
0xFF |
int |
hex |
0b1010 |
int |
binary |
0o755 |
int |
octal |
0xFFL, 0xFFs |
typed hex | s/i/l suffixes work on any base |
255ub |
byte -1 |
unsigned: range-checked, then bit-cast |
Infinity, NaN |
double |
accept +/- and f/d suffix |
A few sharp edges to be aware of:
- In hex literals, a trailing
b/Bis always a hex digit, never a byte suffix (sincebis a hex digit). For a byte from hex, write0xFFub.0xFFbparses as the int4091. 0bfollowed by something other than0or1is not a binary prefix. So0balone parses as the byte0(decimal0with byte suffix).0b1010is binary ten.- Unsigned suffixes range-check the input against
[0, 2ⁿ), then store the value as the corresponding signed type via bit truncation.255ubproduces(byte) -1;256ubis an error;-1ubis an error.
{
// Player position
pos: [
0.5d,
64d,
-12.3d, // trailing commas are fine
],
/* Inventory below.
Block comments work anywhere whitespace works. */
items: [],
}
Apache License 2.0. See LICENSE.