1 #include "core/command.hpp"
2 #include "library/globalwrap.hpp"
3 #include "lua/internal.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"
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
;
35 void pushpair(lua_state
& L
, std::string key
, double value
)
37 L
.pushstring(key
.c_str());
42 void pushpair(lua_state
& L
, std::string key
, std::string value
)
44 L
.pushstring(key
.c_str());
45 L
.pushstring(value
.c_str());
49 std::string
get_mode_str(int mode
)
59 void push_keygroup_parameters(lua_state
& L
, keyboard::key
& p
)
61 keyboard::mouse_calibration p2
;
62 keyboard::axis_calibration p3
;
65 switch(p
.get_type()) {
66 case keyboard::KBD_KEYTYPE_KEY
:
67 pushpair(L
, "value", p
.get_state());
68 pushpair(L
, "type", "key");
70 case keyboard::KBD_KEYTYPE_HAT
:
71 pushpair(L
, "value", p
.get_state());
72 pushpair(L
, "type", "hat");
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");
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
));
87 lua_render_context
* lua_render_ctx
= NULL
;
88 controller_frame
* lua_input_controllerdata
= NULL
;
89 bool lua_booted_flag
= false;
93 int push_keygroup_parameters2(lua_state
& L
, keyboard::key
* p
)
95 push_keygroup_parameters(L
, *p
);
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
;
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
)
125 #if LUA_VERSION_NUM == 501
126 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment");
128 #if LUA_VERSION_NUM == 502
129 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment", "t");
131 if(t
== LUA_ERRSYNTAX
) {
132 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
137 if(t
== LUA_ERRMEM
) {
138 messages
<< "Can't run Lua: Out of memory" << std::endl
;
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
;
149 if(r
== LUA_ERRMEM
) {
150 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
153 if(r
== LUA_ERRERR
) {
154 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
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
;
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
;
180 template<typename
... T
> bool run_callback(lua_state::lua_callback_list
& list
, T
... args
)
184 recursive_flag
= true;
186 if(!list
.callback(args
...)) {
187 recursive_flag
= 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;
202 int system_write_error(lua_State
* L
)
204 lua_pushstring(L
, "_SYSTEM is write-protected");
209 void copy_system_tables(lua_state
& L
)
211 #if LUA_VERSION_NUM == 501
212 L
.pushvalue(LUA_GLOBALSINDEX
);
214 #if LUA_VERSION_NUM == 502
215 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
220 //Stack: _SYSTEM, KEY, VALUE
223 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
225 //Stack: _SYSTEM, KEY, VALUE
227 //Stack: _SYSTEM, KEY
230 L
.pushcfunction(system_write_error
);
231 L
.setfield(-2, "__newindex");
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
)
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 )
257 DEFINE_CB(frame_emulated
);
258 DEFINE_CB(readwrite
);
261 DEFINE_CB(post_load
);
264 DEFINE_CB(post_save
);
272 DEFINE_CB(movie_lost
);
273 DEFINE_CB(pre_rewind
);
274 DEFINE_CB(post_rewind
);
275 DEFINE_CB(set_rewind
);
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
,
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
)))
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
)
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
));
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
) {
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
) {
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
);
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
;
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()
468 case LUA_TIMED_HOOK_IDLE
:
469 return lua_idle_hook_time
;
470 case LUA_TIMED_HOOK_TIMER
:
471 return lua_timer_hook_time
;
476 void lua_callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
, void* u
)
479 lua_unsaferewind
* u2
= reinterpret_cast<lua_obj_pin
<lua_unsaferewind
>*>(u
)->object();
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
);
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
);
499 u2
->hostmemory
= get_host_memory();
500 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
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
)