Merge branch 'rr1-maint'
Conflicts: include/core/rom.hpp src/core/rom.cpp
This commit is contained in:
commit
591770ffa9
19 changed files with 333 additions and 13 deletions
|
@ -13,5 +13,14 @@ void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has
|
||||||
std::vector<std::string> get_jukebox_names();
|
std::vector<std::string> get_jukebox_names();
|
||||||
void set_jukebox_names(const std::vector<std::string>& newj);
|
void set_jukebox_names(const std::vector<std::string>& newj);
|
||||||
void update_movie_state();
|
void update_movie_state();
|
||||||
|
extern std::string msu1_base_path;
|
||||||
|
|
||||||
#endif
|
/**
|
||||||
|
* 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
|
||||||
|
|
|
@ -230,6 +230,15 @@ public:
|
||||||
* movie, reads all released.
|
* movie, reads all released.
|
||||||
*/
|
*/
|
||||||
controller_frame read_subframe(uint64_t frame, uint64_t subframe) throw();
|
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<uint32_t>& counters);
|
||||||
|
/**
|
||||||
|
* Fast load.
|
||||||
|
*/
|
||||||
|
void fast_load(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector<uint32_t>& counters);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//TRUE if readonly mode is active.
|
//TRUE if readonly mode is active.
|
||||||
bool readonly;
|
bool readonly;
|
||||||
|
|
|
@ -33,4 +33,14 @@ std::string translate_name_mprefix(std::string original, bool forio = false);
|
||||||
extern std::string last_save;
|
extern std::string last_save;
|
||||||
extern movie_logic movb;
|
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<char>& state, uint64_t secs, uint64_t ssecs);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -176,7 +176,11 @@ struct loaded_rom
|
||||||
*/
|
*/
|
||||||
std::vector<loaded_slot> markup_slots;
|
std::vector<loaded_slot> markup_slots;
|
||||||
/**
|
/**
|
||||||
* Patch the ROMs.
|
* MSU-1 base.
|
||||||
|
*/
|
||||||
|
std::string msu1_base;
|
||||||
|
/**
|
||||||
|
* Patch the ROM.
|
||||||
*
|
*
|
||||||
* parameter cmdline: The command line.
|
* parameter cmdline: The command line.
|
||||||
* throws std::bad_alloc: Not enough memory.
|
* throws std::bad_alloc: Not enough memory.
|
||||||
|
@ -222,7 +226,27 @@ std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector
|
||||||
throw(std::bad_alloc, std::runtime_error);
|
throw(std::bad_alloc, std::runtime_error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
<<<<<<< HEAD
|
||||||
* Given commandline arguments, load a ROM.
|
* Given commandline arguments, load a ROM.
|
||||||
|
=======
|
||||||
|
* Saves core state into buffer. WARNING: This takes emulated time.
|
||||||
|
*
|
||||||
|
* returns: The saved state.
|
||||||
|
* throws std::bad_alloc: Not enough memory.
|
||||||
|
*/
|
||||||
|
std::vector<char> save_core_state(bool nochecksum = false) throw(std::bad_alloc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads core state from buffer.
|
||||||
|
*
|
||||||
|
* parameter buf: The buffer containing the state.
|
||||||
|
* throws std::runtime_error: Loading state failed.
|
||||||
|
*/
|
||||||
|
void load_core_state(const std::vector<char>& buf, bool nochecksum = false) throw(std::runtime_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read index of ROMs and add ROMs found to content-searchable storage.
|
||||||
|
>>>>>>> rr1-maint
|
||||||
*
|
*
|
||||||
* parameter cmdline: The command line.
|
* parameter cmdline: The command line.
|
||||||
* returns: The loaded ROM set.
|
* returns: The loaded ROM set.
|
||||||
|
|
|
@ -89,8 +89,8 @@ struct sram_slot_structure* emucore_sram_slot(size_t index);
|
||||||
size_t emucore_vma_slots();
|
size_t emucore_vma_slots();
|
||||||
struct vma_structure* emucore_vma_slot(size_t index);
|
struct vma_structure* emucore_vma_slot(size_t index);
|
||||||
void emucore_refresh_cart();
|
void emucore_refresh_cart();
|
||||||
std::vector<char> emucore_serialize();
|
std::vector<char> emucore_serialize(bool nochecksum = false);
|
||||||
void emucore_unserialize(const std::vector<char>& data);
|
void emucore_unserialize(const std::vector<char>& data, bool nochecksum = false);
|
||||||
void emucore_load_rom(systype_info_structure* rtype, region_info_structure* region,
|
void emucore_load_rom(systype_info_structure* rtype, region_info_structure* region,
|
||||||
const std::vector<std::vector<char>>& romslots, const std::vector<std::vector<char>>& markslots);
|
const std::vector<std::vector<char>>& romslots, const std::vector<std::vector<char>>& markslots);
|
||||||
struct region_info_structure* emucore_current_region();
|
struct region_info_structure* emucore_current_region();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "core/controllerframe.hpp"
|
#include "core/controllerframe.hpp"
|
||||||
#include "core/keymapper.hpp"
|
#include "core/keymapper.hpp"
|
||||||
#include "core/render.hpp"
|
#include "core/render.hpp"
|
||||||
|
#include "core/movie.hpp"
|
||||||
|
|
||||||
struct lua_State;
|
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_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw();
|
||||||
void lua_callback_quit() throw();
|
void lua_callback_quit() throw();
|
||||||
void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw();
|
void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw();
|
||||||
|
void lua_callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov, void* u);
|
||||||
|
|
||||||
#define LUA_TIMED_HOOK_IDLE 0
|
#define LUA_TIMED_HOOK_IDLE 0
|
||||||
#define LUA_TIMED_HOOK_TIMER 1
|
#define LUA_TIMED_HOOK_TIMER 1
|
||||||
|
|
15
include/lua/unsaferewind.hpp
Normal file
15
include/lua/unsaferewind.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _lua__unsaferewind__hpp__included__
|
||||||
|
#define _lua__unsaferewind__hpp__included__
|
||||||
|
|
||||||
|
struct lua_unsaferewind
|
||||||
|
{
|
||||||
|
std::vector<char> state;
|
||||||
|
uint64_t frame;
|
||||||
|
uint64_t lag;
|
||||||
|
uint64_t ptr;
|
||||||
|
uint64_t secs;
|
||||||
|
uint64_t ssecs;
|
||||||
|
std::vector<uint32_t> pollcounters;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
69
manual.lyx
69
manual.lyx
|
@ -2918,6 +2918,51 @@ Read specifed subframe in specified frame and return data as array (100
|
||||||
elements, numbered 0-99 currently).
|
elements, numbered 0-99 currently).
|
||||||
\end_layout
|
\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
|
\begin_layout Subsection
|
||||||
Table settings
|
Table settings
|
||||||
\end_layout
|
\end_layout
|
||||||
|
@ -3341,6 +3386,30 @@ Called when requested by set_idle_timeout() and the timeout has expired
|
||||||
(regardless if emulator is waiting).
|
(regardless if emulator is waiting).
|
||||||
\end_layout
|
\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
|
\begin_layout Section
|
||||||
Memory watch expression syntax
|
Memory watch expression syntax
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
34
manual.txt
34
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
|
Read specifed subframe in specified frame and return data as
|
||||||
array (100 elements, numbered 0-99 currently).
|
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
|
8.7 Table settings
|
||||||
|
|
||||||
Routines for settings manipulation
|
Routines for settings manipulation
|
||||||
|
@ -1712,6 +1734,18 @@ expired and emulator is waiting.
|
||||||
Called when requested by set_idle_timeout() and the timeout has
|
Called when requested by set_idle_timeout() and the timeout has
|
||||||
expired (regardless if emulator is waiting).
|
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
|
9 Memory watch expression syntax
|
||||||
|
|
||||||
Memory watch expressions are in RPN (Reverse Polish Notation). At
|
Memory watch expressions are in RPN (Reverse Polish Notation). At
|
||||||
|
|
|
@ -80,6 +80,11 @@ namespace
|
||||||
//Delay reset.
|
//Delay reset.
|
||||||
unsigned long long delayreset_cycles_run;
|
unsigned long long delayreset_cycles_run;
|
||||||
unsigned long long delayreset_cycles_target;
|
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()
|
bool delayreset_fn()
|
||||||
{
|
{
|
||||||
|
@ -97,6 +102,16 @@ namespace
|
||||||
|
|
||||||
path_setting firmwarepath_setting("firmwarepath");
|
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)
|
controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error)
|
||||||
{
|
{
|
||||||
if(lua_requests_subframe_paint)
|
if(lua_requests_subframe_paint)
|
||||||
|
@ -165,7 +180,6 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
enum advance_mode old_mode;
|
|
||||||
|
|
||||||
//Do pending load (automatically unpauses).
|
//Do pending load (automatically unpauses).
|
||||||
void mark_pending_load(const std::string& filename, int lmode)
|
void mark_pending_load(const std::string& filename, int lmode)
|
||||||
|
@ -286,7 +300,7 @@ void update_movie_state()
|
||||||
uint64_t audio_irq_time;
|
uint64_t audio_irq_time;
|
||||||
uint64_t controller_irq_time;
|
uint64_t controller_irq_time;
|
||||||
uint64_t frame_irq_time;
|
uint64_t frame_irq_time;
|
||||||
|
std::string msu1_base_path;
|
||||||
|
|
||||||
class my_interface : public SNES::Interface
|
class my_interface : public SNES::Interface
|
||||||
{
|
{
|
||||||
|
@ -295,6 +309,23 @@ class my_interface : public SNES::Interface
|
||||||
const char* _hint = hint;
|
const char* _hint = hint;
|
||||||
std::string _hint2 = _hint;
|
std::string _hint2 = _hint;
|
||||||
std::string fwp = firmwarepath_setting;
|
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;
|
std::string finalpath = fwp + "/" + _hint2;
|
||||||
return finalpath.c_str();
|
return finalpath.c_str();
|
||||||
}
|
}
|
||||||
|
@ -736,6 +767,18 @@ namespace
|
||||||
//failing.
|
//failing.
|
||||||
int handle_load()
|
int handle_load()
|
||||||
{
|
{
|
||||||
|
if(do_unsafe_rewind && unsafe_rewind_obj) {
|
||||||
|
uint64_t t = get_utime();
|
||||||
|
std::vector<char> 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 != "") {
|
if(pending_load != "") {
|
||||||
system_corrupt = false;
|
system_corrupt = false;
|
||||||
if(loadmode != LOAD_STATE_BEGINNING && !do_load_state(pending_load, loadmode)) {
|
if(loadmode != LOAD_STATE_BEGINNING && !do_load_state(pending_load, loadmode)) {
|
||||||
|
@ -763,12 +806,21 @@ namespace
|
||||||
//If there are pending saves, perform them.
|
//If there are pending saves, perform them.
|
||||||
void handle_saves()
|
void handle_saves()
|
||||||
{
|
{
|
||||||
if(!queued_saves.empty()) {
|
if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) {
|
||||||
stepping_into_save = true;
|
stepping_into_save = true;
|
||||||
SNES::system.runtosave();
|
SNES::system.runtosave();
|
||||||
stepping_into_save = false;
|
stepping_into_save = false;
|
||||||
for(auto i : queued_saves)
|
for(auto i : queued_saves)
|
||||||
do_save_state(i);
|
do_save_state(i);
|
||||||
|
if(do_unsafe_rewind && !unsafe_rewind_obj) {
|
||||||
|
uint64_t t = get_utime();
|
||||||
|
std::vector<char> s = emucore_serialize(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();
|
queued_saves.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,6 +459,25 @@ void movie::reset_state() throw()
|
||||||
clear_caches();
|
clear_caches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void movie::fast_save(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector<uint32_t>& _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<uint32_t>& _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()
|
movie_logic::movie_logic() throw()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,6 +291,7 @@ void do_load_beginning() throw(std::bad_alloc, std::runtime_error)
|
||||||
redraw_framebuffer(screen_corrupt, true);
|
redraw_framebuffer(screen_corrupt, true);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
information_dispatch::do_mode_change(movb.get_movie().readonly_mode());
|
||||||
our_movie.is_savestate = false;
|
our_movie.is_savestate = false;
|
||||||
our_movie.host_memory.clear();
|
our_movie.host_memory.clear();
|
||||||
messages << "Movie rewound to beginning." << std::endl;
|
messages << "Movie rewound to beginning." << std::endl;
|
||||||
|
@ -469,3 +470,11 @@ bool do_load_state(const std::string& filename, int lmode)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
|
||||||
|
{
|
||||||
|
rrdata::add_internal();
|
||||||
|
our_movie.rtc_second = secs;
|
||||||
|
our_movie.rtc_subsecond = ssecs;
|
||||||
|
emucore_unserialize(state, true);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "core/command.hpp"
|
#include "core/command.hpp"
|
||||||
#include "core/dispatch.hpp"
|
#include "core/dispatch.hpp"
|
||||||
#include "core/framerate.hpp"
|
#include "core/framerate.hpp"
|
||||||
|
#include "core/mainloop.hpp"
|
||||||
#include "core/memorymanip.hpp"
|
#include "core/memorymanip.hpp"
|
||||||
#include "core/misc.hpp"
|
#include "core/misc.hpp"
|
||||||
#include "core/rom.hpp"
|
#include "core/rom.hpp"
|
||||||
|
@ -210,6 +211,10 @@ loaded_rom::loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtim
|
||||||
markup_slots[i] = loaded_slot(files.markup_slots[i], files.base_file, *rtype->rom_slot(i),
|
markup_slots[i] = loaded_slot(files.markup_slots[i], files.base_file, *rtype->rom_slot(i),
|
||||||
true);
|
true);
|
||||||
orig_region = region = files.region;
|
orig_region = region = files.region;
|
||||||
|
if(main_slots.size() > 1)
|
||||||
|
msu1_base = resolve_file_relative(files.main_slots[1], files.base_file);
|
||||||
|
else
|
||||||
|
msu1_base = resolve_file_relative(files.main_slots[0], files.base_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loaded_rom::load() throw(std::bad_alloc, std::runtime_error)
|
void loaded_rom::load() throw(std::bad_alloc, std::runtime_error)
|
||||||
|
@ -234,6 +239,7 @@ void loaded_rom::load() throw(std::bad_alloc, std::runtime_error)
|
||||||
auto soundrate = emucore_get_audio_rate();
|
auto soundrate = emucore_get_audio_rate();
|
||||||
set_nominal_framerate(1.0 * framerate.first / framerate.second);
|
set_nominal_framerate(1.0 * framerate.first / framerate.second);
|
||||||
information_dispatch::do_sound_rate(soundrate.first, soundrate.second);
|
information_dispatch::do_sound_rate(soundrate.first, soundrate.second);
|
||||||
|
msu1_base_path = msu1_base;
|
||||||
refresh_cart_mappings();
|
refresh_cart_mappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,12 +446,14 @@ void emucore_refresh_cart()
|
||||||
delete i;
|
delete i;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> emucore_serialize()
|
std::vector<char> emucore_serialize(bool nochecksum)
|
||||||
{
|
{
|
||||||
std::vector<char> ret;
|
std::vector<char> ret;
|
||||||
serializer s = SNES::system.serialize();
|
serializer s = SNES::system.serialize();
|
||||||
ret.resize(s.size());
|
ret.resize(s.size());
|
||||||
memcpy(&ret[0], s.data(), s.size());
|
memcpy(&ret[0], s.data(), s.size());
|
||||||
|
if(nochecksum)
|
||||||
|
return ret;
|
||||||
size_t offset = ret.size();
|
size_t offset = ret.size();
|
||||||
unsigned char tmp[32];
|
unsigned char tmp[32];
|
||||||
sha256::hash(tmp, ret);
|
sha256::hash(tmp, ret);
|
||||||
|
@ -460,8 +462,14 @@ std::vector<char> emucore_serialize()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emucore_unserialize(const std::vector<char>& buf)
|
void emucore_unserialize(const std::vector<char>& buf, bool nochecksum)
|
||||||
{
|
{
|
||||||
|
if(nochecksum) {
|
||||||
|
serializer s(reinterpret_cast<const uint8_t*>(&buf[0]), buf.size());
|
||||||
|
if(!SNES::system.unserialize(s))
|
||||||
|
throw std::runtime_error("SNES core rejected savestate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(buf.size() < 32)
|
if(buf.size() < 32)
|
||||||
throw std::runtime_error("Savestate corrupt");
|
throw std::runtime_error("Savestate corrupt");
|
||||||
unsigned char tmp[32];
|
unsigned char tmp[32];
|
||||||
|
|
|
@ -27,6 +27,8 @@ void lua_callback_keyhook(const std::string& key, const struct keygroup::paramet
|
||||||
void init_lua() throw() {}
|
void init_lua() throw() {}
|
||||||
void quit_lua() throw() {}
|
void quit_lua() throw() {}
|
||||||
uint64_t lua_timed_hook(int timer) throw() { return 0x7EFFFFFFFFFFFFFFULL; }
|
uint64_t lua_timed_hook(int timer) throw() { return 0x7EFFFFFFFFFFFFFFULL; }
|
||||||
|
void lua_callback_do_unsafe_rewind(const std::vector<char>& save, movie& mov, void* u) {}
|
||||||
|
|
||||||
|
|
||||||
bool lua_requests_repaint = false;
|
bool lua_requests_repaint = false;
|
||||||
bool lua_requests_subframe_paint = false;
|
bool lua_requests_subframe_paint = false;
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
#include "core/globalwrap.hpp"
|
#include "core/globalwrap.hpp"
|
||||||
#include "lua/internal.hpp"
|
#include "lua/internal.hpp"
|
||||||
#include "lua/lua.hpp"
|
#include "lua/lua.hpp"
|
||||||
|
#include "lua/unsaferewind.hpp"
|
||||||
#include "core/mainloop.hpp"
|
#include "core/mainloop.hpp"
|
||||||
#include "core/memorymanip.hpp"
|
#include "core/memorymanip.hpp"
|
||||||
|
#include "core/moviedata.hpp"
|
||||||
#include "core/misc.hpp"
|
#include "core/misc.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -555,7 +557,38 @@ uint64_t lua_timed_hook(int timer) throw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov, void* u)
|
||||||
|
{
|
||||||
|
if(u) {
|
||||||
|
lua_unsaferewind* u2 = reinterpret_cast<lua_obj_pin<lua_unsaferewind>*>(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<lua_unsaferewind>::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_repaint = false;
|
||||||
bool lua_requests_subframe_paint = false;
|
bool lua_requests_subframe_paint = false;
|
||||||
bool lua_supported = true;
|
bool lua_supported = true;
|
||||||
|
|
||||||
|
DECLARE_LUACLASS(lua_unsaferewind, "UNSAFEREWIND");
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "lua/internal.hpp"
|
#include "lua/internal.hpp"
|
||||||
|
#include "lua/unsaferewind.hpp"
|
||||||
#include "core/movie.hpp"
|
#include "core/movie.hpp"
|
||||||
#include "core/moviedata.hpp"
|
#include "core/moviedata.hpp"
|
||||||
|
#include "core/mainloop.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -68,4 +70,20 @@ namespace
|
||||||
lua_pushnumber(LS, our_movie.rtc_subsecond);
|
lua_pushnumber(LS, our_movie.rtc_subsecond);
|
||||||
return 2;
|
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<lua_unsaferewind>::is(LS, 1)) {
|
||||||
|
//Load the save.
|
||||||
|
lua_obj_pin<lua_unsaferewind>* u = lua_class<lua_unsaferewind>::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;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,7 +473,7 @@ void boot_emulator(loaded_rom& rom, moviefile& movie)
|
||||||
}
|
}
|
||||||
|
|
||||||
wxwin_mainwindow::panel::panel(wxWindow* win)
|
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_PAINT, wxPaintEventHandler(panel::on_paint), NULL, this);
|
||||||
this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(panel::on_erase), NULL, this);
|
this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(panel::on_erase), NULL, this);
|
||||||
|
|
|
@ -100,11 +100,11 @@ namespace
|
||||||
int horiz_padding = 60;
|
int horiz_padding = 60;
|
||||||
|
|
||||||
wxdialog_pressbutton::wxdialog_pressbutton(wxWindow* parent, const std::string& title)
|
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;
|
wxStaticText* t;
|
||||||
wxBoxSizer* s2 = new wxBoxSizer(wxVERTICAL);
|
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);
|
s2->Add(p, 1, wxGROW);
|
||||||
lastkbdkey = -1;
|
lastkbdkey = -1;
|
||||||
mouseflag = 0;
|
mouseflag = 0;
|
||||||
|
@ -116,7 +116,8 @@ namespace
|
||||||
s->Add(0, 0);
|
s->Add(0, 0);
|
||||||
s->Add(0, 0);
|
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);
|
s->Add(0, 0);
|
||||||
s->Add(0, 0);
|
s->Add(0, 0);
|
||||||
|
|
Loading…
Add table
Reference in a new issue