Files
2026-08-14 15:56:39 -04:00

101 lines
3.8 KiB
JavaScript

import { spawn } from "node:child_process";
import path from "node:path";
import {
clientRootForRecipe,
exists,
fixturesRoot,
loadRecipe,
projectRoot,
readJson,
recipesRoot,
workRoot,
} from "./lib.mjs";
async function runExporter(argumentsList) {
const executable = path.resolve(projectRoot, "../wow335a/dungeon-export-work/tools/wow.export-0.2.19/wow.export.exe");
if (!await exists(executable)) throw new Error("The patched portable wow.export executable was not found.");
await new Promise((resolve, reject) => {
const child = spawn(executable, ["--disable-auto-update", ...argumentsList], {
cwd: path.dirname(executable),
stdio: "inherit",
windowsHide: true,
});
child.once("error", reject);
child.once("exit", (code) => code === 0 ? resolve() : reject(new Error(`wow.export exited with code ${code}.`)));
});
}
async function checkedResult(slug, output) {
const resultFile = path.join(output, "automation-result.json");
if (!await exists(resultFile)) return { status: "blocked", dungeonId: slug, blockers: ["wow.export produced no automation-result.json."] };
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");
await runExporter([
"--export-dungeon",
"--recipe", path.join(recipesRoot, `${slug}.json`),
"--client-root", clientRoot,
"--output", output,
]);
const blocked = await checkedResult(slug, output);
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");
await runExporter([
"--discover-dungeon",
"--recipe", path.join(recipesRoot, `${slug}.json`),
"--client-root", clientRoot,
"--output", output,
]);
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");
await runExporter([
"--export-creatures",
"--recipe", selected,
"--client-root", clientRoot,
"--output", output,
]);
const blocked = await checkedResult(slug, output);
if (blocked) return blocked;
return { status: "green", dungeonId: slug, output: path.relative(projectRoot, output).replace(/\\/g, "/") };
}