#!/usr/bin/env python3 """Encoding-agnostic: which words of an object actually carry live state? Rather than assume the orientation is a matrix (it is not) or a quaternion, classify every 4-byte word of the captured window by how it behaves over the capture: constant, smoothly varying (a continuous quantity), or jumpy. Usage: whatchanges.py [name-substring] [max-report] """ import math import struct import sys sys.path.insert(0, "/home/fabi/RE - Project Sylpheed/sylpheed-reborn/tools/re-capture") from flight_analyze import load # noqa: E402 def main(): path = sys.argv[1] want = sys.argv[2] if len(sys.argv) > 2 else "Player" top = int(sys.argv[3]) if len(sys.argv) > 3 else 60 insts, window, frames = load(path) i = next(k for k, (_, _, nm) in enumerate(insts) if want in nm) print(f"# {insts[i][2]} @ {insts[i][0]:#010x}, {len(frames)} frames, window {window:#x}") nconst = nsmooth = njump = 0 smooth = [] for o in range(0, window - 3, 4): vals = [] ok = True for t, inp, lab, bufs in frames: (v,) = struct.unpack_from(">f", bufs[i], o) if not math.isfinite(v): ok = False break vals.append(v) if not ok: continue lo, hi = min(vals), max(vals) if lo == hi: nconst += 1 continue rng = hi - lo steps = [abs(b - a) for a, b in zip(vals, vals[1:])] mx = max(steps) # smooth = no single step is a large fraction of the whole excursion if mx < 0.25 * rng: nsmooth += 1 smooth.append((o, lo, hi, vals)) else: njump += 1 print(f"# constant {nconst} smooth {nsmooth} jumpy {njump}") print(f"\n# smoothly varying words (candidate continuous state):") for o, lo, hi, vals in smooth[:top]: print(f" +{o:#05x} [{lo:12.4g} .. {hi:12.4g}] " f"start {vals[0]:12.4g} end {vals[-1]:12.4g}") # consecutive runs of smooth words -> vectors offs = [o for o, _, _, _ in smooth] runs, cur = [], [] for o in offs: if cur and o == cur[-1] + 4: cur.append(o) else: if len(cur) >= 3: runs.append(cur) cur = [o] if len(cur) >= 3: runs.append(cur) print(f"\n# runs of >=3 consecutive smooth words (vector-shaped):") for r in runs: print(f" +{r[0]:#05x} .. +{r[-1]:#05x} ({len(r)} words)") if __name__ == "__main__": main()