diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/creative/CreativeTabContents.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/creative/CreativeTabContents.java index 57da252c..b6890182 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/creative/CreativeTabContents.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/creative/CreativeTabContents.java @@ -389,6 +389,7 @@ public final class CreativeTabContents { entry("music_disc_underside", "tools_and_utilities"), entry("music_disc_the_queen", "tools_and_utilities"), entry("music_disc_verdance", "tools_and_utilities"), + entry("music_disc_grotesque", "tools_and_utilities"), entry("diamond_minecart", "tools_and_utilities", "minecart"), entry("bile_bucket", "tools_and_utilities"), entry("ichor_bucket", "tools_and_utilities"), diff --git a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json index 6291c02e..9d672f69 100644 --- a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json +++ b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json @@ -398,6 +398,8 @@ "jukebox_song.antarchy.the_queen": "Karlljp - The Queen", "item.antarchy.music_disc_verdance": "Music Disc", "jukebox_song.antarchy.verdance": "Hewo - Verdance", + "item.antarchy.music_disc_grotesque": "Music Disc", + "jukebox_song.antarchy.grotesque": "DocShrekBot - Grotesque", "item.antarchy.nightmare_helmet": "Nightmare Helmet", "item.antarchy.nightmare_chestplate": "Nightmare Chestplate", "item.antarchy.nightmare_leggings": "Nightmare Leggings", diff --git a/common-1.21.1/src/main/resources/assets/antarchy/models/item/music_disc_grotesque.json b/common-1.21.1/src/main/resources/assets/antarchy/models/item/music_disc_grotesque.json new file mode 100644 index 00000000..2e6dd435 --- /dev/null +++ b/common-1.21.1/src/main/resources/assets/antarchy/models/item/music_disc_grotesque.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "antarchy:item/music_disc_grotesque" + } +} diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds.json b/common-1.21.1/src/main/resources/assets/antarchy/sounds.json index c10b45f8..2b69ba53 100644 --- a/common-1.21.1/src/main/resources/assets/antarchy/sounds.json +++ b/common-1.21.1/src/main/resources/assets/antarchy/sounds.json @@ -1081,6 +1081,14 @@ } ] }, + "music_disc_grotesque": { + "sounds": [ + { + "name": "antarchy:records/grotesque", + "stream": true + } + ] + }, "lucid_lullaby": { "sounds": [ { @@ -1113,6 +1121,14 @@ } ] }, + "inverted_inferno": { + "sounds": [ + { + "name": "antarchy:music/game/thoraxis/inverted_inferno", + "stream": true + } + ] + }, "music.game.thoraxis": { "sounds": [ { @@ -1134,6 +1150,11 @@ "name": "antarchy:inversion_layer", "type": "event", "stream": true + }, + { + "name": "antarchy:inverted_inferno", + "type": "event", + "stream": true } ] }, diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/music/game/thoraxis/inverted_inferno.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/music/game/thoraxis/inverted_inferno.ogg new file mode 100644 index 00000000..fcb7556b Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/music/game/thoraxis/inverted_inferno.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/records/grotesque.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/records/grotesque.ogg new file mode 100644 index 00000000..2cbc7a7d Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/records/grotesque.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/item/music_disc_grotesque.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/item/music_disc_grotesque.png new file mode 100644 index 00000000..a7b3d801 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/item/music_disc_grotesque.png differ diff --git a/common-1.21.1/src/main/resources/data/antarchy/jukebox_song/grotesque.json b/common-1.21.1/src/main/resources/data/antarchy/jukebox_song/grotesque.json new file mode 100644 index 00000000..5ec92b14 --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/jukebox_song/grotesque.json @@ -0,0 +1,8 @@ +{ + "sound_event": "antarchy:music_disc_grotesque", + "description": { + "translate": "jukebox_song.antarchy.grotesque" + }, + "length_in_seconds": 206.86, + "comparator_output": 13 +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/loot_table/chests/tigers_eye_shrine/treasure.json b/common-1.21.1/src/main/resources/data/antarchy/loot_table/chests/tigers_eye_shrine/treasure.json index 00931fa6..5870ab00 100644 --- a/common-1.21.1/src/main/resources/data/antarchy/loot_table/chests/tigers_eye_shrine/treasure.json +++ b/common-1.21.1/src/main/resources/data/antarchy/loot_table/chests/tigers_eye_shrine/treasure.json @@ -155,6 +155,11 @@ } ] }, + { + "type": "minecraft:item", + "name": "antarchy:music_disc_grotesque", + "weight": 2 + }, { "type": "minecraft:item", "name": "antos:floppy_disk", diff --git a/common-1.21.1/src/main/resources/data/c/tags/item/music_discs.json b/common-1.21.1/src/main/resources/data/c/tags/item/music_discs.json index a3be0826..857cedd1 100644 --- a/common-1.21.1/src/main/resources/data/c/tags/item/music_discs.json +++ b/common-1.21.1/src/main/resources/data/c/tags/item/music_discs.json @@ -3,6 +3,7 @@ "values": [ "antarchy:music_disc_underside", "antarchy:music_disc_the_queen", - "antarchy:music_disc_verdance" + "antarchy:music_disc_verdance", + "antarchy:music_disc_grotesque" ] } diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricItems.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricItems.java index 0669d278..71aa84e3 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricItems.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricItems.java @@ -102,6 +102,11 @@ public final class AntarchyFabricItems { .jukeboxPlayable(ResourceKey.create(Registries.JUKEBOX_SONG, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "verdance")))); + public static final DeferredItem MUSIC_DISC_GROTESQUE = ITEMS.registerSimpleItem("music_disc_grotesque", + new Item.Properties().stacksTo(1).rarity(Rarity.RARE) + .jukeboxPlayable(ResourceKey.create(Registries.JUKEBOX_SONG, + ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "grotesque")))); + public static final DeferredItem PRIMORDIAL_SCUTE = ITEMS.registerSimpleItem("primordial_scute", new Item.Properties().rarity(Rarity.UNCOMMON)); diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java index d133177e..ae1728ae 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java @@ -533,6 +533,7 @@ public final class AntarchyFabricSounds { public static final DeferredHolder MUSIC_DISC_UNDERSIDE = registerSoundEvent("music_disc_underside"); public static final DeferredHolder THE_QUEEN = registerSoundEvent("the_queen"); public static final DeferredHolder MUSIC_DISC_VERDANCE = registerSoundEvent("music_disc_verdance"); + public static final DeferredHolder MUSIC_DISC_GROTESQUE = registerSoundEvent("music_disc_grotesque"); public static final DeferredHolder WORM_HOOK_FLYING = registerSoundEvent("worm_hook_flying"); public static final DeferredHolder BLOOD_CRYSTAL_KATANA_DASH = registerSoundEvent("blood_crystal_katana_dash"); public static final DeferredHolder BLOOD_CRYSTAL_ARMOR_EQUIP = registerSoundEvent("blood_crystal_armor_equip"); diff --git a/logs/latest.log b/logs/latest.log deleted file mode 100644 index e69de29b..00000000 diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java index 3a3ab907..e5e8690c 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java @@ -110,6 +110,11 @@ public final class AntarchyNeoforgeItems { .jukeboxPlayable(ResourceKey.create(Registries.JUKEBOX_SONG, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "verdance")))); + public static final DeferredItem MUSIC_DISC_GROTESQUE = ITEMS.registerSimpleItem("music_disc_grotesque", + new Item.Properties().stacksTo(1).rarity(Rarity.RARE) + .jukeboxPlayable(ResourceKey.create(Registries.JUKEBOX_SONG, + ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "grotesque")))); + private static final DeferredHolder ULTIMATE_ARMOR_MATERIAL = ARMOR_MATERIALS.register("ultimate", () -> new ArmorMaterial( createUltimateArmorDefense(), diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java index 3b5bb707..586cc600 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java @@ -210,6 +210,7 @@ public final class AntarchyNeoforgeSounds { public static final DeferredHolder MUSIC_DISC_UNDERSIDE = registerSoundEvent("music_disc_underside"); public static final DeferredHolder THE_QUEEN = registerSoundEvent("the_queen"); public static final DeferredHolder MUSIC_DISC_VERDANCE = registerSoundEvent("music_disc_verdance"); + public static final DeferredHolder MUSIC_DISC_GROTESQUE = registerSoundEvent("music_disc_grotesque"); public static final DeferredHolder WORM_HOOK_FLYING = registerSoundEvent("worm_hook_flying"); public static final DeferredHolder BLOOD_CRYSTAL_KATANA_DASH = registerSoundEvent("blood_crystal_katana_dash"); public static final DeferredHolder BLOOD_CRYSTAL_ARMOR_EQUIP = registerSoundEvent("blood_crystal_armor_equip"); diff --git a/tools/rasterize_pixelarticons.py b/tools/rasterize_pixelarticons.py deleted file mode 100644 index 3b92ffc5..00000000 --- a/tools/rasterize_pixelarticons.py +++ /dev/null @@ -1,125 +0,0 @@ -import re -from pathlib import Path - -from PIL import Image - - -SOURCE_DIR = ( - Path(__file__).resolve().parents[1] - / "common-1.21.1/src/main/resources/assets/antarchy/textures/gui/antpaint" -) -ICON_NAMES = ("undo", "redo", "pencil", "eraser", "trash") -TOKEN = re.compile(r"[MmLlHhVvZz]|-?(?:\d+(?:\.\d*)?|\.\d+)") - - -def polygons_from_path(data): - tokens = TOKEN.findall(data) - polygons = [] - points = [] - x = y = start_x = start_y = 0.0 - command = None - i = 0 - - while i < len(tokens): - if tokens[i].isalpha(): - command = tokens[i] - i += 1 - if command in "Zz": - if len(points) > 2: - polygons.append(points) - points = [] - x, y = start_x, start_y - command = None - continue - - if command is None: - raise ValueError(f"Unexpected SVG path data near token {i}: {data}") - - relative = command.islower() - op = command.upper() - if op in ("M", "L"): - px = float(tokens[i]) - py = float(tokens[i + 1]) - i += 2 - if relative: - px += x - py += y - x, y = px, py - if op == "M": - if len(points) > 2: - polygons.append(points) - points = [(x, y)] - start_x, start_y = x, y - command = "l" if relative else "L" - else: - points.append((x, y)) - elif op == "H": - px = float(tokens[i]) - i += 1 - x = x + px if relative else px - points.append((x, y)) - elif op == "V": - py = float(tokens[i]) - i += 1 - y = y + py if relative else py - points.append((x, y)) - else: - raise ValueError(f"Unsupported SVG command {command!r}: {data}") - - if len(points) > 2: - polygons.append(points) - return polygons - - -def contains_point(polygon, px, py): - inside = False - previous = polygon[-1] - for current in polygon: - x1, y1 = previous - x2, y2 = current - if (y1 > py) != (y2 > py): - crossing_x = (x2 - x1) * (py - y1) / (y2 - y1) + x1 - if px < crossing_x: - inside = not inside - previous = current - return inside - - -def main(): - for icon_name in ICON_NAMES: - source = (SOURCE_DIR / f"{icon_name}.svg").read_text(encoding="utf-8") - paths = re.findall(r']*\bd="([^"]+)"', source) - if not paths: - raise ValueError(f"No SVG path found in {icon_name}.svg") - polygons = [polygon for path in paths for polygon in polygons_from_path(path)] - - mask = [ - [ - any(contains_point(poly, x + 0.5, y + 0.5) for poly in polygons) - for x in range(24) - ] - for y in range(24) - ] - image = Image.new("RGBA", (24, 24), (0, 0, 0, 0)) - pixels = image.load() - for y in range(24): - for x in range(24): - if mask[y][x]: - pixels[x, y] = (101, 255, 101, 255) - continue - outlined = any( - 0 <= nx < 24 and 0 <= ny < 24 and mask[ny][nx] - for nx, ny in ( - (x - 1, y), - (x + 1, y), - (x, y - 1), - (x, y + 1), - ) - ) - if outlined: - pixels[x, y] = (3, 6, 3, 255) - image.save(SOURCE_DIR / f"{icon_name}.png") - - -if __name__ == "__main__": - main() diff --git a/tools/split_kings_tree_nbt.mjs b/tools/split_kings_tree_nbt.mjs deleted file mode 100644 index be924348..00000000 --- a/tools/split_kings_tree_nbt.mjs +++ /dev/null @@ -1,330 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import zlib from "node:zlib"; - -const TAG = { - END: 0, - BYTE: 1, - SHORT: 2, - INT: 3, - LONG: 4, - FLOAT: 5, - DOUBLE: 6, - BYTE_ARRAY: 7, - STRING: 8, - LIST: 9, - COMPOUND: 10, - INT_ARRAY: 11, - LONG_ARRAY: 12 -}; - -class Reader { - constructor(buffer) { - this.buffer = buffer; - this.offset = 0; - } - - byte() { return this.buffer.readInt8(this.offset++); } - ushort() { const value = this.buffer.readUInt16BE(this.offset); this.offset += 2; return value; } - short() { const value = this.buffer.readInt16BE(this.offset); this.offset += 2; return value; } - int() { const value = this.buffer.readInt32BE(this.offset); this.offset += 4; return value; } - long() { const value = this.buffer.readBigInt64BE(this.offset); this.offset += 8; return value; } - float() { const value = this.buffer.readFloatBE(this.offset); this.offset += 4; return value; } - double() { const value = this.buffer.readDoubleBE(this.offset); this.offset += 8; return value; } - string() { const length = this.ushort(); const value = this.buffer.toString("utf8", this.offset, this.offset + length); this.offset += length; return value; } - - payload(type) { - switch (type) { - case TAG.BYTE: return this.byte(); - case TAG.SHORT: return this.short(); - case TAG.INT: return this.int(); - case TAG.LONG: return this.long(); - case TAG.FLOAT: return this.float(); - case TAG.DOUBLE: return this.double(); - case TAG.BYTE_ARRAY: { - const length = this.int(); - const value = Buffer.from(this.buffer.subarray(this.offset, this.offset + length)); - this.offset += length; - return value; - } - case TAG.STRING: return this.string(); - case TAG.LIST: { - const elementType = this.byte(); - const length = this.int(); - const items = new Array(length); - for (let i = 0; i < length; i++) items[i] = this.payload(elementType); - return { elementType, items }; - } - case TAG.COMPOUND: { - const value = {}; - while (true) { - const childType = this.byte(); - if (childType === TAG.END) break; - value[this.string()] = { type: childType, value: this.payload(childType) }; - } - return value; - } - case TAG.INT_ARRAY: { - const length = this.int(); - const value = new Int32Array(length); - for (let i = 0; i < length; i++) value[i] = this.int(); - return value; - } - case TAG.LONG_ARRAY: { - const length = this.int(); - const value = new Array(length); - for (let i = 0; i < length; i++) value[i] = this.long(); - return value; - } - default: throw new Error(`Unsupported NBT tag type ${type}`); - } - } - - root() { - const type = this.byte(); - if (type !== TAG.COMPOUND) throw new Error(`Expected compound root, got ${type}`); - this.string(); - return { type, value: this.payload(type) }; - } -} - -class Writer { - constructor() { this.parts = []; } - push(buffer) { this.parts.push(buffer); } - byte(value) { const b = Buffer.allocUnsafe(1); b.writeInt8(value); this.push(b); } - short(value) { const b = Buffer.allocUnsafe(2); b.writeInt16BE(value); this.push(b); } - ushort(value) { const b = Buffer.allocUnsafe(2); b.writeUInt16BE(value); this.push(b); } - int(value) { const b = Buffer.allocUnsafe(4); b.writeInt32BE(value); this.push(b); } - long(value) { const b = Buffer.allocUnsafe(8); b.writeBigInt64BE(BigInt(value)); this.push(b); } - float(value) { const b = Buffer.allocUnsafe(4); b.writeFloatBE(value); this.push(b); } - double(value) { const b = Buffer.allocUnsafe(8); b.writeDoubleBE(value); this.push(b); } - string(value) { const b = Buffer.from(value, "utf8"); this.ushort(b.length); this.push(b); } - - payload(type, value) { - switch (type) { - case TAG.BYTE: this.byte(value); break; - case TAG.SHORT: this.short(value); break; - case TAG.INT: this.int(value); break; - case TAG.LONG: this.long(value); break; - case TAG.FLOAT: this.float(value); break; - case TAG.DOUBLE: this.double(value); break; - case TAG.BYTE_ARRAY: this.int(value.length); this.push(value); break; - case TAG.STRING: this.string(value); break; - case TAG.LIST: - this.byte(value.elementType); - this.int(value.items.length); - for (const item of value.items) this.payload(value.elementType, item); - break; - case TAG.COMPOUND: - for (const [name, child] of Object.entries(value)) { - this.byte(child.type); - this.string(name); - this.payload(child.type, child.value); - } - this.byte(TAG.END); - break; - case TAG.INT_ARRAY: - this.int(value.length); - for (const item of value) this.int(item); - break; - case TAG.LONG_ARRAY: - this.int(value.length); - for (const item of value) this.long(item); - break; - default: throw new Error(`Unsupported NBT tag type ${type}`); - } - } - - root(root) { - this.byte(TAG.COMPOUND); - this.string(""); - this.payload(TAG.COMPOUND, root.value); - return Buffer.concat(this.parts); - } -} - -const inputDir = path.resolve("common-1.21.1/src/main/resources/data/antarchy/structure/kings_tree"); -const outputDir = path.resolve("common-1.21.1/src/main/resources/data/antarchy/structure/kings_tree_tiles"); -const Y_SHIFT = 22; -const TREE_HEIGHT = 358; -const CENTER_X = 137; -const CENTER_Z = 163; -const sources = [ - { file: "kings_tree_bottom.nbt", offset: [0, -22, 0] }, - { file: "kings_tree1.nbt", offset: [0, 0, 0] }, - { file: "kings_tree2.nbt", offset: [-40, 12, -52] }, - { file: "kings_tree3.nbt", offset: [-40, 149, -52] }, - { file: "kings_tree4.nbt", offset: [-54, 233, -64] } -]; -const expectedConnections = [ - ["kings_tree1.nbt", [287, 0, 363], "kings_tree_bottom.nbt", [287, 21, 363]], - ["kings_tree1.nbt", [274, 11, 363], "kings_tree2.nbt", [314, 0, 415]], - ["kings_tree2.nbt", [314, 136, 442], "kings_tree3.nbt", [314, 0, 442]], - ["kings_tree3.nbt", [314, 83, 420], "kings_tree4.nbt", [328, 0, 432]] -]; - -const intList = (...values) => ({ type: TAG.LIST, value: { elementType: TAG.INT, items: values } }); -const doubleList = (...values) => ({ type: TAG.LIST, value: { elementType: TAG.DOUBLE, items: values } }); -const floorDiv = (value, divisor) => Math.floor(value / divisor); -const floorMod = (value, divisor) => ((value % divisor) + divisor) % divisor; -const paletteKey = value => JSON.stringify(value, (_, item) => typeof item === "bigint" ? `${item}n` : item); -const tileNamePart = value => value < 0 ? `m${-value}` : `p${value}`; - -const tiles = new Map(); -const globalPalette = []; -const globalPaletteIds = new Map(); -let dataVersion; -let sourceBlockCount = 0; -let skippedMarkerCount = 0; -const jigsaws = new Map(); - -function getTile(tileX, tileZ) { - const key = `${tileX},${tileZ}`; - let tile = tiles.get(key); - if (!tile) { - tile = { tileX, tileZ, blocks: new Map(), entities: [] }; - tiles.set(key, tile); - } - return tile; -} - -function paletteId(stateTag) { - const key = paletteKey(stateTag); - let id = globalPaletteIds.get(key); - if (id === undefined) { - id = globalPalette.length; - globalPaletteIds.set(key, id); - globalPalette.push(stateTag); - } - return id; -} - -for (const source of sources) { - const compressed = fs.readFileSync(path.join(inputDir, source.file)); - const root = new Reader(zlib.gunzipSync(compressed)).root(); - dataVersion ??= root.value.DataVersion; - const paletteTag = root.value.palette; - if (!paletteTag || paletteTag.type !== TAG.LIST) throw new Error(`${source.file} has no primary palette`); - const palette = paletteTag.value.items; - const remap = palette.map(paletteId); - const blocks = root.value.blocks?.value.items ?? []; - sourceBlockCount += blocks.length; - - for (const block of blocks) { - const stateIndex = block.state.value; - const blockName = palette[stateIndex].Name.value; - if (blockName === "minecraft:jigsaw") { - jigsaws.set(`${source.file}:${block.pos.value.items.join(",")}`, { - state: palette[stateIndex], - nbt: block.nbt?.value ?? {} - }); - } - if (blockName === "minecraft:jigsaw" || blockName === "minecraft:structure_void" || blockName === "minecraft:structure_block") { - skippedMarkerCount++; - continue; - } - - const [x, y, z] = block.pos.value.items; - const relativeX = x + source.offset[0] - CENTER_X; - const relativeY = y + source.offset[1] + Y_SHIFT; - const relativeZ = z + source.offset[2] - CENTER_Z; - if (relativeY < 0 || relativeY >= TREE_HEIGHT) throw new Error(`${source.file} produced out-of-range Y ${relativeY}`); - const tileX = floorDiv(relativeX, 16); - const tileZ = floorDiv(relativeZ, 16); - const localX = floorMod(relativeX, 16); - const localZ = floorMod(relativeZ, 16); - const translated = { - ...block, - pos: intList(localX, relativeY, localZ), - state: { type: TAG.INT, value: remap[stateIndex] } - }; - getTile(tileX, tileZ).blocks.set(`${localX},${relativeY},${localZ}`, translated); - } - - const entities = root.value.entities?.value.items ?? []; - for (const entity of entities) { - const [blockX, blockY, blockZ] = entity.blockPos.value.items; - const [x, y, z] = entity.pos.value.items; - const relativeBlockX = blockX + source.offset[0] - CENTER_X; - const relativeBlockY = blockY + source.offset[1] + Y_SHIFT; - const relativeBlockZ = blockZ + source.offset[2] - CENTER_Z; - const tileX = floorDiv(relativeBlockX, 16); - const tileZ = floorDiv(relativeBlockZ, 16); - const tileOriginX = tileX * 16; - const tileOriginZ = tileZ * 16; - getTile(tileX, tileZ).entities.push({ - ...entity, - blockPos: intList(relativeBlockX - tileOriginX, relativeBlockY, relativeBlockZ - tileOriginZ), - pos: doubleList( - x + source.offset[0] - CENTER_X - tileOriginX, - y + source.offset[1] + Y_SHIFT, - z + source.offset[2] - CENTER_Z - tileOriginZ - ) - }); - } -} - -for (const [parentFile, parentPos, childFile, childPos] of expectedConnections) { - const parent = sources.find(source => source.file === parentFile); - const child = sources.find(source => source.file === childFile); - const parentJigsaw = jigsaws.get(`${parentFile}:${parentPos.join(",")}`); - const childJigsaw = jigsaws.get(`${childFile}:${childPos.join(",")}`); - if (!parentJigsaw || !childJigsaw) { - throw new Error(`Missing expected jigsaw connection between ${parentFile} and ${childFile}`); - } - const parentTarget = parentJigsaw.nbt.target?.value; - const childName = childJigsaw.nbt.name?.value; - if (parentTarget !== childName) { - throw new Error(`Jigsaw target mismatch: ${parentFile} targets ${parentTarget}, but ${childFile} is named ${childName}`); - } - const parentOrientation = parentJigsaw.state.Properties?.value.orientation?.value; - const childOrientation = childJigsaw.state.Properties?.value.orientation?.value; - console.log(`${parentFile} ${parentOrientation} -> ${childFile} ${childOrientation}`); - const [parentFront, parentTop] = parentOrientation.split("_"); - const [childFront, childTop] = childOrientation.split("_"); - const opposite = { up: "down", down: "up", north: "south", south: "north", east: "west", west: "east" }; - const facingStep = { - up: [0, 1, 0], down: [0, -1, 0], north: [0, 0, -1], - south: [0, 0, 1], east: [1, 0, 0], west: [-1, 0, 0] - }; - const parentWorld = parentPos.map((value, axis) => value + parent.offset[axis]); - const expectedChildWorld = parentWorld.map((value, axis) => value + facingStep[parentFront][axis]); - const childWorld = childPos.map((value, axis) => value + child.offset[axis]); - if (expectedChildWorld.some((value, axis) => value !== childWorld[axis])) { - throw new Error(`Misaligned jigsaw connection: ${parentFile} expects ${expectedChildWorld}, but ${childFile} is at ${childWorld}`); - } - if (opposite[parentFront] !== childFront) { - throw new Error(`Jigsaw facing mismatch: ${parentOrientation} cannot connect to ${childOrientation}`); - } - const joint = parentJigsaw.nbt.joint?.value ?? "rollable"; - if (joint === "aligned" && parentTop !== childTop) { - throw new Error(`Jigsaw ${parentFile} requires a rotated child: ${parentOrientation} vs ${childOrientation}`); - } -} - -fs.rmSync(outputDir, { recursive: true, force: true }); -fs.mkdirSync(outputDir, { recursive: true }); -let outputBlockCount = 0; -for (const tile of tiles.values()) { - if (tile.blocks.size === 0 && tile.entities.length === 0) continue; - const root = { - type: TAG.COMPOUND, - value: { - DataVersion: dataVersion, - size: intList(16, TREE_HEIGHT, 16), - palette: { type: TAG.LIST, value: { elementType: TAG.COMPOUND, items: globalPalette } }, - blocks: { type: TAG.LIST, value: { elementType: TAG.COMPOUND, items: [...tile.blocks.values()] } }, - entities: { type: TAG.LIST, value: { elementType: TAG.COMPOUND, items: tile.entities } } - } - }; - outputBlockCount += tile.blocks.size; - const encoded = new Writer().root(root); - const name = `${tileNamePart(tile.tileX)}_${tileNamePart(tile.tileZ)}.nbt`; - fs.writeFileSync(path.join(outputDir, name), zlib.gzipSync(encoded, { level: 9 })); -} - -console.log(`Read ${sourceBlockCount.toLocaleString()} blocks from ${sources.length} templates.`); -console.log(`Skipped ${skippedMarkerCount.toLocaleString()} structure marker blocks.`); -console.log(`Wrote ${outputBlockCount.toLocaleString()} blocks in ${tiles.size} chunk-local templates.`); -console.log(`Global palette contains ${globalPalette.length} block states.`); -console.log(`Validated ${expectedConnections.length} matching jigsaw connections.`);