forked from phenom/healer-man
Update class mechanics, stat rulesets, and CoA reference catalogs
This commit is contained in:
1 parent
b16821e92e
commit
39458d5de6
221 files changed
+2584962
-568
No files matched your search
@@ -0,0 +1,54 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { activeCatalogPath, decodeJsonBytes, freezeJulyBaseline } from "./baseline.mjs";
|
||||
import { buildLocalReference } from "./local-source.mjs";
|
||||
import { buildCoaPromotion, normalizeArchiveNode } from "./promote.mjs";
|
||||
import { readSupplements } from "./supplements.mjs";
|
||||
import { validateReference } from "./audit.mjs";
|
||||
import { stableJson } from "./snapshot.mjs";
|
||||
import { readArchiveSpells } from "./archive-spells.mjs";
|
||||
|
||||
/** Explicit offline promotion, distinct from the historical reference build. */
|
||||
export async function promoteCachedCoa({ projectRoot, cacheRoot, ...sourceOptions }) {
|
||||
const supplements = await readSupplements({ cacheRoot });
|
||||
if (!supplements) throw new Error("Verified August cache is required; run coa:reference:fetch once");
|
||||
const baselinePath = freezeJulyBaseline(projectRoot);
|
||||
const previous = JSON.parse(decodeJsonBytes(fs.readFileSync(baselinePath), baselinePath).toString("utf8"));
|
||||
const triggered = JSON.parse(fs.readFileSync(path.join(projectRoot, "src/game/generated/coaTriggeredSpellCatalog.json"), "utf8"));
|
||||
previous.classicTriggeredSpells = triggered.classicSpells ?? triggered.spells;
|
||||
const extraNodes = supplements.classes.flatMap((definition) => definition.nodes.map(normalizeArchiveNode));
|
||||
const archivedSpells = await readArchiveSpells({ cacheRoot });
|
||||
const reference = buildLocalReference({ projectRoot, ...sourceOptions, extraNodes, archivedSpells });
|
||||
const { candidate, report } = buildCoaPromotion({ previous, reference, supplements });
|
||||
const spellById = new Map([...candidate.spells, ...(candidate.coaSpellOverrides ?? [])].map((spell) => [spell.id, spell]));
|
||||
const validation = validateReference({
|
||||
...reference,
|
||||
classes: reference.classes.map((definition) => ({ ...definition, tabs: candidate.classes.find((item) => item.classId === definition.classId).tabs })),
|
||||
nodes: candidate.entries,
|
||||
spells: [...spellById.values()],
|
||||
});
|
||||
if (validation.errors.length) throw new Error(`Promotion validation failed; active catalog retained: ${validation.errors.map((item) => item.message).join("; ")}`);
|
||||
for (const entry of candidate.entries) {
|
||||
for (const rank of entry.rankDescriptions) {
|
||||
if (!spellById.get(rank.spellId)?.dbc) throw new Error(`August node ${entry.id} rank ${rank.rank} lacks global Spell.dbc evidence; active catalog retained`);
|
||||
}
|
||||
}
|
||||
const candidateBytes = `${JSON.stringify(candidate, null, 2)}\n`;
|
||||
report.validation = validation;
|
||||
report.candidateSha256 = createHash("sha256").update(candidateBytes).digest("hex");
|
||||
const reportPath = path.join(projectRoot, "data/coa-reference/promotion-report.json");
|
||||
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
|
||||
fs.writeFileSync(reportPath, stableJson(report));
|
||||
const activePath = path.join(projectRoot, activeCatalogPath);
|
||||
const temporaryPath = `${activePath}.${randomUUID()}.tmp`;
|
||||
try {
|
||||
fs.writeFileSync(temporaryPath, candidateBytes, { flag: "wx" });
|
||||
if (createHash("sha256").update(fs.readFileSync(temporaryPath)).digest("hex") !== report.candidateSha256) throw new Error("Staged promotion checksum mismatch");
|
||||
fs.renameSync(temporaryPath, activePath);
|
||||
} finally {
|
||||
if (fs.existsSync(temporaryPath)) fs.unlinkSync(temporaryPath);
|
||||
}
|
||||
return { reportPath, candidateSha256: report.candidateSha256, counts: candidate.counts, validationWarnings: validation.warnings.length,
|
||||
gaps: { missingBaseSpellCount: report.gaps.missingBaseSpellCount, missingBaseProgressionRankIds: report.gaps.missingBaseProgressionRankIds } };
|
||||
}
|
||||
Reference in new issue
Block a user