From b90b7b093b0a3db697e1ebf4f3758cf62dec50fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 8 Nov 2026 10:21:47 +0100 Subject: [PATCH] adhoc_session.py: until --slack, for screens a pixel off Hannah Montana's dialog panels land a pixel higher on one run than another, which a text-only reference can't absorb. Co-Authored-By: Claude Opus 5.5 --- Tools/adhoc_session.py | 14 +++++++++++--- docs/adhoc-multiplayer-testing.md | 4 +++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Tools/adhoc_session.py b/Tools/adhoc_session.py index d861547cc3..c07101a3b7 100644 --- a/Tools/adhoc_session.py +++ b/Tools/adhoc_session.py @@ -478,9 +478,16 @@ def screen_matches(args, image): mask = ref.getchannel("A").point(lambda a: 255 if a >= 128 else 0) if "A" in ref.getbands() else None ref = ref.convert("RGB") x, y = parse_ints(args.box, 2)[:2] if args.box else (0, 0) - region = image.convert("RGB").crop((x, y, x + ref.width, y + ref.height)) - diff = ImageStat.Stat(ImageChops.difference(region, ref), mask).mean - return sum(diff) / len(diff) <= args.tolerance + screen = image.convert("RGB") + # --slack N also tries the reference up to N pixels off in each direction, for screens that land a + # pixel or two away from where they did when the reference was cut. + for dy in range(-args.slack, args.slack + 1): + for dx in range(-args.slack, args.slack + 1): + region = screen.crop((x + dx, y + dy, x + dx + ref.width, y + dy + ref.height)) + diff = ImageStat.Stat(ImageChops.difference(region, ref), mask).mean + if sum(diff) / len(diff) <= args.tolerance: + return True + return False def cmd_until(args): @@ -629,6 +636,7 @@ def build_parser(): p.add_argument("--pixel", help="X,Y of a pixel to check instead") p.add_argument("--color", help="With --pixel: RRGGBB") p.add_argument("--tolerance", type=float, default=12, help="Mean difference per channel allowed (0-255; default 12)") + p.add_argument("--slack", type=int, default=0, help="Also try the reference up to this many pixels off in each direction") p.add_argument("--press", help="Keep pressing this button while waiting") p.add_argument("--every", type=float, default=2, help="With --press: seconds between presses (default 2)") p.add_argument("--timeout", type=float, default=60) diff --git a/docs/adhoc-multiplayer-testing.md b/docs/adhoc-multiplayer-testing.md index 7bd188d2b3..0117a5c084 100644 --- a/docs/adhoc-multiplayer-testing.md +++ b/docs/adhoc-multiplayer-testing.md @@ -66,7 +66,9 @@ until --pixel 20,30 --color ff0000 -i 2 # or until one pixel ha `until` takes screenshots until each selected instance shows the reference image at `--box` (a mean difference of up to `--tolerance` per channel, 12 by default, so moving backgrounds still match). When -it gives up (`--timeout`, 60 s), it saves the screens it saw as `until_failed_N.png`. Make references +it gives up (`--timeout`, 60 s), it saves the screens it saw as `until_failed_N.png`. A screen that +lands a pixel away from where it was when the reference was cut (a dialog panel, say) needs `--slack 1`, +which also tries the reference that far off in each direction. Make references with `crop SHOT.png X,Y,W,H OUT.png` from a screenshot of the screen you want, and keep them next to the script: paths in a script are relative to it. A title screen left alone too long may start an attract demo, so don't wait for one without pressing.