mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-24 22:09:42 +00:00
added basic save slot management and connected main menu save to save function (bypassing the save GUI for now)
This commit is contained in:
parent
4c61deca8d
commit
5e64888227
10 changed files with 304 additions and 9 deletions
|
@ -73,12 +73,12 @@ add_openmw_dir (mwmechanics
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
statemanagerimp
|
statemanagerimp charactermanager character
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||||
inputmanager windowmanager
|
inputmanager windowmanager statemanager
|
||||||
)
|
)
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
|
|
|
@ -323,7 +323,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||||
|
|
||||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
{
|
{
|
||||||
mEnvironment.setStateManager (new MWState::StateManager);
|
mEnvironment.setStateManager (new MWState::StateManager (mCfgMgr.getUserPath() / "saves"));
|
||||||
|
|
||||||
Nif::NIFFile::CacheLock cachelock;
|
Nif::NIFFile::CacheLock cachelock;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#ifndef GAME_MWSTATE_STATEMANAGER_H
|
#ifndef GAME_MWSTATE_STATEMANAGER_H
|
||||||
#define GAME_MWSTATE_STATEMANAGER_H
|
#define GAME_MWSTATE_STATEMANAGER_H
|
||||||
|
|
||||||
|
namespace MWState
|
||||||
|
{
|
||||||
|
struct Slot;
|
||||||
|
class Character;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
{
|
{
|
||||||
/// \brief Interface for game state manager (implemented in MWState)
|
/// \brief Interface for game state manager (implemented in MWState)
|
||||||
|
@ -41,6 +47,14 @@ namespace MWBase
|
||||||
/// \param bypass Skip new game mechanics.
|
/// \param bypass Skip new game mechanics.
|
||||||
|
|
||||||
virtual void endGame() = 0;
|
virtual void endGame() = 0;
|
||||||
|
|
||||||
|
virtual void saveGame (const MWState::Slot *slot = 0) = 0;
|
||||||
|
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||||
|
///
|
||||||
|
/// \note Slot must belong to the current character.
|
||||||
|
|
||||||
|
virtual MWState::Character *getCurrentCharacter() = 0;
|
||||||
|
///< Must not be called, if there is no current character.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,10 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
else if (sender == mButtons["savegame"])
|
else if (sender == mButtons["savegame"])
|
||||||
{
|
{
|
||||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
MWBase::Environment::get().getStateManager()->saveGame (0);
|
||||||
dialog->setLoadOrSave(false);
|
// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||||
dialog->setVisible(true);
|
// dialog->setLoadOrSave(false);
|
||||||
|
// dialog->setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
101
apps/openmw/mwstate/character.cpp
Normal file
101
apps/openmw/mwstate/character.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
#include "character.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
bool MWState::operator< (const Slot& left, const Slot& right)
|
||||||
|
{
|
||||||
|
return left.mTimeStamp<right.mTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MWState::Character::addSlot (const boost::filesystem::path& path)
|
||||||
|
{
|
||||||
|
Slot slot;
|
||||||
|
slot.mPath = path;
|
||||||
|
slot.mTimeStamp = boost::filesystem::last_write_time (path);
|
||||||
|
|
||||||
|
/// \todo load profile
|
||||||
|
|
||||||
|
mSlots.push_back (slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWState::Character::addSlot (const ESM::SavedGame& profile)
|
||||||
|
{
|
||||||
|
Slot slot;
|
||||||
|
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << mNext++;
|
||||||
|
|
||||||
|
slot.mPath = mPath / stream.str();
|
||||||
|
slot.mProfile = profile;
|
||||||
|
slot.mTimeStamp = std::time (0);
|
||||||
|
|
||||||
|
mSlots.push_back (slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWState::Character::Character (const boost::filesystem::path& saves)
|
||||||
|
: mPath (saves), mNext (0)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::is_directory (mPath))
|
||||||
|
{
|
||||||
|
boost::filesystem::create_directories (mPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (boost::filesystem::directory_iterator iter (mPath);
|
||||||
|
iter!=boost::filesystem::directory_iterator(); ++iter)
|
||||||
|
{
|
||||||
|
boost::filesystem::path slotPath = *iter;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
addSlot (slotPath);
|
||||||
|
}
|
||||||
|
catch (...) {} // ignoring bad saved game files for now
|
||||||
|
|
||||||
|
std::istringstream stream (slotPath.filename().string());
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if ((stream >> index) && index>=mNext)
|
||||||
|
mNext = index+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort (mSlots.begin(), mSlots.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profile)
|
||||||
|
{
|
||||||
|
addSlot (profile);
|
||||||
|
|
||||||
|
return &mSlots.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM::SavedGame& profile)
|
||||||
|
{
|
||||||
|
int index = slot - &mSlots[0];
|
||||||
|
|
||||||
|
if (index<0 || index>=static_cast<int> (mSlots.size()))
|
||||||
|
{
|
||||||
|
// sanity check; not entirely reliable
|
||||||
|
throw std::logic_error ("slot not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot newSlot = *slot;
|
||||||
|
newSlot.mProfile = profile;
|
||||||
|
newSlot.mTimeStamp = std::time (0);
|
||||||
|
|
||||||
|
mSlots.erase (mSlots.begin()+index);
|
||||||
|
|
||||||
|
mSlots.push_back (newSlot);
|
||||||
|
|
||||||
|
return &mSlots.back();
|
||||||
|
}
|
45
apps/openmw/mwstate/character.hpp
Normal file
45
apps/openmw/mwstate/character.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef GAME_STATE_CHARACTER_H
|
||||||
|
#define GAME_STATE_CHARACTER_H
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/savedgame.hpp>
|
||||||
|
|
||||||
|
namespace MWState
|
||||||
|
{
|
||||||
|
struct Slot
|
||||||
|
{
|
||||||
|
boost::filesystem::path mPath;
|
||||||
|
ESM::SavedGame mProfile;
|
||||||
|
std::time_t mTimeStamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator< (const Slot& left, const Slot& right);
|
||||||
|
|
||||||
|
class Character
|
||||||
|
{
|
||||||
|
boost::filesystem::path mPath;
|
||||||
|
std::vector<Slot> mSlots;
|
||||||
|
int mNext;
|
||||||
|
|
||||||
|
void addSlot (const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
void addSlot (const ESM::SavedGame& profile);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Character (const boost::filesystem::path& saves);
|
||||||
|
|
||||||
|
const Slot *createSlot (const ESM::SavedGame& profile);
|
||||||
|
///< Create new slot.
|
||||||
|
///
|
||||||
|
/// \attention The ownership of the slot is not transferred.
|
||||||
|
|
||||||
|
const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile);
|
||||||
|
/// \note Slot must belong to this character.
|
||||||
|
///
|
||||||
|
/// \attention The \æ slot pointer will be invalidated by this call.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
57
apps/openmw/mwstate/charactermanager.cpp
Normal file
57
apps/openmw/mwstate/charactermanager.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
#include "charactermanager.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves)
|
||||||
|
: mPath (saves), mNext (0), mCurrent (0)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::is_directory (mPath))
|
||||||
|
{
|
||||||
|
boost::filesystem::create_directories (mPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (boost::filesystem::directory_iterator iter (mPath);
|
||||||
|
iter!=boost::filesystem::directory_iterator(); ++iter)
|
||||||
|
{
|
||||||
|
boost::filesystem::path characterDir = *iter;
|
||||||
|
|
||||||
|
if (boost::filesystem::is_directory (characterDir))
|
||||||
|
{
|
||||||
|
Character character (characterDir);
|
||||||
|
mCharacters.push_back (character);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream stream (characterDir.filename().string());
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if ((stream >> index) && index>=mNext)
|
||||||
|
mNext = index+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWState::Character *MWState::CharacterManager::getCurrentCharacter()
|
||||||
|
{
|
||||||
|
if (!mCurrent)
|
||||||
|
throw std::logic_error ("no character selected");
|
||||||
|
|
||||||
|
return mCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWState::CharacterManager::createCharacter()
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << mNext++;
|
||||||
|
|
||||||
|
boost::filesystem::path path = mPath / stream.str();
|
||||||
|
|
||||||
|
mCharacters.push_back (Character (path));
|
||||||
|
|
||||||
|
mCurrent = &mCharacters.back();
|
||||||
|
}
|
37
apps/openmw/mwstate/charactermanager.hpp
Normal file
37
apps/openmw/mwstate/charactermanager.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef GAME_STATE_CHARACTERMANAGER_H
|
||||||
|
#define GAME_STATE_CHARACTERMANAGER_H
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
#include "character.hpp"
|
||||||
|
|
||||||
|
namespace MWState
|
||||||
|
{
|
||||||
|
class CharacterManager
|
||||||
|
{
|
||||||
|
boost::filesystem::path mPath;
|
||||||
|
int mNext;
|
||||||
|
std::vector<Character> mCharacters;
|
||||||
|
Character *mCurrent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
CharacterManager (const CharacterManager&);
|
||||||
|
///< Not implemented
|
||||||
|
|
||||||
|
CharacterManager& operator= (const CharacterManager&);
|
||||||
|
///< Not implemented
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CharacterManager (const boost::filesystem::path& saves);
|
||||||
|
|
||||||
|
Character *getCurrentCharacter();
|
||||||
|
///< Must not be called, if there is no current character.
|
||||||
|
|
||||||
|
void createCharacter();
|
||||||
|
///< Create new character within saved game management
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,14 +1,16 @@
|
||||||
|
|
||||||
#include "statemanagerimp.hpp"
|
#include "statemanagerimp.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/journal.hpp"
|
#include "../mwbase/journal.hpp"
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
MWState::StateManager::StateManager()
|
MWState::StateManager::StateManager (const boost::filesystem::path& saves)
|
||||||
: mQuitRequest (false), mState (State_NoGame)
|
: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,6 +46,8 @@ void MWState::StateManager::newGame (bool bypass)
|
||||||
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mCharacterManager.createCharacter();
|
||||||
|
|
||||||
mState = State_Running;
|
mState = State_Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,3 +55,26 @@ void MWState::StateManager::endGame()
|
||||||
{
|
{
|
||||||
mState = State_Ended;
|
mState = State_Ended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWState::StateManager::saveGame (const Slot *slot)
|
||||||
|
{
|
||||||
|
ESM::SavedGame profile;
|
||||||
|
|
||||||
|
/// \todo configure profile
|
||||||
|
|
||||||
|
if (!slot)
|
||||||
|
slot = mCharacterManager.getCurrentCharacter()->createSlot (profile);
|
||||||
|
else
|
||||||
|
slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);
|
||||||
|
|
||||||
|
ESM::ESMWriter writer;
|
||||||
|
// writer.setFormat ();
|
||||||
|
writer.save (slot->mPath.string());
|
||||||
|
slot->mProfile.save (writer);
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWState::Character *MWState::StateManager::getCurrentCharacter()
|
||||||
|
{
|
||||||
|
return mCharacterManager.getCurrentCharacter();
|
||||||
|
}
|
|
@ -3,16 +3,21 @@
|
||||||
|
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
#include "charactermanager.hpp"
|
||||||
|
|
||||||
namespace MWState
|
namespace MWState
|
||||||
{
|
{
|
||||||
class StateManager : public MWBase::StateManager
|
class StateManager : public MWBase::StateManager
|
||||||
{
|
{
|
||||||
bool mQuitRequest;
|
bool mQuitRequest;
|
||||||
State mState;
|
State mState;
|
||||||
|
CharacterManager mCharacterManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StateManager();
|
StateManager (const boost::filesystem::path& saves);
|
||||||
|
|
||||||
virtual void requestQuit();
|
virtual void requestQuit();
|
||||||
|
|
||||||
|
@ -26,6 +31,14 @@ namespace MWState
|
||||||
/// \param bypass Skip new game mechanics.
|
/// \param bypass Skip new game mechanics.
|
||||||
|
|
||||||
virtual void endGame();
|
virtual void endGame();
|
||||||
|
|
||||||
|
virtual void saveGame (const Slot *slot = 0);
|
||||||
|
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||||
|
///
|
||||||
|
/// \note Slot must belong to the current character.
|
||||||
|
|
||||||
|
virtual Character *getCurrentCharacter();
|
||||||
|
///< Must not be called, if there is no current character.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue