Netplay: Drop-in at any time
This commit is contained in:
parent
68e7fe0209
commit
f8a06969a8
|
@ -201,12 +201,6 @@ typedef struct {
|
||||||
* functions during the game. All callback functions must be implemented.
|
* functions during the game. All callback functions must be implemented.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*
|
|
||||||
* begin_game callback - This callback has been deprecated. You must
|
|
||||||
* implement it, but should ignore the 'game' parameter.
|
|
||||||
*/
|
|
||||||
bool (__cdecl *begin_game)(void* context, const char *game);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* save_game_state - The client should allocate a buffer, copy the
|
* save_game_state - The client should allocate a buffer, copy the
|
||||||
* entire contents of the current game state into it, and copy the
|
* entire contents of the current game state into it, and copy the
|
||||||
|
@ -340,10 +334,8 @@ typedef struct GGPONetworkStats {
|
||||||
*/
|
*/
|
||||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_session(GGPOSession **session,
|
GGPO_API GGPOErrorCode __cdecl ggpo_start_session(GGPOSession **session,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
const char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
unsigned short localport,
|
|
||||||
int maxPrediction);
|
int maxPrediction);
|
||||||
|
|
||||||
|
|
||||||
|
@ -389,7 +381,6 @@ GGPO_API GGPOErrorCode __cdecl ggpo_add_player(GGPOSession *session,
|
||||||
*/
|
*/
|
||||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_synctest(GGPOSession **session,
|
GGPO_API GGPOErrorCode __cdecl ggpo_start_synctest(GGPOSession **session,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
int frames);
|
int frames);
|
||||||
|
@ -421,12 +412,10 @@ GGPO_API GGPOErrorCode __cdecl ggpo_start_synctest(GGPOSession **session,
|
||||||
*/
|
*/
|
||||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_spectating(GGPOSession **session,
|
GGPO_API GGPOErrorCode __cdecl ggpo_start_spectating(GGPOSession **session,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
const char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
unsigned short local_port,
|
ENetPeer* host);
|
||||||
char *host_ip,
|
|
||||||
unsigned short host_port);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ggpo_close_session --
|
* ggpo_close_session --
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
static const int RECOMMENDATION_INTERVAL = 120;
|
static const int RECOMMENDATION_INTERVAL = 120;
|
||||||
|
|
||||||
Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb,
|
Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb,
|
||||||
const char *gamename,
|
|
||||||
uint16 localport,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size, int nframes) :
|
int input_size, int nframes) :
|
||||||
_num_players(num_players),
|
_num_players(num_players),
|
||||||
|
@ -39,11 +37,6 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb,
|
||||||
for (int i = 0; i < ARRAY_SIZE(_local_connect_status); i++) {
|
for (int i = 0; i < ARRAY_SIZE(_local_connect_status); i++) {
|
||||||
_local_connect_status[i].last_frame = -1;
|
_local_connect_status[i].last_frame = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Preload the ROM
|
|
||||||
*/
|
|
||||||
_callbacks.begin_game(_callbacks.context, gamename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Peer2PeerBackend::~Peer2PeerBackend()
|
Peer2PeerBackend::~Peer2PeerBackend()
|
||||||
|
@ -299,6 +292,11 @@ Peer2PeerBackend::AddPlayer(GGPOPlayer *player,
|
||||||
if (player->type == GGPO_PLAYERTYPE_REMOTE) {
|
if (player->type == GGPO_PLAYERTYPE_REMOTE) {
|
||||||
AddRemotePlayer(player->u.remote.peer, queue);
|
AddRemotePlayer(player->u.remote.peer, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no other players in this session?
|
||||||
|
if (player->type == GGPO_PLAYERTYPE_LOCAL && _num_players == 1)
|
||||||
|
_synchronizing = false;
|
||||||
|
|
||||||
return GGPO_OK;
|
return GGPO_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
class Peer2PeerBackend final : public GGPOSession
|
class Peer2PeerBackend final : public GGPOSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Peer2PeerBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size, int nframes);
|
Peer2PeerBackend(GGPOSessionCallbacks *cb, int num_players, int input_size, int nframes);
|
||||||
virtual ~Peer2PeerBackend();
|
virtual ~Peer2PeerBackend();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,8 @@
|
||||||
|
|
||||||
#include "spectator.h"
|
#include "spectator.h"
|
||||||
|
|
||||||
SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb,
|
SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks* cb, int num_players, int input_size, ENetPeer* peer)
|
||||||
const char* gamename,
|
: _num_players(num_players), _input_size(input_size), _next_input_to_send(0)
|
||||||
uint16 localport,
|
|
||||||
int num_players,
|
|
||||||
int input_size,
|
|
||||||
char *hostip,
|
|
||||||
u_short hostport) :
|
|
||||||
_num_players(num_players),
|
|
||||||
_input_size(input_size),
|
|
||||||
_next_input_to_send(0)
|
|
||||||
{
|
{
|
||||||
_callbacks = *cb;
|
_callbacks = *cb;
|
||||||
_synchronizing = true;
|
_synchronizing = true;
|
||||||
|
@ -37,11 +29,6 @@ SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb,
|
||||||
*/
|
*/
|
||||||
//_host.Init(&_udp, _poll, 0, hostip, hostport, NULL);
|
//_host.Init(&_udp, _poll, 0, hostip, hostport, NULL);
|
||||||
_host.Synchronize();
|
_host.Synchronize();
|
||||||
|
|
||||||
/*
|
|
||||||
* Preload the ROM
|
|
||||||
*/
|
|
||||||
_callbacks.begin_game(_callbacks.context, gamename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectatorBackend::~SpectatorBackend()
|
SpectatorBackend::~SpectatorBackend()
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
class SpectatorBackend final : public GGPOSession {
|
class SpectatorBackend final : public GGPOSession {
|
||||||
public:
|
public:
|
||||||
SpectatorBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size, char *hostip, u_short hostport);
|
SpectatorBackend(GGPOSessionCallbacks *cb, int num_players, int input_size, ENetPeer* peer);
|
||||||
virtual ~SpectatorBackend();
|
virtual ~SpectatorBackend();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "synctest.h"
|
#include "synctest.h"
|
||||||
|
|
||||||
SyncTestBackend::SyncTestBackend(GGPOSessionCallbacks *cb,
|
SyncTestBackend::SyncTestBackend(GGPOSessionCallbacks *cb,
|
||||||
char *gamename,
|
|
||||||
int frames,
|
int frames,
|
||||||
int num_players) :
|
int num_players) :
|
||||||
_sync(NULL, MAX_PREDICTION_FRAMES)
|
_sync(NULL, MAX_PREDICTION_FRAMES)
|
||||||
|
@ -21,7 +20,6 @@ SyncTestBackend::SyncTestBackend(GGPOSessionCallbacks *cb,
|
||||||
_running = false;
|
_running = false;
|
||||||
_logfp = NULL;
|
_logfp = NULL;
|
||||||
_current_input.erase();
|
_current_input.erase();
|
||||||
strcpy_s(_game, gamename);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the synchronziation layer
|
* Initialize the synchronziation layer
|
||||||
|
@ -30,11 +28,6 @@ SyncTestBackend::SyncTestBackend(GGPOSessionCallbacks *cb,
|
||||||
config.callbacks = _callbacks;
|
config.callbacks = _callbacks;
|
||||||
config.num_prediction_frames = MAX_PREDICTION_FRAMES;
|
config.num_prediction_frames = MAX_PREDICTION_FRAMES;
|
||||||
_sync.Init(config);
|
_sync.Init(config);
|
||||||
|
|
||||||
/*
|
|
||||||
* Preload the ROM
|
|
||||||
*/
|
|
||||||
_callbacks.begin_game(_callbacks.context, gamename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncTestBackend::~SyncTestBackend()
|
SyncTestBackend::~SyncTestBackend()
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
class SyncTestBackend final : public GGPOSession {
|
class SyncTestBackend final : public GGPOSession {
|
||||||
public:
|
public:
|
||||||
SyncTestBackend(GGPOSessionCallbacks *cb, char *gamename, int frames, int num_players);
|
SyncTestBackend(GGPOSessionCallbacks *cb, int frames, int num_players);
|
||||||
virtual ~SyncTestBackend();
|
virtual ~SyncTestBackend();
|
||||||
|
|
||||||
virtual GGPOErrorCode DoPoll();
|
virtual GGPOErrorCode DoPoll();
|
||||||
|
@ -52,7 +52,6 @@ protected:
|
||||||
bool _rollingback;
|
bool _rollingback;
|
||||||
bool _running;
|
bool _running;
|
||||||
FILE *_logfp;
|
FILE *_logfp;
|
||||||
char _game[128];
|
|
||||||
|
|
||||||
GameInput _current_input;
|
GameInput _current_input;
|
||||||
GameInput _last_input;
|
GameInput _last_input;
|
||||||
|
|
|
@ -28,6 +28,7 @@ void Log(const char *fmt, ...)
|
||||||
|
|
||||||
void Logv(const char *fmt, va_list args)
|
void Logv(const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
if (!Platform::GetConfigBool("ggpo.log") || Platform::GetConfigBool("ggpo.log.ignore")) {
|
if (!Platform::GetConfigBool("ggpo.log") || Platform::GetConfigBool("ggpo.log.ignore")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +37,9 @@ void Logv(const char *fmt, va_list args)
|
||||||
fopen_s(&logfile, logbuf, "w");
|
fopen_s(&logfile, logbuf, "w");
|
||||||
}
|
}
|
||||||
Logv(logfile, fmt, args);
|
Logv(logfile, fmt, args);
|
||||||
|
#else
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logv(FILE *fp, const char *fmt, va_list args)
|
void Logv(FILE *fp, const char *fmt, va_list args)
|
||||||
|
|
|
@ -40,15 +40,11 @@ ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args)
|
||||||
GGPOErrorCode
|
GGPOErrorCode
|
||||||
ggpo_start_session(GGPOSession **session,
|
ggpo_start_session(GGPOSession **session,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
const char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
unsigned short localport,
|
|
||||||
int maxPrediction)
|
int maxPrediction)
|
||||||
{
|
{
|
||||||
*session= new Peer2PeerBackend(cb,
|
*session= new Peer2PeerBackend(cb,
|
||||||
game,
|
|
||||||
localport,
|
|
||||||
num_players,
|
num_players,
|
||||||
input_size,
|
input_size,
|
||||||
maxPrediction);
|
maxPrediction);
|
||||||
|
@ -71,12 +67,11 @@ ggpo_add_player(GGPOSession *ggpo,
|
||||||
GGPOErrorCode
|
GGPOErrorCode
|
||||||
ggpo_start_synctest(GGPOSession **ggpo,
|
ggpo_start_synctest(GGPOSession **ggpo,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
int frames)
|
int frames)
|
||||||
{
|
{
|
||||||
*ggpo = new SyncTestBackend(cb, game, frames, num_players);
|
*ggpo = new SyncTestBackend(cb, frames, num_players);
|
||||||
return GGPO_OK;
|
return GGPO_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,19 +204,10 @@ ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout)
|
||||||
|
|
||||||
GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
||||||
GGPOSessionCallbacks *cb,
|
GGPOSessionCallbacks *cb,
|
||||||
const char *game,
|
|
||||||
int num_players,
|
int num_players,
|
||||||
int input_size,
|
int input_size,
|
||||||
unsigned short local_port,
|
ENetPeer* host)
|
||||||
char *host_ip,
|
|
||||||
unsigned short host_port)
|
|
||||||
{
|
{
|
||||||
*session= new SpectatorBackend(cb,
|
*session = new SpectatorBackend(cb, num_players, input_size, host);
|
||||||
game,
|
return GGPO_OK;
|
||||||
local_port,
|
|
||||||
num_players,
|
|
||||||
input_size,
|
|
||||||
host_ip,
|
|
||||||
host_port);
|
|
||||||
return GGPO_OK;
|
|
||||||
}
|
}
|
||||||
|
|
1071
src/core/netplay.cpp
1071
src/core/netplay.cpp
File diff suppressed because it is too large
Load Diff
|
@ -78,8 +78,6 @@ SystemBootParameters::~SystemBootParameters() = default;
|
||||||
|
|
||||||
namespace System {
|
namespace System {
|
||||||
static std::optional<ExtendedSaveStateInfo> InternalGetExtendedSaveStateInfo(ByteStream* stream);
|
static std::optional<ExtendedSaveStateInfo> InternalGetExtendedSaveStateInfo(ByteStream* stream);
|
||||||
static bool InternalSaveState(ByteStream* state, u32 screenshot_size = 256,
|
|
||||||
u32 compression_method = SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE);
|
|
||||||
|
|
||||||
static bool LoadEXE(const char* filename);
|
static bool LoadEXE(const char* filename);
|
||||||
|
|
||||||
|
@ -95,7 +93,6 @@ static void InternalReset();
|
||||||
static void ClearRunningGame();
|
static void ClearRunningGame();
|
||||||
static void DestroySystem();
|
static void DestroySystem();
|
||||||
static std::string GetMediaPathFromSaveState(const char* path);
|
static std::string GetMediaPathFromSaveState(const char* path);
|
||||||
static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display);
|
|
||||||
static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state);
|
static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state);
|
||||||
static void WrappedRunFrame();
|
static void WrappedRunFrame();
|
||||||
static void RunFramesToNow();
|
static void RunFramesToNow();
|
||||||
|
@ -1019,7 +1016,7 @@ bool System::LoadState(const char* filename)
|
||||||
|
|
||||||
SaveUndoLoadState();
|
SaveUndoLoadState();
|
||||||
|
|
||||||
if (!DoLoadState(stream.get(), false, true))
|
if (!LoadStateFromStream(stream.get(), true))
|
||||||
{
|
{
|
||||||
Host::ReportFormattedErrorAsync(
|
Host::ReportFormattedErrorAsync(
|
||||||
"Load State Error", Host::TranslateString("OSDMessage", "Loading state from '%s' failed. Resetting."), filename);
|
"Load State Error", Host::TranslateString("OSDMessage", "Loading state from '%s' failed. Resetting."), filename);
|
||||||
|
@ -1057,7 +1054,7 @@ bool System::SaveState(const char* filename, bool backup_existing_save)
|
||||||
Log_InfoPrintf("Saving state to '%s'...", filename);
|
Log_InfoPrintf("Saving state to '%s'...", filename);
|
||||||
|
|
||||||
const u32 screenshot_size = 256;
|
const u32 screenshot_size = 256;
|
||||||
const bool result = InternalSaveState(stream.get(), screenshot_size,
|
const bool result = SaveStateToStream(stream.get(), screenshot_size,
|
||||||
g_settings.compress_save_states ? SAVE_STATE_HEADER::COMPRESSION_TYPE_ZSTD :
|
g_settings.compress_save_states ? SAVE_STATE_HEADER::COMPRESSION_TYPE_ZSTD :
|
||||||
SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE);
|
SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE);
|
||||||
if (!result)
|
if (!result)
|
||||||
|
@ -1312,7 +1309,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DoLoadState(stream.get(), false, true))
|
if (!LoadStateFromStream(stream.get(), true))
|
||||||
{
|
{
|
||||||
DestroySystem();
|
DestroySystem();
|
||||||
return false;
|
return false;
|
||||||
|
@ -1573,7 +1570,7 @@ void System::RecreateSystem()
|
||||||
|
|
||||||
const bool was_paused = System::IsPaused();
|
const bool was_paused = System::IsPaused();
|
||||||
std::unique_ptr<ByteStream> stream = ByteStream::CreateGrowableMemoryStream(nullptr, 8 * 1024);
|
std::unique_ptr<ByteStream> stream = ByteStream::CreateGrowableMemoryStream(nullptr, 8 * 1024);
|
||||||
if (!System::InternalSaveState(stream.get(), 0, SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE) || !stream->SeekAbsolute(0))
|
if (!System::SaveStateToStream(stream.get(), 0, SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE) || !stream->SeekAbsolute(0))
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("Error", "Failed to save state before system recreation. Shutting down.");
|
Host::ReportErrorAsync("Error", "Failed to save state before system recreation. Shutting down.");
|
||||||
DestroySystem();
|
DestroySystem();
|
||||||
|
@ -1589,7 +1586,7 @@ void System::RecreateSystem()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DoLoadState(stream.get(), false, false))
|
if (!LoadStateFromStream(stream.get(), false))
|
||||||
{
|
{
|
||||||
DestroySystem();
|
DestroySystem();
|
||||||
return;
|
return;
|
||||||
|
@ -1890,7 +1887,7 @@ std::string System::GetMediaPathFromSaveState(const char* path)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool update_display)
|
bool System::LoadStateFromStream(ByteStream* state, bool update_display)
|
||||||
{
|
{
|
||||||
Assert(IsValid());
|
Assert(IsValid());
|
||||||
|
|
||||||
|
@ -2043,7 +2040,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 */,
|
bool System::SaveStateToStream(ByteStream* state, u32 screenshot_size /* = 256 */,
|
||||||
u32 compression_method /* = SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE*/)
|
u32 compression_method /* = SAVE_STATE_HEADER::COMPRESSION_TYPE_NONE*/)
|
||||||
{
|
{
|
||||||
if (IsShutdown())
|
if (IsShutdown())
|
||||||
|
@ -3801,7 +3798,7 @@ bool System::UndoLoadState()
|
||||||
Assert(IsValid());
|
Assert(IsValid());
|
||||||
|
|
||||||
m_undo_load_state->SeekAbsolute(0);
|
m_undo_load_state->SeekAbsolute(0);
|
||||||
if (!DoLoadState(m_undo_load_state.get(), false, true))
|
if (!LoadStateFromStream(m_undo_load_state.get(), true))
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("Error", "Failed to load undo state, resetting system.");
|
Host::ReportErrorAsync("Error", "Failed to load undo state, resetting system.");
|
||||||
m_undo_load_state.reset();
|
m_undo_load_state.reset();
|
||||||
|
@ -3820,7 +3817,7 @@ bool System::SaveUndoLoadState()
|
||||||
m_undo_load_state.reset();
|
m_undo_load_state.reset();
|
||||||
|
|
||||||
m_undo_load_state = ByteStream::CreateGrowableMemoryStream(nullptr, System::MAX_SAVE_STATE_SIZE);
|
m_undo_load_state = ByteStream::CreateGrowableMemoryStream(nullptr, System::MAX_SAVE_STATE_SIZE);
|
||||||
if (!InternalSaveState(m_undo_load_state.get()))
|
if (!SaveStateToStream(m_undo_load_state.get()))
|
||||||
{
|
{
|
||||||
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "Failed to save undo load state."), 15.0f);
|
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "Failed to save undo load state."), 15.0f);
|
||||||
m_undo_load_state.reset();
|
m_undo_load_state.reset();
|
||||||
|
|
|
@ -235,6 +235,8 @@ struct MemorySaveState
|
||||||
};
|
};
|
||||||
bool SaveMemoryState(MemorySaveState* mss);
|
bool SaveMemoryState(MemorySaveState* mss);
|
||||||
bool LoadMemoryState(const MemorySaveState& mss);
|
bool LoadMemoryState(const MemorySaveState& mss);
|
||||||
|
bool LoadStateFromStream(ByteStream* stream, bool update_display);
|
||||||
|
bool SaveStateToStream(ByteStream* state, u32 screenshot_size = 256, u32 compression_method = 0);
|
||||||
|
|
||||||
/// Runs the VM until the CPU execution is canceled.
|
/// Runs the VM until the CPU execution is canceled.
|
||||||
void Execute();
|
void Execute();
|
||||||
|
|
Loading…
Reference in New Issue