Skip to content

Commit e06d020

Browse files
zig-forFlySniper
authored andcommitted
LADX: Fix getting old items over and over again in Bizhawk (ArchipelagoMW#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.
1 parent bdaae16 commit e06d020

File tree

2 files changed

+10
-4
lines changed

2 files changed

+10
-4
lines changed

LinksAwakeningClient.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,13 @@ async def wait_for_retroarch_connection(self):
347347
f"Core type should be '{GAME_BOY}', found {core_type} instead - wrong type of ROM?")
348348
await asyncio.sleep(1.0)
349349
continue
350+
self.stop_bizhawk_spam = False
350351
logger.info(f"Connected to Retroarch {version.decode('ascii')} running {rom_name.decode('ascii')}")
351352
return
352353
except (BlockingIOError, TimeoutError, ConnectionResetError):
353354
await asyncio.sleep(1.0)
354355
pass
355-
self.stop_bizhawk_spam = False
356+
356357
async def reset_auth(self):
357358
auth = binascii.hexlify(await self.gameboy.async_read_memory(0x0134, 12)).decode()
358359
self.auth = auth

data/lua/connector_ladx_bizhawk.lua

+8-3
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@
4343

4444

4545
local socket = require("socket")
46-
local udp = socket.socket.udp()
46+
udp = socket.socket.udp()
4747
require('common')
4848

4949
udp:setsockname('127.0.0.1', 55355)
5050
udp:settimeout(0)
5151

52-
while true do
52+
function on_vblank()
5353
-- Attempt to lessen the CPU load by only polling the UDP socket every x frames.
5454
-- x = 10 is entirely arbitrary, very little thought went into it.
5555
-- We could try to make use of client.get_approx_framerate() here, but the values returned
@@ -112,6 +112,7 @@ while true do
112112
for _, v in ipairs(mem) do
113113
hex_string = hex_string .. string.format("%02X ", v)
114114
end
115+
115116
hex_string = hex_string:sub(1, -2) -- Hang head in shame, remove last " "
116117
local reply = string.format("%s %02x %s\n", command, address, hex_string)
117118
udp:sendto(reply, msg_or_ip, port_or_nil)
@@ -135,6 +136,10 @@ while true do
135136
udp:sendto(reply, msg_or_ip, port_or_nil)
136137
end
137138
end
139+
end
138140

139-
emu.frameadvance()
141+
event.onmemoryexecute(on_vblank, 0x40, "ap_connector_vblank")
142+
143+
while true do
144+
emu.yield()
140145
end

0 commit comments

Comments
 (0)