feat(editor): WQGR JSON round-trip closure

Adds --export-wqgr-json / --import-wqgr-json with the established
readEnumField template factoring int+name dual encoding for both
questType ("normal"/"daily"/"repeatable"/"group"/"raid") and
factionAccess ("both"/"alliance"/"horde"/"neutral"). Variable-
length prereq + followup quest arrays serialize as JSON int
arrays.

All 3 presets (starter/branched/dailies) byte-identical binary
roundtrip OK including the branched preset's converging DAG
(Q200 -> {Q201, Q202} -> Q203 with Q203 carrying [201, 202] in
its prevQuestIds).

Live-tested DFS cycle detection: hand-mutated Northshire chain
head Q100 to depend on Q104 (the chain's last quest), creating
a 5-node loop. Validator correctly errored: "prereq cycle
detected: 100 -> 104 -> 103 -> 102 -> 101 -> 100 — quests would
be unreachable (progression deadlock)" with the full back-edge
path extracted exactly as WMOD does for addon dep cycles.

CLI flag count 1389 -> 1391.
This commit is contained in:
Kelsi 2026-05-10 04:24:49 -07:00
parent 76cda20297
commit a4ac12dbeb
3 changed files with 210 additions and 0 deletions

View file

@ -2611,6 +2611,10 @@ void printUsage(const char* argv0) {
std::printf(" Print WQGR entries (questId / minLevel / maxLevel / questType / factionAccess / zoneId / chainHead / prereq + followup counts / name)\n");
std::printf(" --validate-wqgr <wqgr-base> [--json]\n");
std::printf(" Static checks: id+name required, questType 0..4, factionAccess 0..3, maxLevel >= minLevel, no self-prereq (catch-22), no missing prereq questId, DFS cycle detection on prevQuestIds (progression deadlock — quests would be unreachable). Warns on followup hint to self/missing-id (advisory only) and on chainHeadHint=1 with non-empty prereqs (contradicts chain-head semantics)\n");
std::printf(" --export-wqgr-json <wqgr-base> [out.json]\n");
std::printf(" Export binary .wqgr to a human-editable JSON sidecar (defaults to <base>.wqgr.json; emits both questType and factionAccess as int + name string; prevQuestIds/followupQuestIds as JSON int arrays)\n");
std::printf(" --import-wqgr-json <json-path> [out-base]\n");
std::printf(" Import a .wqgr.json sidecar back into binary .wqgr (questType int OR \"normal\"/\"daily\"/\"repeatable\"/\"group\"/\"raid\"; factionAccess int OR \"both\"/\"alliance\"/\"horde\"/\"neutral\"; prereq + followup arrays accept JSON int arrays)\n");
std::printf(" --catalog-pluck <wXXX-file> <id> [--json]\n");
std::printf(" Extract one entry by id from any registered catalog format. Auto-detects magic, dispatches to the per-format --info-* handler internally, then prints just the matching entry. Primary-key field is auto-detected (first *Id field, or first numeric)\n");
std::printf(" --catalog-find <directory> <id> [--magic <WXXX>] [--json]\n");