Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
4.4 kB · 109 lines
Python
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110#!/usr/bin/env python3"""Collect what each machine weighs and costs, for every lobby view to read.
scripts/unit-stats.py --out web/src/content/unit-stats.json scripts/unit-stats.py --out web/src/content/unit-stats.json --check
A force card wants to say what each machine weighs and what the force adds upto. None of that is in a unit file in any form this repo can read, so thisreads what real MegaMek already reported: arena's `ScenarioReport` loads ascenario for real, and its output for the daily challenges is committed besidethe scenarios. Nothing here computes anything.
Weight, price and introduction year only. Battle value is deliberately not inthis file, and the reason is the whole shape of it: BV 2.0 multiplies by thecrew's gunnery and piloting, so the same machine is worth 359 with one pilot init and 323 with another - Stinger STG-3R is exactly this, across two dailies.A table keyed by the machine cannot hold a number that belongs to the machine*and its pilot*, so per-unit BV rides on the scenario instead, in daily.json.What is here is true of the design wherever it turns up.
Keyed by the full designation - "Clint CLNT-5U", chassis and model - becausethat is what a scenario file names and what the catalog names.
Both catalogs are reported now: the dailies, and the vendored scenario filesbeside them. A machine still missing from both gets no entry, `statsFor`returns null and the card shows a dash - nothing is invented to fill a hole.
Refreshing either report is an arena run, not something this script can do:
java -cp <arena.jar:megamek libs> arena.ScenarioReport <files> > report.json"""
import argparseimport jsonimport pathlibimport sys
REPORTS = [ "services/api/src/matches/daily/report.json", "services/api/src/matches/scenarios/report.json",]
def collect(root: pathlib.Path) -> dict[str, dict[str, int]]: """Every unit any report names, with what that report said it was worth.""" units: dict[str, dict[str, int]] = {} for name in REPORTS: path = root / name if not path.exists(): continue for scenario in json.loads(path.read_text()): for faction in scenario.get("factions", []): for unit in faction.get("units", []): designation = unit.get("name") if not designation: continue entry = { "tons": unit["tons"], "cost": unit["cost"], "year": unit["year"], } # A machine fielded by two scenarios is reported twice. # These three are the design's own, so the two agree - and # if they ever do not, the disagreement is a bug worth # failing on rather than a value worth picking between. # (BV would not agree, which is why it is not here.) if designation in units and units[designation] != entry: raise SystemExit( f"{designation}: two reports disagree, " f"{units[designation]} vs {entry}" ) units[designation] = entry return units
def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--out", required=True, type=pathlib.Path) parser.add_argument( "--check", action="store_true", help="write nothing; fail if the committed file is not what this run " "would produce", ) args = parser.parse_args()
root = pathlib.Path(__file__).resolve().parent.parent units = collect(root) text = json.dumps({"units": dict(sorted(units.items()))}, indent=1) + "\n"
if args.check: if not args.out.exists(): print(f"{args.out}: missing; run scripts/unit-stats.py", file=sys.stderr) return 1 if args.out.read_text() != text: print( f"{args.out}: stale; re-run scripts/unit-stats.py", file=sys.stderr, ) return 1 return 0
args.out.write_text(text) print(f"{args.out}: {len(units)} machines.") return 0
if __name__ == "__main__": sys.exit(main())