62 lines
2.4 KiB
TypeScript
62 lines
2.4 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
});
|
|
});
|