mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-31 14:36:39 +00:00
load and save of reference in cells (without CustomData state)
This commit is contained in:
parent
e0de76a6f7
commit
29c3a288e3
11 changed files with 222 additions and 21 deletions
|
@ -282,11 +282,6 @@ void OMW::Engine::setCell (const std::string& cellName)
|
||||||
|
|
||||||
void OMW::Engine::addContentFile(const std::string& file)
|
void OMW::Engine::addContentFile(const std::string& file)
|
||||||
{
|
{
|
||||||
if (file.find_last_of(".") == std::string::npos)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Missing extension in content file!");
|
|
||||||
}
|
|
||||||
|
|
||||||
mContentFiles.push_back(file);
|
mContentFiles.push_back(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define GAME_MWBASE_WORLD_H
|
#define GAME_MWBASE_WORLD_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
@ -102,7 +103,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
const std::map<int, int>& contentFileMap) = 0;
|
||||||
|
|
||||||
virtual OEngine::Render::Fader* getFader() = 0;
|
virtual OEngine::Render::Fader* getFader() = 0;
|
||||||
///< \todo remove this function. Rendering details should not be exposed.
|
///< \todo remove this function. Rendering details should not be exposed.
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include <OgreImage.h>
|
#include <OgreImage.h>
|
||||||
|
@ -43,6 +45,31 @@ void MWState::StateManager::cleanup (bool force)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<int, int> MWState::StateManager::buildContentFileIndexMap (const ESM::ESMReader& reader)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
const std::vector<std::string>& current =
|
||||||
|
MWBase::Environment::get().getWorld()->getContentFiles();
|
||||||
|
|
||||||
|
const std::vector<ESM::Header::MasterData>& prev = reader.getGameFiles();
|
||||||
|
|
||||||
|
std::map<int, int> map;
|
||||||
|
|
||||||
|
for (int iPrev = 0; iPrev<static_cast<int> (prev.size()); ++iPrev)
|
||||||
|
{
|
||||||
|
std::string id = Misc::StringUtils::lowerCase (prev[iPrev].name);
|
||||||
|
|
||||||
|
for (int iCurrent = 0; iCurrent<static_cast<int> (current.size()); ++iCurrent)
|
||||||
|
if (id==Misc::StringUtils::lowerCase (current[iCurrent]))
|
||||||
|
{
|
||||||
|
map.insert (std::make_pair (iPrev, iCurrent));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game)
|
MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game)
|
||||||
: mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0)
|
: mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0)
|
||||||
{
|
{
|
||||||
|
@ -167,7 +194,16 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);
|
slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);
|
||||||
|
|
||||||
std::ofstream stream (slot->mPath.string().c_str());
|
std::ofstream stream (slot->mPath.string().c_str());
|
||||||
|
|
||||||
ESM::ESMWriter writer;
|
ESM::ESMWriter writer;
|
||||||
|
|
||||||
|
const std::vector<std::string>& current =
|
||||||
|
MWBase::Environment::get().getWorld()->getContentFiles();
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
|
||||||
|
++iter)
|
||||||
|
writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0
|
||||||
|
|
||||||
writer.setFormat (ESM::Header::CurrentFormat);
|
writer.setFormat (ESM::Header::CurrentFormat);
|
||||||
writer.setRecordCount (
|
writer.setRecordCount (
|
||||||
1 // saved game header
|
1 // saved game header
|
||||||
|
@ -205,6 +241,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
||||||
ESM::ESMReader reader;
|
ESM::ESMReader reader;
|
||||||
reader.open (slot->mPath.string());
|
reader.open (slot->mPath.string());
|
||||||
|
|
||||||
|
std::map<int, int> contentFileMap = buildContentFileIndexMap (reader);
|
||||||
|
|
||||||
while (reader.hasMoreRecs())
|
while (reader.hasMoreRecs())
|
||||||
{
|
{
|
||||||
ESM::NAME n = reader.getRecName();
|
ESM::NAME n = reader.getRecName();
|
||||||
|
@ -237,7 +275,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
||||||
case ESM::REC_PLAY:
|
case ESM::REC_PLAY:
|
||||||
case ESM::REC_CSTA:
|
case ESM::REC_CSTA:
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val);
|
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESM::REC_GSCR:
|
case ESM::REC_GSCR:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef GAME_STATE_STATEMANAGER_H
|
#ifndef GAME_STATE_STATEMANAGER_H
|
||||||
#define GAME_STATE_STATEMANAGER_H
|
#define GAME_STATE_STATEMANAGER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
@ -21,6 +23,8 @@ namespace MWState
|
||||||
|
|
||||||
void cleanup (bool force = false);
|
void cleanup (bool force = false);
|
||||||
|
|
||||||
|
std::map<int, int> buildContentFileIndexMap (const ESM::ESMReader& reader) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StateManager (const boost::filesystem::path& saves, const std::string& game);
|
StateManager (const boost::filesystem::path& saves, const std::string& game);
|
||||||
|
|
|
@ -352,7 +352,8 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer) const
|
||||||
writeCell (writer, iter->second);
|
writeCell (writer, iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type)
|
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
const std::map<int, int>& contentFileMap)
|
||||||
{
|
{
|
||||||
if (type==ESM::REC_CSTA)
|
if (type==ESM::REC_CSTA)
|
||||||
{
|
{
|
||||||
|
@ -373,7 +374,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||||
|
|
||||||
state.load (reader);
|
state.load (reader);
|
||||||
cellStore->loadState (state);
|
cellStore->loadState (state);
|
||||||
reader.skipRecord();
|
|
||||||
|
if (cellStore->mState!=CellStore::State_Loaded)
|
||||||
|
cellStore->load (mStore, mReader);
|
||||||
|
|
||||||
|
cellStore->readReferences (reader, contentFileMap);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace MWWorld
|
||||||
|
|
||||||
void write (ESM::ESMWriter& writer) const;
|
void write (ESM::ESMWriter& writer) const;
|
||||||
|
|
||||||
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
bool readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
const std::map<int, int>& contentFileMap);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,6 @@ namespace
|
||||||
{
|
{
|
||||||
if (!collection.mList.empty())
|
if (!collection.mList.empty())
|
||||||
{
|
{
|
||||||
// section header
|
|
||||||
writer.writeHNT ("CSEC", collection.mList.front().mBase->sRecordId);
|
|
||||||
|
|
||||||
// references
|
// references
|
||||||
for (typename MWWorld::CellRefList<T>::List::const_iterator
|
for (typename MWWorld::CellRefList<T>::List::const_iterator
|
||||||
iter (collection.mList.begin());
|
iter (collection.mList.begin());
|
||||||
|
@ -55,12 +52,51 @@ namespace
|
||||||
RecordType state;
|
RecordType state;
|
||||||
iter->save (state);
|
iter->save (state);
|
||||||
|
|
||||||
writer.startRecord (ESM::REC_OBJE);
|
writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId);
|
||||||
state.save (writer);
|
state.save (writer);
|
||||||
writer.endRecord (ESM::REC_OBJE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename RecordType, typename T>
|
||||||
|
void readReferenceCollection (ESM::ESMReader& reader,
|
||||||
|
MWWorld::CellRefList<T>& collection, const std::map<int, int>& contentFileMap)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
RecordType state;
|
||||||
|
state.load (reader);
|
||||||
|
|
||||||
|
std::map<int, int>::const_iterator iter =
|
||||||
|
contentFileMap.find (state.mRef.mRefNum.mContentFile);
|
||||||
|
|
||||||
|
if (iter==contentFileMap.end())
|
||||||
|
return; // content file has been removed -> skip
|
||||||
|
|
||||||
|
state.mRef.mRefNum.mContentFile = iter->second;
|
||||||
|
|
||||||
|
if (!MWWorld::LiveCellRef<T>::checkState (state))
|
||||||
|
return; // not valid anymore with current content files -> skip
|
||||||
|
|
||||||
|
const T *record = esmStore.get<T>().search (state.mRef.mRefID);
|
||||||
|
|
||||||
|
if (!record)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (typename MWWorld::CellRefList<T>::List::iterator iter (collection.mList.begin());
|
||||||
|
iter!=collection.mList.end(); ++iter)
|
||||||
|
if (iter->mRef.mRefNum==state.mRef.mRefNum)
|
||||||
|
{
|
||||||
|
// overwrite existing reference
|
||||||
|
iter->load (state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new reference
|
||||||
|
MWWorld::LiveCellRef<T> ref (record);
|
||||||
|
ref.load (state);
|
||||||
|
collection.mList.push_back (ref);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -304,4 +340,121 @@ namespace MWWorld
|
||||||
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
|
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
|
||||||
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
|
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellStore::readReferences (ESM::ESMReader& reader,
|
||||||
|
const std::map<int, int>& contentFileMap)
|
||||||
|
{
|
||||||
|
while (reader.isNextSub ("OBJE"))
|
||||||
|
{
|
||||||
|
unsigned int id = 0;
|
||||||
|
reader.getHT (id);
|
||||||
|
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case ESM::REC_ACTI:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mActivators, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_ALCH:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mPotions, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_APPA:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mAppas, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_ARMO:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mArmors, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_BOOK:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mBooks, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_CLOT:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mClothes, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_CONT:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mContainers, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_CREA:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mCreatures, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_DOOR:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mDoors, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_INGR:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_LEVC:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mCreatureLists, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_LEVI:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_LIGH:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mLights, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_LOCK:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_MISC:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_NPC_:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mNpcs, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_PROB:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mProbes, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_REPA:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_STAT:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mStatics, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_WEAP:
|
||||||
|
|
||||||
|
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, contentFileMap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
throw std::runtime_error ("unknown type in cell reference section");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,8 @@ namespace MWWorld
|
||||||
|
|
||||||
void writeReferences (ESM::ESMWriter& writer) const;
|
void writeReferences (ESM::ESMWriter& writer) const;
|
||||||
|
|
||||||
|
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template<class Functor, class List>
|
template<class Functor, class List>
|
||||||
|
|
|
@ -324,12 +324,13 @@ namespace MWWorld
|
||||||
mPlayer->write (writer);
|
mPlayer->write (writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::readRecord (ESM::ESMReader& reader, int32_t type)
|
void World::readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
const std::map<int, int>& contentFileMap)
|
||||||
{
|
{
|
||||||
if (!mStore.readRecord (reader, type) &&
|
if (!mStore.readRecord (reader, type) &&
|
||||||
!mGlobalVariables.readRecord (reader, type) &&
|
!mGlobalVariables.readRecord (reader, type) &&
|
||||||
!mPlayer->readRecord (reader, type) &&
|
!mPlayer->readRecord (reader, type) &&
|
||||||
!mCells.readRecord (reader, type))
|
!mCells.readRecord (reader, type, contentFileMap))
|
||||||
{
|
{
|
||||||
throw std::runtime_error ("unknown record in saved game");
|
throw std::runtime_error ("unknown record in saved game");
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,8 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer) const;
|
virtual void write (ESM::ESMWriter& writer) const;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
const std::map<int, int>& contentFileMap);
|
||||||
|
|
||||||
virtual OEngine::Render::Fader* getFader();
|
virtual OEngine::Render::Fader* getFader();
|
||||||
///< \todo remove this function. Rendering details should not be exposed.
|
///< \todo remove this function. Rendering details should not be exposed.
|
||||||
|
|
|
@ -90,7 +90,6 @@ enum RecNameInts
|
||||||
REC_GSCR = 0x52435347,
|
REC_GSCR = 0x52435347,
|
||||||
REC_PLAY = 0x59414c50,
|
REC_PLAY = 0x59414c50,
|
||||||
REC_CSTA = 0x41545343,
|
REC_CSTA = 0x41545343,
|
||||||
REC_OBJE = 0x454a424f,
|
|
||||||
REC_GMAP = 0x50414d47,
|
REC_GMAP = 0x50414d47,
|
||||||
|
|
||||||
// format 1
|
// format 1
|
||||||
|
|
Loading…
Reference in a new issue