Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions data/lua/connector_ladx_bizhawk.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-- SPDX-License-Identifier: MIT

-- This script attempts to implement the basic functionality needed in order for
-- the LADXR Archipelago client to be able to talk to EmuHawk instead of RetroArch
-- the some Archipelago clients to be able to talk to EmuHawk instead of RetroArch
-- by reproducing the RetroArch API with EmuHawk's Lua interface.
--
-- RetroArch UDP API: https://github.com/libretro/RetroArch/blob/master/command.c
Expand Down Expand Up @@ -49,20 +49,15 @@ require('common')
udp:setsockname('127.0.0.1', 55355)
udp:settimeout(0)

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
-- seemed more or less arbitrary as well.
--
-- NOTE: Never mind the above, the LADXR Archipelago client appears to run into problems with
-- interwoven GET_STATUS calls, leading to stopped communication.
-- For GB(C), polling the socket on every frame is OK-ish, so we just do that.
--
--while emu.framecount() % 10 ~= 0 do
-- emu.frameadvance()
--end
local domains = {
["READ_CORE_MEMORY"] = "System Bus",
["READ_CORE_RAM"] = "Main RAM",
["WRITE_CORE_MEMORY"] = "System Bus",
["WRITE_CORE_RAM"] = "Main RAM"
}

-- receive a udp packet and handle it
local function server_handle()
local data, msg_or_ip, port_or_nil = udp:receivefrom()
if data then
-- "data" format is "COMMAND [PARAMETERS] [...]"
Expand Down Expand Up @@ -95,7 +90,7 @@ function on_vblank()
-- NOTE: No newline is intentional here for 1:1 RetroArch compatibility
udp:sendto("GET_STATUS CONTENTLESS", msg_or_ip, port_or_nil)
end
elseif command == "READ_CORE_MEMORY" then
elseif command == "READ_CORE_MEMORY" or command == "READ_CORE_RAM" then
local _, address, length = string.match(data, "(%S+) (%S+) (%S+)")
address = stripPrefix(address, "0x")
address = tonumber(address, 16)
Expand All @@ -107,7 +102,7 @@ function on_vblank()
-- Using memory.read_bytes_as_array() and explicitly using the System Bus
-- as the active memory domain solves this incompatibility, allowing us
-- to hopefully use whatever GB(C) emulator we want.
local mem = memory.read_bytes_as_array(address, length, "System Bus")
local mem = memory.read_bytes_as_array(address, length, domains[command])
local hex_string = ""
for _, v in ipairs(mem) do
hex_string = hex_string .. string.format("%02X ", v)
Expand All @@ -116,7 +111,7 @@ function on_vblank()
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)
elseif command == "WRITE_CORE_MEMORY" then
elseif command == "WRITE_CORE_MEMORY" or command == "WRITE_CORE_RAM" then
local _, address = string.match(data, "(%S+) (%S+)")
address = stripPrefix(address, "0x")
address = tonumber(address, 16)
Expand All @@ -131,15 +126,23 @@ function on_vblank()
i = i + 1
end

memory.write_bytes_as_array(address, to_write, "System Bus")
memory.write_bytes_as_array(address, to_write, domains[command])
local reply = string.format("%s %02x %d\n", command, address, i - 3)
udp:sendto(reply, msg_or_ip, port_or_nil)
end
end
end

event.onmemoryexecute(on_vblank, 0x40, "ap_connector_vblank")
if emu.getsystemid() == "GBC" then
-- This is a workaround for: https://github.com/TASEmulators/BizHawk/issues/3711
event.onmemoryexecute(server_handle, 0x40, "ap_connector_vblank")
print("using vblank event")
else
event.onframeend(server_handle, "ap_connector_frame")
print("using frame event")
end

print("connector loaded")
while true do
emu.yield()
end