Get rid of DECLARE_LUACLASS
[lsnes.git] / src / lua / lua.cpp
blobde7413b738eff75e72593f9fe3c8af8e3114a1bf
1 #include "core/command.hpp"
2 #include "library/globalwrap.hpp"
3 #include "lua/internal.hpp"
4 #include "lua/lua.hpp"
5 #include "lua/unsaferewind.hpp"
6 #include "core/mainloop.hpp"
7 #include "core/memorymanip.hpp"
8 #include "core/moviedata.hpp"
9 #include "core/misc.hpp"
11 #include <map>
12 #include <cstring>
13 #include <string>
14 #include <iostream>
15 extern "C" {
16 #include <lualib.h>
19 uint64_t lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
20 uint64_t lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
21 bool* lua_veto_flag = NULL;
22 bool* lua_kill_frame = NULL;
23 extern const char* lua_sysrc_script;
24 void* synchronous_paint_ctx;
26 lua_state lsnes_lua_state;
27 lua_function_group lua_func_bit;
28 lua_function_group lua_func_misc;
29 lua_function_group lua_func_callback;
30 lua_function_group lua_func_load;
31 lua_function_group lua_func_zip;
33 namespace
35 void pushpair(lua_state& L, std::string key, double value)
37 L.pushstring(key.c_str());
38 L.pushnumber(value);
39 L.settable(-3);
42 void pushpair(lua_state& L, std::string key, std::string value)
44 L.pushstring(key.c_str());
45 L.pushstring(value.c_str());
46 L.settable(-3);
49 std::string get_mode_str(int mode)
51 if(mode < 0)
52 return "disabled";
53 else if(mode > 0)
54 return "axis";
55 return "pressure0+";
59 void push_keygroup_parameters(lua_state& L, keyboard::key& p)
61 keyboard::mouse_calibration p2;
62 keyboard::axis_calibration p3;
63 int mode;
64 L.newtable();
65 switch(p.get_type()) {
66 case keyboard::KBD_KEYTYPE_KEY:
67 pushpair(L, "value", p.get_state());
68 pushpair(L, "type", "key");
69 break;
70 case keyboard::KBD_KEYTYPE_HAT:
71 pushpair(L, "value", p.get_state());
72 pushpair(L, "type", "hat");
73 break;
74 case keyboard::KBD_KEYTYPE_MOUSE:
75 p2 = p.cast_mouse()->get_calibration();
76 pushpair(L, "value", p.get_state());
77 pushpair(L, "type", "mouse");
78 break;
79 case keyboard::KBD_KEYTYPE_AXIS:
80 mode = p.cast_axis()->get_mode();
81 pushpair(L, "value", p.get_state());
82 pushpair(L, "type", get_mode_str(mode));
83 break;
87 lua_render_context* lua_render_ctx = NULL;
88 controller_frame* lua_input_controllerdata = NULL;
89 bool lua_booted_flag = false;
91 namespace
93 int push_keygroup_parameters2(lua_state& L, keyboard::key* p)
95 push_keygroup_parameters(L, *p);
96 return 1;
99 bool recursive_flag = false;
100 const char* luareader_fragment = NULL;
102 const char* read_lua_fragment(lua_State* L, void* dummy, size_t* size)
104 if(luareader_fragment) {
105 const char* ret = luareader_fragment;
106 *size = strlen(luareader_fragment);
107 luareader_fragment = NULL;
108 return ret;
109 } else {
110 *size = 0;
111 return NULL;
115 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
117 const char* eval_lua_lua = "local fn = loadstring(" TEMPORARY "); if fn then fn(); else print("
118 "\"Parse error in Lua statement\"); end;";
119 const char* run_lua_lua = "dofile(" TEMPORARY ");";
121 void run_lua_fragment(lua_state& L) throw(std::bad_alloc)
123 if(recursive_flag)
124 return;
125 #if LUA_VERSION_NUM == 501
126 int t = L.load(read_lua_fragment, NULL, "run_lua_fragment");
127 #endif
128 #if LUA_VERSION_NUM == 502
129 int t = L.load(read_lua_fragment, NULL, "run_lua_fragment", "t");
130 #endif
131 if(t == LUA_ERRSYNTAX) {
132 messages << "Can't run Lua: Internal syntax error: " << L.tostring(-1)
133 << std::endl;
134 L.pop(1);
135 return;
137 if(t == LUA_ERRMEM) {
138 messages << "Can't run Lua: Out of memory" << std::endl;
139 L.pop(1);
140 return;
142 recursive_flag = true;
143 int r = L.pcall(0, 0, 0);
144 recursive_flag = false;
145 if(r == LUA_ERRRUN) {
146 messages << "Error running Lua hunk: " << L.tostring(-1) << std::endl;
147 L.pop(1);
149 if(r == LUA_ERRMEM) {
150 messages << "Error running Lua hunk: Out of memory" << std::endl;
151 L.pop(1);
153 if(r == LUA_ERRERR) {
154 messages << "Error running Lua hunk: Double Fault???" << std::endl;
155 L.pop(1);
157 lua_render_ctx = NULL;
158 if(lua_requests_repaint) {
159 lua_requests_repaint = false;
160 lsnes_cmd.invoke("repaint");
164 void do_eval_lua(lua_state& L, const std::string& c) throw(std::bad_alloc)
166 L.pushlstring(c.c_str(), c.length());
167 L.setglobal(TEMPORARY);
168 luareader_fragment = eval_lua_lua;
169 run_lua_fragment(L);
172 void do_run_lua(lua_state& L, const std::string& c) throw(std::bad_alloc)
174 L.pushlstring(c.c_str(), c.length());
175 L.setglobal(TEMPORARY);
176 luareader_fragment = run_lua_lua;
177 run_lua_fragment(L);
180 template<typename... T> bool run_callback(lua_state::lua_callback_list& list, T... args)
182 if(recursive_flag)
183 return true;
184 recursive_flag = true;
185 try {
186 if(!list.callback(args...)) {
187 recursive_flag = false;
188 return false;
190 } catch(std::exception& e) {
191 messages << e.what() << std::endl;
193 lua_render_ctx = NULL;
194 if(lua_requests_repaint) {
195 lua_requests_repaint = false;
196 lsnes_cmd.invoke("repaint");
198 recursive_flag = false;
199 return true;
202 int system_write_error(lua_State* L)
204 lua_pushstring(L, "_SYSTEM is write-protected");
205 lua_error(L);
206 return 0;
209 void copy_system_tables(lua_state& L)
211 #if LUA_VERSION_NUM == 501
212 L.pushvalue(LUA_GLOBALSINDEX);
213 #endif
214 #if LUA_VERSION_NUM == 502
215 L.rawgeti(LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
216 #endif
217 L.newtable();
218 L.pushnil();
219 while(L.next(-3)) {
220 //Stack: _SYSTEM, KEY, VALUE
221 L.pushvalue(-2);
222 L.pushvalue(-2);
223 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
224 L.rawset(-5);
225 //Stack: _SYSTEM, KEY, VALUE
226 L.pop(1);
227 //Stack: _SYSTEM, KEY
229 L.newtable();
230 L.pushcfunction(system_write_error);
231 L.setfield(-2, "__newindex");
232 L.setmetatable(-2);
233 L.setglobal("_SYSTEM");
236 void run_sysrc_lua(lua_state& L)
238 do_eval_lua(L, lua_sysrc_script);
241 void run_synchronous_paint(struct lua_render_context* ctx)
243 if(!synchronous_paint_ctx)
244 return;
245 lua_renderq_run(ctx, synchronous_paint_ctx);
248 #define DEFINE_CB(X) lua_state::lua_callback_list on_##X (lsnes_lua_state, #X , "on_" #X )
250 DEFINE_CB(paint);
251 DEFINE_CB(video);
252 DEFINE_CB(reset);
253 DEFINE_CB(frame);
254 DEFINE_CB(rewind);
255 DEFINE_CB(idle);
256 DEFINE_CB(timer);
257 DEFINE_CB(frame_emulated);
258 DEFINE_CB(readwrite);
259 DEFINE_CB(startup);
260 DEFINE_CB(pre_load);
261 DEFINE_CB(post_load);
262 DEFINE_CB(err_load);
263 DEFINE_CB(pre_save);
264 DEFINE_CB(post_save);
265 DEFINE_CB(err_save);
266 DEFINE_CB(input);
267 DEFINE_CB(snoop);
268 DEFINE_CB(snoop2);
269 DEFINE_CB(button);
270 DEFINE_CB(quit);
271 DEFINE_CB(keyhook);
272 DEFINE_CB(movie_lost);
273 DEFINE_CB(pre_rewind);
274 DEFINE_CB(post_rewind);
275 DEFINE_CB(set_rewind);
276 DEFINE_CB(latch);
279 void lua_callback_do_paint(struct lua_render_context* ctx, bool non_synthetic) throw()
281 run_synchronous_paint(ctx);
282 run_callback(on_paint, lua_state::store_tag(lua_render_ctx, ctx), lua_state::boolean_tag(non_synthetic));
285 void lua_callback_do_video(struct lua_render_context* ctx, bool& kill_frame) throw()
287 run_callback(on_video, lua_state::store_tag(lua_render_ctx, ctx), lua_state::store_tag(lua_kill_frame,
288 &kill_frame));
291 void lua_callback_do_reset() throw()
293 run_callback(on_reset);
296 void lua_callback_do_frame() throw()
298 run_callback(on_frame);
301 void lua_callback_do_rewind() throw()
303 run_callback(on_rewind);
306 void lua_callback_do_idle() throw()
308 lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
309 run_callback(on_idle);
312 void lua_callback_do_timer() throw()
314 lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
315 run_callback(on_timer);
318 void lua_callback_do_frame_emulated() throw()
320 run_callback(on_frame_emulated);
323 void lua_callback_do_readwrite() throw()
325 run_callback(on_readwrite);
328 void lua_callback_startup() throw()
330 lua_booted_flag = true;
331 run_callback(on_startup);
334 void lua_callback_pre_load(const std::string& name) throw()
336 run_callback(on_pre_load, lua_state::string_tag(name));
339 void lua_callback_err_load(const std::string& name) throw()
341 run_callback(on_err_load, lua_state::string_tag(name));
344 void lua_callback_post_load(const std::string& name, bool was_state) throw()
346 run_callback(on_post_load, lua_state::string_tag(name), lua_state::boolean_tag(was_state));
349 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
351 run_callback(on_pre_save, lua_state::string_tag(name), lua_state::boolean_tag(is_state));
354 void lua_callback_err_save(const std::string& name) throw()
356 run_callback(on_err_save, lua_state::string_tag(name));
359 void lua_callback_post_save(const std::string& name, bool is_state) throw()
361 run_callback(on_post_save, lua_state::string_tag(name), lua_state::boolean_tag(is_state));
364 void lua_callback_do_input(controller_frame& data, bool subframe) throw()
366 run_callback(on_input, lua_state::store_tag(lua_input_controllerdata, &data),
367 lua_state::boolean_tag(subframe));
370 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
372 if(run_callback(on_snoop2, lua_state::numeric_tag(port), lua_state::numeric_tag(controller),
373 lua_state::numeric_tag(index), lua_state::numeric_tag(value)))
374 return;
375 run_callback(on_snoop, lua_state::numeric_tag(port), lua_state::numeric_tag(controller),
376 lua_state::numeric_tag(index), lua_state::numeric_tag(value));
379 bool lua_callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type)
381 bool flag = false;
382 run_callback(on_button, lua_state::store_tag(lua_veto_flag, &flag), lua_state::numeric_tag(port),
383 lua_state::numeric_tag(controller), lua_state::numeric_tag(index), lua_state::string_tag(type));
384 return flag;
387 namespace
389 command::fnptr<const std::string&> evaluate_lua(lsnes_cmd, "evaluate-lua", "Evaluate expression in "
390 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
391 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
392 if(args == "")
393 throw std::runtime_error("Expected expression to evaluate");
394 do_eval_lua(lsnes_lua_state, args);
397 command::fnptr<const std::string&> evaluate_lua2(lsnes_cmd, "L", "Evaluate expression in "
398 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
399 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
400 if(args == "")
401 throw std::runtime_error("Expected expression to evaluate");
402 do_eval_lua(lsnes_lua_state, args);
405 command::fnptr<command::arg_filename> run_lua(lsnes_cmd, "run-lua", "Run Lua script in Lua VM",
406 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
407 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error)
409 do_run_lua(lsnes_lua_state, args);
412 command::fnptr<> reset_lua(lsnes_cmd, "reset-lua", "Reset the Lua VM",
413 "Syntax: reset-lua\nReset the Lua VM.\n",
414 []() throw(std::bad_alloc, std::runtime_error)
416 lsnes_lua_state.reset();
417 luaL_openlibs(lsnes_lua_state.handle());
419 run_sysrc_lua(lsnes_lua_state);
420 copy_system_tables(lsnes_lua_state);
421 messages << "Lua VM reset" << std::endl;
424 lua_class<lua_unsaferewind> class_unsaferewind("UNSAFEREWIND");
427 void lua_callback_quit() throw()
429 run_callback(on_quit);
432 void lua_callback_keyhook(const std::string& key, keyboard::key& p) throw()
434 run_callback(on_keyhook, lua_state::string_tag(key), lua_state::fnptr_tag(push_keygroup_parameters2, &p));
437 void init_lua() throw()
439 lsnes_lua_state.set_oom_handler(OOM_panic);
440 try {
441 lsnes_lua_state.reset();
442 lsnes_lua_state.add_function_group(lua_func_bit);
443 lsnes_lua_state.add_function_group(lua_func_load);
444 lsnes_lua_state.add_function_group(lua_func_callback);
445 lsnes_lua_state.add_function_group(lua_func_misc);
446 lsnes_lua_state.add_function_group(lua_func_zip);
447 } catch(std::exception& e) {
448 messages << "Can't initialize Lua." << std::endl;
449 fatal_error();
451 luaL_openlibs(lsnes_lua_state.handle());
452 run_sysrc_lua(lsnes_lua_state);
453 copy_system_tables(lsnes_lua_state);
456 void quit_lua() throw()
458 lsnes_lua_state.deinit();
462 #define LUA_TIMED_HOOK_IDLE 0
463 #define LUA_TIMED_HOOK_TIMER 1
465 uint64_t lua_timed_hook(int timer) throw()
467 switch(timer) {
468 case LUA_TIMED_HOOK_IDLE:
469 return lua_idle_hook_time;
470 case LUA_TIMED_HOOK_TIMER:
471 return lua_timer_hook_time;
473 return 0;
476 void lua_callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov, void* u)
478 if(u) {
479 lua_unsaferewind* u2 = reinterpret_cast<lua_obj_pin<lua_unsaferewind>*>(u)->object();
480 //Load.
481 try {
482 run_callback(on_pre_rewind);
483 run_callback(on_movie_lost, "unsaferewind");
484 mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
485 mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
486 try { get_host_memory() = u2->hostmemory; } catch(...) {}
487 run_callback(on_post_rewind);
488 delete reinterpret_cast<lua_obj_pin<lua_unsaferewind>*>(u);
489 } catch(...) {
490 return;
492 } else {
493 //Save
494 run_callback(on_set_rewind, lua_state::fn_tag([save, secs, ssecs, &mov](lua_state& L) -> int {
495 lua_unsaferewind* u2 = lua_class<lua_unsaferewind>::create(lsnes_lua_state);
496 u2->state = save;
497 u2->secs = secs,
498 u2->ssecs = ssecs;
499 u2->hostmemory = get_host_memory();
500 mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
501 return 1;
502 }));
506 void lua_callback_movie_lost(const char* what)
508 run_callback(on_movie_lost, std::string(what));
511 void lua_callback_do_latch(std::list<std::string>& args)
513 run_callback(on_latch, lua_state::vararg_tag(args));
516 bool lua_requests_repaint = false;
517 bool lua_requests_subframe_paint = false;
519 lua_unsaferewind::lua_unsaferewind(lua_state& L)