103 lines
4.0 KiB
JavaScript
103 lines
4.0 KiB
JavaScript
import { stat } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import {
|
|
clientRootForRecipe,
|
|
exists,
|
|
fixturesRoot,
|
|
loadRecipe,
|
|
projectRoot,
|
|
readJson,
|
|
recipesRoot,
|
|
workRoot,
|
|
} from "./lib.mjs";
|
|
import { runWowExporter } from "./wow-export-tool.mjs";
|
|
|
|
async function resultMtime(output) {
|
|
const resultFile = path.join(output, "automation-result.json");
|
|
return await exists(resultFile) ? (await stat(resultFile)).mtimeMs : 0;
|
|
}
|
|
|
|
async function checkedResult(slug, output, previousMtime) {
|
|
const resultFile = path.join(output, "automation-result.json");
|
|
if (!await exists(resultFile)) return { status: "blocked", dungeonId: slug, blockers: [`wow.export produced no automation result at ${resultFile}.`] };
|
|
if ((await stat(resultFile)).mtimeMs <= previousMtime) return {
|
|
status: "blocked",
|
|
dungeonId: slug,
|
|
blockers: [`wow.export did not refresh ${resultFile}; refusing to accept a stale result from an earlier run.`],
|
|
};
|
|
const result = await readJson(resultFile);
|
|
if (!result.ok) return {
|
|
status: "blocked",
|
|
dungeonId: slug,
|
|
blockers: result.missingDependencies?.length
|
|
? result.missingDependencies.map((dependency) => `Missing ${dependency.type} dependency ${dependency.path}.`)
|
|
: [result.error ?? "wow.export reported an unknown extraction failure."],
|
|
};
|
|
return null;
|
|
}
|
|
|
|
export async function exportDungeonSource(slug) {
|
|
const recipe = await loadRecipe(slug);
|
|
const clientRoot = clientRootForRecipe(recipe);
|
|
const output = path.join(workRoot, slug, "source-export");
|
|
const previousMtime = await resultMtime(output);
|
|
await runWowExporter([
|
|
"--export-dungeon",
|
|
"--recipe", path.join(recipesRoot, `${slug}.json`),
|
|
"--client-root", clientRoot,
|
|
"--output", output,
|
|
], { projectRoot });
|
|
const blocked = await checkedResult(slug, output, previousMtime);
|
|
if (blocked) return blocked;
|
|
return { status: "green", dungeonId: slug, output: path.relative(projectRoot, output).replace(/\\/g, "/") };
|
|
}
|
|
|
|
export async function exportClientDiscoveryTables(slug) {
|
|
const recipe = await loadRecipe(slug);
|
|
const clientRoot = clientRootForRecipe(recipe);
|
|
const output = path.join(workRoot, slug, "client-dbc");
|
|
const previousMtime = await resultMtime(output);
|
|
await runWowExporter([
|
|
"--discover-dungeon",
|
|
"--recipe", path.join(recipesRoot, `${slug}.json`),
|
|
"--client-root", clientRoot,
|
|
"--output", output,
|
|
], { projectRoot });
|
|
const blocked = await checkedResult(slug, output, previousMtime);
|
|
if (blocked) throw new Error(blocked.blockers.join("\n"));
|
|
return output;
|
|
}
|
|
|
|
export async function exportCreatureSource(slug) {
|
|
const recipe = await loadRecipe(slug);
|
|
const clientRoot = clientRootForRecipe(recipe);
|
|
let selected = recipe.creatures?.length ? path.join(recipesRoot, `${slug}.json`) : null;
|
|
for (const candidate of [
|
|
path.join(workRoot, slug, "creature-export.recipe.json"),
|
|
path.join(fixturesRoot, slug, "creature-export.recipe.json"),
|
|
]) {
|
|
if (await exists(candidate)) { selected = candidate; break; }
|
|
}
|
|
if (!selected) throw new Error(`${slug}: reviewed creature-export.recipe.json is missing.`);
|
|
const selectedRecipe = await readJson(selected);
|
|
const unresolved = (selectedRecipe.creatures ?? []).filter((creature) => (
|
|
creature.unresolvedComposite || !creature.displayId || !creature.modelPath
|
|
));
|
|
if (unresolved.length) return {
|
|
status: "blocked",
|
|
dungeonId: slug,
|
|
blockers: unresolved.map((creature) => `${creature.name ?? creature.slug} has an unresolved display/composite recipe.`),
|
|
};
|
|
const output = path.join(workRoot, slug, "creature-source");
|
|
const previousMtime = await resultMtime(output);
|
|
await runWowExporter([
|
|
"--export-creatures",
|
|
"--recipe", selected,
|
|
"--client-root", clientRoot,
|
|
"--output", output,
|
|
], { projectRoot });
|
|
const blocked = await checkedResult(slug, output, previousMtime);
|
|
if (blocked) return blocked;
|
|
return { status: "green", dungeonId: slug, output: path.relative(projectRoot, output).replace(/\\/g, "/") };
|
|
}
|