Allow just-in-time override of input to be recorded from Lua
This is useful e.g., for implementing .r16m playback.
This commit is contained in:
parent
1fe5434797
commit
1b582c8fbd
10 changed files with 102 additions and 7 deletions
|
@ -89,7 +89,12 @@ public:
|
|||
* Release memory for mov, mf and rrd.
|
||||
*/
|
||||
void release_memory();
|
||||
/**
|
||||
* Set frob with data routine.
|
||||
*/
|
||||
void set_frob_with_value(std::function<void(unsigned,unsigned,unsigned,short&)> func);
|
||||
private:
|
||||
std::function<void(unsigned,unsigned,unsigned,short&)> frob_with_value;
|
||||
movie_logic(const movie_logic&);
|
||||
movie_logic& operator=(const movie_logic&);
|
||||
movie* mov;
|
||||
|
|
|
@ -278,6 +278,12 @@ public:
|
|||
* Parameter data: New movie data.
|
||||
*/
|
||||
void set_movie_data(portctrl::frame_vector* data);
|
||||
/**
|
||||
* Set callback to frob with data.
|
||||
*
|
||||
* Parameter func: New callback.
|
||||
*/
|
||||
void set_frob_with_value(std::function<void(unsigned,unsigned,unsigned,short&)> func);
|
||||
private:
|
||||
class fchange_listener : public portctrl::frame_vector::fchange_listener
|
||||
{
|
||||
|
@ -290,6 +296,8 @@ private:
|
|||
} _listener;
|
||||
movie(const movie& mov);
|
||||
movie& operator=(const movie& m);
|
||||
//Frob with value.
|
||||
std::function<void(unsigned,unsigned,unsigned,short&)> frob_with_value;
|
||||
//Sequence number.
|
||||
uint64_t seqno;
|
||||
//The poll flag handling.
|
||||
|
|
|
@ -56,6 +56,7 @@ struct lua_state
|
|||
lua::state::callback_list* on_post_rewind;
|
||||
lua::state::callback_list* on_set_rewind;
|
||||
lua::state::callback_list* on_latch;
|
||||
lua::state::callback_list* on_frob_with_value;
|
||||
|
||||
void callback_do_paint(struct lua::render_context* ctx, bool non_synthethic) throw();
|
||||
void callback_do_video(struct lua::render_context* ctx, bool& kill_frame, uint32_t& hscl, uint32_t& vscl)
|
||||
|
@ -81,6 +82,7 @@ struct lua_state
|
|||
bool callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type);
|
||||
void callback_movie_lost(const char* what);
|
||||
void callback_do_latch(std::list<std::string>& args);
|
||||
void callback_frob_with_value(unsigned a, unsigned b, unsigned c, short& d);
|
||||
void run_startup_scripts();
|
||||
void add_startup_script(const std::string& file);
|
||||
|
||||
|
@ -100,6 +102,7 @@ struct lua_state
|
|||
uint32_t* hscl;
|
||||
uint32_t* vscl;
|
||||
bool* veto_flag;
|
||||
short* frob_output;
|
||||
std::set<std::string> hooked_keys;
|
||||
uint64_t idle_hook_time;
|
||||
uint64_t timer_hook_time;
|
||||
|
|
|
@ -837,10 +837,19 @@ void init_main_callbacks()
|
|||
ecore_callbacks = &lsnes_callbacks_obj;
|
||||
}
|
||||
|
||||
void frob_with_value(unsigned a, unsigned b, unsigned c, short& d)
|
||||
{
|
||||
auto& core = CORE();
|
||||
core.lua2->callback_frob_with_value(a, b, c, d);
|
||||
}
|
||||
|
||||
|
||||
void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed)
|
||||
{
|
||||
lsnes_instance.emu_thread = threads::id();
|
||||
auto& core = CORE();
|
||||
//Set up the frob with inputs routine.
|
||||
core.mlogic->set_frob_with_value(frob_with_value);
|
||||
mywindowcallbacks mywcb(*core.dispatch, *core.runmode, *core.supdater);
|
||||
core.iqueue->system_thread_available = true;
|
||||
//Basic initialization.
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
movie_logic::movie_logic() throw()
|
||||
{
|
||||
frob_with_value = [](unsigned a, unsigned b, unsigned c, unsigned d) {};
|
||||
mf = NULL;
|
||||
mov = NULL;
|
||||
rrd = NULL;
|
||||
|
@ -18,6 +19,7 @@ void movie_logic::set_movie(movie& _mov, bool free_old) throw()
|
|||
{
|
||||
auto tmp = mov;
|
||||
mov = &_mov;
|
||||
mov->set_frob_with_value(frob_with_value);
|
||||
if(free_old) delete tmp;
|
||||
}
|
||||
|
||||
|
@ -91,3 +93,9 @@ void movie_logic::release_memory()
|
|||
delete mf;
|
||||
mf = NULL;
|
||||
}
|
||||
|
||||
void movie_logic::set_frob_with_value(std::function<void(unsigned,unsigned,unsigned,short&)> func)
|
||||
{
|
||||
frob_with_value = func;
|
||||
if(mov) mov->set_frob_with_value(func);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,11 @@ bool movie::get_DRDY(unsigned port, unsigned controller, unsigned ctrl)
|
|||
return pollcounters.get_DRDY(port, controller, ctrl);
|
||||
}
|
||||
|
||||
void movie::set_frob_with_value(std::function<void(unsigned, unsigned, unsigned, short&)> func)
|
||||
{
|
||||
frob_with_value = func;
|
||||
}
|
||||
|
||||
short movie::next_input(unsigned port, unsigned controller, unsigned ctrl)
|
||||
{
|
||||
pollcounters.clear_DRDY(port, controller, ctrl);
|
||||
|
@ -173,6 +178,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl)
|
|||
return (*movie_data)[current_frame_first_subframe].axis3(port, controller, ctrl);
|
||||
}
|
||||
short new_value = current_controls.axis3(port, controller, ctrl);
|
||||
frob_with_value(port, controller, ctrl, new_value);
|
||||
//Fortunately, we know this frame is the last one in movie_data.
|
||||
uint32_t pollcounter = pollcounters.get_polls(port, controller, ctrl);
|
||||
if(current_frame_first_subframe + pollcounter < movie_data->size()) {
|
||||
|
@ -196,6 +202,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl)
|
|||
movie::movie()
|
||||
: _listener(*this), tracker(memtracker::singleton(), movie_id, sizeof(*this))
|
||||
{
|
||||
frob_with_value = [](unsigned a, unsigned b, unsigned c, short& d){};
|
||||
movie_data = NULL;
|
||||
seqno = 0;
|
||||
readonly = false;
|
||||
|
|
|
@ -120,6 +120,21 @@ namespace
|
|||
return 0;
|
||||
}
|
||||
|
||||
int snes_bitplane_split(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
unsigned short a[8];
|
||||
unsigned short b[4] = {0,0,0,0};
|
||||
P(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
for(unsigned j = 0; j < 4; j++) {
|
||||
b[j] |= ((a[i] >> 2*j+0) & 1) << 7-i;
|
||||
b[j] |= ((a[i] >> 2*j+1) & 1) << 15-i;
|
||||
}
|
||||
}
|
||||
for(unsigned i = 0; i < 4; i++) L.pushnumber(b[i]);
|
||||
return 4;
|
||||
}
|
||||
|
||||
lua::functions LUA_guicore_fns(lua_func_misc, "gui", {
|
||||
{"left_gap", lua_gui_set_gap<&lua::render_context::left_gap, false>},
|
||||
{"right_gap", lua_gui_set_gap<&lua::render_context::right_gap, false>},
|
||||
|
@ -137,5 +152,6 @@ namespace
|
|||
{"rainbow", rainbow},
|
||||
{"kill_frame", kill_frame},
|
||||
{"set_video_scale", set_video_scale},
|
||||
{"snes_bitplane_split", snes_bitplane_split},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -411,6 +411,18 @@ namespace
|
|||
return 0;
|
||||
}
|
||||
|
||||
int frob_with_value(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
auto& core = CORE();
|
||||
short value;
|
||||
|
||||
if(P.is_boolean()) value = P.arg<bool>() ? 1 : 0;
|
||||
else if(P.is_number()) value = P.arg<short>();
|
||||
else P.expected("number or boolean");
|
||||
if(core.lua2->frob_output) *core.lua2->frob_output = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int controller_info(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
auto& core = CORE();
|
||||
|
@ -520,5 +532,6 @@ namespace
|
|||
{"port_type", _port_type},
|
||||
{"veto_button", veto_button},
|
||||
{"controller_info", controller_info},
|
||||
{"frob_with_value", frob_with_value},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -53,6 +53,20 @@ namespace
|
|||
setbutton(port, controller, button, value);
|
||||
return 0;
|
||||
}
|
||||
int fast_input(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
unsigned short a[4],m;
|
||||
P(P.skipped(), a[0], a[1], a[2], a[3], m);
|
||||
for(unsigned i = 0; i < 4; i++) a[i] ^= m;
|
||||
for(unsigned i = 0; i < 16; i++) {
|
||||
auto w = a[i / 4];
|
||||
setbutton(1, 0, i, (w >> (6-i%4*2))&1);
|
||||
setbutton(1, 1, i, (w >> (7-i%4*2))&1);
|
||||
setbutton(2, 0, i, (w >> (14-i%4*2))&1);
|
||||
setbutton(2, 1, i, (w >> (15-i%4*2))&1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int serialize(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
char buf[MAX_SERIALIZED_SIZE];
|
||||
|
@ -660,13 +674,14 @@ namespace
|
|||
}, &lua_inputmovie::print);
|
||||
|
||||
lua::_class<lua_inputframe> LUA_class_inputframe(lua_class_movie, "INPUTFRAME", {}, {
|
||||
{"get_button", &lua_inputframe::get_button},
|
||||
{"get_axis", &lua_inputframe::get_axis},
|
||||
{"set_axis", &lua_inputframe::set_axis},
|
||||
{"set_button", &lua_inputframe::set_axis},
|
||||
{"serialize", &lua_inputframe::serialize},
|
||||
{"unserialize", &lua_inputframe::unserialize},
|
||||
{"get_stride", &lua_inputframe::get_stride},
|
||||
{"get_button", &lua_inputframe::get_button},
|
||||
{"get_axis", &lua_inputframe::get_axis},
|
||||
{"set_axis", &lua_inputframe::set_axis},
|
||||
{"set_button", &lua_inputframe::set_axis},
|
||||
{"serialize", &lua_inputframe::serialize},
|
||||
{"unserialize", &lua_inputframe::unserialize},
|
||||
{"get_stride", &lua_inputframe::get_stride},
|
||||
{"snes_fast_input", &lua_inputframe::fast_input},
|
||||
}, &lua_inputframe::print);
|
||||
|
||||
lua::functions LUA_inputmovie_fns(lua_func_misc, "movie", {
|
||||
|
|
|
@ -196,6 +196,7 @@ lua_state::lua_state(lua::state& _L, command::group& _command, settingvar::group
|
|||
|
||||
idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
frob_output = NULL;
|
||||
veto_flag = NULL;
|
||||
kill_frame = NULL;
|
||||
hscl = NULL;
|
||||
|
@ -235,6 +236,7 @@ lua_state::lua_state(lua::state& _L, command::group& _command, settingvar::group
|
|||
on_post_rewind = new lua::state::callback_list(L, "post_rewind", "on_post_rewind");
|
||||
on_set_rewind = new lua::state::callback_list(L, "set_rewind", "on_set_rewind");
|
||||
on_latch = new lua::state::callback_list(L, "latch", "on_latch");
|
||||
on_frob_with_value = new lua::state::callback_list(L, "frob_with_value", "on_frob_with_value");
|
||||
}
|
||||
|
||||
lua_state::~lua_state()
|
||||
|
@ -266,6 +268,7 @@ lua_state::~lua_state()
|
|||
delete on_post_rewind;
|
||||
delete on_set_rewind;
|
||||
delete on_latch;
|
||||
delete on_frob_with_value;
|
||||
}
|
||||
|
||||
void lua_state::callback_do_paint(struct lua::render_context* ctx, bool non_synthetic) throw()
|
||||
|
@ -371,6 +374,14 @@ bool lua_state::callback_do_button(uint32_t port, uint32_t controller, uint32_t
|
|||
return flag;
|
||||
}
|
||||
|
||||
void lua_state::callback_frob_with_value(unsigned a, unsigned b, unsigned c, short& d)
|
||||
{
|
||||
short value = d;
|
||||
run_callback(*on_frob_with_value, lua::state::store_tag(frob_output, &value), lua::state::numeric_tag(a),
|
||||
lua::state::numeric_tag(b), lua::state::numeric_tag(c), lua::state::numeric_tag(d));
|
||||
d = value;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
lua::_class<lua_unsaferewind> LUA_class_unsaferewind(lua_class_movie, "UNSAFEREWIND", {}, {
|
||||
|
|
Loading…
Add table
Reference in a new issue