aschepler

Changing code in mods

Recommended Posts

In a game mod, is it possible to change the actual code in a game asset? I mean the disassembled instructions, as opposed to just replacing globals and such things (as in this example). All my attempts have just resulted in a failure to load the overwritten asset file, "Failed to load {file} (room may be corrupted)".

A simple example:

local fileName = "Data/Content/Game/DorkForest/Rooms/BobTrap.lua"
local disasm = scripts.disassemble(scripts.load(fileName))

local code = disasm.proto.protos[4].code
if #code ~= 305 then error("Wrong proto?") end
for i = 95,305 do
   code[i-5] = code[i]
end
for i = 301,305 do
   code[i] = nil
end

assets.overwrite(fileName, scripts.reassemble(disasm))

protos[4] is the closure assigned to BobTrap.playMumbles. The deleted instructions 90 to 94 are

-- SELF 10 1 291
-- MOVE 12 8
-- LOADK 13 43
-- LOADK 14 44
-- CALL 10 5 1

scene:speakLineLeft(alicePortrait, "Hey! You're a sprite, right?", "Default3")

I checked that no JMP instructions jump past this code in either direction. So I expected this would just result in skipping one line of dialogue when Bob is freed. But entering the second room just gives the "(room may be corrupted)" error.

Also, if I do get replaced code working, is there a good way to insert my own assembly instructions? They appear to be some class-like object, at least to support inst:GET_OPCODE_NAME() etc., but there's no obvious interface to create new objects of that type. Can I just copy one with the correct opcode type from another disassembled function and do inst:SETARG_A() etc.?

Share this post


Link to post
Share on other sites

Progress! It looks like the issue with that example was the mismatch between code and debug.lineinfo. This version does work:

local fileName = "Data/Content/Game/DorkForest/Rooms/BobTrap.lua"
local disasm = scripts.disassemble(scripts.load(fileName))
local playMumbles = disasm.proto.protos[4]

local code = playMumbles.code
if #code ~= 305 then error("Wrong proto?") end
for i = 95,305 do
   code[i-5] = code[i]
end
for i = 301,305 do
   code[i] = nil
end

local lineinfo = playMumbles.debug.lineinfo
for i = 95,305 do
   lineinfo[i-5] = lineinfo[i]
end
for i = 301,305 do
   lineinfo[i] = nil
end

assets.overwrite(fileName, scripts.reassemble(disasm))

I figure a truly additive mod should also adjust debug.locvars in case some other mod examining the same function depends on that. (Not that there seem to be many mods doing this sort of thing, or that anybody is still trying to write new mods.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now