1 #include "cmdhelp/lua.hpp"
2 #include "core/command.hpp"
3 #include "core/misc.hpp"
4 #include "library/globalwrap.hpp"
5 #include "library/keyboard.hpp"
6 #include "library/memtracker.hpp"
7 #include "lua/internal.hpp"
9 #include "lua/unsaferewind.hpp"
10 #include "core/instance.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/messages.hpp"
13 #include "core/memorymanip.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/misc.hpp"
25 extern const char* lua_sysrc_script
;
27 lua::function_group lua_func_bit
;
28 lua::function_group lua_func_misc
;
29 lua::function_group lua_func_load
;
30 lua::function_group lua_func_zip
;
32 lua::class_group lua_class_callback
;
33 lua::class_group lua_class_gui
;
34 lua::class_group lua_class_bind
;
35 lua::class_group lua_class_pure
;
36 lua::class_group lua_class_movie
;
37 lua::class_group lua_class_memory
;
38 lua::class_group lua_class_fileio
;
42 const char* lua_vm_id
= "Lua VM";
43 typedef settingvar::model_int
<32,1024> mb_model
;
44 settingvar::supervariable
<mb_model
> SET_lua_maxmem(lsnes_setgrp
, "lua-maxmem",
45 "Lua‣Maximum memory use (MB)", 128);
47 void pushpair(lua::state
& L
, std::string key
, double value
)
49 L
.pushstring(key
.c_str());
54 void pushpair(lua::state
& L
, std::string key
, std::string value
)
56 L
.pushstring(key
.c_str());
57 L
.pushstring(value
.c_str());
61 std::string
get_mode_str(int mode
)
71 void push_keygroup_parameters(lua::state
& L
, keyboard::key
& p
)
73 keyboard::mouse_calibration p2
;
76 switch(p
.get_type()) {
77 case keyboard::KBD_KEYTYPE_KEY
:
78 pushpair(L
, "value", p
.get_state());
79 pushpair(L
, "type", "key");
81 case keyboard::KBD_KEYTYPE_HAT
:
82 pushpair(L
, "value", p
.get_state());
83 pushpair(L
, "type", "hat");
85 case keyboard::KBD_KEYTYPE_MOUSE
:
86 p2
= p
.cast_mouse()->get_calibration();
87 pushpair(L
, "value", p
.get_state());
88 pushpair(L
, "type", "mouse");
90 case keyboard::KBD_KEYTYPE_AXIS
:
91 mode
= p
.cast_axis()->get_mode();
92 pushpair(L
, "value", p
.get_state());
93 pushpair(L
, "type", get_mode_str(mode
));
101 void soft_oom(int status
)
104 messages
<< "Lua: Memory limit exceeded, attempting to free memory..." << std::endl
;
106 messages
<< "Lua: Memory allocation still failed." << std::endl
;
108 messages
<< "Lua: Allocation successful after freeing some memory." << std::endl
;
111 int push_keygroup_parameters2(lua::state
& L
, keyboard::key
* p
)
113 push_keygroup_parameters(L
, *p
);
118 const char* read_lua_fragment(lua_State
* unused
, void* fragment
, size_t* size
)
120 const char*& luareader_fragment
= *reinterpret_cast<const char**>(fragment
);
121 if(luareader_fragment
) {
122 const char* ret
= luareader_fragment
;
123 *size
= strlen(luareader_fragment
);
124 luareader_fragment
= NULL
;
132 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
134 const char* CONST_eval_sysrc_lua
= "local fn, err = " LUA_LOAD_CMD
"(" TEMPORARY
", \"<built-in>\"); "
135 "if fn then fn(); else print2(\"Parse error in sysrc.lua script: \"..err); end;";
136 const char* CONST_eval_lua_lua
= "local fn, err = " LUA_LOAD_CMD
"(" TEMPORARY
"); if fn then fn(); else "
137 " print(\"Parse error in Lua statement: \"..err); end;";
138 const char* CONST_run_lua_lua
= "dofile(" TEMPORARY
");";
140 int system_write_error(lua::state
& L
)
142 throw std::runtime_error("_SYSTEM is write-protected");
145 void copy_system_tables(lua::state
& L
)
151 //Stack: _SYSTEM, KEY, VALUE
154 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
156 //Stack: _SYSTEM, KEY, VALUE
158 //Stack: _SYSTEM, KEY
161 L
.push_trampoline(system_write_error
, 0);
162 L
.setfield(-2, "__newindex");
164 L
.setglobal("_SYSTEM");
168 void lua_state::_listener::on_setting_change(settingvar::group
& grp
, const settingvar::base
& val
)
170 if(val
.get_iname() == "lua-maxmem")
171 obj
.set_memory_limit(dynamic_cast<const settingvar::variable
<mb_model
>*>(&val
)->get());
174 void lua_state::set_memory_limit(size_t limit_mb
)
176 L
.set_memory_limit(limit_mb
<< 20);
179 lua_state::lua_state(lua::state
& _L
, command::group
& _command
, settingvar::group
& settings
)
180 : r16m_empty_frame_count(0), r16m_capture(nullptr), L(_L
), command(_command
),
181 resetcmd(command
, CLUA::reset
, [this]() { this->do_reset(); }),
182 evalcmd(command
, CLUA::eval
, [this](const std::string
& a
) { this->do_eval_lua(a
); }),
183 evalcmd2(command
, CLUA::eval2
, [this](const std::string
& a
) { this->do_eval_lua(a
); }),
184 runcmd(command
, CLUA::run
, [this](command::arg_filename a
) { this->do_run_lua(a
); }),
185 listener(settings
, *this)
187 memset(r16m_fbuf
, 0, 16);
188 requests_repaint
= false;
189 requests_subframe_paint
= false;
191 input_controllerdata
= NULL
;
192 //We can't read the value of lua maxmem setting here (it crashes), so just set default, it will be changed
194 L
.set_memory_limit(1 << 27);
195 memtracker::singleton()(lua_vm_id
, L
.get_memory_use());
196 L
.set_memory_change_handler([](ssize_t delta
) { memtracker::singleton()(lua_vm_id
, delta
); });
198 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
199 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
205 synchronous_paint_ctx
= NULL
;
206 recursive_flag
= false;
207 luareader_fragment
= NULL
;
209 renderq_saved
= NULL
;
211 renderq_redirect
= false;
213 on_paint
= new lua::state::callback_list(L
, "paint", "on_paint");
214 on_video
= new lua::state::callback_list(L
, "video", "on_video");
215 on_reset
= new lua::state::callback_list(L
, "reset", "on_reset");
216 on_frame
= new lua::state::callback_list(L
, "frame", "on_frame");
217 on_rewind
= new lua::state::callback_list(L
, "rewind", "on_rewind");
218 on_idle
= new lua::state::callback_list(L
, "idle", "on_idle");
219 on_timer
= new lua::state::callback_list(L
, "timer", "on_timer");
220 on_frame_emulated
= new lua::state::callback_list(L
, "frame_emulated", "on_frame_emulated");
221 on_readwrite
= new lua::state::callback_list(L
, "readwrite", "on_readwrite");
222 on_startup
= new lua::state::callback_list(L
, "startup", "on_startup");
223 on_pre_load
= new lua::state::callback_list(L
, "pre_load", "on_pre_load");
224 on_post_load
= new lua::state::callback_list(L
, "post_load", "on_post_load");
225 on_err_load
= new lua::state::callback_list(L
, "err_load", "on_err_load");
226 on_pre_save
= new lua::state::callback_list(L
, "pre_save", "on_pre_save");
227 on_post_save
= new lua::state::callback_list(L
, "post_save", "on_post_save");
228 on_err_save
= new lua::state::callback_list(L
, "err_save", "on_err_save");
229 on_input
= new lua::state::callback_list(L
, "input", "on_input");
230 on_snoop
= new lua::state::callback_list(L
, "snoop", "on_snoop");
231 on_snoop2
= new lua::state::callback_list(L
, "snoop2", "on_snoop2");
232 on_button
= new lua::state::callback_list(L
, "button", "on_button");
233 on_quit
= new lua::state::callback_list(L
, "quit", "on_quit");
234 on_keyhook
= new lua::state::callback_list(L
, "keyhook", "on_keyhook");
235 on_movie_lost
= new lua::state::callback_list(L
, "movie_lost", "on_movie_lost");
236 on_pre_rewind
= new lua::state::callback_list(L
, "pre_rewind", "on_pre_rewind");
237 on_post_rewind
= new lua::state::callback_list(L
, "post_rewind", "on_post_rewind");
238 on_set_rewind
= new lua::state::callback_list(L
, "set_rewind", "on_set_rewind");
239 on_latch
= new lua::state::callback_list(L
, "latch", "on_latch");
240 on_frob_with_value
= new lua::state::callback_list(L
, "frob_with_value", "on_frob_with_value");
243 lua_state::~lua_state()
252 delete on_frame_emulated
;
267 delete on_movie_lost
;
268 delete on_pre_rewind
;
269 delete on_post_rewind
;
270 delete on_set_rewind
;
272 delete on_frob_with_value
;
275 void lua_state::callback_do_paint(struct lua::render_context
* ctx
, bool non_synthetic
) throw()
277 run_synchronous_paint(ctx
);
278 run_callback(*on_paint
, lua::state::store_tag(render_ctx
, ctx
), lua::state::boolean_tag(non_synthetic
));
281 void lua_state::callback_do_video(struct lua::render_context
* ctx
, bool& _kill_frame
, uint32_t& _hscl
,
282 uint32_t& _vscl
) throw()
284 run_callback(*on_video
, lua::state::store_tag(render_ctx
, ctx
), lua::state::store_tag(kill_frame
,
285 &_kill_frame
), lua::state::store_tag(hscl
, &_hscl
), lua::state::store_tag(vscl
, &_vscl
));
288 void lua_state::callback_do_reset() throw()
290 run_callback(*on_reset
);
293 void lua_state::callback_do_frame() throw()
295 run_callback(*on_frame
);
298 void lua_state::callback_do_rewind() throw()
300 run_callback(*on_rewind
);
303 void lua_state::callback_do_idle() throw()
305 idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
306 run_callback(*on_idle
);
309 void lua_state::callback_do_timer() throw()
311 timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
312 run_callback(*on_timer
);
315 void lua_state::callback_do_frame_emulated() throw()
317 run_callback(*on_frame_emulated
);
320 void lua_state::callback_do_readwrite() throw()
322 run_callback(*on_readwrite
);
325 void lua_state::callback_pre_load(const std::string
& name
) throw()
327 run_callback(*on_pre_load
, lua::state::string_tag(name
));
330 void lua_state::callback_err_load(const std::string
& name
) throw()
332 run_callback(*on_err_load
, lua::state::string_tag(name
));
335 void lua_state::callback_post_load(const std::string
& name
, bool was_state
) throw()
337 run_callback(*on_post_load
, lua::state::string_tag(name
), lua::state::boolean_tag(was_state
));
340 void lua_state::callback_pre_save(const std::string
& name
, bool is_state
) throw()
342 run_callback(*on_pre_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
345 void lua_state::callback_err_save(const std::string
& name
) throw()
347 run_callback(*on_err_save
, lua::state::string_tag(name
));
350 void lua_state::callback_post_save(const std::string
& name
, bool is_state
) throw()
352 run_callback(*on_post_save
, lua::state::string_tag(name
), lua::state::boolean_tag(is_state
));
355 void lua_state::callback_do_input(portctrl::frame
& data
, bool subframe
) throw()
357 run_callback(*on_input
, lua::state::store_tag(input_controllerdata
, &data
),
358 lua::state::boolean_tag(subframe
));
361 void lua_state::callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
363 if(port
>= 1 && port
<= 2 && controller
<= 3 && index
<= 15 && r16m_capture
) {
364 auto b
= port
* 8 + controller
* 2 + index
/ 8 - 8;
365 r16m_fbuf
[b
] |= (value
!= 0) << (7 - index
% 8);
367 if(run_callback(*on_snoop2
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
368 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
)))
370 run_callback(*on_snoop
, lua::state::numeric_tag(port
), lua::state::numeric_tag(controller
),
371 lua::state::numeric_tag(index
), lua::state::numeric_tag(value
));
374 bool lua_state::callback_do_button(uint32_t port
, uint32_t controller
, uint32_t index
, const char* type
)
377 run_callback(*on_button
, lua::state::store_tag(veto_flag
, &flag
), lua::state::numeric_tag(port
),
378 lua::state::numeric_tag(controller
), lua::state::numeric_tag(index
), lua::state::string_tag(type
));
382 void lua_state::callback_frob_with_value(unsigned a
, unsigned b
, unsigned c
, short& d
)
385 run_callback(*on_frob_with_value
, lua::state::store_tag(frob_output
, &value
), lua::state::numeric_tag(a
),
386 lua::state::numeric_tag(b
), lua::state::numeric_tag(c
), lua::state::numeric_tag(d
));
392 lua::_class
<lua_unsaferewind
> LUA_class_unsaferewind(lua_class_movie
, "UNSAFEREWIND", {}, {
393 }, &lua_unsaferewind::print
);
396 void lua_state::do_reset()
399 luaL_openlibs(L
.handle());
402 copy_system_tables(L
);
403 messages
<< "Lua VM reset" << std::endl
;
406 void lua_state::do_evaluate(const std::string
& a
)
409 throw std::runtime_error("Expected expression to evaluate");
413 void lua_state::callback_quit() throw()
415 run_callback(*on_quit
);
418 void lua_state::callback_keyhook(const std::string
& key
, keyboard::key
& p
) throw()
420 run_callback(*on_keyhook
, lua::state::string_tag(key
), lua::state::fnptr_tag(push_keygroup_parameters2
, &p
));
423 void init_lua(emulator_instance
& core
) throw()
425 core
.lua
->set_oom_handler(OOM_panic
);
426 core
.lua
->set_soft_oom_handler(soft_oom
);
429 core
.lua
->add_function_group(lua_func_bit
);
430 core
.lua
->add_function_group(lua_func_load
);
431 core
.lua
->add_function_group(lua_func_misc
);
432 core
.lua
->add_function_group(lua_func_zip
);
433 core
.lua
->add_class_group(lua_class_callback
);
434 core
.lua
->add_class_group(lua_class_gui
);
435 core
.lua
->add_class_group(lua_class_bind
);
436 core
.lua
->add_class_group(lua_class_pure
);
437 core
.lua
->add_class_group(lua_class_movie
);
438 core
.lua
->add_class_group(lua_class_memory
);
439 core
.lua
->add_class_group(lua_class_fileio
);
440 } catch(std::exception
& e
) {
441 messages
<< "Can't initialize Lua." << std::endl
;
444 luaL_openlibs(core
.lua
->handle());
445 core
.lua2
->run_sysrc_lua(false);
446 copy_system_tables(*core
.lua
);
449 void quit_lua(emulator_instance
& core
) throw()
455 #define LUA_TIMED_HOOK_IDLE 0
456 #define LUA_TIMED_HOOK_TIMER 1
458 uint64_t lua_state::timed_hook(int timer
) throw()
461 case LUA_TIMED_HOOK_IDLE
:
462 return idle_hook_time
;
463 case LUA_TIMED_HOOK_TIMER
:
464 return timer_hook_time
;
469 void lua_state::callback_do_unsafe_rewind(movie
& mov
, void* u
)
473 lua_unsaferewind
* u2
= reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
)->object();
476 run_callback(*on_pre_rewind
);
477 run_callback(*on_movie_lost
, "unsaferewind");
478 mainloop_restore_state(u2
->console_state
);
479 mov
.fast_load(u2
->console_state
.save_frame
, u2
->ptr
, u2
->console_state
.lagged_frames
,
480 u2
->console_state
.pollcounters
);
481 core
.mlogic
->get_mfile().dyn
= u2
->console_state
;
482 run_callback(*on_post_rewind
);
483 delete reinterpret_cast<lua::objpin
<lua_unsaferewind
>*>(u
);
484 } catch(std::bad_alloc
& e
) {
491 run_callback(*on_set_rewind
, lua::state::fn_tag([&core
, &mov
](lua::state
& L
) ->
493 lua_unsaferewind
* u2
= lua::_class
<lua_unsaferewind
>::create(*core
.lua
);
494 u2
->console_state
= core
.mlogic
->get_mfile().dyn
;
495 mov
.fast_save(u2
->console_state
.save_frame
, u2
->ptr
, u2
->console_state
.lagged_frames
,
496 u2
->console_state
.pollcounters
);
502 void lua_state::callback_movie_lost(const char* what
)
504 run_callback(*on_movie_lost
, std::string(what
));
507 void flush_r16m_blank_frames(FILE* r16m_capture
, uint64_t& r16m_empty_frame_count
)
509 uint8_t dummy
[16] = {0};
510 while(r16m_empty_frame_count
> 0) {
511 if(fwrite(dummy
, 16, 1, r16m_capture
) < 1) {
512 messages
<< "Error writing to R16M dump." << std::endl
;
514 r16m_empty_frame_count
--;
518 void lua_state::set_r16m_dump(FILE* fp
)
521 //Do not flush here, as these are empty frames.
522 fclose(r16m_capture
);
523 messages
<< "Closed R16M dump." << std::endl
;
526 memset(r16m_fbuf
, 0, 16);
527 r16m_empty_frame_count
= 0;
529 messages
<< "Ready for R16M dump." << std::endl
;
533 void lua_state::callback_do_latch(std::list
<std::string
>& args
)
536 uint8_t syndrome
= 0;
537 for(int i
= 0; i
< 16; i
++) { syndrome
|= r16m_fbuf
[i
]; }
539 flush_r16m_blank_frames(r16m_capture
, r16m_empty_frame_count
);
540 if(fwrite(r16m_fbuf
, 16, 1, r16m_capture
) < 1) {
541 messages
<< "Error writing to R16M dump." << std::endl
;
544 r16m_empty_frame_count
++;
546 memset(r16m_fbuf
, 0, 16);
548 run_callback(*on_latch
, lua::state::vararg_tag(args
));
551 lua_unsaferewind::lua_unsaferewind(lua::state
& L
)
555 void lua_state::run_startup_scripts()
557 for(auto i
: startup_scripts
) {
558 messages
<< "Trying to run Lua script: " << i
<< std::endl
;
563 void lua_state::add_startup_script(const std::string
& file
)
565 startup_scripts
.push_back(file
);
568 const std::map
<std::string
, std::u32string
>& lua_state::get_watch_vars()
573 bool lua_state::run_lua_fragment()
578 int t
= L
.load(read_lua_fragment
, &luareader_fragment
, "run_lua_fragment", "t");
579 if(t
== LUA_ERRSYNTAX
) {
580 messages
<< "Can't run Lua: Internal syntax error: " << L
.as_string(-1) << std::endl
;
584 if(t
== LUA_ERRMEM
) {
585 messages
<< "Can't run Lua: Out of memory" << std::endl
;
589 recursive_flag
= true;
590 int r
= L
.pcall(0, 0, 0);
591 recursive_flag
= false;
592 if(r
== LUA_ERRRUN
) {
593 auto msgptr
= L
.tostring(-1);
594 if(!msgptr
) msgptr
= "(null)";
595 messages
<< "Error running Lua hunk: " << L
.as_string(-1) << std::endl
;
599 if(r
== LUA_ERRMEM
) {
600 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
604 if(r
== LUA_ERRERR
) {
605 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
610 if(r
== LUA_ERRGCMM
) {
611 messages
<< "Error running Lua hunk: Fault in garbage collector" << std::endl
;
617 if(requests_repaint
) {
618 requests_repaint
= false;
619 command
.invoke("repaint");
624 void lua_state::do_eval_lua(const std::string
& c
)
626 L
.pushlstring(c
.c_str(), c
.length());
627 L
.setglobal(TEMPORARY
);
628 luareader_fragment
= CONST_eval_lua_lua
;
632 void lua_state::do_run_lua(const std::string
& c
)
634 L
.pushlstring(c
.c_str(), c
.length());
635 L
.setglobal(TEMPORARY
);
636 luareader_fragment
= CONST_run_lua_lua
;
640 template<typename
... T
> bool lua_state::run_callback(lua::state::callback_list
& list
, T
... args
)
644 recursive_flag
= true;
646 if(!list
.callback(args
...)) {
647 recursive_flag
= false;
650 } catch(std::exception
& e
) {
651 messages
<< e
.what() << std::endl
;
653 recursive_flag
= false;
655 if(requests_repaint
) {
656 requests_repaint
= false;
657 command
.invoke("repaint");
662 void lua_state::run_sysrc_lua(bool rerun
)
664 L
.pushstring(lua_sysrc_script
);
665 L
.setglobal(TEMPORARY
);
666 luareader_fragment
= CONST_eval_sysrc_lua
;
667 if(!run_lua_fragment() && !rerun
) {
668 //run_lua_fragment shows error.
669 //messages << "Failed to run sysrc lua script" << std::endl;
674 void lua_state::run_synchronous_paint(struct lua::render_context
* ctx
)
676 if(!synchronous_paint_ctx
)
678 lua_renderq_run(ctx
, synchronous_paint_ctx
);