import test from "node:test"; import assert from "node:assert/strict"; import { getBlockFaceTextures, getFaceUV } from "../block-textures.js"; const names = ["stone", "cobblestone", "oak_planks", "oak_log", "oak_log_top", "dirt", "grass_block_top", "grass_block_side", "sand", "gravel", "bricks", "stone_bricks", "glass", "oak_leaves", "diamond_ore", "iron_ore", "coal_ore", "gold_ore", "redstone_ore", "deepslate", "obsidian", "snow", "netherrack", "oak_door_bottom"]; const layers = new Map(names.map((name, index) => [name, index])); const textureNames = (state, available = layers) => getBlockFaceTextures(state, available).map((face) => face ? names[face.layer] : null); test("partial packs keep missing and unrelated materials on the fallback path", () => { for (const state of ["minecraft:spruce_planks", "minecraft:stripped_oak_log[axis=y]", "minecraft:mossy_cobblestone", "minecraft:deepslate_diamond_ore", "mod:stone", "minecraft:oak_trapdoor", "minecraft:stonecutter", "", undefined]) { assert.deepEqual(textureNames(state), Array(6).fill(null), String(state)); } assert.deepEqual(textureNames("minecraft:stone", new Map()), Array(6).fill(null)); assert.equal(getBlockFaceTextures("minecraft:stone", layers)[0].layer, 0); assert.deepEqual(textureNames("minecraft:stone", new Map([["stone", -1]])), Array(6).fill(null)); }); test("material variants use their own surface without broad substring matching", () => { for (const [state, texture] of [["oak_stairs[facing=east,half=bottom]", "oak_planks"], ["cobblestone_wall[north=low]", "cobblestone"], ["stone_brick_slab[type=top]", "stone_bricks"], ["brick_stairs", "bricks"], ["snow_block", "snow"]]) { assert.deepEqual(textureNames(`minecraft:${state}`), Array(6).fill(texture)); } }); test("grass uses a tinted top, full-color sides and a dirt bottom independently", () => { assert.deepEqual(textureNames("minecraft:grass_block[snowy=false]"), ["grass_block_side", "grass_block_side", "grass_block_top", "dirt", "grass_block_side", "grass_block_side"]); const faces = getBlockFaceTextures("minecraft:grass_block", layers); assert.ok(faces[2].tint[1] > faces[2].tint[0] && faces[2].tint[0] > faces[2].tint[2]); assert.deepEqual(faces[0].tint, [1, 1, 1]); assert.equal(faces[2].cutout, false); assert.deepEqual(textureNames("minecraft:grass_block[snowy=true]"), [null, null, "grass_block_top", "dirt", null, null]); const missingSide = new Map(layers); missingSide.delete("grass_block_side"); assert.deepEqual(textureNames("minecraft:grass_block", missingSide), [null, null, "grass_block_top", "dirt", null, null]); }); test("log end grain follows every axis while oak wood remains bark on all faces", () => { for (const [axis, caps] of [["x", [0, 1]], ["y", [2, 3]], ["z", [4, 5]]]) { assert.deepEqual(textureNames(`minecraft:oak_log[axis=${axis}]`), Array.from({ length: 6 }, (_, face) => caps.includes(face) ? "oak_log_top" : "oak_log")); } assert.deepEqual(textureNames("minecraft:oak_log"), textureNames("minecraft:oak_log[axis=y]")); assert.deepEqual(textureNames("minecraft:oak_wood[axis=x]"), Array(6).fill("oak_log")); }); test("cutout textures preserve full-color glass and tint grayscale leaves", () => { const glass = getBlockFaceTextures("minecraft:glass", layers); const leaves = getBlockFaceTextures("minecraft:oak_leaves[persistent=true]", layers); assert.ok(glass.every((face) => face.cutout)); assert.ok(leaves.every((face) => face.cutout)); assert.deepEqual(glass[0].tint, [1, 1, 1]); assert.ok(leaves[0].tint[1] > leaves[0].tint[0] && leaves[0].tint[0] > leaves[0].tint[2]); }); test("doors use lower artwork only on the lower broad faces, respecting open rotation", () => { const alongZ = ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_door_bottom", "oak_door_bottom"]; const alongX = ["oak_door_bottom", "oak_door_bottom", "oak_planks", "oak_planks", "oak_planks", "oak_planks"]; for (const facing of ["north", "south", "east", "west"]) { const x = ["east", "west"].includes(facing); assert.deepEqual(textureNames(`minecraft:oak_door[half=lower,facing=${facing},open=false]`), x ? alongX : alongZ); assert.deepEqual(textureNames(`minecraft:oak_door[half=lower,facing=${facing},open=true]`), x ? alongZ : alongX); assert.deepEqual(textureNames(`minecraft:oak_door[half=upper,facing=${facing},open=false]`), Array(6).fill(null)); } }); test("face UVs orient a top-left source consistently from outside each cube face", () => { const corners = [ [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]], [[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 0]], [[0, 1, 1], [1, 1, 1], [1, 1, 0], [0, 1, 0]], [[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1]], [[0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], [[1, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], ]; for (let face = 0; face < 6; face++) { assert.deepEqual(corners[face].map((pos) => getFaceUV(face, pos)), [[0, 1], [1, 1], [1, 0], [0, 0]]); } assert.deepEqual(getFaceUV(4, [0.25, 0.5, 1]), [0.25, 0.5]); assert.deepEqual(getFaceUV(0, [1, 1.5, 0.25]), [0.75, -0.5]); assert.throws(() => getFaceUV(6, [0, 0, 0]), RangeError); }); test("horizontal log bark follows the log axis through a proper cube rotation", () => { const vertical = [0.25, 0.75, 0.125]; // Rotate the same point and normal with the complete cube, then compare UVs. const horizontalX = [vertical[1], 1 - vertical[0], vertical[2]]; const horizontalZ = [vertical[0], 1 - vertical[2], vertical[1]]; const faceFromVerticalX = [3, 2, 0, 1, 4, 5]; const faceFromVerticalZ = [0, 1, 4, 5, 3, 2]; for (const block of ["oak_log", "oak_wood"]) { for (let face = 0; face < 6; face++) { const expected = getFaceUV(face, vertical); assert.deepEqual(getFaceUV(faceFromVerticalX[face], horizontalX, `minecraft:${block}[axis=x]`), expected); assert.deepEqual(getFaceUV(faceFromVerticalZ[face], horizontalZ, `minecraft:${block}[axis=z]`), expected); assert.deepEqual(getFaceUV(face, vertical, `minecraft:${block}[axis=y]`), expected); } } for (const [axis, sideFaces] of [["x", [2, 3, 4, 5]], ["z", [0, 1, 2, 3]]]) { for (const face of sideFaces) { const point = [0.25, 0.5, 0.75]; const coordinate = axis === "x" ? point[0] : point[2]; assert.equal(getFaceUV(face, point, `minecraft:oak_log[axis=${axis}]`)[1], 1 - coordinate); } } assert.deepEqual(getFaceUV(4, vertical, "minecraft:deepslate[axis=x]"), getFaceUV(4, vertical)); assert.deepEqual(getFaceUV(4, vertical, "mod:oak_log[axis=x]"), getFaceUV(4, vertical)); });