First pass at continuous state saving in emulation mode, accessible by the debugger:

- Toggle this with Alt-r.  When enabled, state is saved each frame to memory (up to 100 slots)
- Upon entering the debugger, rewind is immediately available, allowing to rewind (for example) back past a breakpoint
- Testing is definitely required.
This commit is contained in:
Stephen Anthony 2017-09-18 20:29:52 -02:30
parent 628f981121
commit aed2945a56
5 changed files with 69 additions and 60 deletions

View File

@ -44,7 +44,7 @@ class RewindManager
@param message Message to display when rewinding to this state
*/
bool addState(const string& message = "");
bool addState(const string& message);
/**
Rewind one level of the state list, and display the message associated

View File

@ -35,16 +35,16 @@
StateManager::StateManager(OSystem& osystem)
: myOSystem(osystem),
myCurrentSlot(0),
myActiveMode(kOffMode)
myActiveMode(Mode::Off)
{
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRecordMode()
{
#if 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::toggleRecordMode()
{
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
{
myActiveMode = kOffMode;
@ -81,15 +81,8 @@ bool StateManager::toggleRecordMode()
}
return myActiveMode == kMovieRecordMode;
#endif
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRewindMode()
{
// FIXME - For now, I'm going to use this to activate movie playback
#if 0
////////////////////////////////////////////////////////
// FIXME - For now, I'm going to use this to activate movie playback
// Close the writer, since we're about to re-open in read mode
myMovieWriter.close();
@ -128,34 +121,44 @@ bool StateManager::toggleRewindMode()
myMovieReader.close();
return false;
}
return myActiveMode == kMoviePlaybackMode;
}
#endif
return false;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::toggleRewindMode()
{
myActiveMode = myActiveMode == Mode::Rewind ? Mode::Off : Mode::Rewind;
if(myActiveMode == Mode::Rewind)
myOSystem.frameBuffer().showMessage("Continuous rewind enabled");
else
myOSystem.frameBuffer().showMessage("Continuous rewind disabled");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::update()
{
#if 0
switch(myActiveMode)
{
case kMovieRecordMode:
case Mode::Rewind:
myRewindManager->addState("1 frame");
break;
#if 0
case Mode::MovieRecord:
myOSystem.console().controller(Controller::Left).save(myMovieWriter);
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
myOSystem.console().switches().save(myMovieWriter);
break;
case kMoviePlaybackMode:
case Mode::MoviePlayback:
myOSystem.console().controller(Controller::Left).load(myMovieReader);
myOSystem.console().controller(Controller::Right).load(myMovieReader);
myOSystem.console().switches().load(myMovieReader);
break;
#endif
default:
break;
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -33,41 +33,58 @@ class OSystem;
class StateManager
{
public:
enum class Mode {
Off,
Rewind,
MovieRecord,
MoviePlayback
};
/**
Create a new statemananger class
Create a new statemananger class.
*/
StateManager(OSystem& osystem);
public:
/**
Answers whether the manager is in record or playback mode
Answers whether the manager is in record or playback mode.
*/
bool isActive() const { return myActiveMode != kOffMode; }
Mode mode() const { return myActiveMode; }
bool toggleRecordMode();
bool toggleRewindMode();
#if 0
/**
Toggle movie recording mode (FIXME - currently disabled)
*/
void toggleRecordMode();
#endif
/**
Updates the state of the system based on the currently active mode
Toggle state rewind recording mode; this uses the RewindManager
for its functionality.
*/
void toggleRewindMode();
/**
Updates the state of the system based on the currently active mode.
*/
void update();
/**
Load a state into the current system
Load a state into the current system.
@param slot The state 'slot' to load state from
*/
void loadState(int slot = -1);
/**
Save the current state from the system
Save the current state from the system.
@param slot The state 'slot' to save into
*/
void saveState(int slot = -1);
/**
Switches to the next higher state slot (circular queue style)
Switches to the next higher state slot (circular queue style).
*/
void changeState();
@ -92,7 +109,7 @@ class StateManager
bool saveState(Serializer& out);
/**
Resets manager to defaults
Resets manager to defaults.
*/
void reset();
@ -102,14 +119,6 @@ class StateManager
RewindManager& rewindManager() const { return *myRewindManager; }
private:
enum Mode {
kOffMode,
kMoviePlaybackMode,
kMovieRecordMode,
kRewindPlaybackMode,
kRewindRecordMode
};
enum {
kVersion = 001
};

View File

@ -505,12 +505,12 @@ void Debugger::setStartState()
// If rewinding is not enabled, always start the debugger with a clean list
RewindManager& r = myOSystem.state().rewindManager();
if(0) // FIXME
if(myOSystem.state().mode() == StateManager::Mode::Off)
r.clear();
myDialog->rewindButton().setEnabled(!r.empty());
// Save initial state, but don't add it to the rewind list
saveOldState(); // FIXME - rework this
saveOldState();
// Set the 're-disassemble' flag, but don't do it until the next scheduled time
myDialog->rom().invalidate(false);

View File

@ -197,27 +197,20 @@ void EventHandler::poll(uInt64 time)
{
myOSystem.console().riot().update();
#if 0
// Now check if the StateManager should be saving or loading state
// Per-frame cheats are disabled if the StateManager is active, since
// it would interfere with proper playback
if(myOSystem.state().isActive())
{
// (for rewind and/or movies
if(myOSystem.state().mode() != StateManager::Mode::Off)
myOSystem.state().update();
}
else
#endif
{
#ifdef CHEATCODE_SUPPORT
for(auto& cheat: myOSystem.cheat().perFrame())
cheat->evaluate();
#endif
// Handle continuous snapshots
if(myContSnapshotInterval > 0 &&
(++myContSnapshotCounter % myContSnapshotInterval == 0))
takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
}
#ifdef CHEATCODE_SUPPORT
for(auto& cheat: myOSystem.cheat().perFrame())
cheat->evaluate();
#endif
// Handle continuous snapshots
if(myContSnapshotInterval > 0 &&
(++myContSnapshotCounter % myContSnapshotInterval == 0))
takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
}
else if(myOverlay)
{
@ -441,6 +434,10 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
myOSystem.frameBuffer().toggleFrameStats();
break;
case KBDK_R: // Alt-r toggles continuous store rewind states
myOSystem.state().toggleRewindMode();
break;
case KBDK_S:
if(myContSnapshotInterval == 0)
{