118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|||
|
|
"""Regenerate the Relic portion of InventoryItemConfig from game tables.
|
||
|
|
|
||
|
|
Pass a directory containing RelicConfig.json, ItemConfigRelic.json,
|
||
|
|
RelicMainAffixConfig.json, and RelicSubAffixConfig.json from the revision
|
||
|
|
recorded in InventoryItemConfig.json. Existing item and Light Cone entries
|
||
|
|
are preserved; only visible BASIC Relic types from ItemConfigRelic are included.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
|
||
|
|
TABLES = (
|
||
|
|
"RelicConfig.json",
|
||
|
|
"ItemConfigRelic.json",
|
||
|
|
"RelicMainAffixConfig.json",
|
||
|
|
"RelicSubAffixConfig.json",
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def read_rows(path: Path) -> list[dict[str, Any]]:
|
||
|
|
with path.open("r", encoding="utf-8") as source:
|
||
|
|
rows = json.load(source)
|
||
|
|
if not isinstance(rows, list):
|
||
|
|
raise ValueError(f"{path.name} must contain a JSON array")
|
||
|
|
return rows
|
||
|
|
|
||
|
|
|
||
|
|
def build_relic_catalog(source_dir: Path) -> list[dict[str, Any]]:
|
||
|
|
relic_rows = read_rows(source_dir / "RelicConfig.json")
|
||
|
|
item_rows = read_rows(source_dir / "ItemConfigRelic.json")
|
||
|
|
main_rows = read_rows(source_dir / "RelicMainAffixConfig.json")
|
||
|
|
sub_rows = read_rows(source_dir / "RelicSubAffixConfig.json")
|
||
|
|
|
||
|
|
visible_item_ids = {
|
||
|
|
int(row["ID"])
|
||
|
|
for row in item_rows
|
||
|
|
if row.get("ItemMainType") == "Relic" and row.get("isVisible") is True
|
||
|
|
}
|
||
|
|
main_by_group: dict[int, list[dict[str, Any]]] = {}
|
||
|
|
for row in main_rows:
|
||
|
|
main_by_group.setdefault(int(row["GroupID"]), []).append(row)
|
||
|
|
sub_by_group: dict[int, list[dict[str, Any]]] = {}
|
||
|
|
for row in sub_rows:
|
||
|
|
sub_by_group.setdefault(int(row["GroupID"]), []).append(row)
|
||
|
|
for rows in (*main_by_group.values(), *sub_by_group.values()):
|
||
|
|
rows.sort(key=lambda row: int(row["AffixID"]))
|
||
|
|
|
||
|
|
catalog: list[dict[str, Any]] = []
|
||
|
|
seen: set[int] = set()
|
||
|
|
for relic in sorted(relic_rows, key=lambda row: int(row["ID"])):
|
||
|
|
relic_id = int(relic["ID"])
|
||
|
|
if relic.get("Mode") != "BASIC" or relic_id not in visible_item_ids:
|
||
|
|
continue
|
||
|
|
if relic_id in seen:
|
||
|
|
raise ValueError(f"duplicate Relic ID {relic_id}")
|
||
|
|
|
||
|
|
main_options = main_by_group.get(int(relic["MainAffixGroup"]), [])
|
||
|
|
if not main_options:
|
||
|
|
raise ValueError(f"Relic {relic_id} has no MainAffixGroup rows")
|
||
|
|
main = main_options[0]
|
||
|
|
|
||
|
|
sub_options = [
|
||
|
|
row
|
||
|
|
for row in sub_by_group.get(int(relic["SubAffixGroup"]), [])
|
||
|
|
if row.get("Property") != main.get("Property")
|
||
|
|
]
|
||
|
|
if len(sub_options) < 4:
|
||
|
|
raise ValueError(f"Relic {relic_id} has fewer than four valid sub-affixes")
|
||
|
|
|
||
|
|
catalog.append(
|
||
|
|
{
|
||
|
|
"relic_id": relic_id,
|
||
|
|
"relic_set_id": int(relic["SetID"]),
|
||
|
|
"main_affix_id": int(main["AffixID"]),
|
||
|
|
"sub_affixes": [
|
||
|
|
{
|
||
|
|
"sub_affix_id": int(row["AffixID"]),
|
||
|
|
"count": 1,
|
||
|
|
"step": 0,
|
||
|
|
}
|
||
|
|
for row in sub_options[:4]
|
||
|
|
],
|
||
|
|
}
|
||
|
|
)
|
||
|
|
seen.add(relic_id)
|
||
|
|
|
||
|
|
if not catalog:
|
||
|
|
raise ValueError("no visible BASIC Relics were found in the supplied tables")
|
||
|
|
return catalog
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
parser.add_argument("--source-dir", type=Path, required=True)
|
||
|
|
parser.add_argument("--inventory-config", type=Path, required=True)
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
missing = [name for name in TABLES if not (args.source_dir / name).is_file()]
|
||
|
|
if missing:
|
||
|
|
raise SystemExit("Missing source tables: " + ", ".join(missing))
|
||
|
|
|
||
|
|
with args.inventory_config.open("r", encoding="utf-8") as source:
|
||
|
|
resource = json.load(source)
|
||
|
|
resource["relics"] = build_relic_catalog(args.source_dir)
|
||
|
|
with args.inventory_config.open("w", encoding="utf-8", newline="\n") as output:
|
||
|
|
json.dump(resource, output, ensure_ascii=False, indent=2)
|
||
|
|
output.write("\n")
|
||
|
|
print(f"Wrote {len(resource['relics'])} Client-configured Relic templates")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|