forked from phenom/healer-man
52 lines
1.9 KiB
JavaScript
52 lines
1.9 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { ensureWithinProject } from "./native-water-build-utils.mjs";
|
|
|
|
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
|
|
async function writeOrVerify(file, bytes, expectedHash) {
|
|
await mkdir(path.dirname(file), { recursive: true });
|
|
try {
|
|
await writeFile(file, bytes, { flag: "wx" });
|
|
} catch (error) {
|
|
if (error.code !== "EEXIST") throw error;
|
|
}
|
|
const persisted = await readFile(file);
|
|
const actualHash = sha256(persisted);
|
|
if (actualHash !== expectedHash || !persisted.equals(bytes)) {
|
|
throw new Error(`Refusing to replace non-identical native water audit-cache alias: ${file}`);
|
|
}
|
|
return { sha256: actualHash, bytes: persisted.length };
|
|
}
|
|
|
|
/** Write exact source and prepared-frame aliases for the environment-quality audit. */
|
|
export async function writeNativeWaterAuditCacheAliases({
|
|
projectRoot,
|
|
auditCacheRoot,
|
|
variantName,
|
|
ddsBytes,
|
|
pngBytes,
|
|
}) {
|
|
if (!auditCacheRoot) return null;
|
|
if (!/^[a-z\d][a-z\d_-]*$/i.test(variantName)) {
|
|
throw new Error(`Native water audit alias must be a safe texture basename: ${variantName}`);
|
|
}
|
|
ensureWithinProject(projectRoot, auditCacheRoot);
|
|
const root = path.resolve(auditCacheRoot);
|
|
const ddsHash = sha256(ddsBytes);
|
|
const pngHash = sha256(pngBytes);
|
|
const ddsFile = path.join(root, "raw", "textures", `${variantName}.dds`);
|
|
const pngFile = path.join(root, "prepared", "textures", `${variantName}.png`);
|
|
const [dds, png] = await Promise.all([
|
|
writeOrVerify(ddsFile, ddsBytes, ddsHash),
|
|
writeOrVerify(pngFile, pngBytes, pngHash),
|
|
]);
|
|
const relative = (file) => path.relative(projectRoot, file).replaceAll("\\", "/");
|
|
return {
|
|
textureBasename: variantName,
|
|
rawDds: { path: relative(ddsFile), ...dds },
|
|
preparedPng: { path: relative(pngFile), ...png },
|
|
};
|
|
}
|