Files
Sylpheed/tools/re-capture/whatchanges.py
sim ac0ad579fd chore: retire the last dead paths and names from the consolidation
Nothing here changes what a tool computes; it changes where tools look.

- tools/re-capture: 33 censuses globbed /work/sylph_extract, a path that has
  existed nowhere since /work became a clone, so they matched nothing and
  printed empty results. They now resolve the disc through a new disc.py
  from $SYLPHEED_DISC and exit loudly without it (the #44 fix, generalised).
  Nine scripts that imported siblings from the retired Reborn checkout or an
  old session scratchpad now import from their own directory. unitgroup.py
  only needs the variable when --pak is not given.
- sylpheed-xex: the loader only ever uses the XEX2 retail key. The dead
  devkit key and a doc comment claiming a devkit fallback that does not
  exist are gone; Project Sylpheed is a retail XEX2, so no XEX1 key either.
- sylpheed-viewer: real_font_rasterizes looked for /tmp/sylph_extract and so
  always skipped. It reads $SYLPHEED_DISC now, and passes against the disc.
- Comments and docs that named xenia-rs, the Reborn repository or /work/*.pe
  as places to look now name sylpheed.db, Canary's ppc_context.h and the
  flat .pe; docs/re/README.md no longer says the native Canary build does not
  run.

Historical records keep their original paths: findings that were measured
against /work/xenia-rs/sylpheed.db still say so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:30:28 +02:00

78 lines
2.5 KiB
Python

#!/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 <probe.bin> [name-substring] [max-report]
"""
import math
import os
import struct
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
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()