1 #include "cmdhelp/lua.hpp"
2 #include "core/command.hpp"
3 #include "library/globalwrap.hpp"
4 #include "library/keyboard.hpp"
5 #include "lua/internal.hpp"
7 #include "lua/unsaferewind.hpp"
8 #include "core/instance.hpp"
9 #include "core/mainloop.hpp"
10 #include "core/messages.hpp"
11 #include "core/memorymanip.hpp"
12 #include "core/moviedata.hpp"
13 #include "core/misc.hpp"
23 extern const char* lua_sysrc_script
;
25 lua::function_group lua_func_bit
;
26 lua::function_group lua_func_misc
;
27 lua::function_group lua_func_load
;
28 lua::function_group lua_func_zip
;
30 lua::class_group lua_class_callback
;
31 lua::class_group lua_class_gui
;
32 lua::class_group lua_class_bind
;
33 lua::class_group lua_class_pure
;
34 lua::class_group lua_class_movie
;
35 lua::class_group lua_class_memory
;
36 lua::class_group lua_class_fileio
;
40 void pushpair(lua::state
& L
, std::string key
, double value
)
42 L
.pushstring(key
.c_str());
47 void pushpair(lua::state
& L
, std::string key
, std::string value
)
49 L
.pushstring(key
.c_str());
50 L
.pushstring(value
.c_str());
54 std::string
get_mode_str(int mode
)
64 void push_keygroup_parameters(lua::state
& L
, keyboard::key
& p
)
66 keyboard::mouse_calibration p2
;
69 switch(p
.get_type()) {
70 case keyboard::KBD_KEYTYPE_KEY
:
71 pushpair(L
, "value", p
.get_state());
72 pushpair(L
, "type", "key");
74 case keyboard::KBD_KEYTYPE_HAT
:
75 pushpair(L
, "value", p
.get_state());
76 pushpair(L
, "type", "hat");
78 case keyboard::KBD_KEYTYPE_MOUSE
:
79 p2
= p
.cast_mouse()->get_calibration();
80 pushpair(L
, "value", p
.get_state());
81 pushpair(L
, "type", "mouse");
83 case keyboard::KBD_KEYTYPE_AXIS
:
84 mode
= p
.cast_axis()->get_mode();
85 pushpair(L
, "value", p
.get_state());
86 pushpair(L
, "type", get_mode_str(mode
));
94 int push_keygroup_parameters2(lua::state
& L
, keyboard::key
* p
)
96 push_keygroup_parameters(L
, *p
);
101 const char* read_lua_fragment(lua_State
* L
, void* fragment
, size_t* size
)
103 const char*& luareader_fragment
= *reinterpret_cast<const char**>(fragment
);
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* CONST_eval_sysrc_lua
= "local fn = loadstring(" TEMPORARY
", \"<built-in>\"); "
118 "if fn then fn(); else print2(\"Parse error in sysrc.lua script\"); end;";
119 const char* CONST_eval_lua_lua
= "local fn = loadstring(" TEMPORARY
"); if fn then fn(); else print("
120 "\"Parse error in Lua statement\"); end;";
121 const char* CONST_run_lua_lua
= "dofile(" TEMPORARY
");";
123 int system_write_error(lua_State
* L
)
125 lua_pushstring(L
, "_SYSTEM is write-protected");
130 void copy_system_tables(lua::state
& L
)
132 #if LUA_VERSION_NUM == 501
133 L
.pushvalue(LUA_GLOBALSINDEX
);
135 #if LUA_VERSION_NUM == 502
136 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
141 //Stack: _SYSTEM, KEY, VALUE
144 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
146 //Stack: _SYSTEM, KEY, VALUE
148 //Stack: _SYSTEM, KEY
151 L
.pushcfunction(system_write_error
);
152 L
.setfield(-2, "__newindex");
154 L
.setglobal("_SYSTEM");
158 lua_state::lua_state(lua::state
& _L
, command::group
& _command
)
159 : L(_L
), command(_command
),
160 resetcmd(command
, CLUA::reset
, [this]() { this->do_reset(); }),
161 evalcmd(command
, CLUA::eval
, [this](const std::string
& a
) { this->do_eval_lua(a
); }),
162 evalcmd2(command
, CLUA::eval2
, [this](const std::string
& a
) { this->do_eval_lua(a
); }),
163 runcmd(command
, CLUA::run
, [this](command::arg_filename a
) { this->do_run_lua(a
); })
165 requests_repaint
= false;
166 requests_subframe_paint
= false;
168 input_controllerdata
= NULL
;
170 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
171 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
176 synchronous_paint_ctx
= NULL
;
177 recursive_flag
= false;
178 luareader_fragment
= NULL
;
180 renderq_saved
= NULL
;
182 renderq_redirect
= false;
184 on_paint
= new lua::state::callback_list(L
, "paint", "on_paint");
185 on_video
= new lua::state::callback_list(L
, "video", "on_video");
186 on_reset
= new lua::state::callback_list(L
, "reset", "on_reset");
187 on_frame
= new lua::state::callback_list(L
, "frame", "on_frame");
188 on_rewind
= new lua::state::callback_list(L
, "rewind", "on_rewind");
189 on_idle
= new lua::state::callback_list(L
, "idle", "on_idle");
190 on_timer
= new lua::state::callback_list(L
, "timer", "on_timer");
191 on_frame_emulated
= new lua::state::callback_list(L
, "frame_emulated", "on_frame_emulated");
192 on_readwrite
= new lua::state::callback_list(L
, "readwrite", "on_readwrite");
193 on_startup
= new lua::state::callback_list(L
, "startup", "on_startup");
194 on_pre_load
= new lua::state::callback_list(L
, "pre_load", "on_pre_load");
195 on_post_load
= new lua::state::callback_list(L
, "post_load", "on_post_load");
196 on_err_load
= new lua::state::callback_list(L
, "err_load", "on_err_load");
197 on_pre_save
= new lua::state::callback_list(L
, "pre_save", "on_pre_save");
198 on_post_save
= new lua::state::callback_list(L
, "post_save", "on_post_save");
199 on_err_save
= new lua::state::callback_list(L
, "err_save", "on_err_save");
200 on_input
= new lua::state::callback_list(L
, "input", "on_input");
201 on_snoop
= new lua::state::callback_list(L
, "snoop", "on_snoop");
202 on_snoop2
= new lua::state::callback_list(L
, "snoop2", "on_snoop2");
203 on_button
= new lua::state::callback_list(L
, "button", "on_button");
204 on_quit
= new lua::state::callback_list(L
, "quit", "on_quit");
205 on_keyhook
= new lua::state::callback_list(L
, "keyhook", "on_keyhook");
206 on_movie_lost
= new lua::state::callback_list(L
, "movie_lost", "on_movie_lost");
207 on_pre_rewind
= new lua::state::callback_list(L
, "pre_rewind", "on_pre_rewind");
208 on_post_rewind
= new lua::state::callback_list(L
, "post_rewind", "on_post_rewind");
209 on_set_rewind
= new lua::state::callback_list(L
, "set_rewind", "on_set_rewind");
210 on_latch
= new lua::state::callback_list(L
, "latch", "on_latch");
213 lua_state::~lua_state()
222 delete on_frame_emulated
;
237 delete on_movie_lost
;
238 delete on_pre_rewind
;
239 delete on_post_rewind
;
240 delete on_set_rewind
;
244 void lua_state::callback_do_paint(struct lua::render_context
* ctx
, bool non_synthetic
) throw()
246 run_synchronous_paint(ctx
);
247 run_callback(*on_paint
, lua::state::store_tag(render_ctx
, ctx
), lua::state::boolean_tag(non_synthetic
));
250 void lua_state::callback_do_video(struct lua::render_context
* ctx
, bool& _kill_frame
, uint32_t& _hscl
,
251 uint32_t& _vscl
) throw()
253 run_callback(*on_video
, lua::state::store_tag(render_ctx
, ctx
), lua::state::store_tag(kill_frame
,
254 &_kill_frame
), lua::state::store_tag(hscl
, &_hscl
), lua::state::store_tag(vscl
, &_vscl
));
257 void lua_state::callback_do_reset() throw()
259 run_callback(*on_reset
);
262 void lua_state::callback_do_frame() throw()
264 run_callback(*on_frame
);
267 void lua_state::callback_do_rewind() throw()
269 run_callback(*on_rewind
);
272 void lua_state::callback_do_idle() throw()
274 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
275 run_callback(*on_idle
);
278 void lua_state::callback_do_timer() throw()
280 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
281 run_callback(*on_timer
);
284 void lua_state::callback_do_frame_emulated() throw()
286 run_callback(*on_frame_emulated
);
289 void lua_state::callback_do_readwrite() throw()
291 run_callback(*on_readwrite
);
294 void lua_state::callback_pre_load(const std::string
& name
) throw()
296 run_callback(*on_pre_load
, lua::state::string_tag(name
));
299 void lua_state::callback_err_load(const std::string
& name
) throw()
301 run_callback(*on_err_load
, lua::state::string_tag(name
));
304 void lua_state::callback_post_load(const std::string
& name
, bool was_state
) throw()
306 run_callback(*on_post_load
, lua::state::string_tag(name
), lua::state::boolean_tag(was_state
));
309 void lua_state::callback_pre_save(const std::string
& name
, bool is_state
) throw()
311 run_callback(*on_pre_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
314 void lua_state::callback_err_save(const std::string
& name
) throw()
316 run_callback(*on_err_save
, lua::state::string_tag(name
));
319 void lua_state::callback_post_save(const std::string
& name
, bool is_state
) throw()
321 run_callback(*on_post_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
324 void lua_state::callback_do_input(portctrl::frame
& data
, bool subframe
) throw()
326 run_callback(*on_input
, lua::state::store_tag(input_controllerdata
, &data
),
327 lua::state::boolean_tag(subframe
));
330 void lua_state::callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
332 if(run_callback(*on_snoop2
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
333 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
)))
335 run_callback(*on_snoop
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
336 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
));
339 bool lua_state::callback_do_button(uint32_t port
, uint32_t controller
, uint32_t index
, const char* type
)
342 run_callback(*on_button
, lua::state::store_tag(veto_flag
, &flag
), lua::state::numeric_tag(port
),
343 lua::state::numeric_tag(controller
), lua::state::numeric_tag(index
), lua::state::string_tag(type
));
349 lua::_class
<lua_unsaferewind
> LUA_class_unsaferewind(lua_class_movie
, "UNSAFEREWIND", {}, {
350 }, &lua_unsaferewind::print
);
353 void lua_state::do_reset()
356 luaL_openlibs(L
.handle());
359 copy_system_tables(L
);
360 messages
<< "Lua VM reset" << std::endl
;
363 void lua_state::do_evaluate(const std::string
& a
)
366 throw std::runtime_error("Expected expression to evaluate");
370 void lua_state::callback_quit() throw()
372 run_callback(*on_quit
);
375 void lua_state::callback_keyhook(const std::string
& key
, keyboard::key
& p
) throw()
377 run_callback(*on_keyhook
, lua::state::string_tag(key
), lua::state::fnptr_tag(push_keygroup_parameters2
, &p
));
380 void init_lua() throw()
382 auto& core
= lsnes_instance
;
383 core
.lua
->set_oom_handler(OOM_panic
);
386 core
.lua
->add_function_group(lua_func_bit
);
387 core
.lua
->add_function_group(lua_func_load
);
388 core
.lua
->add_function_group(lua_func_misc
);
389 core
.lua
->add_function_group(lua_func_zip
);
390 core
.lua
->add_class_group(lua_class_callback
);
391 core
.lua
->add_class_group(lua_class_gui
);
392 core
.lua
->add_class_group(lua_class_bind
);
393 core
.lua
->add_class_group(lua_class_pure
);
394 core
.lua
->add_class_group(lua_class_movie
);
395 core
.lua
->add_class_group(lua_class_memory
);
396 core
.lua
->add_class_group(lua_class_fileio
);
397 } catch(std::exception
& e
) {
398 messages
<< "Can't initialize Lua." << std::endl
;
401 luaL_openlibs(core
.lua
->handle());
402 core
.lua2
->run_sysrc_lua(false);
403 copy_system_tables(*core
.lua
);
406 void quit_lua() throw()
408 lsnes_instance
.lua
->deinit();
412 #define LUA_TIMED_HOOK_IDLE 0
413 #define LUA_TIMED_HOOK_TIMER 1
415 uint64_t lua_state::timed_hook(int timer
) throw()
418 case LUA_TIMED_HOOK_IDLE
:
419 return idle_hook_time
;
420 case LUA_TIMED_HOOK_TIMER
:
421 return timer_hook_time
;
426 void lua_state::callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
,
431 lua_unsaferewind
* u2
= reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
)->object();
434 run_callback(*on_pre_rewind
);
435 run_callback(*on_movie_lost
, "unsaferewind");
436 mainloop_restore_state(u2
->state
, u2
->secs
, u2
->ssecs
);
437 mov
.fast_load(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
438 try { core
.mlogic
->get_mfile().host_memory
= u2
->hostmemory
; } catch(...) {}
439 run_callback(*on_post_rewind
);
440 delete reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
);
446 run_callback(*on_set_rewind
, lua::state::fn_tag([&core
, save
, secs
, ssecs
, &mov
](lua::state
& L
) ->
448 lua_unsaferewind
* u2
= lua::_class
<lua_unsaferewind
>::create(*core
.lua
);
452 u2
->hostmemory
= core
.mlogic
->get_mfile().host_memory
;
453 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
459 void lua_state::callback_movie_lost(const char* what
)
461 run_callback(*on_movie_lost
, std::string(what
));
464 void lua_state::callback_do_latch(std::list
<std::string
>& args
)
466 run_callback(*on_latch
, lua::state::vararg_tag(args
));
469 lua_unsaferewind::lua_unsaferewind(lua::state
& L
)
473 void lua_state::run_startup_scripts()
475 for(auto i
: startup_scripts
) {
476 messages
<< "Trying to run Lua script: " << i
<< std::endl
;
481 void lua_state::add_startup_script(const std::string
& file
)
483 startup_scripts
.push_back(file
);
486 const std::map
<std::string
, std::u32string
>& lua_state::get_watch_vars()
491 bool lua_state::run_lua_fragment() throw(std::bad_alloc
)
496 #if LUA_VERSION_NUM == 501
497 int t
= L
.load(read_lua_fragment
, &luareader_fragment
, "run_lua_fragment");
499 #if LUA_VERSION_NUM == 502
500 int t
= L
.load(read_lua_fragment
, &luareader_fragment
, "run_lua_fragment", "t");
502 if(t
== LUA_ERRSYNTAX
) {
503 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
508 if(t
== LUA_ERRMEM
) {
509 messages
<< "Can't run Lua: Out of memory" << std::endl
;
513 recursive_flag
= true;
514 int r
= L
.pcall(0, 0, 0);
515 recursive_flag
= false;
516 if(r
== LUA_ERRRUN
) {
517 messages
<< "Error running Lua hunk: " << L
.tostring(-1) << std::endl
;
521 if(r
== LUA_ERRMEM
) {
522 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
526 if(r
== LUA_ERRERR
) {
527 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
532 if(requests_repaint
) {
533 requests_repaint
= false;
534 command
.invoke("repaint");
539 void lua_state::do_eval_lua(const std::string
& c
) throw(std::bad_alloc
)
541 L
.pushlstring(c
.c_str(), c
.length());
542 L
.setglobal(TEMPORARY
);
543 luareader_fragment
= CONST_eval_lua_lua
;
547 void lua_state::do_run_lua(const std::string
& c
) throw(std::bad_alloc
)
549 L
.pushlstring(c
.c_str(), c
.length());
550 L
.setglobal(TEMPORARY
);
551 luareader_fragment
= CONST_run_lua_lua
;
555 template<typename
... T
> bool lua_state::run_callback(lua::state::callback_list
& list
, T
... args
)
559 recursive_flag
= true;
561 if(!list
.callback(args
...)) {
562 recursive_flag
= false;
565 } catch(std::exception
& e
) {
566 messages
<< e
.what() << std::endl
;
568 recursive_flag
= false;
570 if(requests_repaint
) {
571 requests_repaint
= false;
572 command
.invoke("repaint");
577 void lua_state::run_sysrc_lua(bool rerun
)
579 L
.pushstring(lua_sysrc_script
);
580 L
.setglobal(TEMPORARY
);
581 luareader_fragment
= CONST_eval_sysrc_lua
;
582 if(!run_lua_fragment() && !rerun
) {
583 //run_lua_fragment shows error.
584 //messages << "Failed to run sysrc lua script" << std::endl;
589 void lua_state::run_synchronous_paint(struct lua::render_context
* ctx
)
591 if(!synchronous_paint_ctx
)
593 lua_renderq_run(ctx
, synchronous_paint_ctx
);