Object cell movement tracker works. Savegame handling is still missing and some game functionality is still stubbed out.

openmw-38
scrawl 9 years ago
parent 64b4926127
commit 3aa53f3cb4

@ -47,13 +47,16 @@ namespace
template<typename T>
MWWorld::Ptr searchViaActorId (MWWorld::CellRefList<T>& actorList, int actorId,
MWWorld::CellStore *cell)
MWWorld::CellStore *cell, const std::map<MWWorld::LiveCellRefBase*, MWWorld::CellStore*>& toIgnore)
{
for (typename MWWorld::CellRefList<T>::List::iterator iter (actorList.mList.begin());
iter!=actorList.mList.end(); ++iter)
{
MWWorld::Ptr actor (&*iter, cell);
if (toIgnore.find(&*iter) != toIgnore.end())
continue;
if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0)
return actor;
}
@ -181,6 +184,7 @@ namespace MWWorld
void CellStore::moveFrom(const Ptr &object, CellStore *from)
{
mHasState = true;
MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase());
if (found != mMovedToAnotherCell.end())
{
@ -192,10 +196,27 @@ namespace MWWorld
{
mMovedHere.insert(std::make_pair(object.getBase(), from));
}
if (mState == State_Loaded)
updateMergedRefs();
else if (mState == State_Preloaded)
{
mIds.push_back(object.getCellRef().getRefId());
std::sort(mIds.begin(), mIds.end());
}
}
void CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo)
MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo)
{
if (cellToMoveTo == this)
throw std::runtime_error("object is already in this cell");
// We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise.
if (mState != State_Loaded)
throw std::runtime_error("can't move object from a non-loaded cell (how did you get this object anyway?)");
// TODO: ensure that the object actually exists in the cell
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())
{
@ -208,21 +229,59 @@ namespace MWWorld
mMovedHere.erase(found);
// Now that object is back to its rightful owner, we can move it
originalCell->moveTo(object, cellToMoveTo);
if (cellToMoveTo != originalCell)
{
originalCell->moveTo(object, cellToMoveTo);
}
updateMergedRefs();
return;
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
}
cellToMoveTo->moveFrom(object, this);
mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo));
updateMergedRefs();
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
}
void CellStore::updateMergedRefs()
struct MergeFunctor
{
MergeFunctor(std::vector<LiveCellRefBase*>& mergeTo, const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedToAnotherCell)
: mMergeTo(mergeTo)
, mMovedHere(movedHere)
, mMovedToAnotherCell(movedToAnotherCell)
{
}
bool operator() (const MWWorld::Ptr& ptr)
{
if (mMovedToAnotherCell.find(ptr.getBase()) != mMovedToAnotherCell.end())
return true;
mMergeTo.push_back(ptr.getBase());
return true;
}
void merge()
{
for (std::map<LiveCellRefBase*, MWWorld::CellStore*>::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
mMergeTo.push_back(it->first);
}
private:
std::vector<LiveCellRefBase*>& mMergeTo;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedHere;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedToAnotherCell;
};
void CellStore::updateMergedRefs()
{
mMergedRefs.clear();
MergeFunctor functor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
forEachInternal(functor);
functor.merge();
}
CellStore::CellStore (const ESM::Cell *cell)
@ -258,85 +317,50 @@ namespace MWWorld
return const_cast<CellStore *> (this)->search (id).isEmpty();
}
struct SearchFunctor
{
MWWorld::Ptr mFound;
std::string mIdToFind;
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getCellRef().getRefId() == mIdToFind)
{
mFound = ptr;
return false;
}
return true;
}
};
Ptr CellStore::search (const std::string& id)
{
bool oldState = mHasState;
mHasState = true;
if (LiveCellRef<ESM::Activator> *ref = mActivators.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Potion> *ref = mPotions.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Apparatus> *ref = mAppas.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Armor> *ref = mArmors.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Book> *ref = mBooks.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Clothing> *ref = mClothes.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Container> *ref = mContainers.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Creature> *ref = mCreatures.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Door> *ref = mDoors.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Ingredient> *ref = mIngreds.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::CreatureLevList> *ref = mCreatureLists.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::ItemLevList> *ref = mItemLists.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Light> *ref = mLights.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Lockpick> *ref = mLockpicks.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Miscellaneous> *ref = mMiscItems.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::NPC> *ref = mNpcs.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Probe> *ref = mProbes.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Repair> *ref = mRepairs.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Static> *ref = mStatics.find (id))
return Ptr (ref, this);
if (LiveCellRef<ESM::Weapon> *ref = mWeapons.find (id))
return Ptr (ref, this);
SearchFunctor searchFunctor;
searchFunctor.mIdToFind = id;
forEach(searchFunctor);
mHasState = oldState;
return Ptr();
return searchFunctor.mFound;
}
Ptr CellStore::searchViaActorId (int id)
{
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this))
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell))
return ptr;
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this))
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell))
return ptr;
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
MWWorld::Ptr actor (it->first, this);
if (!actor.getClass().isActor())
continue;
if (actor.getClass().getCreatureStats (actor).matchesActorId (id) && actor.getRefData().getCount() > 0)
return actor;
}
return Ptr();
}
@ -435,6 +459,8 @@ namespace MWWorld
continue;
}
// We don't need to check mMovedToAnotherCell because listRefs isn't used for loaded cells.
mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID));
}
}
@ -447,6 +473,12 @@ namespace MWWorld
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
}
// List runtime moved references
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
mIds.push_back(Misc::StringUtils::lowerCase(it->first->mRef.getRefId()));
}
std::sort (mIds.begin(), mIds.end());
}
@ -489,6 +521,8 @@ namespace MWWorld
loadRef (ref, false, store);
}
updateMergedRefs();
}
bool CellStore::isExterior() const
@ -610,11 +644,15 @@ namespace MWWorld
writeReferenceCollection<ESM::ObjectState> (writer, mRepairs);
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
// TODO: write moved references
}
void CellStore::readReferences (ESM::ESMReader& reader,
const std::map<int, int>& contentFileMap)
{
// TODO: read moved references
mHasState = true;
while (reader.isNextSub ("OBJE"))

@ -112,11 +112,64 @@ namespace MWWorld
/// Repopulate mMergedRefs.
void updateMergedRefs();
template<typename T>
LiveCellRefBase* insertBase(CellRefList<T>& list, const LiveCellRef<T>* ref)
{
mHasState = true;
LiveCellRefBase* ret = &list.insert(*ref);
updateMergedRefs();
return ret;
}
// helper function for forEachInternal
template<class Functor, class List>
bool forEachImp (Functor& functor, List& list)
{
for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
++iter)
{
if (iter->mData.isDeletedByContentFile())
continue;
if (!functor (MWWorld::Ptr(&*iter, this)))
return false;
}
return true;
}
// listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for.
template<class Functor>
bool forEachInternal (Functor& functor)
{
return
forEachImp (functor, mActivators) &&
forEachImp (functor, mPotions) &&
forEachImp (functor, mAppas) &&
forEachImp (functor, mArmors) &&
forEachImp (functor, mBooks) &&
forEachImp (functor, mClothes) &&
forEachImp (functor, mContainers) &&
forEachImp (functor, mDoors) &&
forEachImp (functor, mIngreds) &&
forEachImp (functor, mItemLists) &&
forEachImp (functor, mLights) &&
forEachImp (functor, mLockpicks) &&
forEachImp (functor, mMiscItems) &&
forEachImp (functor, mProbes) &&
forEachImp (functor, mRepairs) &&
forEachImp (functor, mStatics) &&
forEachImp (functor, mWeapons) &&
forEachImp (functor, mCreatures) &&
forEachImp (functor, mNpcs) &&
forEachImp (functor, mCreatureLists);
}
public:
/// Moves object from this cell to the given cell.
/// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...)
void moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
/// @note throws exception if cellToMoveTo == this
/// @return updated MWWorld::Ptr with the new CellStore pointer set.
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
/// Make a copy of the given object and insert it into this cell.
/// @note If you get a linker error here, this means the given type can not be inserted into a cell.
@ -136,6 +189,7 @@ namespace MWWorld
bool hasId (const std::string& id) const;
///< May return true for deleted IDs when in preload state. Will return false, if cell is
/// unloaded.
/// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded.
Ptr search (const std::string& id);
///< Will return an empty Ptr if cell is not loaded. Does not check references in
@ -166,45 +220,23 @@ namespace MWWorld
/// false will abort the iteration.
/// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed?
///
/// \note Creatures and NPCs are handled last.
template<class Functor>
bool forEach (Functor& functor)
{
mHasState = true;
return
forEachImp (functor, mActivators) &&
forEachImp (functor, mPotions) &&
forEachImp (functor, mAppas) &&
forEachImp (functor, mArmors) &&
forEachImp (functor, mBooks) &&
forEachImp (functor, mClothes) &&
forEachImp (functor, mContainers) &&
forEachImp (functor, mDoors) &&
forEachImp (functor, mIngreds) &&
forEachImp (functor, mItemLists) &&
forEachImp (functor, mLights) &&
forEachImp (functor, mLockpicks) &&
forEachImp (functor, mMiscItems) &&
forEachImp (functor, mProbes) &&
forEachImp (functor, mRepairs) &&
forEachImp (functor, mStatics) &&
forEachImp (functor, mWeapons) &&
forEachImp (functor, mCreatures) &&
forEachImp (functor, mNpcs) &&
forEachImp (functor, mCreatureLists);
}
if (mState != State_Loaded)
return false;
template<class Functor>
bool forEachContainer (Functor& functor)
{
mHasState = true;
return
forEachImp (functor, mContainers) &&
forEachImp (functor, mCreatures) &&
forEachImp (functor, mNpcs);
for (unsigned int i=0; i<mMergedRefs.size(); ++i)
{
if (mMergedRefs[i]->mData.isDeletedByContentFile())
continue;
if (!functor(MWWorld::Ptr(mMergedRefs[i], this)))
return false;
}
return true;
}
/// \todo add const version of forEach
@ -234,20 +266,6 @@ namespace MWWorld
private:
template<class Functor, class List>
bool forEachImp (Functor& functor, List& list)
{
for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
++iter)
{
if (iter->mData.isDeletedByContentFile())
continue;
if (!functor (MWWorld::Ptr(&*iter, this)))
return false;
}
return true;
}
/// Run through references and store IDs
void listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
@ -261,126 +279,105 @@ namespace MWWorld
MWMechanics::PathgridGraph mPathgridGraph;
};
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Activator>(const LiveCellRef<ESM::Activator>* ref)
{
mHasState = true;
return &mActivators.insert(*ref);
return insertBase(mActivators, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Potion>(const LiveCellRef<ESM::Potion>* ref)
{
mHasState = true;
return &mPotions.insert(*ref);
return insertBase(mPotions, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Apparatus>(const LiveCellRef<ESM::Apparatus>* ref)
{
mHasState = true;
return &mAppas.insert(*ref);
return insertBase(mAppas, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Armor>(const LiveCellRef<ESM::Armor>* ref)
{
mHasState = true;
return &mArmors.insert(*ref);
return insertBase(mArmors, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Book>(const LiveCellRef<ESM::Book>* ref)
{
mHasState = true;
return &mBooks.insert(*ref);
return insertBase(mBooks, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Clothing>(const LiveCellRef<ESM::Clothing>* ref)
{
mHasState = true;
return &mClothes.insert(*ref);
return insertBase(mClothes, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Container>(const LiveCellRef<ESM::Container>* ref)
{
mHasState = true;
return &mContainers.insert(*ref);
return insertBase(mContainers, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Creature>(const LiveCellRef<ESM::Creature>* ref)
{
mHasState = true;
return &mCreatures.insert(*ref);
return insertBase(mCreatures, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Door>(const LiveCellRef<ESM::Door>* ref)
{
mHasState = true;
return &mDoors.insert(*ref);
return insertBase(mDoors, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Ingredient>(const LiveCellRef<ESM::Ingredient>* ref)
{
mHasState = true;
return &mIngreds.insert(*ref);
return insertBase(mIngreds, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::CreatureLevList>(const LiveCellRef<ESM::CreatureLevList>* ref)
{
mHasState = true;
return &mCreatureLists.insert(*ref);
return insertBase(mCreatureLists, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::ItemLevList>(const LiveCellRef<ESM::ItemLevList>* ref)
{
mHasState = true;
return &mItemLists.insert(*ref);
return insertBase(mItemLists, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Light>(const LiveCellRef<ESM::Light>* ref)
{
mHasState = true;
return &mLights.insert(*ref);
return insertBase(mLights, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Lockpick>(const LiveCellRef<ESM::Lockpick>* ref)
{
mHasState = true;
return &mLockpicks.insert(*ref);
return insertBase(mLockpicks, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Miscellaneous>(const LiveCellRef<ESM::Miscellaneous>* ref)
{
mHasState = true;
return &mMiscItems.insert(*ref);
return insertBase(mMiscItems, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::NPC>(const LiveCellRef<ESM::NPC>* ref)
{
mHasState = true;
return &mNpcs.insert(*ref);
return insertBase(mNpcs, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Probe>(const LiveCellRef<ESM::Probe>* ref)
{
mHasState = true;
return &mProbes.insert(*ref);
return insertBase(mProbes, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Repair>(const LiveCellRef<ESM::Repair>* ref)
{
mHasState = true;
return &mRepairs.insert(*ref);
return insertBase(mRepairs, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Static>(const LiveCellRef<ESM::Static>* ref)
{
mHasState = true;
return &mStatics.insert(*ref);
return insertBase(mStatics, ref);
}
template<>
inline LiveCellRefBase* CellStore::insert<ESM::Weapon>(const LiveCellRef<ESM::Weapon>* ref)
{
mHasState = true;
return &mWeapons.insert(*ref);
return insertBase(mWeapons, ref);
}
bool operator== (const CellStore& left, const CellStore& right);

@ -116,7 +116,6 @@ namespace
{
addObject(ptr, mPhysics, mRendering);
updateObjectRotation(ptr, mPhysics, mRendering, false);
ptr.getClass().adjustPosition (ptr, false);
}
catch (const std::exception& e)
{
@ -129,6 +128,17 @@ namespace
return true;
}
struct AdjustPositionFunctor
{
bool operator() (const MWWorld::Ptr& ptr)
{
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
ptr.getClass().adjustPosition (ptr, false);
return true;
}
};
}
@ -553,6 +563,10 @@ namespace MWWorld
{
InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering);
cell.forEach (functor);
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
AdjustPositionFunctor adjustPosFunctor;
cell.forEach (adjustPosFunctor);
}
void Scene::addObjectToScene (const Ptr& ptr)

@ -722,7 +722,7 @@ namespace MWWorld
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{
FindContainerFunctor functor(ptr);
(*cellIt)->forEachContainer(functor);
//(*cellIt)->forEachContainer(functor);
if (!functor.mResult.isEmpty())
return functor.mResult;
@ -1146,7 +1146,7 @@ namespace MWWorld
bool newCellActive = mWorldScene->isCellActive(*newCell);
if (!currCellActive && newCellActive)
{
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos);
newPtr = currCell->moveTo(ptr, newCell);
mWorldScene->addObjectToScene(newPtr);
std::string script = newPtr.getClass().getScript(newPtr);
@ -1162,14 +1162,14 @@ namespace MWWorld
removeContainerScripts (ptr);
haveToMove = false;
newPtr = ptr.getClass().copyToCell(ptr, *newCell);
newPtr = currCell->moveTo(ptr, newCell);
newPtr.getRefData().setBaseNode(0);
}
else if (!currCellActive && !newCellActive)
newPtr = ptr.getClass().copyToCell(ptr, *newCell);
newPtr = currCell->moveTo(ptr, newCell);
else // both cells active
{
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos);
newPtr = currCell->moveTo(ptr, newCell);
mRendering->updatePtr(ptr, newPtr);
ptr.getRefData().setBaseNode(NULL);
@ -1189,7 +1189,6 @@ namespace MWWorld
addContainerScripts (newPtr, newCell);
}
}
ptr.getRefData().setCount(0);
}
}
if (haveToMove && newPtr.getRefData().getBaseNode())

Loading…
Cancel
Save