66 lines
3.8 KiB
JavaScript
66 lines
3.8 KiB
JavaScript
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 stage = "artifacts/playtest/rom-deep-review/water-screen-effects";
|
|
const proof = JSON.parse(await readFile(`${stage}/proof.json`, "utf8"));
|
|
const browser = JSON.parse(await readFile(`${stage}/browser-proof.json`, "utf8"));
|
|
assert.ok(browser.some(row => row.staged && !row.errors.length && row.water.some(layer => layer.screenEffectsReady === 1)));
|
|
const sha = bytes => createHash("sha256").update(bytes).digest("hex");
|
|
const writeJson = (file, data) => writeFile(file, `${JSON.stringify(data, null, 2)}\n`);
|
|
const canonical = proof.files.find(row => row.kind === "canonical");
|
|
const shipping = proof.files.find(row => row.kind === "shipping");
|
|
const backup = `${stage}/pre-promotion-backup`;
|
|
const directories = ["src/assets/game/dungeons/the-origin", "runewaker-export-work/the-origin/converted"];
|
|
const edits = [];
|
|
for (const directory of directories) {
|
|
for (const name of ["import-metadata.json", "optimization-report.json", "conversion-report.json"]) {
|
|
const file = `${directory}/${name}`;
|
|
const bytes = await readFile(file);
|
|
const data = JSON.parse(bytes);
|
|
if (name === "import-metadata.json") {
|
|
const visual = data.assets.find(row => row.role === "visual");
|
|
assert.equal(visual.sha256, shipping.previousSha256);
|
|
visual.sha256 = shipping.sha256;
|
|
visual.size = shipping.bytes;
|
|
data.nativeMaterialSemantics.assembledSourceSha256 = canonical.sha256;
|
|
data.continuationReview.waterScreenEffects = proof;
|
|
} else if (name === "optimization-report.json") {
|
|
assert.equal(data.source.checksum, canonical.previousSha256);
|
|
assert.equal(data.optimized.checksum, shipping.previousSha256);
|
|
data.source.checksum = canonical.sha256;
|
|
data.source.size = canonical.bytes;
|
|
data.optimized.checksum = shipping.sha256;
|
|
data.optimized.size = shipping.bytes;
|
|
data.waterScreenEffects = proof;
|
|
} else {
|
|
data.continuationIntegrityProof.waterScreenEffects = proof;
|
|
}
|
|
edits.push({ file, bytes, data });
|
|
}
|
|
}
|
|
const nativeFile = "src/assets/game/dungeons/the-origin/native-water-report.json";
|
|
const nativeBytes = await readFile(nativeFile);
|
|
const native = JSON.parse(nativeBytes);
|
|
native.waterScreenEffects = proof;
|
|
native.nativeMaterialSemantics.viewportMaterial = "Source-enabled browser reflection/refraction with native split planes, .025 bump perturbation and Fresnel .02037/.97963 coefficients. Three.js lighting replaces native SH; reflect-class filtering is unsupported.";
|
|
native.limitations = native.limitations.filter(row => !row.includes("projected screen reflection/refraction paths"));
|
|
native.limitations.push("Browser screen effects use up to four 512px plane pairs per asset and at most ten two-pass captures per second. Additional planes and below-plane views retain the lit animated fallback. Native SH and reflect-class filtering remain unsupported.");
|
|
edits.push({ file: nativeFile, bytes: nativeBytes, data: native });
|
|
|
|
// Verify every expected old/new identity before any canonical mutation.
|
|
for (const row of proof.files) {
|
|
assert.equal(sha(await readFile(row.file)), row.previousSha256);
|
|
assert.equal(sha(await readFile(row.staged)), row.sha256);
|
|
}
|
|
for (const row of [...proof.files, ...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 proof.files) await copyFile(row.staged, row.file);
|
|
for (const row of edits) await writeJson(row.file, row.data);
|
|
console.log(JSON.stringify({ promoted: proof.files.map(row => ({ file: row.file, sha256: row.sha256 })), backup }));
|