stella/src/emucore/StateManager.cxx

354 lines
9.4 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <sstream>
#include "OSystem.hxx"
#include "Settings.hxx"
#include "Console.hxx"
#include "Cart.hxx"
#include "Control.hxx"
#include "Switches.hxx"
#include "System.hxx"
#include "Serializable.hxx"
#include "StateManager.hxx"
#define STATE_HEADER "03090100state"
#define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StateManager::StateManager(OSystem& osystem)
: myOSystem(osystem),
myCurrentSlot(0),
myActiveMode(kOffMode)
{
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRecordMode()
{
#if 0
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
{
myActiveMode = kOffMode;
string moviefile = /*myOSystem.baseDir() +*/ "test.inp";
if(myMovieWriter.isOpen())
myMovieWriter.close();
if(!myMovieWriter.open(moviefile))
return false;
// Prepend the ROM md5 so this state file only works with that ROM
myMovieWriter.putString(myOSystem.console().properties().get(Cartridge_MD5));
if(!myOSystem.console().save(myMovieWriter))
return false;
// Save controller types for this ROM
// We need to check this, since some controllers save more state than
// normal, and those states files wouldn't be compatible with normal
// controllers.
myMovieWriter.putString(
myOSystem.console().controller(Controller::Left).name());
myMovieWriter.putString(
myOSystem.console().controller(Controller::Right).name());
// If we get this far, we're really in movie record mode
myActiveMode = kMovieRecordMode;
}
else // Turn off movie record mode
{
myActiveMode = kOffMode;
myMovieWriter.close();
return false;
}
return myActiveMode == kMovieRecordMode;
#endif
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRewindMode()
{
// FIXME - For now, I'm going to use this to activate movie playback
#if 0
// Close the writer, since we're about to re-open in read mode
myMovieWriter.close();
if(myActiveMode != kMoviePlaybackMode) // Turn on movie playback mode
{
myActiveMode = kOffMode;
string moviefile = /*myOSystem.baseDir() + */ "test.inp";
if(myMovieReader.isOpen())
myMovieReader.close();
if(!myMovieReader.open(moviefile))
return false;
// Check the ROM md5
if(myMovieReader.getString() !=
myOSystem.console().properties().get(Cartridge_MD5))
return false;
if(!myOSystem.console().load(myMovieReader))
return false;
// Check controller types
const string& left = myMovieReader.getString();
const string& right = myMovieReader.getString();
if(left != myOSystem.console().controller(Controller::Left).name() ||
right != myOSystem.console().controller(Controller::Right).name())
return false;
// If we get this far, we're really in movie record mode
myActiveMode = kMoviePlaybackMode;
}
else // Turn off movie playback mode
{
myActiveMode = kOffMode;
myMovieReader.close();
return false;
}
return myActiveMode == kMoviePlaybackMode;
#endif
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::update()
{
#if 0
switch(myActiveMode)
{
case kMovieRecordMode:
myOSystem.console().controller(Controller::Left).save(myMovieWriter);
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
myOSystem.console().switches().save(myMovieWriter);
break;
case kMoviePlaybackMode:
myOSystem.console().controller(Controller::Left).load(myMovieReader);
myOSystem.console().controller(Controller::Right).load(myMovieReader);
myOSystem.console().switches().load(myMovieReader);
break;
default:
break;
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::loadState(int slot)
{
if(myOSystem.hasConsole())
{
if(slot < 0) slot = myCurrentSlot;
ostringstream buf;
buf << myOSystem.stateDir()
<< myOSystem.console().properties().get(Cartridge_Name)
<< ".st" << slot;
// Make sure the file can be opened in read-only mode
Serializer in(buf.str(), true);
if(!in)
{
buf.str("");
buf << "Can't open/load from state file " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
return;
}
// First test if we have a valid header
// If so, do a complete state load using the Console
buf.str("");
try
{
if(in.getString() != STATE_HEADER)
buf << "Incompatible state " << slot << " file";
else if(in.getString() != myOSystem.console().cartridge().name())
buf << "State " << slot << " file doesn't match current ROM";
else
{
if(myOSystem.console().load(in))
buf << "State " << slot << " loaded";
else
buf << "Invalid data in state " << slot << " file";
}
}
catch(...)
{
buf << "Invalid data in state " << slot << " file";
}
myOSystem.frameBuffer().showMessage(buf.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::saveState(int slot)
{
if(myOSystem.hasConsole())
{
if(slot < 0) slot = myCurrentSlot;
ostringstream buf;
buf << myOSystem.stateDir()
<< myOSystem.console().properties().get(Cartridge_Name)
<< ".st" << slot;
// Make sure the file can be opened for writing
Serializer out(buf.str());
if(!out)
{
buf.str("");
buf << "Can't open/save to state file " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
return;
}
try
{
// Add header so that if the state format changes in the future,
// we'll know right away, without having to parse the rest of the file
out.putString(STATE_HEADER);
// Sanity check; prepend the cart type/name
out.putString(myOSystem.console().cartridge().name());
}
catch(...)
{
buf << "Error saving state " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
return;
}
// Do a complete state save using the Console
buf.str("");
if(myOSystem.console().save(out))
{
buf << "State " << slot << " saved";
if(myOSystem.settings().getBool("autoslot"))
{
myCurrentSlot = (slot + 1) % 10;
buf << ", switching to slot " << slot;
}
}
else
buf << "Error saving state " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::changeState()
{
myCurrentSlot = (myCurrentSlot + 1) % 10;
// Print appropriate message
ostringstream buf;
buf << "Changed to slot " << myCurrentSlot;
myOSystem.frameBuffer().showMessage(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::loadState(Serializer& in)
{
try
{
if(myOSystem.hasConsole())
{
// Make sure the file can be opened for reading
if(in)
{
// First test if we have a valid header and cart type
// If so, do a complete state load using the Console
return in.getString() == STATE_HEADER &&
in.getString() == myOSystem.console().cartridge().name() &&
myOSystem.console().load(in);
}
}
}
catch(...)
{
cerr << "ERROR: StateManager::loadState(Serializer&)" << endl;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::saveState(Serializer& out)
{
try
{
if(myOSystem.hasConsole())
{
// Make sure the file can be opened for writing
if(out)
{
// Add header so that if the state format changes in the future,
// we'll know right away, without having to parse the rest of the file
out.putString(STATE_HEADER);
// Sanity check; prepend the cart type/name
out.putString(myOSystem.console().cartridge().name());
// Do a complete state save using the Console
if(myOSystem.console().save(out))
return true;
}
}
}
catch(...)
{
cerr << "ERROR: StateManager::saveState(Serializer&)" << endl;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::reset()
{
#if 0
myCurrentSlot = 0;
switch(myActiveMode)
{
case kMovieRecordMode:
myMovieWriter.close();
break;
case kMoviePlaybackMode:
myMovieReader.close();
break;
default:
break;
}
myActiveMode = kOffMode;
#endif
}