summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Luca Bruno <lucab@debian.org>2015-03-16 11:35:38 +0100
committer Luca Bruno <lucab@debian.org>2015-03-16 12:03:09 +0100
commit1fa8b4ea4febee62516ea45a57568d0274cbd09a (patch)
tree928ba9e4c590e75c852e8e0c45348623f42e9d4c
parent05609ab9b1504a2ba62a6a23955590c82fd3865d (diff)
docs: add initial documentation for luaengine API
This commits add some initial documentation for current API exposed via luaengine. This doc is meant to be a quick walkthrough for script writers coming from mame-rr. Full methods reference is not yet included, as the API is still rapidly changing. Signed-off-by: Luca Bruno <lucab@debian.org>
-rw-r--r--docs/luaengine.md154
1 files changed, 154 insertions, 0 deletions
diff --git a/docs/luaengine.md b/docs/luaengine.md
new file mode 100644
index 00000000000..c2f2b961492
--- /dev/null
+++ b/docs/luaengine.md
@@ -0,0 +1,154 @@
+# Scripting MAME via LUA
+
+## Introduction
+
+It is now possible to externally drive MAME via LUA scripts.
+This feature initially appeared in version 0.148, when a minimal `luaengine`
+was implemented. Nowadays, the LUA interface is rich enough
+to let you inspect and manipulate devices state, access CPU
+registers, read and write memory, and draw a custom HUD on screen.
+
+Internally, MAME makes extensive use of `luabridge` to implement
+this feature: the idea is to transparently expose as many of
+the useful internals as possible.
+
+Finally, a warning: LUA API is not yet declared stable and may
+suddenly change without prior notice.
+However, we expose methods to let you know at runtime which API
+version you are running against, and you can introspect most of the
+objects at runtime.
+
+## Features
+
+The API is not yet complete, but this is a partial list of capabilities
+currently available to LUA scripts:
+
+ * machine metadata (app version, current rom, rom details)
+ * machine control (starting, pausing, resetting, stopping)
+ * machine hooks (on frame painting and on user events)
+ * devices introspection (device tree listing, memory and register enumeration)
+ * screens introspection (screens listing, screen details, frames counting)
+ * screen HUD drawing (text, lines, boxes on multiple screens)
+ * memory read/write (8/16/32/64 bits, signed and unsigned)
+ * registers and states control (states enumeration, get and set)
+
+## Usage
+
+MAME supports external scripting via LUA (>= 5.3) scripts, either
+written on the interactive console or loaded as a file.
+To reach the console, just run MAME with `-console`; you will be
+greeted by a naked `>` prompt where you can input your script.
+
+To load a whole script at once, store it in a plaintext file and
+pass it via the `-autoboot_script`. Please note that script
+loading may be delayed (few seconds by default), but you can
+override the default with the `-autoboot_delay` argument.
+
+To control the execution of your code, you can use a loop-based or
+an event-based approach. The former is not encouraged as it is
+resource-intensive and makes control flow unnecessarily complex.
+Instead, we suggest to register custom hooks to be invoked on specific
+events (eg. at each frame rendering).
+
+## Walktrough
+
+Let's first run MAME in a terminal to reach the LUA console:
+```
+$ mame -console YOUR_ROM
+M.A.M.E. v0.158 (Feb 5 2015) - Multiple Arcade Machine Emulator
+Copyright Nicola Salmoria and the MAME team
+Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
+
+>
+```
+
+At this point, your game is probably running in demo mode, let's pause it:
+```
+> emu.pause()
+>
+```
+Even without textual feedback on the console, you'll notice the game is now paused.
+In general, commands are quiet and only print back error messages.
+
+You can check at runtime which version of MAME you are running, with:
+```
+> print(emu.app_name() .. " " .. emu.app_version())
+mame 0.158
+```
+
+We now start exploring screen related methods. First, let's enumerate available screens:
+```
+> for i,v in pairs(manager:machine().screens) do print(i) end
+:screen
+```
+
+`manager:machine()` is the root object of your currently running machine:
+we will be using this often. `screens` is a table with all available screens;
+most machines only have one main screen.
+In our case, the main and only screen is tagged as `:screen`, and we can further
+inspect it:
+```
+> -- let's define a shorthand for the main screen
+> s = manager:machine().screens[":screen"]
+> print(s:width() .. "x" .. s:height())
+320x224
+```
+
+We have several methods to draw on the screen a HUD composed of lines, boxes and text:
+```
+> -- we define a HUD-drawing function, and then call it
+> function draw_hud()
+>> s:draw_text(40, 40, "foo"); -- (x0, y0, msg)
+>> s:draw_box(20, 20, 80, 80, 0, 0xff00ffff); -- (x0, y0, x1, y1, fill-color, line-color)
+>> s:draw_line(20, 20, 80, 80, 0xff00ffff); -- (x0, y0, x1, y1, line-color)
+>> end
+> draw_hud();
+```
+
+This will draw some useless art on the screen. However, when unpausing the game, your HUD
+needs to be refreshed otherwise it will just disappear. In order to do this, you have to register
+your hook to be called on every frame repaint:
+```
+> emu.sethook(draw_hud, "frame")
+```
+
+Similarly to screens, you can inspect all the devices attached to a
+machine:
+```
+> for k,v in pairs(manager:machine().devices) do print(k) end
+:audiocpu
+:maincpu
+:saveram
+:screen
+:palette
+[...]
+```
+
+On some of them, you can also inspect and manipulate memory and state:
+```
+> cpu = manager:machine().devices[":maincpu"]
+> -- enumerate, read and write state registers
+> for k,v in pairs(cpu.state) do print(k) end
+D5
+SP
+A4
+A3
+D0
+PC
+[...]
+> print(cpu.state["D0"].value)
+303
+> cpu.state["D0"].value = 255
+> print(cpu.state["D0"].value)
+255
+```
+
+```
+> -- inspect memory
+> for k,v in pairs(cpu.spaces) do print(k) end
+program
+> mem = cpu.spaces["program"]
+> print(mem:read_i8(0xC000))
+41
+```
+