forked from phenom/healer-man
113 lines
6.4 KiB
JavaScript
113 lines
6.4 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createHash } from "node:crypto";
|
|
import { existsSync } from "node:fs";
|
|
import { readFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { Document, NodeIO } from "@gltf-transform/core";
|
|
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
|
import { MeshoptDecoder } from "meshoptimizer";
|
|
import { applyRunewakerDerivedSupportStyling, listRunewakerDerivedSupportStylingPolicies } from "./rom-derived-support-styling.mjs";
|
|
import { applyRunewakerDerivedSupportStylingToFile } from "./rom-derived-support-styling-file.mjs";
|
|
|
|
const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
const mysticVisual = path.join(repositoryRoot, "runewaker-export-work/mystic-altar/converted/mystic-altar-visual.glb");
|
|
const mysticReport = path.join(repositoryRoot, "runewaker-export-work/mystic-altar/prepared/export-report.json");
|
|
const mysticMetadata = path.join(repositoryRoot, "src/assets/game/dungeons/mystic-altar/import-metadata.json");
|
|
const mysticDds = path.join(repositoryRoot, "runewaker-export-work/mystic-altar/raw/textures/caa8475c_mystic_altar_floor.dds");
|
|
const mysticRos = path.resolve(repositoryRoot, "../rom-pvt-server-backups/Runewaker/Resource/model/dungeon/mystic_altar/act_mystic_altar_instance.ros");
|
|
const sourceSha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
|
|
function accessorSnapshot(document) {
|
|
return document.getRoot().listAccessors().map((accessor) => {
|
|
const array = accessor.getArray();
|
|
return JSON.stringify({
|
|
name: accessor.getName(),
|
|
type: accessor.getType(),
|
|
count: accessor.getCount(),
|
|
hash: array ? sourceSha256(Buffer.from(array.buffer, array.byteOffset, array.byteLength)) : null,
|
|
});
|
|
}).sort();
|
|
}
|
|
|
|
function imageSnapshot(document) {
|
|
return document.getRoot().listTextures().map((texture) => JSON.stringify({
|
|
name: texture.getName(),
|
|
hash: sourceSha256(Buffer.from(texture.getImage() ?? [])),
|
|
})).sort();
|
|
}
|
|
|
|
test("unlisted packages do not read or mutate a converted source", async () => {
|
|
assert.deepEqual(await applyRunewakerDerivedSupportStylingToFile("missing-source.glb", {}), {
|
|
status: "not-requested", geometryChanged: false,
|
|
});
|
|
});
|
|
|
|
test("the base Demon support policy refuses the level125 variant before mutation", () => {
|
|
const document = new Document();
|
|
assert.throws(() => applyRunewakerDerivedSupportStyling(document, {
|
|
dungeonId: "demon-stronghold-125", policyId: listRunewakerDerivedSupportStylingPolicies()[0].id,
|
|
}), /cannot run/);
|
|
assert.equal(document.getRoot().listMaterials().length, 0);
|
|
});
|
|
|
|
test("the reviewed floor cannot be substituted with mismatched source DDS content", () => {
|
|
const policy = listRunewakerDerivedSupportStylingPolicies()[0];
|
|
const document = new Document();
|
|
assert.throws(() => applyRunewakerDerivedSupportStyling(document, {
|
|
dungeonId: policy.dungeonId, policyId: policy.id,
|
|
sourceReport: { sourceModel: policy.sourceModel, sourceResourceSha256: policy.sourceModelSha256,
|
|
materials: [{ name: policy.sourceMaterial, sourceTexture: policy.sourceTexture, stagedTexture: policy.stagedTexture }] },
|
|
sourceDdsBytes: Buffer.from("unreviewed floor"),
|
|
}), /source DDS hash/);
|
|
assert.equal(document.getRoot().listMaterials().length, 0);
|
|
});
|
|
|
|
test("Mystic derived pads use the source floor UV mapping without changing native accessors or images", {
|
|
skip: ![mysticVisual, mysticReport, mysticMetadata, mysticDds, mysticRos].every(existsSync),
|
|
}, async () => {
|
|
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS).registerDependencies({ "meshopt.decoder": MeshoptDecoder });
|
|
await MeshoptDecoder.ready;
|
|
const document = await io.read(mysticVisual);
|
|
const policy = listRunewakerDerivedSupportStylingPolicies().find(({ dungeonId }) => dungeonId === "mystic-altar");
|
|
assert.ok(policy);
|
|
const sourceReport = JSON.parse(await readFile(mysticReport, "utf8"));
|
|
const metadata = JSON.parse(await readFile(mysticMetadata, "utf8"));
|
|
sourceReport.sourceResourceSha256 = metadata.source.modelSha256;
|
|
const sourceDdsBytes = await readFile(mysticDds);
|
|
assert.equal(sourceSha256(await readFile(mysticRos)), policy.sourceModelSha256);
|
|
const originalAccessors = accessorSnapshot(document);
|
|
const originalImages = imageSnapshot(document);
|
|
const floorMaterial = document.getRoot().listMaterials().find((material) => material.getName() === policy.sourceMaterial);
|
|
const floorUv = floorMaterial?.getBaseColorTextureInfo()?.getTexCoord();
|
|
const floorImageHash = sourceSha256(Buffer.from(floorMaterial?.getBaseColorTexture()?.getImage() ?? []));
|
|
|
|
const result = applyRunewakerDerivedSupportStyling(document, {
|
|
dungeonId: "mystic-altar",
|
|
policyId: policy.id,
|
|
sourceReport,
|
|
sourceDdsBytes,
|
|
});
|
|
|
|
assert.equal(result.status, "applied");
|
|
assert.equal(result.padCount, 250);
|
|
assert.equal(result.triangleCount, 3000);
|
|
assert.deepEqual(result.sourceFloorReference.anchorWorld, policy.anchorWorld);
|
|
assert.deepEqual(result.sourceFloorReference.anchorUv, policy.anchorUv);
|
|
assert.equal(result.sourceFloorReference.densityPixelsPerMeter, 22.176030799610068);
|
|
assert.ok(Object.values(result.sourceFloorReference.fullRankFaceDeterminants).every((value) => Math.abs(value) > 1e-8));
|
|
const support = document.getRoot().listNodes().find((node) => node.getName() === policy.supportNode);
|
|
const supportPrimitive = support?.getMesh()?.listPrimitives()[0];
|
|
assert.ok(supportPrimitive?.getAttribute("TEXCOORD_1"));
|
|
assert.equal(supportPrimitive.getAttribute("TEXCOORD_0"), null);
|
|
assert.equal(supportPrimitive.getExtras().romDerivedSupportStyling.sourcePositionHash, result.policy.sourcePositionHash);
|
|
assert.equal(supportPrimitive.getExtras().romDerivedSupportStyling.sourceIndexHash, result.policy.sourceIndexHash);
|
|
const styledAccessors = accessorSnapshot(document);
|
|
for (const original of originalAccessors) assert.ok(styledAccessors.includes(original), `missing original accessor ${original}`);
|
|
assert.deepEqual(imageSnapshot(document), originalImages);
|
|
const unchangedFloorMaterial = document.getRoot().listMaterials().find((material) => material.getName() === policy.sourceMaterial);
|
|
assert.equal(unchangedFloorMaterial?.getBaseColorTextureInfo()?.getTexCoord(), floorUv);
|
|
assert.equal(sourceSha256(Buffer.from(unchangedFloorMaterial?.getBaseColorTexture()?.getImage() ?? [])), floorImageHash);
|
|
});
|