mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-13 14:09:41 +00:00
store cell state in saved game files (no references yet)
This commit is contained in:
parent
9ebe66e693
commit
22cb4784b5
11 changed files with 261 additions and 67 deletions
|
@ -24,9 +24,9 @@
|
|||
|
||||
#include "../mwscript/globalscripts.hpp"
|
||||
|
||||
void MWState::StateManager::cleanup()
|
||||
void MWState::StateManager::cleanup (bool force)
|
||||
{
|
||||
if (mState!=State_NoGame)
|
||||
if (mState!=State_NoGame || force)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->clear();
|
||||
MWBase::Environment::get().getDialogueManager()->clear();
|
||||
|
@ -184,77 +184,86 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
|
||||
void MWState::StateManager::loadGame (const Character *character, const Slot *slot)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
mTimePlayed = slot->mProfile.mTimePlayed;
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.open (slot->mPath.string());
|
||||
|
||||
while (reader.hasMoreRecs())
|
||||
try
|
||||
{
|
||||
ESM::NAME n = reader.getRecName();
|
||||
reader.getRecHeader();
|
||||
cleanup();
|
||||
|
||||
switch (n.val)
|
||||
mTimePlayed = slot->mProfile.mTimePlayed;
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.open (slot->mPath.string());
|
||||
|
||||
while (reader.hasMoreRecs())
|
||||
{
|
||||
case ESM::REC_SAVE:
|
||||
ESM::NAME n = reader.getRecName();
|
||||
reader.getRecHeader();
|
||||
|
||||
// don't need to read that here
|
||||
reader.skipRecord();
|
||||
break;
|
||||
switch (n.val)
|
||||
{
|
||||
case ESM::REC_SAVE:
|
||||
|
||||
case ESM::REC_JOUR:
|
||||
case ESM::REC_QUES:
|
||||
// don't need to read that here
|
||||
reader.skipRecord();
|
||||
break;
|
||||
|
||||
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
|
||||
break;
|
||||
case ESM::REC_JOUR:
|
||||
case ESM::REC_QUES:
|
||||
|
||||
case ESM::REC_ALCH:
|
||||
case ESM::REC_ARMO:
|
||||
case ESM::REC_BOOK:
|
||||
case ESM::REC_CLAS:
|
||||
case ESM::REC_CLOT:
|
||||
case ESM::REC_ENCH:
|
||||
case ESM::REC_NPC_:
|
||||
case ESM::REC_SPEL:
|
||||
case ESM::REC_WEAP:
|
||||
case ESM::REC_GLOB:
|
||||
case ESM::REC_PLAY:
|
||||
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val);
|
||||
break;
|
||||
case ESM::REC_ALCH:
|
||||
case ESM::REC_ARMO:
|
||||
case ESM::REC_BOOK:
|
||||
case ESM::REC_CLAS:
|
||||
case ESM::REC_CLOT:
|
||||
case ESM::REC_ENCH:
|
||||
case ESM::REC_NPC_:
|
||||
case ESM::REC_SPEL:
|
||||
case ESM::REC_WEAP:
|
||||
case ESM::REC_GLOB:
|
||||
case ESM::REC_PLAY:
|
||||
case ESM::REC_CSTA:
|
||||
|
||||
case ESM::REC_GSCR:
|
||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
|
||||
break;
|
||||
case ESM::REC_GSCR:
|
||||
|
||||
default:
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
// ignore invalid records
|
||||
/// \todo log error
|
||||
reader.skipRecord();
|
||||
default:
|
||||
|
||||
// ignore invalid records
|
||||
/// \todo log error
|
||||
reader.skipRecord();
|
||||
}
|
||||
}
|
||||
|
||||
mCharacterManager.setCurrentCharacter(character);
|
||||
|
||||
mState = State_Running;
|
||||
|
||||
Settings::Manager::setString ("character", "Saves",
|
||||
slot->mPath.parent_path().filename().string());
|
||||
|
||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||
MWBase::Environment::get().getWorld()->renderPlayer();
|
||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||
MWBase::Environment::get().getMechanicsManager()->playerLoaded();
|
||||
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
ESM::CellId cellId = ptr.getCell()->mCell->getCellId();
|
||||
|
||||
MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "failed to load saved game: " << e.what() << std::endl;
|
||||
cleanup (true);
|
||||
}
|
||||
|
||||
mCharacterManager.setCurrentCharacter(character);
|
||||
|
||||
mState = State_Running;
|
||||
|
||||
Settings::Manager::setString ("character", "Saves",
|
||||
slot->mPath.parent_path().filename().string());
|
||||
|
||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||
MWBase::Environment::get().getWorld()->renderPlayer();
|
||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||
MWBase::Environment::get().getMechanicsManager()->playerLoaded();
|
||||
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
ESM::CellId cellId = ptr.getCell()->mCell->getCellId();
|
||||
|
||||
MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition());
|
||||
}
|
||||
|
||||
MWState::Character *MWState::StateManager::getCurrentCharacter (bool create)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace MWState
|
|||
|
||||
private:
|
||||
|
||||
void cleanup();
|
||||
void cleanup (bool force = false);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "cells.hpp"
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/cellstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -59,6 +64,30 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore&
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, const CellStore& cell) const
|
||||
{
|
||||
ESM::CellState cellState;
|
||||
|
||||
cell.saveState (cellState);
|
||||
|
||||
writer.startRecord (ESM::REC_CSTA);
|
||||
cellState.mId.save (writer);
|
||||
cellState.save (writer);
|
||||
/// \todo write references
|
||||
writer.endRecord (ESM::REC_CSTA);
|
||||
}
|
||||
|
||||
bool MWWorld::Cells::hasState (const CellStore& cellStore) const
|
||||
{
|
||||
if (cellStore.mState==CellStore::State_Loaded)
|
||||
return true;
|
||||
|
||||
if (cellStore.mCell->mData.mFlags & ESM::Cell::Interior)
|
||||
return cellStore.mCell->mData.mFlags & ESM::Cell::HasWater;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader)
|
||||
: mStore (store), mReader (reader),
|
||||
mIdCache (40, std::pair<std::string, CellStore *> ("", (CellStore*)0)), /// \todo make cache size configurable
|
||||
|
@ -121,6 +150,14 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name)
|
|||
return &result->second;
|
||||
}
|
||||
|
||||
MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id)
|
||||
{
|
||||
if (id.mPaged)
|
||||
return getExterior (id.mIndex.mX, id.mIndex.mY);
|
||||
|
||||
return getInterior (id.mWorldspace);
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell,
|
||||
bool searchInContainers)
|
||||
{
|
||||
|
@ -271,3 +308,62 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorl
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
int MWWorld::Cells::countSavedGameRecords() const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (std::map<std::string, CellStore>::const_iterator iter (mInteriors.begin());
|
||||
iter!=mInteriors.end(); ++iter)
|
||||
if (hasState (iter->second))
|
||||
++count;
|
||||
|
||||
for (std::map<std::pair<int, int>, CellStore>::const_iterator iter (mExteriors.begin());
|
||||
iter!=mExteriors.end(); ++iter)
|
||||
if (hasState (iter->second))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void MWWorld::Cells::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (std::map<std::pair<int, int>, CellStore>::const_iterator iter (mExteriors.begin());
|
||||
iter!=mExteriors.end(); ++iter)
|
||||
if (hasState (iter->second))
|
||||
writeCell (writer, iter->second);
|
||||
|
||||
for (std::map<std::string, CellStore>::const_iterator iter (mInteriors.begin());
|
||||
iter!=mInteriors.end(); ++iter)
|
||||
if (hasState (iter->second))
|
||||
writeCell (writer, iter->second);
|
||||
}
|
||||
|
||||
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_CSTA)
|
||||
{
|
||||
ESM::CellState state;
|
||||
state.mId.load (reader);
|
||||
|
||||
CellStore *cellStore = 0;
|
||||
|
||||
try
|
||||
{
|
||||
cellStore = getCell (state.mId);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// silently drop cells that don't exist anymore
|
||||
/// \todo log
|
||||
}
|
||||
|
||||
state.load (reader);
|
||||
cellStore->loadState (state);
|
||||
reader.skipRecord();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -10,6 +10,8 @@
|
|||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -33,18 +35,23 @@ namespace MWWorld
|
|||
|
||||
Ptr getPtrAndCache (const std::string& name, CellStore& cellStore);
|
||||
|
||||
void writeCell (ESM::ESMWriter& writer, const CellStore& cell) const;
|
||||
|
||||
bool hasState (const CellStore& cellStore) const;
|
||||
///< Check if cell has state that needs to be included in a saved game file.
|
||||
|
||||
public:
|
||||
|
||||
void clear();
|
||||
|
||||
Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader);
|
||||
///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole
|
||||
/// world
|
||||
|
||||
CellStore *getExterior (int x, int y);
|
||||
|
||||
CellStore *getInterior (const std::string& name);
|
||||
|
||||
CellStore *getCell (const ESM::CellId& id);
|
||||
|
||||
Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false);
|
||||
///< \param searchInContainers Only affect loaded cells.
|
||||
/// @note name must be lower case
|
||||
|
@ -56,6 +63,12 @@ namespace MWWorld
|
|||
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||
/// @note name must be lower case
|
||||
void getExteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out);
|
||||
|
||||
int countSavedGameRecords() const;
|
||||
|
||||
void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <components/esm/cellstate.hpp>
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -230,4 +233,22 @@ namespace MWWorld
|
|||
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::loadState (const ESM::CellState& state)
|
||||
{
|
||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||
mWaterLevel = state.mWaterLevel;
|
||||
|
||||
mWaterLevel = state.mWaterLevel;
|
||||
}
|
||||
|
||||
void CellStore::saveState (ESM::CellState& state) const
|
||||
{
|
||||
state.mId = mCell->getCellId();
|
||||
|
||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||
state.mWaterLevel = mWaterLevel;
|
||||
|
||||
state.mWaterLevel = mWaterLevel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
#include "livecellref.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct CellState;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
||||
|
@ -133,6 +138,10 @@ namespace MWWorld
|
|||
|
||||
Ptr searchInContainer (const std::string& id);
|
||||
|
||||
void loadState (const ESM::CellState& state);
|
||||
|
||||
void saveState (ESM::CellState& state) const;
|
||||
|
||||
private:
|
||||
|
||||
template<class Functor, class List>
|
||||
|
@ -158,7 +167,6 @@ namespace MWWorld
|
|||
///< Make case-adjustments to \a ref and insert it into the respective container.
|
||||
///
|
||||
/// Invalid \a ref objects are silently dropped.
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -304,13 +304,16 @@ namespace MWWorld
|
|||
{
|
||||
return
|
||||
mStore.countSavedGameRecords()
|
||||
+mGlobalVariables.countSavedGameRecords();
|
||||
+mGlobalVariables.countSavedGameRecords()
|
||||
+1 // player record
|
||||
+mCells.countSavedGameRecords();
|
||||
}
|
||||
|
||||
void World::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
mStore.write (writer);
|
||||
mGlobalVariables.write (writer);
|
||||
mCells.write (writer);
|
||||
mPlayer->write (writer);
|
||||
}
|
||||
|
||||
|
@ -318,7 +321,8 @@ namespace MWWorld
|
|||
{
|
||||
if (!mStore.readRecord (reader, type) &&
|
||||
!mGlobalVariables.readRecord (reader, type) &&
|
||||
!mPlayer->readRecord (reader, type))
|
||||
!mPlayer->readRecord (reader, type) &&
|
||||
!mCells.readRecord (reader, type))
|
||||
{
|
||||
throw std::runtime_error ("unknown record in saved game");
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ add_component_dir (esm
|
|||
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
|
||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate
|
||||
)
|
||||
|
||||
add_component_dir (misc
|
||||
|
|
17
components/esm/cellstate.cpp
Normal file
17
components/esm/cellstate.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#include "cellstate.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::CellState::load (ESMReader &esm)
|
||||
{
|
||||
mWaterLevel = 0;
|
||||
esm.getHNOT (mWaterLevel, "WLVL");
|
||||
}
|
||||
|
||||
void ESM::CellState::save (ESMWriter &esm) const
|
||||
{
|
||||
if (!mId.mPaged)
|
||||
esm.writeHNT ("WLVL", mWaterLevel);
|
||||
}
|
25
components/esm/cellstate.hpp
Normal file
25
components/esm/cellstate.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef OPENMW_ESM_CELLSTATE_H
|
||||
#define OPENMW_ESM_CELLSTATE_H
|
||||
|
||||
#include "cellid.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
|
||||
/// \note Does not include references
|
||||
struct CellState
|
||||
{
|
||||
CellId mId;
|
||||
|
||||
float mWaterLevel;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -88,7 +88,8 @@ enum RecNameInts
|
|||
REC_JOUR = 0x524f55a4,
|
||||
REC_QUES = 0x53455551,
|
||||
REC_GSCR = 0x52435347,
|
||||
REC_PLAY = 0x504c4159,
|
||||
REC_PLAY = 0x59414c50,
|
||||
REC_CSTA = 0x41545343,
|
||||
|
||||
// format 1
|
||||
REC_FILT = 0x544C4946
|
||||
|
|
Loading…
Reference in a new issue