Sync script modified to work on very old versions of BizHawk, with code specific to syncing DK64.
package.path = package.path .. ';luasocket/lua/?.lua;luasocket/lua/socket/?.lua'
package.cpath = package.cpath .. ';luasocket/?.dll;luasocket/mime/?.dll;luasocket/socket/?.dll'
local socket = require 'socket'
local tab = {} -- entire parsed file broken into lines
local gap_minimum = 10 -- Set the minimum number of frames between savestates. This can help prevent thrashing in bad sections.
function ParseFile()
print("Parsing file...")
local logfile = io.open("log.txt", "r")
local char
repeat
char = logfile:read("*l")
table.insert(tab, char)
until char == nil
logfile:close()
print("File parsed! Line count: "..#tab.."\n")
end
local function fl(val)
return mainmemory.readfloat(val, true)
end
local function sigfig(value, figs)
str = string.format("%f", value)
return str:sub(1, figs+1) -- account for '.' character
end
u32 = mainmemory.read_u32_be
-- Customize this function to retrieve your sync data and format it the same way as it appears in log.txt. An example of how
-- to do this for N64 Star Wars Episode 1: Racer, matching the example in sync-collect.lua, is the default implementation. this
-- value will get compared, as a string, to the corresponding line in log.txt to verify sync.
function GetData()
-- get pointers
local player = u32(0x7FBB4C)
local camera = u32(0x7FB968)
-- the actual values are floats
-- but let's just use their raw hex view for simplicity
if player >= 0x80000000 and player < 0x80800000 then
player = player - 0x80000000
pos = string.format("%s,%s,%s",
sigfig(fl(player + 0x7C), 8), -- x
sigfig(fl(player + 0x80), 8), -- y
sigfig(fl(player + 0x84), 8)) -- z
else
pos = "00000000,00000000,00000000"
end
if camera >= 0x80000000 and camera < 0x80800000 then
camera = camera - 0x80000000
cam = string.format("%s,%s,%s",
sigfig(fl(camera + 0x1FC), 8), -- x
sigfig(fl(camera + 0x200), 8), -- y
sigfig(fl(camera + 0x204), 8)) -- z
else
cam = "00000000,00000000,00000000"
end
-- conbined string
return pos.. "," .. cam
end
-- Pause the client and establish a tcp connection to the server.
client.pause()
local tcp = assert(socket.connect("127.0.0.1", 45678), "Socket client failed to establish tcp connection with server. Script aborted.")
console.write("Connection to server established!\n")
tcp:settimeout(2)
emu.yield()
ParseFile()
local onExitEvent = event.onexit(
function()
console.log("\nScript exiting. Sending quit command to server." );
tcp:send("quit\n")
end
, "OnExit" );
local function endsWith(str, ending)
return ending == "" or str:sub(-#ending) == ending
end
local function trimNewLine(str)
return string.sub(str, 1, string.len(str) - 1)
end
local last_ss = 0
while true do
local frame = emu.framecount()
local original = tab[frame+1]
local yours = GetData()
gui.pixelText(0, 40, string.format( "%s - original\n%s - yours", original, yours))
-- mismatch
if (yours ~= original) and ((frame - last_ss) > gap_minimum) then
last_ss = frame
client.pause()
-- screen and console alarm
gui.pixelText(0, 40, string.format( "%s - original\n%s - yours\ndesync at frame %d", original, yours, frame), "red")
print(string.format( "desync at frame %d\n%s\n%s\n", frame, yours, original))
emu.yield()
local response = ""
tcp:send(frame .. ".State\n")
console.write("Sent packet asking for frame " .. tostring(frame) .. " ...")
emu.yield()
while true do
local line, err, partial = tcp:receive()
if not err then
response = line
console.log("\nReceived message that savestate " .. tostring(frame) .. " is available. Loading ...")
emu.yield()
savestate.load("states/" .. response)
client.unpause()
break
elseif err == "timeout" then
response = response .. partial
console.write('.')
elseif err == "closed" then
console.log("\nConnection with server closed. Exiting now.")
break
else
console.log("\nUnknown communication error.")
end
emu.yield()
end
end
-- so far so good
emu.frameadvance()
end