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 extern const char* lua_sysrc_script
;
25 void push_keygroup_parameters(lua_state
& L
, const struct keygroup::parameters
& p
)
28 L
.pushstring("last_rawval");
29 L
.pushnumber(p
.last_rawval
);
31 L
.pushstring("cal_left");
32 L
.pushnumber(p
.cal_left
);
34 L
.pushstring("cal_center");
35 L
.pushnumber(p
.cal_center
);
37 L
.pushstring("cal_right");
38 L
.pushnumber(p
.cal_right
);
40 L
.pushstring("cal_tolerance");
41 L
.pushnumber(p
.cal_tolerance
);
43 L
.pushstring("ktype");
45 case keygroup::KT_DISABLED
: L
.pushstring("disabled"); break;
46 case keygroup::KT_KEY
: L
.pushstring("key"); break;
47 case keygroup::KT_AXIS_PAIR
: L
.pushstring("axis"); break;
48 case keygroup::KT_AXIS_PAIR_INVERSE
: L
.pushstring("axis-inverse"); break;
49 case keygroup::KT_HAT
: L
.pushstring("hat"); break;
50 case keygroup::KT_MOUSE
: L
.pushstring("mouse"); break;
51 case keygroup::KT_PRESSURE_PM
: L
.pushstring("pressure-pm"); break;
52 case keygroup::KT_PRESSURE_P0
: L
.pushstring("pressure-p0"); break;
53 case keygroup::KT_PRESSURE_0M
: L
.pushstring("pressure-0m"); break;
54 case keygroup::KT_PRESSURE_0P
: L
.pushstring("pressure-0p"); break;
55 case keygroup::KT_PRESSURE_M0
: L
.pushstring("pressure-m0"); break;
56 case keygroup::KT_PRESSURE_MP
: L
.pushstring("pressure-mp"); break;
61 lua_render_context
* lua_render_ctx
= NULL
;
62 controller_frame
* lua_input_controllerdata
= NULL
;
63 bool lua_booted_flag
= false;
67 int push_keygroup_parameters2(lua_state
& L
, const struct keygroup::parameters
* p
)
69 push_keygroup_parameters(L
, *p
);
73 bool recursive_flag
= false;
74 const char* luareader_fragment
= NULL
;
76 const char* read_lua_fragment(lua_State
* LS
, void* dummy
, size_t* size
)
78 if(luareader_fragment
) {
79 const char* ret
= luareader_fragment
;
80 *size
= strlen(luareader_fragment
);
81 luareader_fragment
= NULL
;
89 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
91 const char* eval_lua_lua
= "loadstring(" TEMPORARY
")();";
92 const char* run_lua_lua
= "dofile(" TEMPORARY
");";
94 void run_lua_fragment(lua_state
& L
) throw(std::bad_alloc
)
98 #if LUA_VERSION_NUM == 501
99 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment");
101 #if LUA_VERSION_NUM == 502
102 int t
= L
.load(read_lua_fragment
, NULL
, "run_lua_fragment", "bt");
104 if(t
== LUA_ERRSYNTAX
) {
105 messages
<< "Can't run Lua: Internal syntax error: " << L
.tostring(-1)
110 if(t
== LUA_ERRMEM
) {
111 messages
<< "Can't run Lua: Out of memory" << std::endl
;
115 recursive_flag
= true;
116 int r
= L
.pcall(0, 0, 0);
117 recursive_flag
= false;
118 if(r
== LUA_ERRRUN
) {
119 messages
<< "Error running Lua hunk: " << L
.tostring(-1) << std::endl
;
122 if(r
== LUA_ERRMEM
) {
123 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
126 if(r
== LUA_ERRERR
) {
127 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
130 if(lua_requests_repaint
) {
131 lua_requests_repaint
= false;
132 lsnes_cmd
.invoke("repaint");
136 void do_eval_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
138 L
.pushlstring(c
.c_str(), c
.length());
139 L
.setglobal(TEMPORARY
);
140 luareader_fragment
= eval_lua_lua
;
144 void do_run_lua(lua_state
& L
, const std::string
& c
) throw(std::bad_alloc
)
146 L
.pushlstring(c
.c_str(), c
.length());
147 L
.setglobal(TEMPORARY
);
148 luareader_fragment
= run_lua_lua
;
152 template<typename
... T
> void run_callback(T
... args
)
156 recursive_flag
= true;
158 LS
.callback(args
...);
159 } catch(std::exception
& e
) {
160 messages
<< e
.what() << std::endl
;
162 if(lua_requests_repaint
) {
163 lua_requests_repaint
= false;
164 lsnes_cmd
.invoke("repaint");
166 recursive_flag
= false;
169 int system_write_error(lua_State
* L
)
171 lua_pushstring(L
, "_SYSTEM is write-protected");
176 void copy_system_tables(lua_state
& L
)
178 #if LUA_VERSION_NUM == 501
179 L
.pushvalue(LUA_GLOBALSINDEX
);
181 #if LUA_VERSION_NUM == 502
182 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
187 //Stack: _SYSTEM, KEY, VALUE
190 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
192 //Stack: _SYSTEM, KEY, VALUE
194 //Stack: _SYSTEM, KEY
197 L
.pushcfunction(system_write_error
);
198 L
.setfield(-2, "__newindex");
200 L
.setglobal("_SYSTEM");
203 void run_sysrc_lua(lua_state
& L
)
205 do_eval_lua(L
, lua_sysrc_script
);
210 void lua_callback_do_paint(struct lua_render_context
* ctx
, bool non_synthetic
) throw()
212 run_callback("on_paint", lua_state::store_tag(lua_render_ctx
, ctx
), lua_state::boolean_tag(non_synthetic
));
215 void lua_callback_do_video(struct lua_render_context
* ctx
) throw()
217 run_callback("on_video", lua_state::store_tag(lua_render_ctx
, ctx
));
220 void lua_callback_do_reset() throw()
222 run_callback("on_reset");
225 void lua_callback_do_frame() throw()
227 run_callback("on_frame");
230 void lua_callback_do_rewind() throw()
232 run_callback("on_rewind");
235 void lua_callback_do_idle() throw()
237 lua_idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
238 run_callback("on_idle");
241 void lua_callback_do_timer() throw()
243 lua_timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
244 run_callback("on_timer");
247 void lua_callback_do_frame_emulated() throw()
249 run_callback("on_frame_emulated");
252 void lua_callback_do_readwrite() throw()
254 run_callback("on_readwrite");
257 void lua_callback_startup() throw()
259 lua_booted_flag
= true;
260 run_callback("on_startup");
263 void lua_callback_pre_load(const std::string
& name
) throw()
265 run_callback("on_pre_load", lua_state::string_tag(name
));
268 void lua_callback_err_load(const std::string
& name
) throw()
270 run_callback("on_err_load", lua_state::string_tag(name
));
273 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw()
275 run_callback("on_post_load", lua_state::string_tag(name
), lua_state::boolean_tag(was_state
));
278 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw()
280 run_callback("on_pre_save", lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
283 void lua_callback_err_save(const std::string
& name
) throw()
285 run_callback("on_err_save", lua_state::string_tag(name
));
288 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw()
290 run_callback("on_post_save", lua_state::string_tag(name
), lua_state::boolean_tag(is_state
));
293 void lua_callback_do_input(controller_frame
& data
, bool subframe
) throw()
295 run_callback("on_input", lua_state::store_tag(lua_input_controllerdata
, &data
),
296 lua_state::boolean_tag(subframe
));
299 void lua_callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
301 run_callback("on_snoop", lua_state::numeric_tag(port
), lua_state::numeric_tag(controller
),
302 lua_state::numeric_tag(index
), lua_state::numeric_tag(value
));
307 function_ptr_command
<const std::string
&> evaluate_lua(lsnes_cmd
, "evaluate-lua", "Evaluate expression in "
308 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
309 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
311 throw std::runtime_error("Expected expression to evaluate");
312 do_eval_lua(LS
, args
);
315 function_ptr_command
<arg_filename
> run_lua(lsnes_cmd
, "run-lua", "Run Lua script in Lua VM",
316 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
317 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
)
319 do_run_lua(LS
, args
);
322 function_ptr_command
<> reset_lua(lsnes_cmd
, "reset-lua", "Reset the Lua VM",
323 "Syntax: reset-lua\nReset the Lua VM.\n",
324 []() throw(std::bad_alloc
, std::runtime_error
)
327 luaL_openlibs(LS
.handle());
330 copy_system_tables(LS
);
331 messages
<< "Lua VM reset" << std::endl
;
336 void lua_callback_quit() throw()
338 run_callback("on_quit");
341 void lua_callback_keyhook(const std::string
& key
, const struct keygroup::parameters
& p
) throw()
343 run_callback("on_keyhook", lua_state::string_tag(key
), lua_state::fnptr_tag(push_keygroup_parameters2
, &p
));
346 void init_lua(bool soft
) throw()
349 LS
.set_oom_handler(OOM_panic
);
352 } catch(std::exception
& e
) {
353 messages
<< "Can't initialize Lua." << std::endl
;
358 LS
.getglobal("print");
359 luaL_openlibs(LS
.handle());
360 LS
.setglobal("print");
362 copy_system_tables(LS
);
365 void quit_lua() throw()
371 #define LUA_TIMED_HOOK_IDLE 0
372 #define LUA_TIMED_HOOK_TIMER 1
374 uint64_t lua_timed_hook(int timer
) throw()
377 case LUA_TIMED_HOOK_IDLE
:
378 return lua_idle_hook_time
;
379 case LUA_TIMED_HOOK_TIMER
:
380 return lua_timer_hook_time
;
384 void lua_callback_do_unsafe_rewind(const std::vector
<char>& save
, uint64_t secs
, uint64_t ssecs
, movie
& mov
, void* u
)
387 lua_unsaferewind
* u2
= reinterpret_cast<lua_obj_pin
<lua_unsaferewind
>*>(u
)->object();
390 run_callback("on_pre_rewind");
391 mainloop_restore_state(u2
->state
, u2
->secs
, u2
->ssecs
);
392 mov
.fast_load(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
393 run_callback("on_post_rewind");
399 run_callback("on_set_rewind", lua_state::fn_tag([save
, secs
, ssecs
, &mov
](lua_state
& L
) -> int {
400 lua_unsaferewind
* u2
= lua_class
<lua_unsaferewind
>::create(LS
);
404 mov
.fast_save(u2
->frame
, u2
->ptr
, u2
->lag
, u2
->pollcounters
);
410 bool lua_requests_repaint
= false;
411 bool lua_requests_subframe_paint
= false;
413 DECLARE_LUACLASS(lua_unsaferewind
, "UNSAFEREWIND");