Eine .nbt-Struktur speichert Palettenindizes, keine Blocknamen — deshalb ist sie so klein
Drei Schlüssel enthalten ein ganzes Bauwerk: size, palette und blocks. Jeder Block ist eine Ganzzahl, die in die Palette zeigt, sodass ein 32³-Volumen aus Stein einen String und 32.768 kleine Einträge kostet — jeweils eine Position und einen Index, niemals einen Namen.
Eine .nbt-Struktudatei — das, was ein Konstruktionsblock speichert und ein Datapack ausliefert — ist ein viel einfacheres Format, als es von außen aussieht. Alles, was ein Bauwerk braucht, steckt in einer Handvoll Schlüssel auf oberster Ebene, und eine einzige Designentscheidung erklärt, warum die Dateien so klein sind, wie sie sind.
Die drei Schlüssel, die das Bauwerk tragen
size [x, y, z] — a list of exactly three integers
palette [ { Name, Properties } … ] — every DISTINCT block state, once
blocks [ { pos, state, nbt } … ] — one entry per placed block
palette enthält jeden einzelnen Blockzustand genau einmal. Ein Eintrag ist ein Name — die Block-ID, wie minecraft:oak_stairs — plus ein optionales Properties-Compound, das seinen Blockzustand enthält, etwa facing: north und half: bottom.
blocks wiederholt niemals einen Namen. Jeder Eintrag trägt ein pos aus drei Ganzzahlen und einen state, und state ist ein Index in die Palette, keine Block-ID. Eichenholztreppen, die nach Norden zeigen, sind einmal String- Daten, und jede weitere danach ist eine kleine Ganzzahl.
Das ist der ganze Trick. Ein 32 × 32 × 32 großes Volumen aus reinem Stein ist ein Paletteneintrag und 32.768 Blockeinträge aus einer Position plus einem Index — nicht 32.768 Kopien des Wortes minecraft:stone. Die Palette wächst damit, wie viele verschiedene Dinge du verbaut hast, und die Blockliste wächst damit, wie groß du gebaut hast. Das sind sehr unterschiedliche Zahlen, und nur eine davon ist normalerweise groß.
Zwei Konsequenzen, um die man herum planen sollte
Blockzustände vervielfachen deine Palette, nicht deine Blockliste. Eichenholztreppen sind nicht ein Paletteneintrag — sie sind einer pro Ausrichtung, die du tatsächlich verwendet hast. Vier Himmelsrichtungen, obere und untere Hälfte, gerade sowie beide Innen- und Außenecken: Derselbe Block kann ein Dutzend Palettenplätze belegen. Ein detailreiches Bauwerk hat also eine große Palette und ein schlichtes nicht, unabhängig von der Größe.
Nur gespeicherte Positionen bekommen einen Eintrag. Die Blockliste ist eine Liste, kein dichtes 3D-Array, und ein Eintrag, der nicht da ist, ist einfach nicht da — der Betrachter auf dieser Seite füllt sein Raster mit -1 und behandelt eine fehlende Koordinate als nichts platziert. Ein Konstruktionsblock speichert jedoch Luft wie jeden anderen Block; nur Konstruktionsleere wird ausgelassen. Ein hohles Bauwerk ist nur dann günstiger zu speichern, wenn du sein Inneres vor dem Speichern mit Konstruktionsleere füllst.
nbt ist pro Block und optional
Jeder Eintrag in blocks kann sein eigenes nbt-Compound tragen, und die meisten tun es nicht. Hier leben der Inhalt einer Truhe, der Text eines Schilds, der Mob eines Spawners und die Muster eines Banners — angehängt an den einzelnen Block statt an die Palette.
Der Unterschied ist wichtig: Palettendaten sind geteilt, Blockdaten nicht. Zwei Truhen sind ein Paletteneintrag, weil sie derselbe Blockzustand sind — aber jede führt ihr eigenes Inventar in ihrem eigenen nbt. Ändere den Blockzustand, und du berührst die Palette; ändere, was darin ist, und du berührst einen Eintrag in der Blockliste.
Eine Ebene nach der anderen lesen
Der Betrachter hier ist bewusst 2D. Um Ebene y zu zeichnen, durchläuft er die Blockliste, behält Einträge, deren pos[1] gleich y ist, und schlägt deren jeweiligen state in der Palette nach. Das ist der ganze Algorithmus, und es lohnt sich, ihn zu kennen, denn genauso würdest du eine dieser Dateien selbst untersuchen: Es gibt keinen räumlichen Index aufzubauen und keine Dekompression jenseits des gzip-Wrappers. Das Format ist eine flache Liste, die du filterst.
Was auch bedeutet, dass eine Strukturdatei dir nichts darüber sagt, wohin sie in einer Welt gehört. size ist eine Bounding Box und pos-Werte sind relativ zu ihrer Ecke. Die Platzierung ist Sache des Konstruktionsblocks, nicht der Datei.