mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 18:45:31 +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
|
||||
statemanagerimp
|
||||
statemanagerimp charactermanager character
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||
inputmanager windowmanager
|
||||
inputmanager windowmanager statemanager
|
||||
)
|
||||
|
||||
# Main executable
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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 <components/esm/esmwriter.hpp>
|
||||
|
||||
#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();
|
||||
}
|
|
@ -3,16 +3,21 @@
|
|||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#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.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue