import { readFile } from "node:fs/promises"; import { fileURLToPath } from "node:url"; import { dirname, resolve } from "node:path"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; globalThis.self = globalThis; globalThis.createImageBitmap = async () => ({ width: 1, height: 1, close() {}, }); globalThis.ProgressEvent ??= class ProgressEvent { constructor(type, init = {}) { this.type = type; Object.assign(this, init); } }; const here = dirname(fileURLToPath(import.meta.url)); const visualPath = resolve( here, "../src/assets/game/dungeons/wailing-caverns/wailing-caverns-visual.glb", ); const bytes = await readFile(visualPath); const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); const gltf = await new Promise((resolveLoad, rejectLoad) => { new GLTFLoader().parse(arrayBuffer, "", resolveLoad, rejectLoad); }); const summarize = (root) => { const uniqueMaterials = new Map(); let meshes = 0; let instancedMeshes = 0; let representedInstances = 0; root.traverse((object) => { if (!object.isMesh) return; meshes += 1; if (object.isInstancedMesh) { instancedMeshes += 1; representedInstances += object.count; } const materials = Array.isArray(object.material) ? object.material : [object.material]; for (const material of materials) { const existing = uniqueMaterials.get(material.uuid) ?? { name: material.name || "(unnamed)", uses: 0, transparent: material.transparent, opacity: material.opacity, alphaTest: material.alphaTest, depthWrite: material.depthWrite, side: material.side, map: material.map?.name ?? null, }; existing.uses += 1; uniqueMaterials.set(material.uuid, existing); } }); return { name: root.name, meshes, instancedMeshes, representedInstances, materials: [...uniqueMaterials.values()].sort((a, b) => a.name.localeCompare(b.name)), }; }; const shell = gltf.scene.getObjectByName("WailingCaverns_Shell"); console.log(JSON.stringify({ topLevel: gltf.scene.children.map((child) => ({ name: child.name, type: child.type, children: child.children.length, })), fullScene: summarize(gltf.scene), shell: shell ? summarize(shell) : null, }, null, 2));