1
0
Fork 1
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:
scrawl 2015-12-06 19:53:06 +01:00
parent 671561ea37
commit 176a3c16f4
3 changed files with 91 additions and 10 deletions

View file

@ -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;
}

View file

@ -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();

View file

@ -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.