import { spawn } from "node:child_process"; import { stat } from "node:fs/promises"; import path from "node:path"; import { exists, loadRecipe, projectRoot, readJson, recipesRoot, workRoot, writeJson } from "./lib.mjs"; function run(executable, args) { return new Promise((resolve, reject) => { const child = spawn(executable, args, { cwd: projectRoot, stdio: "inherit", windowsHide: true }); child.once("error", reject); child.once("exit", (code) => code === 0 ? resolve() : reject(new Error(`Blender exited with code ${code}.`))); }); } export async function convertDungeonEnvironment(slug) { await loadRecipe(slug); const blender = path.resolve(process.env.BLENDER_BIN ?? path.join(projectRoot, "../wow335a/dungeon-export-work/tools/blender-5.0.1-windows-x64/blender.exe")); const addon = path.resolve(process.env.WOW_EXPORT_ADDON ?? path.join(projectRoot, "../wow335a/dungeon-export-work/tools/wow.export-0.2.19/addon")); const source = path.join(workRoot, slug, "source-export"); const output = path.join(workRoot, slug, "staging", "environment"); const blockers = []; if (!await exists(blender)) blockers.push("Blender was not found; set BLENDER_BIN."); if (!await exists(path.join(addon, "io_scene_wowobj"))) blockers.push("wow.export Blender addon was not found; set WOW_EXPORT_ADDON."); if (!await exists(source)) blockers.push("Recipe extraction output is missing; run dungeon:extract first."); if (blockers.length) { const report = { schemaVersion: 1, dungeonId: slug, status: "blocked", blockers }; await writeJson(path.join(workRoot, slug, "conversion-report.json"), report); return report; } const reportFile = path.join(output, "conversion-report.json"); const previousMtime = await exists(reportFile) ? (await stat(reportFile)).mtimeMs : 0; await run(blender, [ "--background", "--factory-startup", "--python", path.join(projectRoot, "scripts/dungeon-pipeline/blender/convert-dungeon.py"), "--", path.join(recipesRoot, `${slug}.json`), source, output, addon, ]); if (!await exists(reportFile) || (await stat(reportFile)).mtimeMs <= previousMtime) { const report = { schemaVersion: 1, dungeonId: slug, status: "blocked", blockers: ["Blender exited without producing a fresh conversion report."] }; await writeJson(path.join(workRoot, slug, "conversion-report.json"), report); return report; } return await readJson(reportFile); }