forked from teamnwah/openmw-tes3coop
Resolve moved references loaded from a save game
This commit is contained in:
parent
671561ea37
commit
176a3c16f4
3 changed files with 91 additions and 10 deletions
|
@ -1,5 +1,7 @@
|
||||||
#include "cells.hpp"
|
#include "cells.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
@ -303,6 +305,29 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GetCellStoreCallback(MWWorld::Cells& cells)
|
||||||
|
: mCells(cells)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Cells& mCells;
|
||||||
|
|
||||||
|
virtual MWWorld::CellStore* getCellStore(const ESM::CellId& cellId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return mCells.getCell(cellId);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
||||||
const std::map<int, int>& contentFileMap)
|
const std::map<int, int>& contentFileMap)
|
||||||
{
|
{
|
||||||
|
@ -320,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
// silently drop cells that don't exist anymore
|
// silently drop cells that don't exist anymore
|
||||||
|
std::cerr << "Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)" << std::endl;
|
||||||
reader.skipRecord();
|
reader.skipRecord();
|
||||||
return true;
|
return true;
|
||||||
/// \todo log
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.load (reader);
|
state.load (reader);
|
||||||
|
@ -334,7 +359,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
||||||
if (cellStore->getState()!=CellStore::State_Loaded)
|
if (cellStore->getState()!=CellStore::State_Loaded)
|
||||||
cellStore->load ();
|
cellStore->load ();
|
||||||
|
|
||||||
cellStore->readReferences (reader, contentFileMap);
|
GetCellStoreCallback callback(*this);
|
||||||
|
|
||||||
|
cellStore->readReferences (reader, contentFileMap, &callback);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -613,6 +613,28 @@ namespace MWWorld
|
||||||
mFogState->load(reader);
|
mFogState->load(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SearchByRefNumVisitor
|
||||||
|
{
|
||||||
|
LiveCellRefBase* mFound;
|
||||||
|
ESM::RefNum mRefNumToFind;
|
||||||
|
|
||||||
|
SearchByRefNumVisitor(const ESM::RefNum& toFind)
|
||||||
|
: mFound(NULL)
|
||||||
|
, mRefNumToFind(toFind)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
if (ptr.getCellRef().getRefNum() == mRefNumToFind)
|
||||||
|
{
|
||||||
|
mFound = ptr.getBase();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void CellStore::writeReferences (ESM::ESMWriter& writer) const
|
void CellStore::writeReferences (ESM::ESMWriter& writer) const
|
||||||
{
|
{
|
||||||
writeReferenceCollection<ESM::ObjectState> (writer, mActivators);
|
writeReferenceCollection<ESM::ObjectState> (writer, mActivators);
|
||||||
|
@ -647,11 +669,8 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellStore::readReferences (ESM::ESMReader& reader,
|
void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback)
|
||||||
const std::map<int, int>& contentFileMap)
|
|
||||||
{
|
{
|
||||||
// TODO: read moved references
|
|
||||||
|
|
||||||
mHasState = true;
|
mHasState = true;
|
||||||
|
|
||||||
while (reader.isNextSub ("OBJE"))
|
while (reader.isNextSub ("OBJE"))
|
||||||
|
@ -787,7 +806,35 @@ namespace MWWorld
|
||||||
refnum.load(reader, true, "MVRF");
|
refnum.load(reader, true, "MVRF");
|
||||||
movedTo.load(reader);
|
movedTo.load(reader);
|
||||||
|
|
||||||
std::cout << "moved to " << movedTo.mWorldspace << " " << movedTo.mIndex.mX << " " << movedTo.mIndex.mY << std::endl;
|
// Search for the reference. It might no longer exist if its content file was removed.
|
||||||
|
SearchByRefNumVisitor visitor(refnum);
|
||||||
|
forEachInternal(visitor);
|
||||||
|
|
||||||
|
if (!visitor.mFound)
|
||||||
|
{
|
||||||
|
std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CellStore* otherCell = callback->getCellStore(movedTo);
|
||||||
|
|
||||||
|
if (otherCell == NULL)
|
||||||
|
{
|
||||||
|
std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId()
|
||||||
|
<< " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl;
|
||||||
|
// Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates.
|
||||||
|
// Restore original coordinates:
|
||||||
|
visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherCell == this)
|
||||||
|
{
|
||||||
|
std::cerr << "Found invalid moved ref, ignoring" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMergedRefs();
|
updateMergedRefs();
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include "livecellref.hpp"
|
#include "livecellref.hpp"
|
||||||
#include "cellreflist.hpp"
|
#include "cellreflist.hpp"
|
||||||
|
|
||||||
#include <components/esm/cellid.hpp>
|
|
||||||
|
|
||||||
#include <components/esm/loadacti.hpp>
|
#include <components/esm/loadacti.hpp>
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
#include <components/esm/loadappa.hpp>
|
#include <components/esm/loadappa.hpp>
|
||||||
|
@ -42,6 +40,7 @@ namespace ESM
|
||||||
{
|
{
|
||||||
struct CellState;
|
struct CellState;
|
||||||
struct FogState;
|
struct FogState;
|
||||||
|
struct CellId;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -263,7 +262,15 @@ 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);
|
struct GetCellStoreCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
///@note must return NULL if the cell is not found
|
||||||
|
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references)
|
||||||
|
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback);
|
||||||
|
|
||||||
void respawn ();
|
void respawn ();
|
||||||
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
||||||
|
|
Loading…
Reference in a new issue