Joined: 11/21/2019
Posts: 247
Location: Washington
I ended up finding the motivation to open up Ghidra and spend a lot of time reversing AC for other reasons, and that ended up with me ultimately looking for the model rendering code:
Link to video
It took me probably a week of reversing unrelated code before I could even make sense of the stuff that dealt with 3d projection and rendering, and I spent probably 2 weeks in there before I was sure that I had found the code that walked model vertices. However, I did have the camera's transformation matrix in hand, and with your code for your GE wallhack, I had a great launching point for getting a very basic hack working that just placed a dot over enemies in the game. I have to thank you again for posting your code, without it, the difficulty curve probably would have turned me off from even trying, especially since I ultimately had to learn a LOT about PSX hardware and how it does 3d rendering to get it working correctly.
A discovery I made very late into the process was that AC does not actually use hitboxes at all! It uses axis-aligned bounding-boxes. This was both relieving and disappointing at the same time. I spent a lot of time writing a function that would find model vertices and traverse the skeleton, only to find that every time I thought I had found the right data, I ended up rendering vertices for every single triangle on the entity model. I had passed right over the AABB collision function for the game probably dozens of times and never payed any attention to it because it seemed too simple and didn't reference any model data. One I realized it used AABBs, getting bounding boxes around the entities was a piece of cake.
In the end, I'm glad to have done this and am pretty done with it, but am a little disappointed that my solution did not ultimately actually find model data and walk the structures because that was exercise I wanted to do. It feels like my work is sorta a "fake" wallhack compared to yours in that regard, but the only alternative to what I did would be to invent my own boudning boxes for the game's models based on model vertex data and a bounding algorithm or something, and that is WAAAY more work than I am willing to put into this!
The code for my wall hack (and a number of other scripts for AC) is here: https://gist.github.com/Zinfidel/d47287cec638f0f915c3d99bccef3a7d
P.S.: Thank for the compliment on my TAS! It's boring I know, but it has already inspired another TASer to do a "proper" TAS so that's something to look forward to.
NLua.Exceptions.LuaException: unprotected error in call to Lua API (0)
à NLua.Lua.PanicCallback(IntPtr luaState)
à lua_error(lua_State* )
à NLua.ObjectTranslator.throwError(IntPtr luaState, Object e)
à NLua.Lua.SetPendingException(Exception e)
à NLua.LuaMethodWrapper.call(IntPtr luaState)
à NLua.MetaFunctions.runFunctionDelegate(IntPtr luaState)
à lua_resume(lua_State* , Int32 )
à BizHawk.Client.EmuHawk.Win32LuaLibraries.ResumeScript(LuaFile lf)
à BizHawk.Client.EmuHawk.LuaConsole.<>c__DisplayClass59_1.<ResumeScripts>b__1()
à BizHawk.Client.Common.LuaSandbox.Sandbox(Action callback, Action exceptionCallback)
In Bizhawk, I'm trying to run a lua that opens a file "test.log" that contains text.
Language: Lua
local file_name = "test.log"
function readAll(file)
local f = assert(io.open(file, "r"))
local content = f:read("*all")
f:close()
return content
end
text=print(readAll(file_name))
It seems that when the log file is not currently used by an application, the lua runs fine and it prints the text normally. But if it is used then I get this:
There isn't really a good way to recognize that BIOS mode is currently active at the moment. The best way would likely just to check the hash of 0x0000-0x00FF of the ROM and System Bus domains to see if they match (if they don't, you're very likely in BIOS mode). This will break for multicart games, but it would cover most games.
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
The value passed for scope must be a string matching one shown in event.availableScopes(). You can omit both name and scope arguments though:
Language: lua
local exec_cb_id = event.on_bus_exec(function(addr, val, flags) print("hi"); end, 0x14B4);
edit: Took too long to reply :P Make sure you're passing the address of the byte written to, not another part of a word, and mind the endianness.
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
Are you just after a template? Here you go
Language: lua
local hitbox_width = 16;
local hitbox_height = 16;
local pos_x = 0;
local pos_y = 0;
while true do
if not client.ispaused() then
pos_x = memory.readbyte(0xABCD);
pos_y = memory.readbyte(0x1234);
end
gui.drawBox(pos_x, pos_y, pos_x + hitbox_width, pos_y + hitbox_height);
emu.yield();
end
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Joined: 1/6/2012
Posts: 587
Location: Azerbaijan, Baku
Am i supposed only to change pos_x and pos_y ? I did it but in output i get message NLua.Exceptions.LuaScriptException: [string "main"]:2: function arguments expected near 'local'
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
Yes, but don't change them where they're initialised, change the function that updates them (I've used readbyte with bogus addresses).
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
Can you post the whole script and also copy the rom name/hash?
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Joined: 1/6/2012
Posts: 587
Location: Azerbaijan, Baku
local hitbox_width = 16;
local hitbox_height = 16;
local pos_x = 0;
local pos_y = 0;
while true do
if not client.ispaused() then
pos_x = memory.readbyte(0x01E2);
pos_y = memory.readbyte(0x01E5);
end
gui.drawBox(pos_x, pos_y, pos_x + hitbox_width, pos_y + hitbox_height);
emu.yield();
end
Lion King, The - Simba's Mighty Adventure (USA, Europe).gbc
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
There were a few problems here. First, you need to set the memory domain to WRAM because the default is System Bus. Second, those addresses seem to be 16 bits wide. Lastly, they point to the position in the level, relative to the world origin. You already posted the camera position in another thread so I was able to calculate the camera-relative position.
I've also added an offset so the hitbox lines up with the sprite, just by eye, and it seems to be correct except for when crouching.
Language: lua
memory.usememorydomain("WRAM");
local hitbox_width = 16;
local hitbox_height = 16;
local hitbox_offset_x = 8;
local hitbox_offset_y = 16;
local pos_x = 0;
local pos_y = 0;
while true do
if not client.ispaused() then
pos_x = memory.read_u16_le(0x01E2) - memory.read_u16_le(0x098B) - hitbox_offset_x;
pos_y = memory.read_u16_le(0x01E5) - memory.read_u16_le(0x098E) - hitbox_offset_y;
end
gui.drawBox(pos_x, pos_y, pos_x + hitbox_width, pos_y + hitbox_height);
emu.yield();
end
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Thank you. Now I need help with a different problem.
Is it possible to save a savestate via savestate.save("HelloWorld.State") to a certain file path?
I can only seem to save it to the same path as the .lua
Thanks again.
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
You can pass an absolute path e.g. "C:\\Users\\user\\Desktop\\A.State"
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
I'm trying to get a script set up that fires when the game executes specific code. The help page on the site here tells me to use event.on_bus_read, but when I do, I get the error "attempt to call field 'on_bus_read' (a nil value)" the parser doesn't seem to understand what I'm doing. I've googled ' lua "on_bus_read" ' and the only result is said help page, so there doesn't seem to be a lot of info online for how to do this kind of thing with Bizhawk.
Thanks for the help
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
You must be using an old version. onmemoryread was renamed to on_bus_read in 2.9. If you want your script to run on older versions, you can continue using the old name; it will be kept for a few more releases.
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Ahh, the version of 2.9 I was using was a dev build, probably before that change was implemented. I tried downloading a fresh copy and it seems to be behaving correctly now. It doesn't appear to work in QuickNES though, so back to square one I guess.
I tried to make a script to pause at specific frame, but i keep getting syntax error. Im not good with C and other languages, but i used something similar with psxjin (just changing client.pause with emu.pause) and it worked, but in EmuHawk it doesnt:
while true do
if emu.framecount() == xxx then
client.pause
emu.frameadvance()
end
(xxx is the frame number)
What i did wrong?
For reference, you should use Wiki: Bizhawk/LuaFunctions to know what functions are available in bizhawk. Syntax-wise you're missing the () parentheses on the pause function, and you're missing an end keyword. I also suggest indenting your code, it helps with readability and knowing where the end keywords should exist.
Language: lua
while true do
if emu.framecount() == xxx then
client.pause()
end
emu.frameadvance()
end
Thanks! It worked.
Another thing: how should it look about longer or multi line conditional code?
I know with a simple code like this
"D003475c 00EA
1003475c 0001"
the lua looks like:
Language: lua
while true do
if memory.read_u16_le(0x03475C) == 0xEA then
memory.write_u16_le(0x03475C, 0xEB)
end
emu.frameadvance()
end
How about a code like this?
D0022E88 0201
800AA718 0000
D0022E88 0201
800AA71A 0000
80022E88 0000
EDIT: ok, i resolved (it was pretty easy...).
By the way, how to "convert" a code that start with 10xxxxxx?
The cheat type says: 10aaaaaa dddd ;-16bit Increment [aaaaaa]=[aaaaaa]+dddd
but i dont have any idea how a lua script would look about that...
Joined: 8/30/2020
Posts: 111
Location: Sydney, Australia
Darth_Marios wrote:
By the way, how to "convert" a code that start with 10xxxxxx?
The cheat type says: 10aaaaaa dddd ;-16bit Increment [aaaaaa]=[aaaaaa]+dddd
but i dont have any idea how a lua script would look about that...
Just based on what you've said, memory.write_u16_le(a, memory.read_u16_le(a) + d).
I contribute to BizHawk as Linux/cross-platform lead, testing and automation lead, and UI designer. This year, I'm experimenting with streaming BizHawk development on Twitch. nope
Links to find me elsewhere and to some of my side projects are on my personal site. I will respond on Discord faster than to PMs on this site.
Hey look buddy, I'm an engineer. That means I solve problems. Not problems like "What is software," because that would fall within the purview of your conundrums of philosophy. I solve practical problems. For instance, how am I gonna stop some high-wattage thread-ripping monster of a CPU dead in its tracks? The answer: use code. And if that don't work? Use more code.