import { createHash } from "node:crypto"; import { readFile, stat, writeFile } from "node:fs/promises"; import path from "node:path"; import { NodeIO } from "@gltf-transform/core"; import { ALL_EXTENSIONS } from "@gltf-transform/extensions"; import { MeshoptDecoder } from "meshoptimizer"; import { extractNavigationComponent } from "./extract-navigation-component.mjs"; const projectRoot = path.resolve(import.meta.dirname, "../.."); const directory = path.join(projectRoot, "public/assets/game/arenas/warnorken-arena"); const source = path.join(directory, "navigation-source.glb"); const output = path.join(directory, "navigation.glb"); const teamSpawns = [[-42.7, -21.75, 14.12], [41.3, -21.65, -6.58]]; const connected = await extractNavigationComponent({ source, output, teamSpawns }); const io = new NodeIO().registerExtensions(ALL_EXTENSIONS).registerDependencies({ "meshopt.decoder": MeshoptDecoder }); const assets = []; for (const name of ["visual", "collision", "navigation"]) { const file = path.join(directory, `${name}.glb`); const bytes = await readFile(file); const document = await io.read(file); const triangles = document.getRoot().listMeshes().reduce((sum, mesh) => sum + mesh.listPrimitives().reduce((primitiveSum, primitive) => primitiveSum + (primitive.getIndices()?.getCount() ?? primitive.getAttribute("POSITION")?.getCount() ?? 0) / 3, 0), 0); assets.push({ file: `${name}.glb`, bytes: (await stat(file)).size, triangles: Math.round(triangles), sha256: createHash("sha256").update(bytes).digest("hex") }); } await writeFile(path.join(directory, "stage-pack.json"), `${JSON.stringify({ schemaVersion: 1, id: "warnorken-arena", title: "Warnorken Arena", status: "validated", source: { kind: "validated-runewaker-package", navigationSource: "navigation-source.glb" }, navigation: connected, assets, }, null, 2)}\n`); console.log(`warnorken-arena: ${connected.triangles} connected navigation triangles`);