diff --git a/fifa17-recon/tools/live/probe_resident_fields.py b/fifa17-recon/tools/live/probe_resident_fields.py index c707135..4819fed 100755 --- a/fifa17-recon/tools/live/probe_resident_fields.py +++ b/fifa17-recon/tools/live/probe_resident_fields.py @@ -77,7 +77,7 @@ for label, vbeg, vend in (("players (cardtype 1)", mgr + 0xd8, mgr + 0xe0), if span % stride: continue n = span // stride - recs, nulls = [], 0 + recs, nulls = [], [] ok = True for k in range(n): try: @@ -85,23 +85,29 @@ for label, vbeg, vend in (("players (cardtype 1)", mgr + 0xd8, mgr + 0xe0), except OSError: ok = False; break if not rec: - nulls += 1; continue + nulls.append(k); continue d = decode(rec) if d is None: ok = False; break - recs.append((rec, d)) + recs.append((k, rec, d)) if not ok: continue - print(f" stride {stride} (ptr at +{ptr_off:#x}): {n} slots, {len(recs)} populated, {nulls} null") - if not recs and nulls != n: + print(f" stride {stride} (ptr at +{ptr_off:#x}): {n} slots, {len(recs)} populated, {len(nulls)} null") + if not recs and len(nulls) != n: continue - hist = collections.Counter(d[0:2] for _, d in recs) + hist = collections.Counter(d[0:2] for _, _, d in recs) for key, c in sorted(hist.items(), key=lambda x: -x[1]): print(f" (cardtype,subtype)={key} x{c}") - print(f" {'ptr':>14} " + " ".join(f"{f:>8}" for f in FIELDS)) - for rec, d in recs[:8]: - print(f" {rec:#14x} " + " ".join(f"{v:>8}" for v in d)) - cats = collections.Counter(d[3] for _, d in recs) + # The SLOT INDEX is load-bearing evidence: the squad parser's `actives` + # arm writes element i to slot `r15d + i`, and r15d is shared scratch + # that other atom handlers clobber. Which slots are filled therefore + # reveals the index the parse actually started from. + print(f" {'slot':>4} {'ptr':>14} " + " ".join(f"{f:>8}" for f in FIELDS)) + for k, rec, d in recs[:8]: + print(f" {k:>4} {rec:#14x} " + " ".join(f"{v:>8}" for v in d)) + if nulls: + print(f" empty slots: {nulls[:16]}") + cats = collections.Counter(d[3] for _, _, d in recs) if cats: print(f" CATEGORY (+0x60) distribution: {dict(cats)}") break diff --git a/fifa17-recon/tools/live/verify_kits.sh b/fifa17-recon/tools/live/verify_kits.sh index 81b1c08..4037146 100755 --- a/fifa17-recon/tools/live/verify_kits.sh +++ b/fifa17-recon/tools/live/verify_kits.sh @@ -23,3 +23,15 @@ echo cd "$(dirname "$0")" || exit 1 python3 probe_map2.py "$PID" 100004873 100004874 100004870 + +echo +echo " ================ squad survival + slot indices ================" +# The kit milestone is only real if the REST of the squad survives with it. +# A populated `squad.actives` was once seen to leave the map holding just the +# 2 kits with a fully null 23-slot player vector and an empty starting 11, so +# the player-vector fill below is a PASS/FAIL gate, not decoration. +# +# The club-item slot indices are the other half: the parser writes element i to +# slot r15d+i, and r15d is scratch other atom handlers clobber. Kits landing +# somewhere other than slots 0 and 1 means the index did not start at zero. +python3 probe_resident_fields.py "$PID"