Previous | 199869 Revisions | Next |
r36597 Monday 16th March, 2015 at 11:03:09 UTC by Luca Bruno |
---|
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> |
[docs] | luaengine.md* |
r0 | r245109 | |
---|---|---|
1 | # Scripting MAME via LUA | |
2 | ||
3 | ## Introduction | |
4 | ||
5 | It is now possible to externally drive MAME via LUA scripts. | |
6 | This feature initially appeared in version 0.148, when a minimal `luaengine` | |
7 | was implemented. Nowadays, the LUA interface is rich enough | |
8 | to let you inspect and manipulate devices state, access CPU | |
9 | registers, read and write memory, and draw a custom HUD on screen. | |
10 | ||
11 | Internally, MAME makes extensive use of `luabridge` to implement | |
12 | this feature: the idea is to transparently expose as many of | |
13 | the useful internals as possible. | |
14 | ||
15 | Finally, a warning: LUA API is not yet declared stable and may | |
16 | suddenly change without prior notice. | |
17 | However, we expose methods to let you know at runtime which API | |
18 | version you are running against, and you can introspect most of the | |
19 | objects at runtime. | |
20 | ||
21 | ## Features | |
22 | ||
23 | The API is not yet complete, but this is a partial list of capabilities | |
24 | currently available to LUA scripts: | |
25 | ||
26 | * machine metadata (app version, current rom, rom details) | |
27 | * machine control (starting, pausing, resetting, stopping) | |
28 | * machine hooks (on frame painting and on user events) | |
29 | * devices introspection (device tree listing, memory and register enumeration) | |
30 | * screens introspection (screens listing, screen details, frames counting) | |
31 | * screen HUD drawing (text, lines, boxes on multiple screens) | |
32 | * memory read/write (8/16/32/64 bits, signed and unsigned) | |
33 | * registers and states control (states enumeration, get and set) | |
34 | ||
35 | ## Usage | |
36 | ||
37 | MAME supports external scripting via LUA (>= 5.3) scripts, either | |
38 | written on the interactive console or loaded as a file. | |
39 | To reach the console, just run MAME with `-console`; you will be | |
40 | greeted by a naked `>` prompt where you can input your script. | |
41 | ||
42 | To load a whole script at once, store it in a plaintext file and | |
43 | pass it via the `-autoboot_script`. Please note that script | |
44 | loading may be delayed (few seconds by default), but you can | |
45 | override the default with the `-autoboot_delay` argument. | |
46 | ||
47 | To control the execution of your code, you can use a loop-based or | |
48 | an event-based approach. The former is not encouraged as it is | |
49 | resource-intensive and makes control flow unnecessarily complex. | |
50 | Instead, we suggest to register custom hooks to be invoked on specific | |
51 | events (eg. at each frame rendering). | |
52 | ||
53 | ## Walktrough | |
54 | ||
55 | Let's first run MAME in a terminal to reach the LUA console: | |
56 | ``` | |
57 | $ mame -console YOUR_ROM | |
58 | M.A.M.E. v0.158 (Feb 5 2015) - Multiple Arcade Machine Emulator | |
59 | Copyright Nicola Salmoria and the MAME team | |
60 | Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio | |
61 | ||
62 | > | |
63 | ``` | |
64 | ||
65 | At this point, your game is probably running in demo mode, let's pause it: | |
66 | ``` | |
67 | > emu.pause() | |
68 | > | |
69 | ``` | |
70 | Even without textual feedback on the console, you'll notice the game is now paused. | |
71 | In general, commands are quiet and only print back error messages. | |
72 | ||
73 | You can check at runtime which version of MAME you are running, with: | |
74 | ``` | |
75 | > print(emu.app_name() .. " " .. emu.app_version()) | |
76 | mame 0.158 | |
77 | ``` | |
78 | ||
79 | We now start exploring screen related methods. First, let's enumerate available screens: | |
80 | ``` | |
81 | > for i,v in pairs(manager:machine().screens) do print(i) end | |
82 | :screen | |
83 | ``` | |
84 | ||
85 | `manager:machine()` is the root object of your currently running machine: | |
86 | we will be using this often. `screens` is a table with all available screens; | |
87 | most machines only have one main screen. | |
88 | In our case, the main and only screen is tagged as `:screen`, and we can further | |
89 | inspect it: | |
90 | ``` | |
91 | > -- let's define a shorthand for the main screen | |
92 | > s = manager:machine().screens[":screen"] | |
93 | > print(s:width() .. "x" .. s:height()) | |
94 | 320x224 | |
95 | ``` | |
96 | ||
97 | We have several methods to draw on the screen a HUD composed of lines, boxes and text: | |
98 | ``` | |
99 | > -- we define a HUD-drawing function, and then call it | |
100 | > function draw_hud() | |
101 | >> s:draw_text(40, 40, "foo"); -- (x0, y0, msg) | |
102 | >> s:draw_box(20, 20, 80, 80, 0, 0xff00ffff); -- (x0, y0, x1, y1, fill-color, line-color) | |
103 | >> s:draw_line(20, 20, 80, 80, 0xff00ffff); -- (x0, y0, x1, y1, line-color) | |
104 | >> end | |
105 | > draw_hud(); | |
106 | ``` | |
107 | ||
108 | This will draw some useless art on the screen. However, when unpausing the game, your HUD | |
109 | needs to be refreshed otherwise it will just disappear. In order to do this, you have to register | |
110 | your hook to be called on every frame repaint: | |
111 | ``` | |
112 | > emu.sethook(draw_hud, "frame") | |
113 | ``` | |
114 | ||
115 | Similarly to screens, you can inspect all the devices attached to a | |
116 | machine: | |
117 | ``` | |
118 | > for k,v in pairs(manager:machine().devices) do print(k) end | |
119 | :audiocpu | |
120 | :maincpu | |
121 | :saveram | |
122 | :screen | |
123 | :palette | |
124 | [...] | |
125 | ``` | |
126 | ||
127 | On some of them, you can also inspect and manipulate memory and state: | |
128 | ``` | |
129 | > cpu = manager:machine().devices[":maincpu"] | |
130 | > -- enumerate, read and write state registers | |
131 | > for k,v in pairs(cpu.state) do print(k) end | |
132 | D5 | |
133 | SP | |
134 | A4 | |
135 | A3 | |
136 | D0 | |
137 | PC | |
138 | [...] | |
139 | > print(cpu.state["D0"].value) | |
140 | 303 | |
141 | > cpu.state["D0"].value = 255 | |
142 | > print(cpu.state["D0"].value) | |
143 | 255 | |
144 | ``` | |
145 | ||
146 | ``` | |
147 | > -- inspect memory | |
148 | > for k,v in pairs(cpu.spaces) do print(k) end | |
149 | program | |
150 | > mem = cpu.spaces["program"] | |
151 | > print(mem:read_i8(0xC000)) | |
152 | 41 | |
153 | ``` | |
154 |
Previous | 199869 Revisions | Next |