From 5e64888227f3f8e6a7796cf74ce70ac268bed5ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 15:38:26 +0100 Subject: [PATCH] added basic save slot management and connected main menu save to save function (bypassing the save GUI for now) --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/statemanager.hpp | 14 ++++ apps/openmw/mwgui/mainmenu.cpp | 7 +- apps/openmw/mwstate/character.cpp | 101 +++++++++++++++++++++++ apps/openmw/mwstate/character.hpp | 45 ++++++++++ apps/openmw/mwstate/charactermanager.cpp | 57 +++++++++++++ apps/openmw/mwstate/charactermanager.hpp | 37 +++++++++ apps/openmw/mwstate/statemanagerimp.cpp | 31 ++++++- apps/openmw/mwstate/statemanagerimp.hpp | 15 +++- 10 files changed, 304 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwstate/character.cpp create mode 100644 apps/openmw/mwstate/character.hpp create mode 100644 apps/openmw/mwstate/charactermanager.cpp create mode 100644 apps/openmw/mwstate/charactermanager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0358b96d1..2b078a7ff 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,12 +73,12 @@ add_openmw_dir (mwmechanics ) add_openmw_dir (mwstate - statemanagerimp + statemanagerimp charactermanager character ) add_openmw_dir (mwbase environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager - inputmanager windowmanager + inputmanager windowmanager statemanager ) # Main executable diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4de198b64..cda068347 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -323,7 +323,7 @@ std::string OMW::Engine::loadSettings (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; diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 74fcc3f7a..b341fbb03 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -1,6 +1,12 @@ #ifndef GAME_MWSTATE_STATEMANAGER_H #define GAME_MWSTATE_STATEMANAGER_H +namespace MWState +{ + struct Slot; + class Character; +} + namespace MWBase { /// \brief Interface for game state manager (implemented in MWState) @@ -41,6 +47,14 @@ namespace MWBase /// \param bypass Skip new game mechanics. 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. }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d4a4e74ba..f25b72d37 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -61,9 +61,10 @@ namespace MWGui } else if (sender == mButtons["savegame"]) { - MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); - dialog->setLoadOrSave(false); - dialog->setVisible(true); + MWBase::Environment::get().getStateManager()->saveGame (0); +// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); +// dialog->setLoadOrSave(false); +// dialog->setVisible(true); } } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp new file mode 100644 index 000000000..dc16085d8 --- /dev/null +++ b/apps/openmw/mwstate/character.cpp @@ -0,0 +1,101 @@ + +#include "character.hpp" + +#include + +#include +#include +#include + +#include + +bool MWState::operator< (const Slot& left, const Slot& right) +{ + return left.mTimeStamp> 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 (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(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp new file mode 100644 index 000000000..30182e404 --- /dev/null +++ b/apps/openmw/mwstate/character.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_STATE_CHARACTER_H +#define GAME_STATE_CHARACTER_H + +#include + +#include + +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 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 diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp new file mode 100644 index 000000000..c73adb5bb --- /dev/null +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -0,0 +1,57 @@ + +#include "charactermanager.hpp" + +#include +#include + +#include + +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(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp new file mode 100644 index 000000000..a3fe17131 --- /dev/null +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_STATE_CHARACTERMANAGER_H +#define GAME_STATE_CHARACTERMANAGER_H + +#include + +#include "character.hpp" + +namespace MWState +{ + class CharacterManager + { + boost::filesystem::path mPath; + int mNext; + std::vector 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 diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 66a44872c..f068093a0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,14 +1,16 @@ #include "statemanagerimp.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" -MWState::StateManager::StateManager() -: mQuitRequest (false), mState (State_NoGame) +MWState::StateManager::StateManager (const boost::filesystem::path& saves) +: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves) { } @@ -44,6 +46,8 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); } + mCharacterManager.createCharacter(); + mState = State_Running; } @@ -51,3 +55,26 @@ void MWState::StateManager::endGame() { 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(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 007a9b136..9dfcc4d8f 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -3,16 +3,21 @@ #include "../mwbase/statemanager.hpp" +#include + +#include "charactermanager.hpp" + namespace MWState { class StateManager : public MWBase::StateManager { bool mQuitRequest; State mState; + CharacterManager mCharacterManager; public: - StateManager(); + StateManager (const boost::filesystem::path& saves); virtual void requestQuit(); @@ -26,6 +31,14 @@ namespace MWState /// \param bypass Skip new game mechanics. 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. }; }