Each instance paced itself against the wall clock, so on a busy machine
the one that got less CPU fell behind, and anything a test times across
instances (a peer leaving, a matching timeout) came out differently with
the load: pair/vanish and pair/matching3 failed on macOS CI.
With --sync-file and --sync-count, instances on one machine share a file
of one slot per instance. CoreTiming ends a slice at every emulated
millisecond, publishes it there, and waits until every other instance
has reached it too, so they're never more than a millisecond apart. It
works for any number of instances. One that stops moving (a debugger
pause, a crash) is waited for 2 s and then left out until it moves
again, and one that blocks the CPU thread in real time on something the
others must do (the relay PTP connect) stands aside meanwhile.
Tools/adhoc_multi.py and adhoc_session.py use it (--no-sync turns it
off). The host's 1 s head start is gone: they wait for the server's
port instead. adhoc_multi writes each instance's output to a file, as a
full pipe would now stop the other instances too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Games that show the system nickname in their lobbies can then tell the
instances apart. Also: press --times N --every S for menus that need
several presses, and start clears the last session's screenshots, which
could otherwise pass for this one's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
until waits for a region of the screen to match a reference crop (or
a pixel its color), optionally pressing a button meanwhile, since
loading screens take a different time on every run and a press before
a menu is ready is lost. crop makes the references. log sets a log
channel's level and watch collects the log messages for a while.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Starts N headless instances of a game against each other, with or
without the relay, and drives them over the debugger: button presses,
side-by-side screenshots, frame rates, and scripts of those. Each
instance gets its own memory stick with a copy of the savedata, so
autosaves can't collide. docs/adhoc-multiplayer-testing.md describes the
setup, by hand too, and the network simulation options.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>