From c2b2239df04c6ad8e0e953bc05ac537c6ef968f2 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 7 Oct 2023 18:50:00 -0700 Subject: [PATCH] bring back patch_flycast_memory.py --- README.md | 9 ++++++++- TODO.md | 1 - patch_flycast_memory.py | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100755 patch_flycast_memory.py diff --git a/README.md b/README.md index f6596c28..0b400f32 100644 --- a/README.md +++ b/README.md @@ -338,9 +338,16 @@ If you're emulating PSO DC, all versions will connect to newserv by setting the - EmulateBBA = no (while some versions support the BBA, some do not, and all versions support the modem) - Enable = yes - Once set up, the EU and US versions will work without any extra set up (other than the HL Check Disable code for USv2), while the JP versions require HL Check Disable codes to be running, and an e-mail account set up. The easiest way to set up an e-mail account is through PlanetWeb's Internet Browser for Dreamcast. +If the server is running on the same machine as Flycast, this might not work, even if you point Flycast's DNS queries at your local IP address (instead of 127.0.0.1). In this case, you can modify the loaded executable in memory to make it connect anywhere you want. There is a script included with newserv that can do this on macOS; a similar technique could be done manually using scanmem on Linux or Cheat Engine on Windows. To use the script, do this: +1. Build and install memwatch (https://github.com/fuzziqersoftware/memwatch). +2. Start Flycast and run PSO. (You must start PSO before running the script; it won't work if you run the script before loading the game.) +3. Run `sudo patch_flycast_memory.py `. Replace `` with the hostname that PSO wants to connect to (you can find this out by using Wireshark and looking for DNS queries). The script may take up to a minute; you can continue using Flycast while it runs, but don't start an online game until the script is done. +4. Run newserv and start an online game in PSO. + +If you use this method, you'll have to run the script every time you start PSO in Flycast, but you won't have to run it again if you start another online game without restarting emulation. + #### PSO PC The version of PSO PC I have has the server addresses starting at offset 0x29CB34 in pso.exe. Using a hex editor, change those to "localhost" (without quotes) if you just want to connect to a locally-running newserv instance. Alternatively, you can add an entry to the Windows hosts file (C:\Windows\System32\drivers\etc\hosts) to redirect the connection to 127.0.0.1 (localhost) or any other IP address. diff --git a/TODO.md b/TODO.md index 2ce52c00..fdb9176e 100644 --- a/TODO.md +++ b/TODO.md @@ -16,7 +16,6 @@ - Build an exception-handling abstraction in ChatCommands that shows formatted error messages in all cases - Make non-BB detector encryption match more than the first 4 bytes - Make reloading happen on separate threads so compression doesn't block active clients -- Try emu.cfg change instead of patch_flycast_memory (https://github.com/fuzziqersoftware/newserv/issues/132) - Try DCv2/PC crossplay - Implement decrypt/encrypt actions for VMS files and PC save files - Write shell server diff --git a/patch_flycast_memory.py b/patch_flycast_memory.py new file mode 100755 index 00000000..04a75072 --- /dev/null +++ b/patch_flycast_memory.py @@ -0,0 +1,39 @@ +#!/bin/env python3 + +import os +import subprocess +import sys + + +def get_ip_address(ifname): + data = subprocess.check_output(['ifconfig', ifname]) + for line in data.splitlines(): + line = line.strip() + if line.startswith(b'inet '): + return line.split()[1].decode('ascii') + raise RuntimeError('cannot get address for interface ' + ifname) + + +def main(argv): + if len(argv) < 2: + raise RuntimeError(f'Usage: {argv[0]} [new-destination]') + if os.geteuid() != 0: + raise RuntimeError('You must use sudo to run this script') + original_destination = argv[1] + new_destination = argv[2] if len(argv) > 2 else get_ip_address('en0') + + print(f'Finding occurrences of \"{original_destination}\"') + addresses_str = subprocess.check_output(['memwatch', 'Flycast.app', 'find', f'\"{original_destination}\"']) + for line in addresses_str.splitlines(): + # line is like '(0) 00007FFF038500A0 (rw-)' (we care only about the address) + tokens = line.split() + if len(tokens) != 3: + continue + print(f'Replacing \"{original_destination}\" with \"{new_destination}\" at {tokens[1]} in Flycast') + subprocess.check_call(['memwatch', 'Flycast.app', 'write', tokens[1], f'\"{new_destination}\" 00']) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv))