Add debug CSV tables showing before/after values for each override

- Writes output/<mod>/debug_ammo.csv and debug_armor.csv
- Columns: classname, source_mod, field, old_value, new_value
- Helps verify rebalance changes make sense
This commit is contained in:
Samuele Lorefice
2026-07-20 19:54:37 +02:00
parent 5d1be18c35
commit c7d925da7d
+47
View File
@@ -449,6 +449,7 @@ class AmmoOverride:
classname: str
source_mod: str
changes: dict = field(default_factory=dict)
originals: dict = field(default_factory=dict)
@dataclass
@@ -457,6 +458,7 @@ class ArmorOverride:
source_mod: str
item_type: str
changes: dict = field(default_factory=dict)
originals: dict = field(default_factory=dict)
def find_ammo_overrides(
@@ -472,11 +474,13 @@ def find_ammo_overrides(
base = baseline[key]
changes = {}
originals = {}
for field_name in AMMO_FIELDS:
mod_val = getattr(e, field_name)
base_val = getattr(base, field_name)
if mod_val != base_val and mod_val != 0:
changes[field_name] = base_val
originals[field_name] = mod_val
# Check ACE array fields (compare as strings)
for array_field in ["ace_bc", "ace_mv", "ace_bl", "ace_vb"]:
@@ -484,12 +488,14 @@ def find_ammo_overrides(
base_val = getattr(base, array_field)
if mod_val != base_val and mod_val not in ("[]", ""):
changes[array_field] = base_val
originals[array_field] = mod_val
if changes:
overrides.append(AmmoOverride(
classname=e.classname,
source_mod=e.source_mod,
changes=changes,
originals=originals,
))
return overrides
@@ -508,6 +514,7 @@ def find_armor_overrides(
base = baseline[key]
changes = {}
originals = {}
for field_name in ARMOR_FIELDS:
mod_val = getattr(e, field_name)
base_val = getattr(base, field_name)
@@ -516,6 +523,7 @@ def find_armor_overrides(
continue
if mod_val != base_val:
changes[field_name] = base_val
originals[field_name] = mod_val
if changes:
overrides.append(AmmoOverride(
@@ -523,11 +531,13 @@ def find_armor_overrides(
source_mod=e.source_mod,
item_type=e.item_type,
changes=changes,
originals=originals,
) if hasattr(AmmoOverride, 'item_type') else ArmorOverride(
classname=e.classname,
source_mod=e.source_mod,
item_type=e.item_type,
changes=changes,
originals=originals,
))
return overrides
@@ -684,6 +694,42 @@ def write_unmatched(
f"{len(unmatched_armor)} unmatched armor to {out_path}")
def write_debug_csvs(
mod: str,
ammo_overrides: list[AmmoOverride],
armor_overrides: list[ArmorOverride],
):
"""Write per-mod debug CSVs showing old -> new values for each override."""
mod_dir = OUTPUT_DIR / mod
if ammo_overrides:
path = mod_dir / "debug_ammo.csv"
with open(path, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f, delimiter=";")
writer.writerow(["classname", "source_mod", "field",
"old_value", "new_value"])
for o in sorted(ammo_overrides, key=lambda x: x.classname):
for field_name in sorted(o.changes.keys()):
old_val = o.originals.get(field_name, "")
new_val = o.changes[field_name]
writer.writerow([o.classname, o.source_mod,
field_name, old_val, new_val])
if armor_overrides:
path = mod_dir / "debug_armor.csv"
with open(path, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f, delimiter=";")
writer.writerow(["classname", "source_mod", "item_type",
"field", "old_value", "new_value"])
for o in sorted(armor_overrides, key=lambda x: x.classname):
for field_name in sorted(o.changes.keys()):
old_val = o.originals.get(field_name, "")
new_val = o.changes[field_name]
writer.writerow([o.classname, o.source_mod,
o.item_type, field_name,
old_val, new_val])
# ============================================================================
# Main
# ============================================================================
@@ -790,6 +836,7 @@ def main():
config_path = mod_dir / "config.cpp"
with open(config_path, "w", encoding="utf-8") as f:
f.write(config_cpp)
write_debug_csvs(mod, mod_ammo, mod_armor)
mods_with_overrides.add(mod)
print(f" {mod}/config.cpp ({len(mod_ammo)} ammo, {len(mod_armor)} armor)")