mirror of https://github.com/mgba-emu/mgba.git
Qt: Add savestate load undo
This commit is contained in:
parent
5ed05dc66f
commit
f50f98416b
1
CHANGES
1
CHANGES
|
@ -24,6 +24,7 @@ Features:
|
||||||
- Preliminary support for yanking out the game pak while a game is running
|
- Preliminary support for yanking out the game pak while a game is running
|
||||||
- Thumb-drive mode by putting a file called portable.ini in the same folder
|
- Thumb-drive mode by putting a file called portable.ini in the same folder
|
||||||
- Configurable display driver, between software and OpenGL
|
- Configurable display driver, between software and OpenGL
|
||||||
|
- Undo-able savestate loading
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- ARM7: Fix SWI and IRQ timings
|
- ARM7: Fix SWI and IRQ timings
|
||||||
- GBA Audio: Force audio FIFOs to 32-bit
|
- GBA Audio: Force audio FIFOs to 32-bit
|
||||||
|
|
|
@ -51,6 +51,8 @@ GameController::GameController(QObject* parent)
|
||||||
, m_inputController(nullptr)
|
, m_inputController(nullptr)
|
||||||
, m_multiplayer(nullptr)
|
, m_multiplayer(nullptr)
|
||||||
, m_stateSlot(1)
|
, m_stateSlot(1)
|
||||||
|
, m_backupLoadState(nullptr)
|
||||||
|
, m_backupSaveState(nullptr)
|
||||||
{
|
{
|
||||||
m_renderer = new GBAVideoSoftwareRenderer;
|
m_renderer = new GBAVideoSoftwareRenderer;
|
||||||
GBAVideoSoftwareRendererCreate(m_renderer);
|
GBAVideoSoftwareRendererCreate(m_renderer);
|
||||||
|
@ -162,6 +164,7 @@ GameController::~GameController() {
|
||||||
GBACheatDeviceDestroy(&m_cheatDevice);
|
GBACheatDeviceDestroy(&m_cheatDevice);
|
||||||
delete m_renderer;
|
delete m_renderer;
|
||||||
delete[] m_drawContext;
|
delete[] m_drawContext;
|
||||||
|
delete m_backupLoadState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::setMultiplayerController(MultiplayerController* controller) {
|
void GameController::setMultiplayerController(MultiplayerController* controller) {
|
||||||
|
@ -561,6 +564,10 @@ void GameController::loadState(int slot) {
|
||||||
}
|
}
|
||||||
GBARunOnThread(&m_threadContext, [](GBAThread* context) {
|
GBARunOnThread(&m_threadContext, [](GBAThread* context) {
|
||||||
GameController* controller = static_cast<GameController*>(context->userData);
|
GameController* controller = static_cast<GameController*>(context->userData);
|
||||||
|
if (!controller->m_backupLoadState) {
|
||||||
|
controller->m_backupLoadState = new GBASerializedState;
|
||||||
|
}
|
||||||
|
GBASerialize(context->gba, controller->m_backupLoadState);
|
||||||
if (GBALoadState(context, context->stateDir, controller->m_stateSlot)) {
|
if (GBALoadState(context, context->stateDir, controller->m_stateSlot)) {
|
||||||
controller->frameAvailable(controller->m_drawContext);
|
controller->frameAvailable(controller->m_drawContext);
|
||||||
controller->stateLoaded(context);
|
controller->stateLoaded(context);
|
||||||
|
@ -578,6 +585,23 @@ void GameController::saveState(int slot) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameController::loadBackupState() {
|
||||||
|
if (!m_backupLoadState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBARunOnThread(&m_threadContext, [](GBAThread* context) {
|
||||||
|
GameController* controller = static_cast<GameController*>(context->userData);
|
||||||
|
if (GBADeserialize(context->gba, controller->m_backupLoadState)) {
|
||||||
|
GBALog(context->gba, GBA_LOG_STATUS, "Undid state load");
|
||||||
|
controller->frameAvailable(controller->m_drawContext);
|
||||||
|
controller->stateLoaded(context);
|
||||||
|
}
|
||||||
|
delete controller->m_backupLoadState;
|
||||||
|
controller->m_backupLoadState = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void GameController::setVideoSync(bool set) {
|
void GameController::setVideoSync(bool set) {
|
||||||
m_videoSync = set;
|
m_videoSync = set;
|
||||||
if (!m_turbo) {
|
if (!m_turbo) {
|
||||||
|
|
|
@ -120,6 +120,7 @@ public slots:
|
||||||
void setFPSTarget(float fps);
|
void setFPSTarget(float fps);
|
||||||
void loadState(int slot = 0);
|
void loadState(int slot = 0);
|
||||||
void saveState(int slot = 0);
|
void saveState(int slot = 0);
|
||||||
|
void loadBackupState();
|
||||||
void setVideoSync(bool);
|
void setVideoSync(bool);
|
||||||
void setAudioSync(bool);
|
void setAudioSync(bool);
|
||||||
void setFrameskip(int);
|
void setFrameskip(int);
|
||||||
|
@ -192,6 +193,8 @@ private:
|
||||||
bool m_wasPaused;
|
bool m_wasPaused;
|
||||||
|
|
||||||
int m_stateSlot;
|
int m_stateSlot;
|
||||||
|
GBASerializedState* m_backupLoadState;
|
||||||
|
GBASerializedState* m_backupSaveState; // TODO: Use this
|
||||||
|
|
||||||
InputController* m_inputController;
|
InputController* m_inputController;
|
||||||
MultiplayerController* m_multiplayer;
|
MultiplayerController* m_multiplayer;
|
||||||
|
|
|
@ -697,6 +697,14 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
m_gameActions.append(quickSave);
|
m_gameActions.append(quickSave);
|
||||||
addControlledAction(quickSaveMenu, quickSave, "quickSave");
|
addControlledAction(quickSaveMenu, quickSave, "quickSave");
|
||||||
|
|
||||||
|
quickLoadMenu->addSeparator();
|
||||||
|
|
||||||
|
QAction* undoLoadState = new QAction(tr("Undo load state"), quickLoadMenu);
|
||||||
|
undoLoadState->setShortcut(tr("F11"));
|
||||||
|
connect(undoLoadState, SIGNAL(triggered()), m_controller, SLOT(loadBackupState()));
|
||||||
|
m_gameActions.append(undoLoadState);
|
||||||
|
addControlledAction(quickLoadMenu, undoLoadState, "undoLoadState");
|
||||||
|
|
||||||
quickLoadMenu->addSeparator();
|
quickLoadMenu->addSeparator();
|
||||||
quickSaveMenu->addSeparator();
|
quickSaveMenu->addSeparator();
|
||||||
|
|
||||||
|
@ -961,14 +969,12 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
|
|
||||||
#ifdef USE_FFMPEG
|
#ifdef USE_FFMPEG
|
||||||
QAction* recordOutput = new QAction(tr("Record output..."), avMenu);
|
QAction* recordOutput = new QAction(tr("Record output..."), avMenu);
|
||||||
recordOutput->setShortcut(tr("F11"));
|
|
||||||
connect(recordOutput, SIGNAL(triggered()), this, SLOT(openVideoWindow()));
|
connect(recordOutput, SIGNAL(triggered()), this, SLOT(openVideoWindow()));
|
||||||
addControlledAction(avMenu, recordOutput, "recordOutput");
|
addControlledAction(avMenu, recordOutput, "recordOutput");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MAGICK
|
#ifdef USE_MAGICK
|
||||||
QAction* recordGIF = new QAction(tr("Record GIF..."), avMenu);
|
QAction* recordGIF = new QAction(tr("Record GIF..."), avMenu);
|
||||||
recordGIF->setShortcut(tr("Shift+F11"));
|
|
||||||
connect(recordGIF, SIGNAL(triggered()), this, SLOT(openGIFWindow()));
|
connect(recordGIF, SIGNAL(triggered()), this, SLOT(openGIFWindow()));
|
||||||
addControlledAction(avMenu, recordGIF, "recordGIF");
|
addControlledAction(avMenu, recordGIF, "recordGIF");
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue