mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
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 <iostream>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/esmwriter.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,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
|
@ -320,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
|||
catch (...)
|
||||
{
|
||||
// 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();
|
||||
return true;
|
||||
/// \todo log
|
||||
}
|
||||
|
||||
state.load (reader);
|
||||
|
@ -334,7 +359,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
|||
if (cellStore->getState()!=CellStore::State_Loaded)
|
||||
cellStore->load ();
|
||||
|
||||
cellStore->readReferences (reader, contentFileMap);
|
||||
GetCellStoreCallback callback(*this);
|
||||
|
||||
cellStore->readReferences (reader, contentFileMap, &callback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -613,6 +613,28 @@ namespace MWWorld
|
|||
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
|
||||
{
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mActivators);
|
||||
|
@ -647,11 +669,8 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
void CellStore::readReferences (ESM::ESMReader& reader,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback)
|
||||
{
|
||||
// TODO: read moved references
|
||||
|
||||
mHasState = true;
|
||||
|
||||
while (reader.isNextSub ("OBJE"))
|
||||
|
@ -787,7 +806,35 @@ namespace MWWorld
|
|||
refnum.load(reader, true, "MVRF");
|
||||
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();
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "livecellref.hpp"
|
||||
#include "cellreflist.hpp"
|
||||
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
||||
#include <components/esm/loadacti.hpp>
|
||||
#include <components/esm/loadalch.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
|
@ -42,6 +40,7 @@ namespace ESM
|
|||
{
|
||||
struct CellState;
|
||||
struct FogState;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -263,7 +262,15 @@ namespace MWWorld
|
|||
|
||||
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 ();
|
||||
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
||||
|
|
Loading…
Reference in a new issue