diff --git a/Core/CmdLine.cpp b/Core/CmdLine.cpp index 9fd41529c0..7ea12e14a1 100644 --- a/Core/CmdLine.cpp +++ b/Core/CmdLine.cpp @@ -257,6 +257,7 @@ static const CommandLineParam g_autoParams[] = { {POFF(instance), CmdParamType::Int, "instance", '\0', "Run as instance N of several talking to each other over ad hoc (own 127.0.0.N address and MAC)", CmdLineMode::Headless}, {POFF(realtime), CmdParamType::Bool, "realtime", '\0', "Run at PSP speed instead of as fast as possible", CmdLineMode::Headless}, {POFF(adhocServer), CmdParamType::Bool, "adhoc-server", '\0', "Run the built-in ad hoc server"}, + {POFF(nickname), CmdParamType::String, "nickname", '\0', "The PSP's nickname (System settings), for this run only"}, {POFF(lagSync), CmdParamType::Bool, "lag-sync", '\0', "Keep emulated time in step with the wall clock every millisecond, not every frame (the Force real clock sync setting)"}, {POFF(frameStats), CmdParamType::Bool, "frame-stats", '\0', "Print flips per emulated second at the end of the run, counted from --state's load", CmdLineMode::Headless}, {POFF(maxScreenshotError), CmdParamType::Double, "max-mse", '\0', "Maximum allowed MSE error for screenshot comparison", CmdLineMode::Headless}, @@ -574,6 +575,10 @@ void CommandLineOptions::ApplyToConfig() const { g_Config.bEnableAdhocServer = adhocServer.value(); g_Config.DoNotSaveSetting(&g_Config.bEnableAdhocServer); } + if (nickname.has_value()) { + g_Config.sNickName = nickname.value(); + g_Config.DoNotSaveSetting(&g_Config.sNickName); + } if (lagSync.has_value()) { g_Config.bForceLagSync = lagSync.value(); g_Config.DoNotSaveSetting(&g_Config.bForceLagSync); diff --git a/Core/CmdLine.h b/Core/CmdLine.h index d2a6dce1d3..cfb79b2be8 100644 --- a/Core/CmdLine.h +++ b/Core/CmdLine.h @@ -201,6 +201,7 @@ struct CommandLineOptions { std::optional realtime; std::optional adhocServer; std::optional lagSync; + std::optional nickname; std::optional screenshotFilename; std::optional screenshotFilenameSave; diff --git a/Tools/adhoc_session.py b/Tools/adhoc_session.py index 10f4dab9a9..09a0004787 100644 --- a/Tools/adhoc_session.py +++ b/Tools/adhoc_session.py @@ -187,9 +187,14 @@ def cmd_start(args): "\n".join(" sudo ifconfig lo0 alias 127.0.0.%d up" % i for i in missing)) headless = args.headless or find_headless() os.makedirs(args.dir, exist_ok=True) + # The last session's screenshots would pass for this one's. + for name in os.listdir(args.dir): + if name.endswith(".png"): + os.remove(os.path.join(args.dir, name)) ini = os.path.join(args.dir, "network.ini") with open(ini, "w") as f: f.write("[Network]\nproAdhocServer = 127.0.0.1\nAdhocServerRelayMode = %d\n" % (0 if args.p2p else 1)) + names = [name.strip() for name in args.names.split(",")] if args.names else [] instances = [] for n in range(1, args.n + 1): memstick = os.path.join(args.dir, "memstick%d" % n) @@ -203,6 +208,7 @@ def cmd_start(args): cmd.append("--lag-sync") if n == 1: cmd.append("--adhoc-server") + cmd.append("--nickname=" + (names[n - 1] if n <= len(names) else "PPSSPP %d" % n)) if args.delay: cmd.append("--adhoc-delay=%d" % args.delay) if args.jitter: @@ -257,11 +263,14 @@ def cmd_stop(args): def cmd_press(args): session = load_session(args) - for inst in selected(session, args.i): - dbg = Debugger(inst["port"]) - # The answer only comes once the press is over, so don't wait for it. - dbg.send("input.buttons.press", button=args.button, duration=args.frames) - dbg.close() + for t in range(args.times): + if t > 0: + time.sleep(args.every) + for inst in selected(session, args.i): + dbg = Debugger(inst["port"]) + # The answer only comes once the press is over, so don't wait for it. + dbg.send("input.buttons.press", button=args.button, duration=args.frames) + dbg.close() def cmd_wait(args): @@ -435,6 +444,7 @@ def build_parser(): p.add_argument("game") p.add_argument("-n", type=int, default=2, help="Number of instances (default 2)") p.add_argument("--p2p", action="store_true", help="Talk directly instead of through the relay (needs a loopback address per instance)") + p.add_argument("--names", help="Comma-separated nicknames for the instances (default: PPSSPP 1, PPSSPP 2, ...)") p.add_argument("--delay", type=int, default=0, help="Simulated delay in ms on received relay datagrams (each way)") p.add_argument("--jitter", type=int, default=0, help="Up to this many ms more, at random") p.add_argument("--loss", type=int, default=0, help="Percentage of received relay datagrams dropped") @@ -451,6 +461,8 @@ def build_parser(): p.add_argument("button", help="cross, circle, square, triangle, up, down, left, right, start, select, ltrigger, rtrigger") p.add_argument("-i", help="Instances, like 1,2 (default all)") p.add_argument("--frames", type=int, default=6, help="How many vblanks to hold it") + p.add_argument("--times", type=int, default=1, help="Press it this many times (for menus that need several)") + p.add_argument("--every", type=float, default=2, help="With --times: seconds between presses (default 2)") p = sub.add_parser("wait", help="Wait (wall clock)") p.add_argument("seconds", type=float) diff --git a/docs/adhoc-multiplayer-testing.md b/docs/adhoc-multiplayer-testing.md index 2cea40c96d..84f6c5db8c 100644 --- a/docs/adhoc-multiplayer-testing.md +++ b/docs/adhoc-multiplayer-testing.md @@ -18,7 +18,7 @@ python3 Tools/adhoc_session.py stop `start` launches N instances of the newest `build*/PPSSPPHeadless`, running freely at PSP speed, each with a WebSocket debugger port. Instance 1 also runs the ad hoc server. The other commands talk to the -instances over the debugger: `press BUTTON [-i 1,2] [--frames N]`, `wait SECONDS`, `shot NAME`, +instances over the debugger: `press BUTTON [-i 1,2] [--frames N] [--times N --every SECONDS]`, `wait SECONDS`, `shot NAME`, `stats`, and `run SCRIPT`, which runs a file of those commands, one per line (`#` starts a comment). The session (ports, logs, screenshots, memory sticks) lives in `$TMPDIR/ppsspp-adhoc-session`, or wherever `--dir` says. @@ -34,6 +34,8 @@ What `start` sets up, and why: 15-31 ms instead of about 3 ms. `--no-lag-sync` turns it off, to see what the app's default does. - **Relay mode** by default, since most players use it. `--p2p` makes the instances talk directly instead (see below). +- **Each instance has its own nickname** (`--nickname`), "PPSSPP 1", "PPSSPP 2" and so on, or what + `--names A,B,...` says, so games that show it in their lobbies tell the instances apart. - `--state FILE` loads a savestate in every instance at boot. A state only loads into a build with the same savestate sections, so a state made on a branch with ad hoc changes may not load on master. @@ -73,7 +75,8 @@ What `start` does for each instance N (instance 1 also gets `--adhoc-server`): ```bash build-release/PPSSPPHeadless --graphics=vulkan --memstick=MEMSTICK_N --nand=$HOME/.config/ppsspp/PSP/NAND \ - --realtime --lag-sync --instance=N --appendconfig=network.ini --debugger-run=0 --timeout-wall=3600 GAME.iso + --realtime --lag-sync --instance=N --nickname="PPSSPP N" --appendconfig=network.ini --debugger-run=0 \ + --timeout-wall=3600 GAME.iso ``` `--instance=N` gives the instance its own MAC address and its own address, 127.0.0.N, for ad hoc data.