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
;
34 void pushpair(lua_state
& L
, std::string key
, double value
)
36 L
.pushstring(key
.c_str());
41 void pushpair(lua_state
& L
, std::string key
, std::string value
)
43 L
.pushstring(key
.c_str());
44 L
.pushstring(value
.c_str());
48 std::string
get_mode_str(int mode
)
58 void push_keygroup_parameters(lua_state
& L
, keyboard_key
& p
)
60 keyboard_mouse_calibration p2
;
61 keyboard_axis_calibration p3
;
64 switch(p
.get_type()) {
66 pushpair(L
, "value", p
.get_state());
67 pushpair(L
, "type", "key");
70 pushpair(L
, "value", p
.get_state());
71 pushpair(L
, "type", "hat");
73 case KBD_KEYTYPE_MOUSE
:
74 p2
= p
.cast_mouse()->get_calibration();
75 pushpair(L
, "value", p
.get_state());
76 pushpair(L
, "type", "mouse");
78 case KBD_KEYTYPE_AXIS
:
79 mode
= p
.cast_axis()->get_mode();
80 pushpair(L
, "value", p
.get_state());
81 pushpair(L
, "type", get_mode_str(mode
));
86 lua_render_context
* lua_render_ctx
= NULL
;
87 controller_frame
* lua_input_controllerdata
= NULL
;
88 bool lua_booted_flag
= false;
92 int push_keygroup_parameters2(lua_state
& L
, keyboard_key
* p
)
94 push_keygroup_parameters(L
, *p
);
98 bool recursive_flag
= false;
99 const char* luareader_fragment
= NULL
;
101 const char* read_lua_fragment(lua_State
* L
, void* dummy
, size_t* size
)
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* eval_lua_lua
= "loadstring(" TEMPORARY
")();";
117 const char* run_lua_lua
= "dofile(" TEMPORARY
");";
119 void run_lua_fragment(lua_state
& L
) throw(std::bad_alloc
)
123 #if LUA_VERSION_NUM == 501
124 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment");
126 #if LUA_VERSION_NUM == 502
127 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment", "t");
129 if(t
== LUA_ERRSYNTAX
) {
130 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
135 if(t
== LUA_ERRMEM
) {
136 messages
<< "Can't run Lua: Out of memory" << std::endl
;
140 recursive_flag
= true;
141 int r
= L
.pcall(0, 0, 0);
142 recursive_flag
= false;
143 if(r
== LUA_ERRRUN
) {
144 messages
<< "Error running Lua hunk: " << L
.tostring(-1) << std::endl
;
147 if(r
== LUA_ERRMEM
) {
148 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
151 if(r
== LUA_ERRERR
) {
152 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
155 lua_render_ctx
= NULL
;
156 if(lua_requests_repaint
) {
157 lua_requests_repaint
= false;
158 lsnes_cmd
.invoke("repaint");
162 void do_eval_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
164 L
.pushlstring(c
.c_str(), c
.length());
165 L
.setglobal(TEMPORARY
);
166 luareader_fragment
= eval_lua_lua
;
170 void do_run_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
172 L
.pushlstring(c
.c_str(), c
.length());
173 L
.setglobal(TEMPORARY
);
174 luareader_fragment
= run_lua_lua
;
178 template<typename
... T
> bool run_callback(lua_state::lua_callback_list
& list
, T
... args
)
182 recursive_flag
= true;
184 if(!list
.callback(args
...)) {
185 recursive_flag
= false;
188 } catch(std::exception
& e
) {
189 messages
<< e
.what() << std::endl
;
191 lua_render_ctx
= NULL
;
192 if(lua_requests_repaint
) {
193 lua_requests_repaint
= false;
194 lsnes_cmd
.invoke("repaint");
196 recursive_flag
= false;
200 int system_write_error(lua_State
* L
)
202 lua_pushstring(L
, "_SYSTEM is write-protected");
207 void copy_system_tables(lua_state
& L
)
209 #if LUA_VERSION_NUM == 501
210 L
.pushvalue(LUA_GLOBALSINDEX
);
212 #if LUA_VERSION_NUM == 502
213 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
218 //Stack: _SYSTEM, KEY, VALUE
221 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
223 //Stack: _SYSTEM, KEY, VALUE
225 //Stack: _SYSTEM, KEY
228 L
.pushcfunction(system_write_error
);
229 L
.setfield(-2, "__newindex");
231 L
.setglobal("_SYSTEM");
234 void run_sysrc_lua(lua_state
& L
)
236 do_eval_lua(L
, lua_sysrc_script
);
239 void run_synchronous_paint(struct lua_render_context
* ctx
)
241 if(!synchronous_paint_ctx
)
243 lua_renderq_run(ctx
, synchronous_paint_ctx
);
246 #define DEFINE_CB(X) lua_state::lua_callback_list on_##X (lsnes_lua_state, #X , "on_" #X )
255 DEFINE_CB(frame_emulated
);
256 DEFINE_CB(readwrite
);
259 DEFINE_CB(post_load
);
262 DEFINE_CB(post_save
);
270 DEFINE_CB(movie_lost
);
271 DEFINE_CB(pre_rewind
);
272 DEFINE_CB(post_rewind
);
273 DEFINE_CB(set_rewind
);
276 void lua_callback_do_paint(struct lua_render_context
* ctx
, bool non_synthetic
) throw()
278 run_synchronous_paint(ctx
);
279 run_callback(on_paint
, lua_state::store_tag(lua_render_ctx
, ctx
), lua_state::boolean_tag(non_synthetic
));
282 void lua_callback_do_video(struct lua_render_context
* ctx
, bool& kill_frame
) throw()
284 run_callback(on_video
, lua_state::store_tag(lua_render_ctx
, ctx
), lua_state::store_tag(lua_kill_frame
,
288 void lua_callback_do_reset() throw()
290 run_callback(on_reset
);
293 void lua_callback_do_frame() throw()
295 run_callback(on_frame
);
298 void lua_callback_do_rewind() throw()
300 run_callback(on_rewind
);
303 void lua_callback_do_idle() throw()
305 lua_idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
306 run_callback(on_idle
);
309 void lua_callback_do_timer() throw()
311 lua_timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
312 run_callback(on_timer
);
315 void lua_callback_do_frame_emulated() throw()
317 run_callback(on_frame_emulated
);
320 void lua_callback_do_readwrite() throw()
322 run_callback(on_readwrite
);
325 void lua_callback_startup() throw()
327 lua_booted_flag
= true;
328 run_callback(on_startup
);
331 void lua_callback_pre_load(const std::string
& name
) throw()
333 run_callback(on_pre_load
, lua_state::string_tag(name
));
336 void lua_callback_err_load(const std::string
& name
) throw()
338 run_callback(on_err_load
, lua_state::string_tag(name
));
341 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw()
343 run_callback(on_post_load
, lua_state::string_tag(name
), lua_state::boolean_tag(was_state
));
346 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw()
348 run_callback(on_pre_save
, lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
351 void lua_callback_err_save(const std::string
& name
) throw()
353 run_callback(on_err_save
, lua_state::string_tag(name
));
356 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw()
358 run_callback(on_post_save
, lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
361 void lua_callback_do_input(controller_frame
& data
, bool subframe
) throw()
363 run_callback(on_input
, lua_state::store_tag(lua_input_controllerdata
, &data
),
364 lua_state::boolean_tag(subframe
));
367 void lua_callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
369 if(run_callback(on_snoop2
, lua_state::numeric_tag(port
), lua_state::numeric_tag(controller
),
370 lua_state::numeric_tag(index
), lua_state::numeric_tag(value
)))
372 run_callback(on_snoop
, lua_state::numeric_tag(port
), lua_state::numeric_tag(controller
),
373 lua_state::numeric_tag(index
), lua_state::numeric_tag(value
));
376 bool lua_callback_do_button(uint32_t port
, uint32_t controller
, uint32_t index
, const char* type
)
379 run_callback(on_button
, lua_state::store_tag(lua_veto_flag
, &flag
), lua_state::numeric_tag(port
),
380 lua_state::numeric_tag(controller
), lua_state::numeric_tag(index
), lua_state::string_tag(type
));
386 function_ptr_command
<const std::string
&> evaluate_lua(lsnes_cmd
, "evaluate-lua", "Evaluate expression in "
387 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
388 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
390 throw std::runtime_error("Expected expression to evaluate");
391 do_eval_lua(lsnes_lua_state
, args
);
394 function_ptr_command
<const std::string
&> evaluate_lua2(lsnes_cmd
, "L", "Evaluate expression in "
395 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
396 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
398 throw std::runtime_error("Expected expression to evaluate");
399 do_eval_lua(lsnes_lua_state
, args
);
402 function_ptr_command
<arg_filename
> run_lua(lsnes_cmd
, "run-lua", "Run Lua script in Lua VM",
403 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
404 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
)
406 do_run_lua(lsnes_lua_state
, args
);
409 function_ptr_command
<> reset_lua(lsnes_cmd
, "reset-lua", "Reset the Lua VM",
410 "Syntax: reset-lua\nReset the Lua VM.\n",
411 []() throw(std::bad_alloc
, std::runtime_error
)
413 lsnes_lua_state
.reset();
414 luaL_openlibs(lsnes_lua_state
.handle());
416 run_sysrc_lua(lsnes_lua_state
);
417 copy_system_tables(lsnes_lua_state
);
418 messages
<< "Lua VM reset" << std::endl
;
423 void lua_callback_quit() throw()
425 run_callback(on_quit
);
428 void lua_callback_keyhook(const std::string
& key
, keyboard_key
& p
) throw()
430 run_callback(on_keyhook
, lua_state::string_tag(key
), lua_state::fnptr_tag(push_keygroup_parameters2
, &p
));
433 void init_lua() throw()
435 lsnes_lua_state
.set_oom_handler(OOM_panic
);
437 lsnes_lua_state
.reset();
438 lsnes_lua_state
.add_function_group(lua_func_bit
);
439 lsnes_lua_state
.add_function_group(lua_func_load
);
440 lsnes_lua_state
.add_function_group(lua_func_callback
);
441 lsnes_lua_state
.add_function_group(lua_func_misc
);
442 } catch(std::exception
& e
) {
443 messages
<< "Can't initialize Lua." << std::endl
;
446 luaL_openlibs(lsnes_lua_state
.handle());
447 run_sysrc_lua(lsnes_lua_state
);
448 copy_system_tables(lsnes_lua_state
);
451 void quit_lua() throw()
453 lsnes_lua_state
.deinit();
457 #define LUA_TIMED_HOOK_IDLE 0
458 #define LUA_TIMED_HOOK_TIMER 1
460 uint64_t lua_timed_hook(int timer
) throw()
463 case LUA_TIMED_HOOK_IDLE
:
464 return lua_idle_hook_time
;
465 case LUA_TIMED_HOOK_TIMER
:
466 return lua_timer_hook_time
;
471 void lua_callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
, void* u
)
474 lua_unsaferewind
* u2
= reinterpret_cast<lua_obj_pin
<lua_unsaferewind
>*>(u
)->object();
477 run_callback(on_pre_rewind
);
478 run_callback(on_movie_lost
, "unsaferewind");
479 mainloop_restore_state(u2
->state
, u2
->secs
, u2
->ssecs
);
480 mov
.fast_load(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
481 try { get_host_memory() = u2
->hostmemory
; } catch(...) {}
482 run_callback(on_post_rewind
);
488 run_callback(on_set_rewind
, lua_state::fn_tag([save
, secs
, ssecs
, &mov
](lua_state
& L
) -> int {
489 lua_unsaferewind
* u2
= lua_class
<lua_unsaferewind
>::create(lsnes_lua_state
);
493 u2
->hostmemory
= get_host_memory();
494 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
500 void lua_callback_movie_lost(const char* what
)
502 run_callback(on_movie_lost
, std::string(what
));
505 bool lua_requests_repaint
= false;
506 bool lua_requests_subframe_paint
= false;
508 DECLARE_LUACLASS(lua_unsaferewind
, "UNSAFEREWIND");