import { readFile, stat } from "node:fs/promises"; import path from "node:path"; import { describe, expect, it } from "vitest"; import type { AvatarManifest } from "./characterManifest"; interface RunewakerGlbDocument { readonly animations?: readonly { readonly name?: string }[]; readonly nodes?: readonly { readonly name?: string }[]; } function readGlbDocument(glb: Buffer): RunewakerGlbDocument { expect(glb.readUInt32LE(0)).toBe(0x46546c67); const jsonLength = glb.readUInt32LE(12); return JSON.parse( glb.subarray(20, 20 + jsonLength).toString("utf8").trimEnd(), ) as RunewakerGlbDocument; } const manifestFile = path.resolve("public/assets/characters/runewaker-v1/manifest.json"); describe("runewaker-v1 playable avatar pack", () => { it("ships all five authentic race/gender rigs and no female Dwarf", async () => { const manifest = JSON.parse(await readFile(manifestFile, "utf8")) as AvatarManifest; expect(Object.keys(manifest.entries).sort()).toEqual([ "rom-dwarf:male", "rom-elf:female", "rom-elf:male", "rom-human:female", "rom-human:male", ]); expect(manifest.entries["rom-dwarf:female"]).toBeUndefined(); for (const entry of Object.values(manifest.entries)) { expect(entry.rendererStrategy).toMatchObject({ kind: "runewaker-modular", nativeBodyRig: true, sharedSkeleton: true, starterPaperdoll: true, }); expect(entry.animations).toMatchObject({ idle: "Stand - stand_idle01", walk: "Walk - walk_forward", run: "Run - run_forward", attack: "Attack - unarmed_attack01", cast: "Cast - cast01", }); const model = path.resolve("public", entry.model.replace(/^\//, "")); expect((await stat(model)).size).toBe(entry.bytes); const document = readGlbDocument(await readFile(model)); const animationNames = new Set( document.animations?.map((animation) => animation.name ?? "") ?? [], ); for (const animationName of ["Idle - 1h_idle", "Idle - 2h_idle", "Idle - bow_idle"]) { expect(animationNames.has(animationName), `${entry.model} ${animationName}`).toBe(true); } const nodeNames = new Set(document.nodes?.map((node) => node.name ?? "") ?? []); for (const nodeName of ["p_left_hand", "p_right_hand", "p_hand_shield"]) { expect(nodeNames.has(nodeName), `${entry.model} ${nodeName}`).toBe(true); } } }); });