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 extern const char* lua_sysrc_script
;
28 void pushpair(lua_state
& L
, std::string key
, double value
)
30 L
.pushstring(key
.c_str());
35 void pushpair(lua_state
& L
, std::string key
, std::string value
)
37 L
.pushstring(key
.c_str());
38 L
.pushstring(value
.c_str());
42 std::string
calibration_to_type(keyboard_axis_calibration p
)
44 if(p
.mode
== -1) return "disabled";
45 if(p
.mode
== 1 && p
.esign_b
== 1) return "axis";
46 if(p
.mode
== 1 && p
.esign_b
== -1) return "axis-inverse";
47 if(p
.mode
== 0 && p
.esign_a
== -1 && p
.esign_b
== 0) return "pressure-m0";
48 if(p
.mode
== 0 && p
.esign_a
== -1 && p
.esign_b
== 1) return "pressure-mp";
49 if(p
.mode
== 0 && p
.esign_a
== 0 && p
.esign_b
== -1) return "pressure-0m";
50 if(p
.mode
== 0 && p
.esign_a
== 0 && p
.esign_b
== 1) return "pressure-0p";
51 if(p
.mode
== 0 && p
.esign_a
== 1 && p
.esign_b
== -1) return "pressure-pm";
52 if(p
.mode
== 0 && p
.esign_a
== 1 && p
.esign_b
== 0) return "pressure-p0";
58 void push_keygroup_parameters(lua_state
& L
, keyboard_key
& p
)
60 keyboard_mouse_calibration p2
;
61 keyboard_axis_calibration p3
;
63 switch(p
.get_type()) {
65 pushpair(L
, "value", p
.get_state());
66 pushpair(L
, "type", "key");
69 pushpair(L
, "value", p
.get_state());
70 pushpair(L
, "type", "hat");
72 case KBD_KEYTYPE_MOUSE
:
73 p2
= p
.cast_mouse()->get_calibration();
74 pushpair(L
, "value", p
.get_state());
75 pushpair(L
, "type", "mouse");
77 case KBD_KEYTYPE_AXIS
:
78 p3
= p
.cast_axis()->get_calibration();
79 pushpair(L
, "value", p
.get_state());
80 pushpair(L
, "type", calibration_to_type(p3
));
85 lua_render_context
* lua_render_ctx
= NULL
;
86 controller_frame
* lua_input_controllerdata
= NULL
;
87 bool lua_booted_flag
= false;
91 int push_keygroup_parameters2(lua_state
& L
, keyboard_key
* p
)
93 push_keygroup_parameters(L
, *p
);
97 bool recursive_flag
= false;
98 const char* luareader_fragment
= NULL
;
100 const char* read_lua_fragment(lua_State
* LS
, void* dummy
, size_t* size
)
102 if(luareader_fragment
) {
103 const char* ret
= luareader_fragment
;
104 *size
= strlen(luareader_fragment
);
105 luareader_fragment
= NULL
;
113 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
115 const char* eval_lua_lua
= "loadstring(" TEMPORARY
")();";
116 const char* run_lua_lua
= "dofile(" TEMPORARY
");";
118 void run_lua_fragment(lua_state
& L
) throw(std::bad_alloc
)
122 #if LUA_VERSION_NUM == 501
123 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment");
125 #if LUA_VERSION_NUM == 502
126 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment", "bt");
128 if(t
== LUA_ERRSYNTAX
) {
129 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
134 if(t
== LUA_ERRMEM
) {
135 messages
<< "Can't run Lua: Out of memory" << std::endl
;
139 recursive_flag
= true;
140 int r
= L
.pcall(0, 0, 0);
141 recursive_flag
= false;
142 if(r
== LUA_ERRRUN
) {
143 messages
<< "Error running Lua hunk: " << L
.tostring(-1) << std::endl
;
146 if(r
== LUA_ERRMEM
) {
147 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
150 if(r
== LUA_ERRERR
) {
151 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
154 lua_render_ctx
= NULL
;
155 if(lua_requests_repaint
) {
156 lua_requests_repaint
= false;
157 lsnes_cmd
.invoke("repaint");
161 void do_eval_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
163 L
.pushlstring(c
.c_str(), c
.length());
164 L
.setglobal(TEMPORARY
);
165 luareader_fragment
= eval_lua_lua
;
169 void do_run_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
171 L
.pushlstring(c
.c_str(), c
.length());
172 L
.setglobal(TEMPORARY
);
173 luareader_fragment
= run_lua_lua
;
177 template<typename
... T
> bool run_callback(T
... args
)
181 recursive_flag
= true;
183 if(!LS
.callback(args
...)) {
184 recursive_flag
= false;
187 } catch(std::exception
& e
) {
188 messages
<< e
.what() << std::endl
;
190 lua_render_ctx
= NULL
;
191 if(lua_requests_repaint
) {
192 lua_requests_repaint
= false;
193 lsnes_cmd
.invoke("repaint");
195 recursive_flag
= false;
199 int system_write_error(lua_State
* L
)
201 lua_pushstring(L
, "_SYSTEM is write-protected");
206 void copy_system_tables(lua_state
& L
)
208 #if LUA_VERSION_NUM == 501
209 L
.pushvalue(LUA_GLOBALSINDEX
);
211 #if LUA_VERSION_NUM == 502
212 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
217 //Stack: _SYSTEM, KEY, VALUE
220 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
222 //Stack: _SYSTEM, KEY, VALUE
224 //Stack: _SYSTEM, KEY
227 L
.pushcfunction(system_write_error
);
228 L
.setfield(-2, "__newindex");
230 L
.setglobal("_SYSTEM");
233 void run_sysrc_lua(lua_state
& L
)
235 do_eval_lua(L
, lua_sysrc_script
);
240 void lua_callback_do_paint(struct lua_render_context
* ctx
, bool non_synthetic
) throw()
242 run_callback("on_paint", lua_state::store_tag(lua_render_ctx
, ctx
), lua_state::boolean_tag(non_synthetic
));
245 void lua_callback_do_video(struct lua_render_context
* ctx
) throw()
247 run_callback("on_video", lua_state::store_tag(lua_render_ctx
, ctx
));
250 void lua_callback_do_reset() throw()
252 run_callback("on_reset");
255 void lua_callback_do_frame() throw()
257 run_callback("on_frame");
260 void lua_callback_do_rewind() throw()
262 run_callback("on_rewind");
265 void lua_callback_do_idle() throw()
267 lua_idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
268 run_callback("on_idle");
271 void lua_callback_do_timer() throw()
273 lua_timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
274 run_callback("on_timer");
277 void lua_callback_do_frame_emulated() throw()
279 run_callback("on_frame_emulated");
282 void lua_callback_do_readwrite() throw()
284 run_callback("on_readwrite");
287 void lua_callback_startup() throw()
289 lua_booted_flag
= true;
290 run_callback("on_startup");
293 void lua_callback_pre_load(const std::string
& name
) throw()
295 run_callback("on_pre_load", lua_state::string_tag(name
));
298 void lua_callback_err_load(const std::string
& name
) throw()
300 run_callback("on_err_load", lua_state::string_tag(name
));
303 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw()
305 run_callback("on_post_load", lua_state::string_tag(name
), lua_state::boolean_tag(was_state
));
308 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw()
310 run_callback("on_pre_save", lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
313 void lua_callback_err_save(const std::string
& name
) throw()
315 run_callback("on_err_save", lua_state::string_tag(name
));
318 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw()
320 run_callback("on_post_save", lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
323 void lua_callback_do_input(controller_frame
& data
, bool subframe
) throw()
325 run_callback("on_input", lua_state::store_tag(lua_input_controllerdata
, &data
),
326 lua_state::boolean_tag(subframe
));
329 void lua_callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
331 if(run_callback("on_snoop2", lua_state::numeric_tag(port
), lua_state::numeric_tag(controller
),
332 lua_state::numeric_tag(index
), lua_state::numeric_tag(value
)))
334 run_callback("on_snoop", lua_state::numeric_tag(port
), lua_state::numeric_tag(controller
),
335 lua_state::numeric_tag(index
), lua_state::numeric_tag(value
));
338 bool lua_callback_do_button(uint32_t port
, uint32_t controller
, uint32_t index
, const char* type
)
341 run_callback("on_button", lua_state::store_tag(lua_veto_flag
, &flag
), lua_state::numeric_tag(port
),
342 lua_state::numeric_tag(controller
), lua_state::numeric_tag(index
), lua_state::string_tag(type
));
348 function_ptr_command
<const std::string
&> evaluate_lua(lsnes_cmd
, "evaluate-lua", "Evaluate expression in "
349 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
350 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
352 throw std::runtime_error("Expected expression to evaluate");
353 do_eval_lua(LS
, args
);
356 function_ptr_command
<arg_filename
> run_lua(lsnes_cmd
, "run-lua", "Run Lua script in Lua VM",
357 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
358 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
)
360 do_run_lua(LS
, args
);
363 function_ptr_command
<> reset_lua(lsnes_cmd
, "reset-lua", "Reset the Lua VM",
364 "Syntax: reset-lua\nReset the Lua VM.\n",
365 []() throw(std::bad_alloc
, std::runtime_error
)
368 luaL_openlibs(LS
.handle());
371 copy_system_tables(LS
);
372 messages
<< "Lua VM reset" << std::endl
;
377 void lua_callback_quit() throw()
379 run_callback("on_quit");
382 void lua_callback_keyhook(const std::string
& key
, keyboard_key
& p
) throw()
384 run_callback("on_keyhook", lua_state::string_tag(key
), lua_state::fnptr_tag(push_keygroup_parameters2
, &p
));
387 void init_lua(bool soft
) throw()
389 LS
.set_oom_handler(OOM_panic
);
392 } catch(std::exception
& e
) {
393 messages
<< "Can't initialize Lua." << std::endl
;
398 luaL_openlibs(LS
.handle());
400 copy_system_tables(LS
);
403 void quit_lua() throw()
409 #define LUA_TIMED_HOOK_IDLE 0
410 #define LUA_TIMED_HOOK_TIMER 1
412 uint64_t lua_timed_hook(int timer
) throw()
415 case LUA_TIMED_HOOK_IDLE
:
416 return lua_idle_hook_time
;
417 case LUA_TIMED_HOOK_TIMER
:
418 return lua_timer_hook_time
;
423 void lua_callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
, void* u
)
426 lua_unsaferewind
* u2
= reinterpret_cast<lua_obj_pin
<lua_unsaferewind
>*>(u
)->object();
429 run_callback("on_pre_rewind");
430 mainloop_restore_state(u2
->state
, u2
->secs
, u2
->ssecs
);
431 mov
.fast_load(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
432 try { get_host_memory() = u2
->hostmemory
; } catch(...) {}
433 run_callback("on_post_rewind");
439 run_callback("on_set_rewind", lua_state::fn_tag([save
, secs
, ssecs
, &mov
](lua_state
& L
) -> int {
440 lua_unsaferewind
* u2
= lua_class
<lua_unsaferewind
>::create(LS
);
444 u2
->hostmemory
= get_host_memory();
445 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
451 bool lua_requests_repaint
= false;
452 bool lua_requests_subframe_paint
= false;
454 DECLARE_LUACLASS(lua_unsaferewind
, "UNSAFEREWIND");