From 71379f62ca0ca41cb8b5a318855dbde6f70110f0 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Fri, 18 May 2012 16:52:54 +0300 Subject: [PATCH 1/4] Try to fix the "arrow keys get lost" problem --- src/platform/wxwidgets/mainwindow.cpp | 2 +- src/platform/wxwidgets/settings.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/platform/wxwidgets/mainwindow.cpp b/src/platform/wxwidgets/mainwindow.cpp index 8b5ab134..8413c4a3 100644 --- a/src/platform/wxwidgets/mainwindow.cpp +++ b/src/platform/wxwidgets/mainwindow.cpp @@ -467,7 +467,7 @@ void boot_emulator(loaded_rom& rom, moviefile& movie) } wxwin_mainwindow::panel::panel(wxWindow* win) - : wxPanel(win) + : wxPanel(win, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS) { this->Connect(wxEVT_PAINT, wxPaintEventHandler(panel::on_paint), NULL, this); this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(panel::on_erase), NULL, this); diff --git a/src/platform/wxwidgets/settings.cpp b/src/platform/wxwidgets/settings.cpp index 253ac939..dfa587e8 100644 --- a/src/platform/wxwidgets/settings.cpp +++ b/src/platform/wxwidgets/settings.cpp @@ -100,11 +100,11 @@ namespace int horiz_padding = 60; wxdialog_pressbutton::wxdialog_pressbutton(wxWindow* parent, const std::string& title) - : wxDialog(parent, wxID_ANY, towxstring(title), wxDefaultPosition, wxSize(-1, -1)) + : wxDialog(parent, wxID_ANY, towxstring(title)) { wxStaticText* t; wxBoxSizer* s2 = new wxBoxSizer(wxVERTICAL); - wxPanel* p = new wxPanel(this, wxID_ANY); + wxPanel* p = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxWANTS_CHARS); s2->Add(p, 1, wxGROW); lastkbdkey = -1; mouseflag = 0; @@ -116,7 +116,8 @@ namespace s->Add(0, 0); s->Add(0, 0); s->Add(0, 0); - s->Add(t = new wxStaticText(p, wxID_ANY, wxT("Press the key to assign")), 1, wxGROW); + s->Add(t = new wxStaticText(p, wxID_ANY, wxT("Press the key to assign"), wxDefaultPosition, + wxSize(-1, -1), wxWANTS_CHARS), 1, wxGROW); s->Add(0, 0); s->Add(0, 0); s->Add(0, 0); From b000ec93ce7c642b19a2d1356d5a46f792e5f59e Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Fri, 18 May 2012 19:03:32 +0300 Subject: [PATCH 2/4] MSU-1 support This is at least enough to play Super Road Blaster... --- include/core/mainloop.hpp | 3 ++- include/core/rom.hpp | 5 ++++- src/core/mainloop.cpp | 19 ++++++++++++++++++- src/core/rom.cpp | 6 ++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/core/mainloop.hpp b/include/core/mainloop.hpp index beaed31c..e3a58c4b 100644 --- a/include/core/mainloop.hpp +++ b/include/core/mainloop.hpp @@ -13,5 +13,6 @@ void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has std::vector get_jukebox_names(); void set_jukebox_names(const std::vector& newj); void update_movie_state(); +extern std::string msu1_base_path; -#endif \ No newline at end of file +#endif diff --git a/include/core/rom.hpp b/include/core/rom.hpp index 1d4ea84a..1d7cb192 100644 --- a/include/core/rom.hpp +++ b/include/core/rom.hpp @@ -376,7 +376,10 @@ struct loaded_rom * Loaded slot B XML (.st). */ loaded_slot slotb_xml; - +/** + * MSU-1 base. + */ + std::string msu1_base; /** * Patch the ROM. * diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index cf601cdd..8d9c4c2c 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -285,7 +285,7 @@ void update_movie_state() uint64_t audio_irq_time; uint64_t controller_irq_time; uint64_t frame_irq_time; - +std::string msu1_base_path; class my_interface : public SNES::Interface { @@ -294,6 +294,23 @@ class my_interface : public SNES::Interface const char* _hint = hint; std::string _hint2 = _hint; std::string fwp = firmwarepath_setting; + regex_results r; + std::string msubase = msu1_base_path; + if(regex_match(".*\\.sfc", msu1_base_path)) + msubase = msu1_base_path.substr(0, msu1_base_path.length() - 4); + + if(_hint2 == "msu1.rom" || _hint2 == ".msu") { + //MSU-1 main ROM. + std::string x = msubase + ".msu"; + messages << "MSU main data file: " << x << std::endl; + return x.c_str(); + } + if(r = regex("(track)?(-([0-9])+\\.pcm)", _hint2)) { + //MSU track. + std::string x = msubase + r[2]; + messages << "MSU track " << r[3] << "': " << x << std::endl; + return x.c_str(); + } std::string finalpath = fwp + "/" + _hint2; return finalpath.c_str(); } diff --git a/src/core/rom.cpp b/src/core/rom.cpp index d19deb11..b9e177ef 100644 --- a/src/core/rom.cpp +++ b/src/core/rom.cpp @@ -3,6 +3,7 @@ #include "core/command.hpp" #include "core/dispatch.hpp" #include "core/framerate.hpp" +#include "core/mainloop.hpp" #include "core/memorymanip.hpp" #include "core/misc.hpp" #include "core/patchrom.hpp" @@ -384,6 +385,10 @@ loaded_rom::loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtim slotb = loaded_slot(_slotb, files.base_file, false); slotb_xml = loaded_slot(_slotb_xml, files.base_file, true); orig_region = region = files.region; + if(files.rtype == ROMTYPE_SNES) + msu1_base = resolve_file_relative(files.rom, files.base_file); + else + msu1_base = resolve_file_relative(_slota, files.base_file); } void loaded_rom::load() throw(std::bad_alloc, std::runtime_error) @@ -449,6 +454,7 @@ void loaded_rom::load() throw(std::bad_alloc, std::runtime_error) information_dispatch::do_sound_rate(SNES::system.apu_frequency(), 768); current_rom_type = rtype; current_region = region; + msu1_base_path = msu1_base; refresh_cart_mappings(); } From d66ddeb7dccb7cd16c9ce4795b62ebffb0dbc87f Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 19 May 2012 09:57:12 +0300 Subject: [PATCH 3/4] Fix bug where mode change due to rewind is not shown --- src/core/moviedata.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/moviedata.cpp b/src/core/moviedata.cpp index ac4be77f..9f6644ca 100644 --- a/src/core/moviedata.cpp +++ b/src/core/moviedata.cpp @@ -293,6 +293,7 @@ void do_load_beginning() throw(std::bad_alloc, std::runtime_error) redraw_framebuffer(screen_corrupt, true); throw; } + information_dispatch::do_mode_change(movb.get_movie().readonly_mode()); our_movie.is_savestate = false; our_movie.host_memory.clear(); messages << "Movie rewound to beginning." << std::endl; From 6f796f9601a60e71ce662afd7734e0f6427f5a0f Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 19 May 2012 14:37:49 +0300 Subject: [PATCH 4/4] Unsafe rewinding Unsafe rewinding is unsafe, but in exchange, a lot faster than normal save/load cycle. --- include/core/mainloop.hpp | 8 +++++ include/core/movie.hpp | 9 +++++ include/core/moviedata.hpp | 10 ++++++ include/core/rom.hpp | 4 +-- include/lua/lua.hpp | 2 ++ include/lua/unsaferewind.hpp | 15 ++++++++ manual.lyx | 69 ++++++++++++++++++++++++++++++++++++ manual.txt | 34 ++++++++++++++++++ src/core/mainloop.cpp | 39 ++++++++++++++++++-- src/core/movie.cpp | 19 ++++++++++ src/core/moviedata.cpp | 8 +++++ src/core/rom.cpp | 13 +++++-- src/lua/dummy.cpp | 2 ++ src/lua/lua.cpp | 33 +++++++++++++++++ src/lua/movie.cpp | 18 ++++++++++ 15 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 include/lua/unsaferewind.hpp diff --git a/include/core/mainloop.hpp b/include/core/mainloop.hpp index e3a58c4b..08ec9b89 100644 --- a/include/core/mainloop.hpp +++ b/include/core/mainloop.hpp @@ -15,4 +15,12 @@ void set_jukebox_names(const std::vector& newj); void update_movie_state(); extern std::string msu1_base_path; +/** + * Signal that fast rewind operation is needed. + * + * Parameter ptr: If NULL, saves a state and calls lua_callback_do_unsafe_rewind() with quicksave, movie and NULL. + * If non-NULL, calls lua_callback_do_unsafe_rewind() with movie and this parameter, but without quicksave. + */ +void mainloop_signal_need_rewind(void* ptr); + #endif diff --git a/include/core/movie.hpp b/include/core/movie.hpp index 5fbae63f..71891115 100644 --- a/include/core/movie.hpp +++ b/include/core/movie.hpp @@ -228,6 +228,15 @@ public: * movie, reads all released. */ controller_frame read_subframe(uint64_t frame, uint64_t subframe) throw(); +/** + * Fast save. + */ + void fast_save(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector& counters); +/** + * Fast load. + */ + void fast_load(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector& counters); + private: //TRUE if readonly mode is active. bool readonly; diff --git a/include/core/moviedata.hpp b/include/core/moviedata.hpp index e17e5856..6eadfe2b 100644 --- a/include/core/moviedata.hpp +++ b/include/core/moviedata.hpp @@ -33,4 +33,14 @@ std::string translate_name_mprefix(std::string original, bool forio = false); extern std::string last_save; extern movie_logic movb; +/** + * Restore the actual core state from quicksave. Only call in rewind callback. + * + * Parameter state: The state to restore. + * Parameter secs: The seconds counter. + * Parameter ssecs: The subsecond counter. + */ +void mainloop_restore_state(const std::vector& state, uint64_t secs, uint64_t ssecs); + + #endif diff --git a/include/core/rom.hpp b/include/core/rom.hpp index 1d7cb192..5032cb1e 100644 --- a/include/core/rom.hpp +++ b/include/core/rom.hpp @@ -469,7 +469,7 @@ std::map> load_sram_commandline(const std::vector * returns: The saved state. * throws std::bad_alloc: Not enough memory. */ -std::vector save_core_state() throw(std::bad_alloc); +std::vector save_core_state(bool nochecksum = false) throw(std::bad_alloc); /** * Loads core state from buffer. @@ -477,7 +477,7 @@ std::vector save_core_state() throw(std::bad_alloc); * parameter buf: The buffer containing the state. * throws std::runtime_error: Loading state failed. */ -void load_core_state(const std::vector& buf) throw(std::runtime_error); +void load_core_state(const std::vector& buf, bool nochecksum = false) throw(std::runtime_error); /** * Read index of ROMs and add ROMs found to content-searchable storage. diff --git a/include/lua/lua.hpp b/include/lua/lua.hpp index 086ee4ff..c481856c 100644 --- a/include/lua/lua.hpp +++ b/include/lua/lua.hpp @@ -4,6 +4,7 @@ #include "core/controllerframe.hpp" #include "core/keymapper.hpp" #include "core/render.hpp" +#include "core/movie.hpp" struct lua_State; @@ -88,6 +89,7 @@ void lua_callback_post_save(const std::string& name, bool is_state) throw(); void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw(); void lua_callback_quit() throw(); void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw(); +void lua_callback_do_unsafe_rewind(const std::vector& save, uint64_t secs, uint64_t ssecs, movie& mov, void* u); #define LUA_TIMED_HOOK_IDLE 0 #define LUA_TIMED_HOOK_TIMER 1 diff --git a/include/lua/unsaferewind.hpp b/include/lua/unsaferewind.hpp new file mode 100644 index 00000000..f8cf109d --- /dev/null +++ b/include/lua/unsaferewind.hpp @@ -0,0 +1,15 @@ +#ifndef _lua__unsaferewind__hpp__included__ +#define _lua__unsaferewind__hpp__included__ + +struct lua_unsaferewind +{ + std::vector state; + uint64_t frame; + uint64_t lag; + uint64_t ptr; + uint64_t secs; + uint64_t ssecs; + std::vector pollcounters; +}; + +#endif \ No newline at end of file diff --git a/manual.lyx b/manual.lyx index 92d9c59f..51fc6a2a 100644 --- a/manual.lyx +++ b/manual.lyx @@ -2918,6 +2918,51 @@ Read specifed subframe in specified frame and return data as array (100 elements, numbered 0-99 currently). \end_layout +\begin_layout Subsubsection +movie.unsafe_rewind([UNSAFEREWIND state]) +\end_layout + +\begin_layout Standard +Start setting point for unsafe rewind or jump to point of unsafe rewind. +\end_layout + +\begin_layout Itemize +If called without argument, causes emulator to start process of setting + unsafe rewind point. + When this has finished, callback on_set_rewind occurs, passing the rewind + state to lua script. +\end_layout + +\begin_layout Itemize +If called with argument, causes emulator rewind to passed rewind point as + soon as possible. + Readwrite mode is implicitly activated. +\end_layout + +\begin_layout Standard +The following warnings apply to unsafe rewinding: +\end_layout + +\begin_layout Itemize +There are no safety checks against misuse (that's what +\begin_inset Quotes eld +\end_inset + +unsafe +\begin_inset Quotes erd +\end_inset + + comes from)! +\end_layout + +\begin_layout Itemize +Only call rewind from timeline rewind point was set from. +\end_layout + +\begin_layout Itemize +Only call rewind from after the rewind point was set. +\end_layout + \begin_layout Subsection Table settings \end_layout @@ -3341,6 +3386,30 @@ Called when requested by set_idle_timeout() and the timeout has expired (regardless if emulator is waiting). \end_layout +\begin_layout Subsubsection +Callback: on_set_rewind(UNSAFEREWIND r) +\end_layout + +\begin_layout Standard +Called when unsafe rewind object has been constructed. +\end_layout + +\begin_layout Subsubsection +Callback: on_pre_rewind() +\end_layout + +\begin_layout Standard +Called just before unsafe rewind is about to occur. +\end_layout + +\begin_layout Subsubsection +Callback: on_post_rewind() +\end_layout + +\begin_layout Standard +Called just after unsafe rewind has occured. +\end_layout + \begin_layout Section Memory watch expression syntax \end_layout diff --git a/manual.txt b/manual.txt index 34de1642..49769fd5 100644 --- a/manual.txt +++ b/manual.txt @@ -1476,6 +1476,28 @@ Count number of subframes in specified frame (frame numbers are Read specifed subframe in specified frame and return data as array (100 elements, numbered 0-99 currently). +8.6.7 movie.unsafe_rewind([UNSAFEREWIND state]) + +Start setting point for unsafe rewind or jump to point of unsafe +rewind. + +• If called without argument, causes emulator to start process of + setting unsafe rewind point. When this has finished, callback + on_set_rewind occurs, passing the rewind state to lua script. + +• If called with argument, causes emulator rewind to passed + rewind point as soon as possible. Readwrite mode is implicitly + activated. + +The following warnings apply to unsafe rewinding: + +• There are no safety checks against misuse (that's what “unsafe” + comes from)! + +• Only call rewind from timeline rewind point was set from. + +• Only call rewind from after the rewind point was set. + 8.7 Table settings Routines for settings manipulation @@ -1712,6 +1734,18 @@ expired and emulator is waiting. Called when requested by set_idle_timeout() and the timeout has expired (regardless if emulator is waiting). +8.10.21 Callback: on_set_rewind(UNSAFEREWIND r) + +Called when unsafe rewind object has been constructed. + +8.10.22 Callback: on_pre_rewind() + +Called just before unsafe rewind is about to occur. + +8.10.23 Callback: on_post_rewind() + +Called just after unsafe rewind has occured. + 9 Memory watch expression syntax Memory watch expressions are in RPN (Reverse Polish Notation). At diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index 8d9c4c2c..da7a5ff4 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -79,6 +79,11 @@ namespace //Delay reset. unsigned long long delayreset_cycles_run; unsigned long long delayreset_cycles_target; + //Unsafe rewind. + bool do_unsafe_rewind = false; + void* unsafe_rewind_obj = NULL; + + enum advance_mode old_mode; bool delayreset_fn() { @@ -96,6 +101,16 @@ namespace path_setting firmwarepath_setting("firmwarepath"); +void mainloop_signal_need_rewind(void* ptr) +{ + if(ptr) { + old_mode = amode; + amode = ADVANCE_LOAD; + } + do_unsafe_rewind = true; + unsafe_rewind_obj = ptr; +} + controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error) { if(lua_requests_subframe_paint) @@ -164,7 +179,6 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo namespace { - enum advance_mode old_mode; //Do pending load (automatically unpauses). void mark_pending_load(const std::string& filename, int lmode) @@ -774,6 +788,18 @@ namespace //failing. int handle_load() { + if(do_unsafe_rewind && unsafe_rewind_obj) { + uint64_t t = get_utime(); + std::vector s; + lua_callback_do_unsafe_rewind(s, 0, 0, movb.get_movie(), unsafe_rewind_obj); + information_dispatch::do_mode_change(false); + do_unsafe_rewind = false; + our_movie.is_savestate = true; + location_special = SPECIAL_SAVEPOINT; + update_movie_state(); + messages << "Rewind done in " << (get_utime() - t) << " usec." << std::endl; + return 1; + } if(pending_load != "") { system_corrupt = false; if(loadmode != LOAD_STATE_BEGINNING && !do_load_state(pending_load, loadmode)) { @@ -801,12 +827,21 @@ namespace //If there are pending saves, perform them. void handle_saves() { - if(!queued_saves.empty()) { + if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) { stepping_into_save = true; SNES::system.runtosave(); stepping_into_save = false; for(auto i : queued_saves) do_save_state(i); + if(do_unsafe_rewind && !unsafe_rewind_obj) { + uint64_t t = get_utime(); + std::vector s = save_core_state(true); + uint64_t secs = our_movie.rtc_second; + uint64_t ssecs = our_movie.rtc_subsecond; + lua_callback_do_unsafe_rewind(s, secs, ssecs, movb.get_movie(), NULL); + do_unsafe_rewind = false; + messages << "Rewind point set in " << (get_utime() - t) << " usec." << std::endl; + } } queued_saves.clear(); } diff --git a/src/core/movie.cpp b/src/core/movie.cpp index 96402d16..61a4cb7f 100644 --- a/src/core/movie.cpp +++ b/src/core/movie.cpp @@ -455,6 +455,25 @@ void movie::reset_state() throw() clear_caches(); } +void movie::fast_save(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector& _counters) +{ + pollcounters.save_state(_counters); + _frame = current_frame; + _ptr = current_frame_first_subframe; + _lagc = lag_frames; +} + +void movie::fast_load(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector& _counters) +{ + readonly = true; + current_frame = _frame; + current_frame_first_subframe = (_ptr <= movie_data.size()) ? _ptr : movie_data.size(); + lag_frames = _lagc; + pollcounters.load_state(_counters); + readonly_mode(false); +} + + movie_logic::movie_logic() throw() { } diff --git a/src/core/moviedata.cpp b/src/core/moviedata.cpp index 9f6644ca..b9b2f3fb 100644 --- a/src/core/moviedata.cpp +++ b/src/core/moviedata.cpp @@ -495,3 +495,11 @@ bool do_load_state(const std::string& filename, int lmode) } return true; } + +void mainloop_restore_state(const std::vector& state, uint64_t secs, uint64_t ssecs) +{ + rrdata::add_internal(); + our_movie.rtc_second = secs; + our_movie.rtc_subsecond = ssecs; + load_core_state(state, true); +} diff --git a/src/core/rom.cpp b/src/core/rom.cpp index b9e177ef..0e5dada2 100644 --- a/src/core/rom.cpp +++ b/src/core/rom.cpp @@ -600,12 +600,14 @@ std::map> load_sram_commandline(const std::vector return ret; } -std::vector save_core_state() throw(std::bad_alloc) +std::vector save_core_state(bool nochecksum) throw(std::bad_alloc) { std::vector ret; serializer s = SNES::system.serialize(); ret.resize(s.size()); memcpy(&ret[0], s.data(), s.size()); + if(nochecksum) + return ret; size_t offset = ret.size(); unsigned char tmp[32]; sha256::hash(tmp, ret); @@ -614,8 +616,15 @@ std::vector save_core_state() throw(std::bad_alloc) return ret; } -void load_core_state(const std::vector& buf) throw(std::runtime_error) +void load_core_state(const std::vector& buf, bool nochecksum) throw(std::runtime_error) { + if(nochecksum) { + serializer s(reinterpret_cast(&buf[0]), buf.size()); + if(!SNES::system.unserialize(s)) + throw std::runtime_error("SNES core rejected savestate"); + return; + } + if(buf.size() < 32) throw std::runtime_error("Savestate corrupt"); unsigned char tmp[32]; diff --git a/src/lua/dummy.cpp b/src/lua/dummy.cpp index 107c2674..38bd91b4 100644 --- a/src/lua/dummy.cpp +++ b/src/lua/dummy.cpp @@ -27,6 +27,8 @@ void lua_callback_keyhook(const std::string& key, const struct keygroup::paramet void init_lua() throw() {} void quit_lua() throw() {} uint64_t lua_timed_hook(int timer) throw() { return 0x7EFFFFFFFFFFFFFFULL; } +void lua_callback_do_unsafe_rewind(const std::vector& save, movie& mov, void* u) {} + bool lua_requests_repaint = false; bool lua_requests_subframe_paint = false; diff --git a/src/lua/lua.cpp b/src/lua/lua.cpp index 2aa25164..93b318ed 100644 --- a/src/lua/lua.cpp +++ b/src/lua/lua.cpp @@ -2,8 +2,10 @@ #include "core/globalwrap.hpp" #include "lua/internal.hpp" #include "lua/lua.hpp" +#include "lua/unsaferewind.hpp" #include "core/mainloop.hpp" #include "core/memorymanip.hpp" +#include "core/moviedata.hpp" #include "core/misc.hpp" #include @@ -555,7 +557,38 @@ uint64_t lua_timed_hook(int timer) throw() } } +void lua_callback_do_unsafe_rewind(const std::vector& save, uint64_t secs, uint64_t ssecs, movie& mov, void* u) +{ + if(u) { + lua_unsaferewind* u2 = reinterpret_cast*>(u)->object(); + //Load. + try { + if(callback_exists("on_pre_rewind")) + run_lua_cb(0); + mainloop_restore_state(u2->state, u2->secs, u2->ssecs); + mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters); + if(callback_exists("on_post_rewind")) + run_lua_cb(0); + } catch(...) { + return; + } + } else { + //Save + if(callback_exists("on_set_rewind")) { + lua_unsaferewind* u2 = lua_class::create(L); + u2->state = save; + u2->secs = secs, + u2->ssecs = ssecs; + mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters); + run_lua_cb(1); + } + + } +} + bool lua_requests_repaint = false; bool lua_requests_subframe_paint = false; bool lua_supported = true; + +DECLARE_LUACLASS(lua_unsaferewind, "UNSAFEREWIND"); diff --git a/src/lua/movie.cpp b/src/lua/movie.cpp index 8cac05b7..d1f88deb 100644 --- a/src/lua/movie.cpp +++ b/src/lua/movie.cpp @@ -1,6 +1,8 @@ #include "lua/internal.hpp" +#include "lua/unsaferewind.hpp" #include "core/movie.hpp" #include "core/moviedata.hpp" +#include "core/mainloop.hpp" namespace { @@ -68,4 +70,20 @@ namespace lua_pushnumber(LS, our_movie.rtc_subsecond); return 2; }); + + function_ptr_luafun musv("movie.unsafe_rewind", [](lua_State* LS, const std::string& fname) -> int { + if(lua_isnoneornil(LS, 1)) { + //Start process to mark save. + mainloop_signal_need_rewind(NULL); + } else if(lua_class::is(LS, 1)) { + //Load the save. + lua_obj_pin* u = lua_class::pin(LS, 1, fname.c_str()); + mainloop_signal_need_rewind(u); + } else { + lua_pushstring(LS, "movie.unsafe_rewind: Expected nil or UNSAFEREWIND as 1st argument"); + lua_error(LS); + return 0; + } + }); } +