-
Notifications
You must be signed in to change notification settings - Fork 0
Lua Scripting Guide
-
Method 1 (Content-Specific): Save the script in the same folder as your ROM with a matching filename. E.g.:
Momotarou Katsugeki (Japan).pce->Momotarou Katsugeki (Japan).lua. The script will autostart when the content is loaded with any compatible core. -
Method 2 (Global): Save your script as
$HOME/.config/retroarch/system/global.lua. This script will run automatically with any content and core.
Tip
You can combine multiple scripts with dofile()/loadfile()/require()
The script keeps running and it is terminated with the associated content:
| Content status | Script status |
|---|---|
| Running | Running |
| Paused | Paused |
| Frontend menu opened | Running, but not drawing shapes |
| Reset | Running, not restarted |
| Closed | Terminated |
-- Global vars and functions definitions
local foo = "hello"
local bar = 1
function foo_bar()
-- ...
end
-- Main loop, executed once per frame
-- without this loop the script will terminate immediately!
while true do
-- ...
emu.frameadvance(); -- Required
endThe API is mostly compatible with Bizhawk. Use this page as reference.
Coverage:
| Status | Module | Coverage Notes |
|---|---|---|
| π‘ Partial | bizstring |
Implemented contains(), endswith(), startswith(), tolower(), toupper(), trim(), encode(), decode(). The last two requires libiconv, which could be missing on some platforms. |
| π‘ Partial | console |
Missing only clear(), getluafunctionslist()
|
| π‘ Partial | emu |
Implemented only frameadvance(), framecount(), getsystemid()
|
| π‘ Partial | gameinfo |
Implemented only getromhash() and getromname(). Missing all database functions. |
| π’ Full | input |
All functions implemented. |
| π’ Full | memory |
All functions implemented. |
| π’ Full | mainmemory |
Alias to memory
|
| π‘ Partial | client |
Implemented ispaused(), isturbo(), screenheight(), screenwidth(), bufferheight(),bufferwidth(), getversion(), pause(), unpause(), togglepause(), exit(), reboot_core(), closerom(), screenshot(), sleep(), getconfig(), transformPoint(), get_lua_engine()
|
| π‘ Partial | comm |
Implemented only httpget(), httppost(), httpput(). HTTP functions are non-blocking; no response body access. |
| π‘ Partial | gui |
Implemented only addmessage(), drawString(), drawPixelText(), drawRectangle(), drawBox(), clearGraphics()
|
| π‘ Partial | joypad |
Implemented only joypad.get()
|
| π’ Full | savestate |
|
| π΄ None | bit |
Not implemented (Standard Lua 5.3 bitwise operators available). |
| π΄ None | event |
|
| π΄ None | forms |
|
| π΄ None | genesis |
|
| π΄ None | LuaCanvas |
|
| π΄ None | memorysavestate |
|
| π΄ None | movie |
|
| π΄ None | nds |
|
| π΄ None | nes |
|
| π΄ None | snes |
|
| π΄ None | SQL |
|
| π΄ None | tastudio |
|
| π΄ None | userdata |
Notable differences:
-
gameinfo.getromhash()returns the content CRC32, while Bizhawk uses SHA1 for ROM-based systems and MD5 for CD-based systems. -
gui.draw...()functions do not support thesurfacenamearg. They draw in a separate buffer with an higher resolution than the emulated core. -
client.getconfig()returns a table with different setting names -
comm_http...()functions send non-blocking requests, and there is no way to get the response body. -
client.screenshot()does not support the path arg
New functions not in Bizhawk:
-
gameinfo.getrompath()= returns the full path of the currently loaded rom (can be a relative path) -
rom.readbyte(int address)= Get an unsigned byte from the actual ROM file at the given address. -
emu.getscreenpixel(int x, int y, bool getemuscreen)= Returns the separate RGB components of the given screen pixel, and the palette. -
gui.drawStringO(...),gui.pixelTextO(...).gui.drawRectangleO(...)= Draws outside the emulator screen space -
memory.dump(filename, [string domain = nil], [ long start_address = 0 ], [long stop_address = memsize])= Dump a memory region into a file.
Tip
Check the source code as additional reference of missing functions/features.
Unlike Bizhawk, all cores share the same memory domain names: "Battery RAM", "RTC", "RAM", "VRAM", "ROM".
However, availability varies by core. Use this check to prevent errors:
-- check if the VRAM memory domain is available
if(memory.usememorydomain("VRAM")) then
-- safe to access VRAM here
print(memory.readbyte(0x0, "VRAM"))
else
print("err: VRAM domain NOT available")
end
-- this will fall back to default domain if VRAM is not available
print(memory.readbyte(0x0, "VRAM"))To list all available domains for the current core:
console.write(memory.getmemorydomainlist())
-- alt. iterative way
for i, name in ipairs(memory.getmemorydomainlist()) do
print(i, name, " size=" .. memory.getmemorydomainsize(name))
endThe full Lua 5.3 stdlib is also available.
Some stdlib functions can be disabled via the user setting lua_scripts_sandboxed, to prevent the execution of malicious scripts:
os.execute()os.remove()os.rename()-
io.open()is restricted to read-only access files in the same folder of the current content.
To debug a script, run RetroArch from a terminal to view stdout and stderr messages.
Since the API is mostly compatible, you can also load your scripts in BizHawk and use its Lua Interactive Console as a playground for testing and practice.
- Generic test script covering most available features: example.lua
- RetroGuides, read and render text from local txt files
- RetroSubs, render in-game subtitles based on memory context
- RetroHiscores, a port of the MAME hiscore plugin.