1 #include "core/command.hpp"
2 #include "library/globalwrap.hpp"
3 #include "library/keyboard.hpp"
4 #include "lua/internal.hpp"
6 #include "lua/unsaferewind.hpp"
7 #include "core/instance.hpp"
8 #include "core/mainloop.hpp"
9 #include "core/messages.hpp"
10 #include "core/memorymanip.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/misc.hpp"
22 extern const char* lua_sysrc_script
;
24 lua::function_group lua_func_bit
;
25 lua::function_group lua_func_misc
;
26 lua::function_group lua_func_load
;
27 lua::function_group lua_func_zip
;
29 lua::class_group lua_class_callback
;
30 lua::class_group lua_class_gui
;
31 lua::class_group lua_class_bind
;
32 lua::class_group lua_class_pure
;
33 lua::class_group lua_class_movie
;
34 lua::class_group lua_class_memory
;
35 lua::class_group lua_class_fileio
;
39 void pushpair(lua::state
& L
, std::string key
, double value
)
41 L
.pushstring(key
.c_str());
46 void pushpair(lua::state
& L
, std::string key
, std::string value
)
48 L
.pushstring(key
.c_str());
49 L
.pushstring(value
.c_str());
53 std::string
get_mode_str(int mode
)
63 void push_keygroup_parameters(lua::state
& L
, keyboard::key
& p
)
65 keyboard::mouse_calibration p2
;
68 switch(p
.get_type()) {
69 case keyboard::KBD_KEYTYPE_KEY
:
70 pushpair(L
, "value", p
.get_state());
71 pushpair(L
, "type", "key");
73 case keyboard::KBD_KEYTYPE_HAT
:
74 pushpair(L
, "value", p
.get_state());
75 pushpair(L
, "type", "hat");
77 case keyboard::KBD_KEYTYPE_MOUSE
:
78 p2
= p
.cast_mouse()->get_calibration();
79 pushpair(L
, "value", p
.get_state());
80 pushpair(L
, "type", "mouse");
82 case keyboard::KBD_KEYTYPE_AXIS
:
83 mode
= p
.cast_axis()->get_mode();
84 pushpair(L
, "value", p
.get_state());
85 pushpair(L
, "type", get_mode_str(mode
));
93 int push_keygroup_parameters2(lua::state
& L
, keyboard::key
* p
)
95 push_keygroup_parameters(L
, *p
);
100 const char* read_lua_fragment(lua_State
* L
, void* fragment
, size_t* size
)
102 const char*& luareader_fragment
= *reinterpret_cast<const char**>(fragment
);
103 if(luareader_fragment
) {
104 const char* ret
= luareader_fragment
;
105 *size
= strlen(luareader_fragment
);
106 luareader_fragment
= NULL
;
114 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
116 const char* CONST_eval_sysrc_lua
= "local fn = loadstring(" TEMPORARY
", \"<built-in>\"); "
117 "if fn then fn(); else print2(\"Parse error in sysrc.lua script\"); end;";
118 const char* CONST_eval_lua_lua
= "local fn = loadstring(" TEMPORARY
"); if fn then fn(); else print("
119 "\"Parse error in Lua statement\"); end;";
120 const char* CONST_run_lua_lua
= "dofile(" TEMPORARY
");";
122 int system_write_error(lua_State
* L
)
124 lua_pushstring(L
, "_SYSTEM is write-protected");
129 void copy_system_tables(lua::state
& L
)
131 #if LUA_VERSION_NUM == 501
132 L
.pushvalue(LUA_GLOBALSINDEX
);
134 #if LUA_VERSION_NUM == 502
135 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
140 //Stack: _SYSTEM, KEY, VALUE
143 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
145 //Stack: _SYSTEM, KEY, VALUE
147 //Stack: _SYSTEM, KEY
150 L
.pushcfunction(system_write_error
);
151 L
.setfield(-2, "__newindex");
153 L
.setglobal("_SYSTEM");
157 lua_state::lua_state(lua::state
& _L
, command::group
& _command
)
158 : L(_L
), command(_command
)
160 requests_repaint
= false;
161 requests_subframe_paint
= false;
163 input_controllerdata
= NULL
;
165 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
166 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
171 synchronous_paint_ctx
= NULL
;
172 recursive_flag
= false;
173 luareader_fragment
= NULL
;
175 renderq_saved
= NULL
;
177 renderq_redirect
= false;
179 on_paint
= new lua::state::callback_list(L
, "paint", "on_paint");
180 on_video
= new lua::state::callback_list(L
, "video", "on_video");
181 on_reset
= new lua::state::callback_list(L
, "reset", "on_reset");
182 on_frame
= new lua::state::callback_list(L
, "frame", "on_frame");
183 on_rewind
= new lua::state::callback_list(L
, "rewind", "on_rewind");
184 on_idle
= new lua::state::callback_list(L
, "idle", "on_idle");
185 on_timer
= new lua::state::callback_list(L
, "timer", "on_timer");
186 on_frame_emulated
= new lua::state::callback_list(L
, "frame_emulated", "on_frame_emulated");
187 on_readwrite
= new lua::state::callback_list(L
, "readwrite", "on_readwrite");
188 on_startup
= new lua::state::callback_list(L
, "startup", "on_startup");
189 on_pre_load
= new lua::state::callback_list(L
, "pre_load", "on_pre_load");
190 on_post_load
= new lua::state::callback_list(L
, "post_load", "on_post_load");
191 on_err_load
= new lua::state::callback_list(L
, "err_load", "on_err_load");
192 on_pre_save
= new lua::state::callback_list(L
, "pre_save", "on_pre_save");
193 on_post_save
= new lua::state::callback_list(L
, "post_save", "on_post_save");
194 on_err_save
= new lua::state::callback_list(L
, "err_save", "on_err_save");
195 on_input
= new lua::state::callback_list(L
, "input", "on_input");
196 on_snoop
= new lua::state::callback_list(L
, "snoop", "on_snoop");
197 on_snoop2
= new lua::state::callback_list(L
, "snoop2", "on_snoop2");
198 on_button
= new lua::state::callback_list(L
, "button", "on_button");
199 on_quit
= new lua::state::callback_list(L
, "quit", "on_quit");
200 on_keyhook
= new lua::state::callback_list(L
, "keyhook", "on_keyhook");
201 on_movie_lost
= new lua::state::callback_list(L
, "movie_lost", "on_movie_lost");
202 on_pre_rewind
= new lua::state::callback_list(L
, "pre_rewind", "on_pre_rewind");
203 on_post_rewind
= new lua::state::callback_list(L
, "post_rewind", "on_post_rewind");
204 on_set_rewind
= new lua::state::callback_list(L
, "set_rewind", "on_set_rewind");
205 on_latch
= new lua::state::callback_list(L
, "latch", "on_latch");
208 lua_state::~lua_state()
217 delete on_frame_emulated
;
232 delete on_movie_lost
;
233 delete on_pre_rewind
;
234 delete on_post_rewind
;
235 delete on_set_rewind
;
239 void lua_state::callback_do_paint(struct lua::render_context
* ctx
, bool non_synthetic
) throw()
241 run_synchronous_paint(ctx
);
242 run_callback(*on_paint
, lua::state::store_tag(render_ctx
, ctx
), lua::state::boolean_tag(non_synthetic
));
245 void lua_state::callback_do_video(struct lua::render_context
* ctx
, bool& _kill_frame
, uint32_t& _hscl
,
246 uint32_t& _vscl
) throw()
248 run_callback(*on_video
, lua::state::store_tag(render_ctx
, ctx
), lua::state::store_tag(kill_frame
,
249 &_kill_frame
), lua::state::store_tag(hscl
, &_hscl
), lua::state::store_tag(vscl
, &_vscl
));
252 void lua_state::callback_do_reset() throw()
254 run_callback(*on_reset
);
257 void lua_state::callback_do_frame() throw()
259 run_callback(*on_frame
);
262 void lua_state::callback_do_rewind() throw()
264 run_callback(*on_rewind
);
267 void lua_state::callback_do_idle() throw()
269 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
270 run_callback(*on_idle
);
273 void lua_state::callback_do_timer() throw()
275 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
276 run_callback(*on_timer
);
279 void lua_state::callback_do_frame_emulated() throw()
281 run_callback(*on_frame_emulated
);
284 void lua_state::callback_do_readwrite() throw()
286 run_callback(*on_readwrite
);
289 void lua_state::callback_pre_load(const std::string
& name
) throw()
291 run_callback(*on_pre_load
, lua::state::string_tag(name
));
294 void lua_state::callback_err_load(const std::string
& name
) throw()
296 run_callback(*on_err_load
, lua::state::string_tag(name
));
299 void lua_state::callback_post_load(const std::string
& name
, bool was_state
) throw()
301 run_callback(*on_post_load
, lua::state::string_tag(name
), lua::state::boolean_tag(was_state
));
304 void lua_state::callback_pre_save(const std::string
& name
, bool is_state
) throw()
306 run_callback(*on_pre_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
309 void lua_state::callback_err_save(const std::string
& name
) throw()
311 run_callback(*on_err_save
, lua::state::string_tag(name
));
314 void lua_state::callback_post_save(const std::string
& name
, bool is_state
) throw()
316 run_callback(*on_post_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
319 void lua_state::callback_do_input(controller_frame
& data
, bool subframe
) throw()
321 run_callback(*on_input
, lua::state::store_tag(input_controllerdata
, &data
),
322 lua::state::boolean_tag(subframe
));
325 void lua_state::callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
327 if(run_callback(*on_snoop2
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
328 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
)))
330 run_callback(*on_snoop
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
331 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
));
334 bool lua_state::callback_do_button(uint32_t port
, uint32_t controller
, uint32_t index
, const char* type
)
337 run_callback(*on_button
, lua::state::store_tag(veto_flag
, &flag
), lua::state::numeric_tag(port
),
338 lua::state::numeric_tag(controller
), lua::state::numeric_tag(index
), lua::state::string_tag(type
));
344 command::fnptr
<const std::string
&> CMD_evaluate_lua(lsnes_cmds
, "evaluate-lua", "Evaluate expression in "
345 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
346 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
348 throw std::runtime_error("Expected expression to evaluate");
350 core
.lua2
->do_eval_lua(args
);
353 command::fnptr
<const std::string
&> CMD_evaluate_lua2(lsnes_cmds
, "L", "Evaluate expression in "
354 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
355 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
357 throw std::runtime_error("Expected expression to evaluate");
359 core
.lua2
->do_eval_lua(args
);
362 command::fnptr
<command::arg_filename
> CMD_run_lua(lsnes_cmds
, "run-lua", "Run Lua script in Lua VM",
363 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
364 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
)
367 core
.lua2
->do_run_lua(args
);
370 command::fnptr
<> CMD_reset_lua(lsnes_cmds
, "reset-lua", "Reset the Lua VM",
371 "Syntax: reset-lua\nReset the Lua VM.\n",
372 []() throw(std::bad_alloc
, std::runtime_error
)
376 luaL_openlibs(core
.lua
->handle());
378 core
.lua2
->run_sysrc_lua(true);
379 copy_system_tables(*core
.lua
);
380 messages
<< "Lua VM reset" << std::endl
;
383 lua::_class
<lua_unsaferewind
> LUA_class_unsaferewind(lua_class_movie
, "UNSAFEREWIND", {}, {
384 }, &lua_unsaferewind::print
);
387 void lua_state::callback_quit() throw()
389 run_callback(*on_quit
);
392 void lua_state::callback_keyhook(const std::string
& key
, keyboard::key
& p
) throw()
394 run_callback(*on_keyhook
, lua::state::string_tag(key
), lua::state::fnptr_tag(push_keygroup_parameters2
, &p
));
397 void init_lua() throw()
399 auto& core
= lsnes_instance
;
400 core
.lua
->set_oom_handler(OOM_panic
);
403 core
.lua
->add_function_group(lua_func_bit
);
404 core
.lua
->add_function_group(lua_func_load
);
405 core
.lua
->add_function_group(lua_func_misc
);
406 core
.lua
->add_function_group(lua_func_zip
);
407 core
.lua
->add_class_group(lua_class_callback
);
408 core
.lua
->add_class_group(lua_class_gui
);
409 core
.lua
->add_class_group(lua_class_bind
);
410 core
.lua
->add_class_group(lua_class_pure
);
411 core
.lua
->add_class_group(lua_class_movie
);
412 core
.lua
->add_class_group(lua_class_memory
);
413 core
.lua
->add_class_group(lua_class_fileio
);
414 } catch(std::exception
& e
) {
415 messages
<< "Can't initialize Lua." << std::endl
;
418 luaL_openlibs(core
.lua
->handle());
419 core
.lua2
->run_sysrc_lua(false);
420 copy_system_tables(*core
.lua
);
423 void quit_lua() throw()
425 lsnes_instance
.lua
->deinit();
429 #define LUA_TIMED_HOOK_IDLE 0
430 #define LUA_TIMED_HOOK_TIMER 1
432 uint64_t lua_state::timed_hook(int timer
) throw()
435 case LUA_TIMED_HOOK_IDLE
:
436 return idle_hook_time
;
437 case LUA_TIMED_HOOK_TIMER
:
438 return timer_hook_time
;
443 void lua_state::callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
,
448 lua_unsaferewind
* u2
= reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
)->object();
451 run_callback(*on_pre_rewind
);
452 run_callback(*on_movie_lost
, "unsaferewind");
453 mainloop_restore_state(u2
->state
, u2
->secs
, u2
->ssecs
);
454 mov
.fast_load(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
455 try { core
.mlogic
->get_mfile().host_memory
= u2
->hostmemory
; } catch(...) {}
456 run_callback(*on_post_rewind
);
457 delete reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
);
463 run_callback(*on_set_rewind
, lua::state::fn_tag([&core
, save
, secs
, ssecs
, &mov
](lua::state
& L
) ->
465 lua_unsaferewind
* u2
= lua::_class
<lua_unsaferewind
>::create(*core
.lua
);
469 u2
->hostmemory
= core
.mlogic
->get_mfile().host_memory
;
470 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
476 void lua_state::callback_movie_lost(const char* what
)
478 run_callback(*on_movie_lost
, std::string(what
));
481 void lua_state::callback_do_latch(std::list
<std::string
>& args
)
483 run_callback(*on_latch
, lua::state::vararg_tag(args
));
486 lua_unsaferewind::lua_unsaferewind(lua::state
& L
)
490 void lua_state::run_startup_scripts()
492 for(auto i
: startup_scripts
) {
493 messages
<< "Trying to run Lua script: " << i
<< std::endl
;
498 void lua_state::add_startup_script(const std::string
& file
)
500 startup_scripts
.push_back(file
);
503 const std::map
<std::string
, std::u32string
>& lua_state::get_watch_vars()
508 bool lua_state::run_lua_fragment() throw(std::bad_alloc
)
513 #if LUA_VERSION_NUM == 501
514 int t
= L
.load(read_lua_fragment
, &luareader_fragment
, "run_lua_fragment");
516 #if LUA_VERSION_NUM == 502
517 int t
= L
.load(read_lua_fragment
, &luareader_fragment
, "run_lua_fragment", "t");
519 if(t
== LUA_ERRSYNTAX
) {
520 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
525 if(t
== LUA_ERRMEM
) {
526 messages
<< "Can't run Lua: Out of memory" << std::endl
;
530 recursive_flag
= true;
531 int r
= L
.pcall(0, 0, 0);
532 recursive_flag
= false;
533 if(r
== LUA_ERRRUN
) {
534 messages
<< "Error running Lua hunk: " << L
.tostring(-1) << std::endl
;
538 if(r
== LUA_ERRMEM
) {
539 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
543 if(r
== LUA_ERRERR
) {
544 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
549 if(requests_repaint
) {
550 requests_repaint
= false;
551 command
.invoke("repaint");
556 void lua_state::do_eval_lua(const std::string
& c
) throw(std::bad_alloc
)
558 L
.pushlstring(c
.c_str(), c
.length());
559 L
.setglobal(TEMPORARY
);
560 luareader_fragment
= CONST_eval_lua_lua
;
564 void lua_state::do_run_lua(const std::string
& c
) throw(std::bad_alloc
)
566 L
.pushlstring(c
.c_str(), c
.length());
567 L
.setglobal(TEMPORARY
);
568 luareader_fragment
= CONST_run_lua_lua
;
572 template<typename
... T
> bool lua_state::run_callback(lua::state::callback_list
& list
, T
... args
)
576 recursive_flag
= true;
578 if(!list
.callback(args
...)) {
579 recursive_flag
= false;
582 } catch(std::exception
& e
) {
583 messages
<< e
.what() << std::endl
;
585 recursive_flag
= false;
587 if(requests_repaint
) {
588 requests_repaint
= false;
589 command
.invoke("repaint");
594 void lua_state::run_sysrc_lua(bool rerun
)
596 L
.pushstring(lua_sysrc_script
);
597 L
.setglobal(TEMPORARY
);
598 luareader_fragment
= CONST_eval_sysrc_lua
;
599 if(!run_lua_fragment() && !rerun
) {
600 //run_lua_fragment shows error.
601 //messages << "Failed to run sysrc lua script" << std::endl;
606 void lua_state::run_synchronous_paint(struct lua::render_context
* ctx
)
608 if(!synchronous_paint_ctx
)
610 lua_renderq_run(ctx
, synchronous_paint_ctx
);