From 3bf86cd8f062b8a4810e369df44a4ce7d06185ac Mon Sep 17 00:00:00 2001 From: zig-for Date: Thu, 27 Jul 2023 07:08:14 -0700 Subject: [PATCH] LADX: Fix getting old items over and over again in Bizhawk (#2011) There was a bug that randomly after opening and closing the menu, some players on Bizhawk would get old items again. Tracking this down took multiple hours over the course of several weeks. The root cause turned out to be reading from the System Bus domain while an DMA copy was happening. Doing so is undefined behavior on GBC (though I'm sure some game relies on it). On Gambatte, you end up reading some garbage byte no matter what the read is (unsure what the providence of the byte is - some garbage, some register, the actual DMA data, who knows?). Normally, this isn't an issue, as Bizhawk callbacks only happen during vblank/halt, which is generally a state where we have valid WRAM to read from. However - a setting is being passed around the community for Bizhawk that changes the frame counter to go from "only when Vblank happens" to "whenever some number of audio samples have happened" which causes the bizhawk callbacks to happen....nearly whenever. Including during a DMA. You can tell this is happening if you print the `PC` register when reading memory - if it matches `FFXX` then you are executing in a routine in HRAM and likely doing a DMA. Additionally, the check items counter specifically is in WRAM Bank 1 which could be swapped out of - will have to keep an eye on this - generally LADX lives in Bank 1, but there are a few things that use the other banks (swap space for some objects??). This could be a problem on any platform - if we get more reports of bad items gets, that's probably why. Also, fixes some logging that was never getting reenabled. --- LinksAwakeningClient.py | 3 ++- data/lua/connector_ladx_bizhawk.lua | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/LinksAwakeningClient.py b/LinksAwakeningClient.py index 8f1cbc1e..f3fc9d2c 100644 --- a/LinksAwakeningClient.py +++ b/LinksAwakeningClient.py @@ -347,12 +347,13 @@ class LinksAwakeningClient(): f"Core type should be '{GAME_BOY}', found {core_type} instead - wrong type of ROM?") await asyncio.sleep(1.0) continue + self.stop_bizhawk_spam = False logger.info(f"Connected to Retroarch {version.decode('ascii')} running {rom_name.decode('ascii')}") return except (BlockingIOError, TimeoutError, ConnectionResetError): await asyncio.sleep(1.0) pass - self.stop_bizhawk_spam = False + async def reset_auth(self): auth = binascii.hexlify(await self.gameboy.async_read_memory(0x0134, 12)).decode() self.auth = auth diff --git a/data/lua/connector_ladx_bizhawk.lua b/data/lua/connector_ladx_bizhawk.lua index 038971be..6a5fbf70 100644 --- a/data/lua/connector_ladx_bizhawk.lua +++ b/data/lua/connector_ladx_bizhawk.lua @@ -43,13 +43,13 @@ local socket = require("socket") -local udp = socket.socket.udp() +udp = socket.socket.udp() require('common') udp:setsockname('127.0.0.1', 55355) udp:settimeout(0) -while true do +function on_vblank() -- Attempt to lessen the CPU load by only polling the UDP socket every x frames. -- x = 10 is entirely arbitrary, very little thought went into it. -- We could try to make use of client.get_approx_framerate() here, but the values returned @@ -112,6 +112,7 @@ while true do for _, v in ipairs(mem) do hex_string = hex_string .. string.format("%02X ", v) end + hex_string = hex_string:sub(1, -2) -- Hang head in shame, remove last " " local reply = string.format("%s %02x %s\n", command, address, hex_string) udp:sendto(reply, msg_or_ip, port_or_nil) @@ -135,6 +136,10 @@ while true do udp:sendto(reply, msg_or_ip, port_or_nil) end end - - emu.frameadvance() +end + +event.onmemoryexecute(on_vblank, 0x40, "ap_connector_vblank") + +while true do + emu.yield() end