Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -0,0 +1,128 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { constants } from "node:fs";
|
||||
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
const magma = process.argv.includes("--magma");
|
||||
const stage = magma ? "artifacts/playtest/rom-room-coverage/lair-magma-alpha-stage" : "artifacts/playtest/rom-room-coverage/native-alpha-stage";
|
||||
const slugs = magma ? ["lair-demon-dragon"] : ["cave-water-dragon", "kulech-bones-nest", "mystic-altar", "raksha-temple", "sardo-castle", "tomb-seven-heroes"];
|
||||
const proofKey = magma ? "nativeMagmaAlpha" : "nativeWaterfallAlpha";
|
||||
const backup = `${stage}/pre-promotion-backup`;
|
||||
const sha = bytes => createHash("sha256").update(bytes).digest("hex");
|
||||
const json = async file => JSON.parse(await readFile(file, "utf8"));
|
||||
const copies = [];
|
||||
const edits = [];
|
||||
const proofs = [];
|
||||
const visuals = await json(`${stage}/${magma ? "lair-magma-alpha-ab.json" : "gate-waterfall-triangle-pairs-report.json"}`);
|
||||
|
||||
for (const slug of slugs) {
|
||||
const directory = magma ? stage : `${stage}/${slug}`;
|
||||
const reportFile = `${directory}/${magma ? "lair-magma-alpha-stage-report.json" : "native-waterfall-alpha-stage-report.json"}`;
|
||||
const report = await json(reportFile);
|
||||
assert.equal(report.dungeonId, slug);
|
||||
const visual = magma ? visuals : visuals.dungeons.find(row => row.slug === slug);
|
||||
if (magma) {
|
||||
for (const value of Object.values(visual.checks)) assert.equal(value, true);
|
||||
assert.equal(visual.candidateSha256, report.optimized.sha256);
|
||||
assert.equal(report.optimized.targetAlphaMode, "MASK");
|
||||
assert.equal(report.optimized.targetAlphaCutoff, 192 / 255);
|
||||
assert.equal(report.optimized.targetUnlit, true);
|
||||
} else {
|
||||
assert.equal(visual?.status, "direct-hit-paired", `${slug}: require a same-camera visible waterfall pair`);
|
||||
assert.equal(visual.errors.length, 0);
|
||||
assert.equal(visual.afterFirstHit.transparent, true, `${slug}: candidate must actually supply native blending`);
|
||||
assert.ok(visual.afterFirstHit.nativeSourceModel, `${slug}: candidate provenance missing from runtime hit`);
|
||||
assert.equal(visual.stagedResponseSha256, report.optimized.sha256);
|
||||
}
|
||||
assert.ok(report.alphaPatch.bindingCount > 0);
|
||||
assert.equal(report.alphaPatch.binBytesUnchanged, true);
|
||||
assert.equal(report.alphaPatch.beforeBinSha256, report.alphaPatch.afterBinSha256);
|
||||
const layout = await json(`${directory}/final-source-layout-proof.json`);
|
||||
assert.equal(layout.geometryAndHierarchyUnchanged, true);
|
||||
assert.equal(layout.sourceImageBytesUnchanged, true);
|
||||
assert.equal(layout.sourceSha256, report.sourceVisual.sha256);
|
||||
assert.equal(layout.stagedSha256, report.stagedSource.sha256);
|
||||
const alphaImages = magma ? [report.optimized.decodedKtxAlpha] : report.optimized.gateWaterfallKtxAlpha;
|
||||
assert.ok(alphaImages?.length > 0, `${slug}: decode alpha before promotion`);
|
||||
for (const image of alphaImages) {
|
||||
if (!magma) assert.equal(image.hasAlpha, true);
|
||||
assert.ok(image.decodedAlphaRange[0] < image.decodedAlphaRange[1] && image.decodedAlphaRange[1] <= 255);
|
||||
if (!magma) assert.ok(image.decodedAlphaRange[1] < 255);
|
||||
}
|
||||
for (const source of report.sourceTextureProvenance) {
|
||||
assert.equal(sha(await readFile(source.sourceTexturePath)), source.sourceTextureSha256);
|
||||
assert.equal(sha(await readFile(source.sourcePngPath)), source.sourcePngSha256);
|
||||
}
|
||||
assert.equal(sha(await readFile(report.sourceVisual.file)), report.sourceVisual.sha256);
|
||||
const canonicalBytes = await readFile(report.stagedSource.file);
|
||||
assert.equal(sha(canonicalBytes), report.stagedSource.sha256);
|
||||
assert.equal(canonicalBytes.length, report.stagedSource.bytes);
|
||||
assert.equal(sha(await readFile(report.optimized.file)), report.optimized.sha256);
|
||||
const ship = `src/assets/game/dungeons/${slug}`;
|
||||
const converted = `runewaker-export-work/${slug}/converted`;
|
||||
const oldShipping = sha(await readFile(`${ship}/${slug}-visual.glb`));
|
||||
assert.equal(sha(await readFile(`${converted}/${slug}-visual.optimized.glb`)), oldShipping);
|
||||
copies.push(
|
||||
{ file: report.sourceVisual.file, staged: report.stagedSource.file, previousSha256: report.sourceVisual.sha256, sha256: report.stagedSource.sha256 },
|
||||
...[`${ship}/${slug}-visual.glb`, `${converted}/${slug}-visual.optimized.glb`].map(file => ({ file, staged: report.optimized.file, previousSha256: oldShipping, sha256: report.optimized.sha256 })),
|
||||
);
|
||||
const proof = {
|
||||
stageReport: reportFile,
|
||||
canonicalBefore: report.sourceVisual.sha256, canonicalAfter: report.stagedSource.sha256,
|
||||
shippingBefore: oldShipping, shippingAfter: report.optimized.sha256,
|
||||
bindingCount: report.alphaPatch.bindingCount,
|
||||
sourceTextureProvenance: report.sourceTextureProvenance,
|
||||
alphaPatch: report.alphaPatch,
|
||||
finalSourceLayout: layout,
|
||||
directVisualProof: visual,
|
||||
decodedKtxAlpha: alphaImages,
|
||||
};
|
||||
proofs.push({ dungeonId: slug, ...proof });
|
||||
for (const directory of [ship, converted]) {
|
||||
for (const name of ["import-metadata.json", "optimization-report.json", "conversion-report.json"]) {
|
||||
const file = `${directory}/${name}`;
|
||||
const bytes = await readFile(file).catch(error => {
|
||||
if (directory === converted && name === "import-metadata.json" && error.code === "ENOENT") return null;
|
||||
throw error;
|
||||
});
|
||||
if (!bytes) continue;
|
||||
const data = JSON.parse(bytes);
|
||||
if (name === "import-metadata.json") {
|
||||
const visual = data.assets.find(row => row.role === "visual");
|
||||
if (directory === ship) assert.equal(visual.sha256, oldShipping);
|
||||
visual.sha256 = report.optimized.sha256;
|
||||
visual.size = report.optimized.bytes;
|
||||
data.continuationReview ??= {};
|
||||
data.continuationReview[proofKey] = proof;
|
||||
if (data.nativeMaterialSemantics?.assembledSourceSha256) data.nativeMaterialSemantics.assembledSourceSha256 = report.stagedSource.sha256;
|
||||
} else if (name === "optimization-report.json") {
|
||||
if (directory === ship) assert.equal(data.optimized.checksum, oldShipping);
|
||||
data.source.checksum = report.stagedSource.sha256;
|
||||
data.source.size = report.stagedSource.bytes;
|
||||
data.optimized.checksum = report.optimized.sha256;
|
||||
data.optimized.size = report.optimized.bytes;
|
||||
data.compression = "meshopt+ktx2";
|
||||
data.textureQuality = await json(report.optimized.textureQualityReport);
|
||||
data.nativeMaterialSemantics = report.nativeMaterialSemantics;
|
||||
data[proofKey] = proof;
|
||||
} else {
|
||||
data.continuationIntegrityProof ??= {};
|
||||
data.continuationIntegrityProof[proofKey] = proof;
|
||||
}
|
||||
edits.push({ file, bytes, data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All old and candidate identities have been checked before the first write.
|
||||
// Exclusive backups make an accidental repeat fail without losing the baseline.
|
||||
for (const row of [...copies, ...edits]) {
|
||||
const destination = path.join(backup, row.file);
|
||||
await mkdir(path.dirname(destination), { recursive: true });
|
||||
await copyFile(row.file, destination, constants.COPYFILE_EXCL);
|
||||
}
|
||||
for (const row of copies) await copyFile(row.staged, row.file);
|
||||
for (const row of edits) await writeFile(row.file, `${JSON.stringify(row.data, null, 2)}\n`);
|
||||
await writeFile(`${stage}/promotion-proof.json`, `${JSON.stringify({ schemaVersion: 1, backup, files: copies, dungeons: proofs }, null, 2)}\n`);
|
||||
console.log(JSON.stringify({ promoted: slugs, files: copies.length, backup }));
|
||||
Reference in new issue
Block a user