Merge pull request #840 from scrawl/movedrefs

Object movement between cells
openmw-38
scrawl 9 years ago
commit bdae572264

@ -62,7 +62,7 @@ add_openmw_dir (mwsound
add_openmw_dir (mwworld
refdata worldimp scene globals class action nullaction actionteleport
containerstore actiontalk actiontake manualref player cellfunctors failedaction
containerstore actiontalk actiontake manualref player cellvisitors failedaction
cells localscripts customdata inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor

@ -130,6 +130,6 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Activator> *ref =
ptr.get<ESM::Activator>();
return MWWorld::Ptr(&cell.get<ESM::Activator>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
}

@ -148,7 +148,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Apparatus> *ref =
ptr.get<ESM::Apparatus>();
return MWWorld::Ptr(&cell.get<ESM::Apparatus>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -382,7 +382,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Armor> *ref =
ptr.get<ESM::Armor>();
return MWWorld::Ptr(&cell.get<ESM::Armor>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -187,7 +187,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Book> *ref =
ptr.get<ESM::Book>();
return MWWorld::Ptr(&cell.get<ESM::Book>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -276,7 +276,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Clothing> *ref =
ptr.get<ESM::Clothing>();
return MWWorld::Ptr(&cell.get<ESM::Clothing>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -293,7 +293,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Container> *ref =
ptr.get<ESM::Container>();
return MWWorld::Ptr(&cell.get<ESM::Container>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const

@ -600,7 +600,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Creature::isBipedal(const MWWorld::Ptr &ptr) const

@ -310,7 +310,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Door> *ref =
ptr.get<ESM::Door>();
return MWWorld::Ptr(&cell.get<ESM::Door>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
void Door::ensureCustomData(const MWWorld::Ptr &ptr) const

@ -185,7 +185,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Ingredient> *ref =
ptr.get<ESM::Ingredient>();
return MWWorld::Ptr(&cell.get<ESM::Ingredient>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -217,7 +217,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Light> *ref =
ptr.get<ESM::Light>();
return MWWorld::Ptr(&cell.get<ESM::Light>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -166,7 +166,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Lockpick> *ref =
ptr.get<ESM::Lockpick>();
return MWWorld::Ptr(&cell.get<ESM::Lockpick>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -215,13 +215,14 @@ namespace MWClass
MWWorld::ManualRef newRef(store, base);
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
newRef.getPtr().get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(&cell.get<ESM::Miscellaneous>().insert(*ref), &cell);
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
newPtr.getCellRef().setGoldValue(goldAmount);
newPtr.getRefData().setCount(1);
} else {
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(&cell.get<ESM::Miscellaneous>().insert(*ref), &cell);
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
}
return newPtr;
}

@ -1130,7 +1130,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::NPC> *ref =
ptr.get<ESM::NPC>();
return MWWorld::Ptr(&cell.get<ESM::NPC>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const

@ -178,7 +178,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Potion> *ref =
ptr.get<ESM::Potion>();
return MWWorld::Ptr(&cell.get<ESM::Potion>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -165,7 +165,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Probe> *ref =
ptr.get<ESM::Probe>();
return MWWorld::Ptr(&cell.get<ESM::Probe>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -160,7 +160,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Repair> *ref =
ptr.get<ESM::Repair>();
return MWWorld::Ptr(&cell.get<ESM::Repair>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
boost::shared_ptr<MWWorld::Action> Repair::use (const MWWorld::Ptr& ptr) const

@ -60,6 +60,6 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Static> *ref =
ptr.get<ESM::Static>();
return MWWorld::Ptr(&cell.get<ESM::Static>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
}

@ -417,7 +417,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Weapon> *ref =
ptr.get<ESM::Weapon>();
return MWWorld::Ptr(&cell.get<ESM::Weapon>().insert(*ref), &cell);
return MWWorld::Ptr(cell.insert(ref), &cell);
}
int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -44,9 +44,9 @@ namespace MWMechanics
return MWWorld::Ptr(); // check interior cells only
// Check all the doors in this cell
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
const MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
MWWorld::CellRefList<ESM::Door>::List::const_iterator it = refList.begin();
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
/// TODO: How to check whether the actor is facing a door? Below code is for
@ -59,11 +59,12 @@ namespace MWMechanics
/// opposite of the code in World::activateDoor() ::confused::
for (; it != refList.end(); ++it)
{
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr
&& ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2])
{
return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching
// FIXME cast
return MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell()); // found, stop searching
}
}
return MWWorld::Ptr(); // none found

@ -300,14 +300,16 @@ namespace MWScript
}
catch(std::exception&)
{
// cell not found, move to exterior instead (vanilla PositionCell compatibility)
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID);
int cx,cy;
MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy);
store = MWBase::Environment::get().getWorld()->getExterior(cx,cy);
if(!cell)
{
runtime.getContext().report ("unknown cell (" + cellID + ")");
std::cerr << "unknown cell (" << cellID << ")\n";
std::string error = "PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead";
runtime.getContext().report (error);
std::cerr << error << std::endl;
}
}
if(store)

@ -1,5 +1,7 @@
#include "cells.hpp"
#include <iostream>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/defs.hpp>
@ -23,7 +25,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
if (result==mInteriors.end())
{
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first;
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first;
}
return &result->second;
@ -36,7 +38,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
if (result==mExteriors.end())
{
result = mExteriors.insert (std::make_pair (
std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell))).first;
std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell, mStore, mReader))).first;
}
@ -70,7 +72,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore&
void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const
{
if (cell.getState()!=CellStore::State_Loaded)
cell.load (mStore, mReader);
cell.load ();
ESM::CellState cellState;
@ -114,13 +116,12 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y)
}
result = mExteriors.insert (std::make_pair (
std::make_pair (x, y), CellStore (cell))).first;
std::make_pair (x, y), CellStore (cell, mStore, mReader))).first;
}
if (result->second.getState()!=CellStore::State_Loaded)
{
// Multiple plugin support for landscape data is much easier than for references. The last plugin wins.
result->second.load (mStore, mReader);
result->second.load ();
}
return &result->second;
@ -135,12 +136,12 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name)
{
const ESM::Cell *cell = mStore.get<ESM::Cell>().find(lowerName);
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first;
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first;
}
if (result->second.getState()!=CellStore::State_Loaded)
{
result->second.load (mStore, mReader);
result->second.load ();
}
return &result->second;
@ -158,13 +159,13 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell,
bool searchInContainers)
{
if (cell.getState()==CellStore::State_Unloaded)
cell.preload (mStore, mReader);
cell.preload ();
if (cell.getState()==CellStore::State_Preloaded)
{
if (cell.hasId (name))
{
cell.load (mStore, mReader);
cell.load ();
}
else
return Ptr();
@ -304,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)
{
@ -321,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);
@ -333,9 +357,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
cellStore->readFog(reader);
if (cellStore->getState()!=CellStore::State_Loaded)
cellStore->load (mStore, mReader);
cellStore->load ();
GetCellStoreCallback callback(*this);
cellStore->readReferences (reader, contentFileMap);
cellStore->readReferences (reader, contentFileMap, &callback);
return true;
}

@ -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;
}
@ -141,6 +144,28 @@ namespace
ref.load (state);
collection.mList.push_back (ref);
}
struct SearchByRefNumVisitor
{
MWWorld::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;
}
};
}
namespace MWWorld
@ -179,8 +204,121 @@ namespace MWWorld
return (ref.mRef.mRefnum == pRefnum);
}
CellStore::CellStore (const ESM::Cell *cell)
: mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
void CellStore::moveFrom(const Ptr &object, CellStore *from)
{
if (mState != State_Loaded)
load();
mHasState = true;
MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase());
if (found != mMovedToAnotherCell.end())
{
// A cell we had previously moved an object to is returning it to us.
assert (found->second == from);
mMovedToAnotherCell.erase(found);
}
else
{
mMovedHere.insert(std::make_pair(object.getBase(), from));
}
updateMergedRefs();
}
MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo)
{
if (cellToMoveTo == this)
throw std::runtime_error("moveTo: 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("moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)");
// Ensure that the object actually exists in the cell
SearchByRefNumVisitor searchVisitor(object.getCellRef().getRefNum());
forEach(searchVisitor);
if (!searchVisitor.mFound)
throw std::runtime_error("moveTo: object is not in this cell");
// Objects with no refnum can't be handled correctly in the merging process that happens
// on a save/load, so do a simple copy & delete for these objects.
if (!object.getCellRef().getRefNum().hasContentFile())
{
MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo);
object.getRefData().setCount(0);
object.getRefData().setBaseNode(NULL);
return copied;
}
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())
{
// Special case - object didn't originate in this cell
// Move it back to its original cell first
CellStore* originalCell = found->second;
assert (originalCell != this);
originalCell->moveFrom(object, this);
mMovedHere.erase(found);
// Now that object is back to its rightful owner, we can move it
if (cellToMoveTo != originalCell)
{
originalCell->moveTo(object, cellToMoveTo);
}
updateMergedRefs();
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);
}
struct MergeVisitor
{
MergeVisitor(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();
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
forEachInternal(visitor);
visitor.merge();
}
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
{
mWaterLevel = cell->mWater;
}
@ -212,85 +350,50 @@ namespace MWWorld
return const_cast<CellStore *> (this)->search (id).isEmpty();
}
struct SearchVisitor
{
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);
SearchVisitor searchVisitor;
searchVisitor.mIdToFind = id;
forEach(searchVisitor);
mHasState = oldState;
return Ptr();
return searchVisitor.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();
}
@ -309,37 +412,17 @@ namespace MWWorld
int CellStore::count() const
{
return
mActivators.mList.size()
+ mPotions.mList.size()
+ mAppas.mList.size()
+ mArmors.mList.size()
+ mBooks.mList.size()
+ mClothes.mList.size()
+ mContainers.mList.size()
+ mDoors.mList.size()
+ mIngreds.mList.size()
+ mCreatureLists.mList.size()
+ mItemLists.mList.size()
+ mLights.mList.size()
+ mLockpicks.mList.size()
+ mMiscItems.mList.size()
+ mProbes.mList.size()
+ mRepairs.mList.size()
+ mStatics.mList.size()
+ mWeapons.mList.size()
+ mCreatures.mList.size()
+ mNpcs.mList.size();
}
void CellStore::load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
return mMergedRefs.size();
}
void CellStore::load ()
{
if (mState!=State_Loaded)
{
if (mState==State_Preloaded)
mIds.clear();
loadRefs (store, esm);
loadRefs ();
mState = State_Loaded;
@ -349,18 +432,20 @@ namespace MWWorld
}
}
void CellStore::preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
void CellStore::preload ()
{
if (mState==State_Unloaded)
{
listRefs (store, esm);
listRefs ();
mState = State_Preloaded;
}
}
void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
void CellStore::listRefs()
{
std::vector<ESM::ESMReader>& esm = mReader;
assert (mCell);
if (mCell->mContextList.empty())
@ -404,8 +489,10 @@ namespace MWWorld
std::sort (mIds.begin(), mIds.end());
}
void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
void CellStore::loadRefs()
{
std::vector<ESM::ESMReader>& esm = mReader;
assert (mCell);
if (mCell->mContextList.empty())
@ -432,7 +519,7 @@ namespace MWWorld
continue;
}
loadRef (ref, deleted, store);
loadRef (ref, deleted);
}
}
@ -441,8 +528,10 @@ namespace MWWorld
{
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
loadRef (ref, false, store);
loadRef (ref, false);
}
updateMergedRefs();
}
bool CellStore::isExterior() const
@ -470,10 +559,12 @@ namespace MWWorld
return Ptr();
}
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store)
void CellStore::loadRef (ESM::CellRef& ref, bool deleted)
{
Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
const MWWorld::ESMStore& store = mStore;
switch (store.find (ref.mRefID))
{
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
@ -564,10 +655,19 @@ namespace MWWorld
writeReferenceCollection<ESM::ObjectState> (writer, mRepairs);
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it)
{
LiveCellRefBase* base = it->first;
ESM::RefNum refNum = base->mRef.getRefNum();
ESM::CellId movedTo = it->second->getCell()->getCellId();
refNum.save(writer, true, "MVRF");
movedTo.save(writer);
}
}
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)
{
mHasState = true;
@ -695,6 +795,48 @@ namespace MWWorld
throw std::runtime_error ("unknown type in cell reference section");
}
}
while (reader.isNextSub("MVRF"))
{
reader.cacheSubName();
ESM::RefNum refnum;
ESM::CellId movedTo;
refnum.load(reader, true, "MVRF");
movedTo.load(reader);
// 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)
{
// Should never happen unless someone's tampering with files.
std::cerr << "Found invalid moved ref, ignoring" << std::endl;
continue;
}
moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell);
}
updateMergedRefs();
}
bool operator== (const CellStore& left, const CellStore& right)

@ -40,6 +40,7 @@ namespace ESM
{
struct CellState;
struct FogState;
struct CellId;
}
namespace MWWorld
@ -60,6 +61,9 @@ namespace MWWorld
private:
const MWWorld::ESMStore& mStore;
std::vector<ESM::ESMReader>& mReader;
// Even though fog actually belongs to the player and not cells,
// it makes sense to store it here since we need it once for each cell.
// Note this is NULL until the cell is explored to save some memory
@ -73,6 +77,7 @@ namespace MWWorld
MWWorld::TimeStamp mLastRespawn;
// List of refs owned by this cell
CellRefList<ESM::Activator> mActivators;
CellRefList<ESM::Potion> mPotions;
CellRefList<ESM::Apparatus> mAppas;
@ -94,9 +99,95 @@ namespace MWWorld
CellRefList<ESM::Static> mStatics;
CellRefList<ESM::Weapon> mWeapons;
typedef std::map<LiveCellRefBase*, MWWorld::CellStore*> MovedRefTracker;
// References owned by a different cell that have been moved here.
// <reference, cell the reference originally came from>
MovedRefTracker mMovedHere;
// References owned by this cell that have been moved to another cell.
// <reference, cell the reference was moved to>
MovedRefTracker mMovedToAnotherCell;
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
std::vector<LiveCellRefBase*> mMergedRefs;
/// Moves object from the given cell to this cell.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
/// Repopulate mMergedRefs.
void updateMergedRefs();
// helper function for forEachInternal
template<class Visitor, class List>
bool forEachImp (Visitor& visitor, List& list)
{
for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
++iter)
{
if (iter->mData.isDeletedByContentFile())
continue;
if (!visitor (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 Visitor>
bool forEachInternal (Visitor& visitor)
{
return
forEachImp (visitor, mActivators) &&
forEachImp (visitor, mPotions) &&
forEachImp (visitor, mAppas) &&
forEachImp (visitor, mArmors) &&
forEachImp (visitor, mBooks) &&
forEachImp (visitor, mClothes) &&
forEachImp (visitor, mContainers) &&
forEachImp (visitor, mDoors) &&
forEachImp (visitor, mIngreds) &&
forEachImp (visitor, mItemLists) &&
forEachImp (visitor, mLights) &&
forEachImp (visitor, mLockpicks) &&
forEachImp (visitor, mMiscItems) &&
forEachImp (visitor, mProbes) &&
forEachImp (visitor, mRepairs) &&
forEachImp (visitor, mStatics) &&
forEachImp (visitor, mWeapons) &&
forEachImp (visitor, mCreatures) &&
forEachImp (visitor, mNpcs) &&
forEachImp (visitor, mCreatureLists);
}
/// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are
/// defined at the bottom of this file.
template <class T>
CellRefList<T>& get();
public:
CellStore (const ESM::Cell *cell_);
/// Moves object from this cell to the given cell.
/// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...)
/// @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.
/// The supported types are defined at the bottom of this file.
template <typename T>
LiveCellRefBase* insert(const LiveCellRef<T>* ref)
{
mHasState = true;
CellRefList<T>& list = get<T>();
LiveCellRefBase* ret = &list.insert(*ref);
updateMergedRefs();
return ret;
}
/// @param readerList The readers to use for loading of the cell on-demand.
CellStore (const ESM::Cell *cell_,
const MWWorld::ESMStore& store,
std::vector<ESM::ESMReader>& readerList);
const ESM::Cell *getCell() const;
@ -108,6 +199,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
@ -128,55 +220,82 @@ namespace MWWorld
int count() const;
///< Return total number of references, including deleted ones.
void load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
void load ();
///< Load references from content file.
void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
void preload ();
///< Build ID list from content file.
/// Call functor (ref) for each reference. functor must return a bool. Returning
/// Call visitor (ref) for each reference. visitor must return a bool. Returning
/// 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)
template<class Visitor>
bool forEach (Visitor& visitor)
{
if (mState != State_Loaded)
return false;
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);
for (unsigned int i=0; i<mMergedRefs.size(); ++i)
{
if (mMergedRefs[i]->mData.isDeletedByContentFile())
continue;
if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
return false;
}
return true;
}
template<class Functor>
bool forEachContainer (Functor& functor)
/// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
/// false will abort the iteration.
/// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed?
template <class T, class Visitor>
bool forEachType(Visitor& visitor)
{
if (mState != State_Loaded)
return false;
mHasState = true;
return
forEachImp (functor, mContainers) &&
forEachImp (functor, mCreatures) &&
forEachImp (functor, mNpcs);
CellRefList<T>& list = get<T>();
for (typename CellRefList<T>::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it)
{
LiveCellRefBase* base = &*it;
if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end())
continue;
if (base->mData.isDeletedByContentFile())
continue;
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
LiveCellRefBase* base = it->first;
if (dynamic_cast<LiveCellRef<T>*>(base))
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
return true;
}
/// \todo add const version of forEach
// NOTE: does not account for moved references
// Should be phased out when we have const version of forEach
inline const CellRefList<ESM::Door>& getReadOnlyDoors() const
{
return mDoors;
}
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const
{
return mStatics;
}
bool isExterior() const;
@ -193,47 +312,31 @@ 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.
template <class T>
CellRefList<T>& get() {
throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells");
}
template <class T>
const CellRefList<T>& getReadOnly() {
throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) );
}
bool isPointConnected(const int start, const int end) const;
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
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);
void listRefs();
void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
void loadRefs();
void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store);
void loadRef (ESM::CellRef& ref, bool deleted);
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.
@ -381,12 +484,6 @@ namespace MWWorld
return mWeapons;
}
template<>
inline const CellRefList<ESM::Door>& CellStore::getReadOnly<ESM::Door>()
{
return mDoors;
}
bool operator== (const CellStore& left, const CellStore& right);
bool operator!= (const CellStore& left, const CellStore& right);
}

@ -1,5 +1,5 @@
#ifndef GAME_MWWORLD_CELLFUNCTORS_H
#define GAME_MWWORLD_CELLFUNCTORS_H
#ifndef GAME_MWWORLD_CELLVISITORS_H
#define GAME_MWWORLD_CELLVISITORS_H
#include <vector>
#include <string>
@ -9,7 +9,7 @@
namespace MWWorld
{
struct ListAndResetObjects
struct ListAndResetObjectsVisitor
{
std::vector<MWWorld::Ptr> mObjects;

@ -11,46 +11,54 @@
namespace
{
template<typename T>
void listCellScripts (MWWorld::LocalScripts& localScripts,
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
struct AddScriptsVisitor
{
for (typename MWWorld::CellRefList<T>::List::iterator iter (
cellRefList.mList.begin());
iter!=cellRefList.mList.end(); ++iter)
AddScriptsVisitor(MWWorld::LocalScripts& scripts)
: mScripts(scripts)
{
if (!iter->mBase->mScript.empty() && !iter->mData.isDeleted())
{
localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell));
}
}
}
MWWorld::LocalScripts& mScripts;
// Adds scripts for items in containers (containers/npcs/creatures)
template<typename T>
void listCellScriptsCont (MWWorld::LocalScripts& localScripts,
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
{
for (typename MWWorld::CellRefList<T>::List::iterator iter (
cellRefList.mList.begin());
iter!=cellRefList.mList.end(); ++iter)
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getRefData().isDeleted())
return true;
std::string script = ptr.getClass().getScript(ptr);
if (!script.empty())
mScripts.add(script, ptr);
return true;
}
};
MWWorld::Ptr containerPtr (&*iter, cell);
struct AddContainerItemScriptsVisitor
{
AddContainerItemScriptsVisitor(MWWorld::LocalScripts& scripts)
: mScripts(scripts)
{
}
MWWorld::LocalScripts& mScripts;
bool operator()(const MWWorld::Ptr& containerPtr)
{
MWWorld::ContainerStore& container = containerPtr.getClass().getContainerStore(containerPtr);
for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3)
for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
{
std::string script = it3->getClass().getScript(*it3);
std::string script = it->getClass().getScript(*it);
if(script != "")
{
MWWorld::Ptr item = *it3;
item.mCell = cell;
localScripts.add (script, item);
MWWorld::Ptr item = *it;
item.mCell = containerPtr.getCell();
mScripts.add (script, item);
}
}
return true;
}
}
};
}
MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {}
@ -116,26 +124,13 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr)
void MWWorld::LocalScripts::addCell (CellStore *cell)
{
listCellScripts (*this, cell->get<ESM::Activator>(), cell);
listCellScripts (*this, cell->get<ESM::Potion>(), cell);
listCellScripts (*this, cell->get<ESM::Apparatus>(), cell);
listCellScripts (*this, cell->get<ESM::Armor>(), cell);
listCellScripts (*this, cell->get<ESM::Book>(), cell);
listCellScripts (*this, cell->get<ESM::Clothing>(), cell);
listCellScripts (*this, cell->get<ESM::Container>(), cell);
listCellScriptsCont (*this, cell->get<ESM::Container>(), cell);
listCellScripts (*this, cell->get<ESM::Creature>(), cell);
listCellScriptsCont (*this, cell->get<ESM::Creature>(), cell);
listCellScripts (*this, cell->get<ESM::Door>(), cell);
listCellScripts (*this, cell->get<ESM::Ingredient>(), cell);
listCellScripts (*this, cell->get<ESM::Light>(), cell);
listCellScripts (*this, cell->get<ESM::Lockpick>(), cell);
listCellScripts (*this, cell->get<ESM::Miscellaneous>(), cell);
listCellScripts (*this, cell->get<ESM::NPC>(), cell);
listCellScriptsCont (*this, cell->get<ESM::NPC>(), cell);
listCellScripts (*this, cell->get<ESM::Probe>(), cell);
listCellScripts (*this, cell->get<ESM::Repair>(), cell);
listCellScripts (*this, cell->get<ESM::Weapon>(), cell);
AddScriptsVisitor addScriptsVisitor(*this);
cell->forEach(addScriptsVisitor);
AddContainerItemScriptsVisitor addContainerItemScriptsVisitor(*this);
cell->forEachType<ESM::NPC>(addContainerItemScriptsVisitor);
cell->forEachType<ESM::Creature>(addContainerItemScriptsVisitor);
cell->forEachType<ESM::Container>(addContainerItemScriptsVisitor);
}
void MWWorld::LocalScripts::clear()

@ -182,7 +182,7 @@ namespace MWWorld
mPosition = pos;
}
const ESM::Position& RefData::getPosition()
const ESM::Position& RefData::getPosition() const
{
return mPosition;
}

@ -103,7 +103,7 @@ namespace MWWorld
void disable();
void setPosition (const ESM::Position& pos);
const ESM::Position& getPosition();
const ESM::Position& getPosition() const;
void setCustomData (CustomData *data);
///< Set custom data (potentially replacing old custom data). The ownership of \a data is

@ -22,7 +22,7 @@
#include "localscripts.hpp"
#include "esmstore.hpp"
#include "class.hpp"
#include "cellfunctors.hpp"
#include "cellvisitors.hpp"
#include "cellstore.hpp"
namespace
@ -78,7 +78,7 @@ namespace
}
}
struct InsertFunctor
struct InsertVisitor
{
MWWorld::CellStore& mCell;
bool mRescale;
@ -86,13 +86,13 @@ namespace
MWPhysics::PhysicsSystem& mPhysics;
MWRender::RenderingManager& mRendering;
InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener,
InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener,
MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering);
bool operator() (const MWWorld::Ptr& ptr);
};
InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale,
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale,
Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
: mCell (cell), mRescale (rescale), mLoadingListener (loadingListener),
@ -100,7 +100,7 @@ namespace
mRendering (rendering)
{}
bool InsertFunctor::operator() (const MWWorld::Ptr& ptr)
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
{
if (mRescale)
{
@ -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 AdjustPositionVisitor
{
bool operator() (const MWWorld::Ptr& ptr)
{
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
ptr.getClass().adjustPosition (ptr, false);
return true;
}
};
}
@ -196,11 +206,11 @@ namespace MWWorld
void Scene::unloadCell (CellStoreCollection::iterator iter)
{
std::cout << "Unloading cell\n";
ListAndResetObjects functor;
ListAndResetObjectsVisitor visitor;
(*iter)->forEach<ListAndResetObjects>(functor);
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (functor.mObjects.begin());
iter2!=functor.mObjects.end(); ++iter2)
(*iter)->forEach<ListAndResetObjectsVisitor>(visitor);
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (visitor.mObjects.begin());
iter2!=visitor.mObjects.end(); ++iter2)
{
mPhysics->remove(*iter2);
}
@ -551,8 +561,12 @@ namespace MWWorld
void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener)
{
InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering);
cell.forEach (functor);
InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering);
cell.forEach (insertVisitor);
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
AdjustPositionVisitor adjustPosVisitor;
cell.forEach (adjustPosVisitor);
}
void Scene::addObjectToScene (const Ptr& ptr)

@ -54,7 +54,6 @@
#include "player.hpp"
#include "manualref.hpp"
#include "cellstore.hpp"
#include "cellfunctors.hpp"
#include "containerstore.hpp"
#include "inventorystore.hpp"
#include "actionteleport.hpp"
@ -690,12 +689,12 @@ namespace MWWorld
return mWorldScene->searchPtrViaActorId (actorId);
}
struct FindContainerFunctor
struct FindContainerVisitor
{
Ptr mContainedPtr;
Ptr mResult;
FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {}
FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {}
bool operator() (Ptr ptr)
{
@ -721,11 +720,15 @@ namespace MWWorld
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{
FindContainerFunctor functor(ptr);
(*cellIt)->forEachContainer(functor);
FindContainerVisitor visitor(ptr);
(*cellIt)->forEachType<ESM::Container>(visitor);
if (visitor.mResult.isEmpty())
(*cellIt)->forEachType<ESM::Creature>(visitor);
if (visitor.mResult.isEmpty())
(*cellIt)->forEachType<ESM::NPC>(visitor);
if (!functor.mResult.isEmpty())
return functor.mResult;
if (!visitor.mResult.isEmpty())
return visitor.mResult;
}
return Ptr();
@ -1149,7 +1152,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);
@ -1165,17 +1168,16 @@ 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);
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
mPhysics->updatePtr(ptr, newPtr);
@ -1192,7 +1194,6 @@ namespace MWWorld
addContainerScripts (newPtr, newCell);
}
}
ptr.getRefData().setCount(0);
}
}
if (haveToMove && newPtr.getRefData().getBaseNode())
@ -1708,27 +1709,32 @@ namespace MWWorld
osg::Vec2f World::getNorthVector (CellStore* cell)
{
MWWorld::CellRefList<ESM::Static>& statics = cell->get<ESM::Static>();
MWWorld::LiveCellRef<ESM::Static>* ref = statics.find("northmarker");
if (!ref)
MWWorld::Ptr northmarker = cell->search("northmarker");
if (northmarker.isEmpty())
return osg::Vec2f(0, 1);
osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1));
osg::Quat orient (-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0,0,1));
osg::Vec3f dir = orient * osg::Vec3f(0,1,0);
osg::Vec2f d (dir.x(), dir.y());
return d;
}
void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
struct GetDoorMarkerVisitor
{
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
CellRefList<ESM::Door>::List& refList = doors.mList;
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
GetDoorMarkerVisitor(std::vector<World::DoorMarker>& out)
: mOut(out)
{
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
}
if (!ref.mData.isEnabled())
continue;
std::vector<World::DoorMarker>& mOut;
bool operator()(const MWWorld::Ptr& ptr)
{
MWWorld::LiveCellRef<ESM::Door>& ref = *static_cast<MWWorld::LiveCellRef<ESM::Door>* >(ptr.getBase());
if (!ref.mData.isEnabled() || ref.mData.isDeleted())
return true;
if (ref.mRef.getTeleport())
{
@ -1744,7 +1750,7 @@ namespace MWWorld
else
{
cellid.mPaged = true;
positionToIndex(
MWBase::Environment::get().getWorld()->positionToIndex(
ref.mRef.getDoorDest().pos[0],
ref.mRef.getDoorDest().pos[1],
cellid.mIndex.mX,
@ -1756,9 +1762,16 @@ namespace MWWorld
newMarker.x = pos.pos[0];
newMarker.y = pos.pos[1];
out.push_back(newMarker);
mOut.push_back(newMarker);
}
return true;
}
};
void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
{
GetDoorMarkerVisitor visitor(out);
cell->forEachType<ESM::Door>(visitor);
}
void World::setWaterHeight(const float height)
@ -2253,25 +2266,40 @@ namespace MWWorld
return osg::Vec3f(0,1,0);
}
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
struct GetContainersOwnedByVisitor
{
GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector<MWWorld::Ptr>& out)
: mOwner(owner)
, mOut(out)
{
}
MWWorld::Ptr mOwner;
std::vector<MWWorld::Ptr>& mOut;
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getRefData().isDeleted())
return true;
if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId()))
mOut.push_back(ptr);
return true;
}
};
void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector<MWWorld::Ptr>& out)
{
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{
MWWorld::CellRefList<ESM::Container>& containers = (*cellIt)->get<ESM::Container>();
CellRefList<ESM::Container>::List& refList = containers.mList;
for (CellRefList<ESM::Container>::List::iterator container = refList.begin(); container != refList.end(); ++container)
{
MWWorld::Ptr ptr (&*container, *cellIt);
if (ptr.getRefData().isDeleted())
continue;
if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId()))
out.push_back(ptr);
}
GetContainersOwnedByVisitor visitor (owner, out);
(*cellIt)->forEachType<ESM::Container>(visitor);
}
}
struct ListObjectsFunctor
struct ListObjectsVisitor
{
std::vector<MWWorld::Ptr> mObjects;
@ -2288,10 +2316,10 @@ namespace MWWorld
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{
ListObjectsFunctor functor;
(*cellIt)->forEach<ListObjectsFunctor>(functor);
ListObjectsVisitor visitor;
(*cellIt)->forEach(visitor);
for (std::vector<MWWorld::Ptr>::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it)
for (std::vector<MWWorld::Ptr>::iterator it = visitor.mObjects.begin(); it != visitor.mObjects.end(); ++it)
if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId()))
out.push_back(*it);
}
@ -2342,7 +2370,8 @@ namespace MWWorld
if (0 == cellStore) {
return false;
}
const DoorList &doors = cellStore->get<ESM::Door>().mList;
const DoorList &doors = cellStore->getReadOnlyDoors().mList;
for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) {
if (!it->mRef.getTeleport()) {
continue;
@ -2364,7 +2393,7 @@ namespace MWWorld
if (0 != source) {
// Find door leading to our current teleport door
// and use it destination to position inside cell.
const DoorList &doors = source->get<ESM::Door>().mList;
const DoorList &doors = source->getReadOnlyDoors().mList;
for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) {
if (it->mRef.getTeleport() &&
Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell()))
@ -2378,7 +2407,7 @@ namespace MWWorld
}
}
// Fall back to the first static location.
const StaticList &statics = cellStore->get<ESM::Static>().mList;
const StaticList &statics = cellStore->getReadOnlyStatics().mList;
if ( statics.begin() != statics.end() ) {
pos = statics.begin()->mRef.getPosition();
return true;
@ -2747,7 +2776,7 @@ namespace MWWorld
MWWorld::CellStore *next = getInterior( *i );
if ( !next ) continue;
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>();
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnlyDoors();
const CellRefList<ESM::Door>::List& refList = doors.mList;
// Check if any door in the cell leads to an exterior directly
@ -2807,7 +2836,7 @@ namespace MWWorld
return closestMarker;
}
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>();
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnlyDoors();
const CellRefList<ESM::Door>::List& doorList = doors.mList;
// Check if any door in the cell leads to an exterior directly
@ -2831,7 +2860,6 @@ namespace MWWorld
}
}
}
return MWWorld::Ptr();
}
@ -2888,9 +2916,9 @@ namespace MWWorld
mWeatherManager->update(duration, paused);
}
struct AddDetectedReference
struct AddDetectedReferenceVisitor
{
AddDetectedReference(std::vector<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist)
AddDetectedReferenceVisitor(std::vector<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist)
: mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type)
{
}
@ -2899,7 +2927,7 @@ namespace MWWorld
Ptr mDetector;
float mSquaredDist;
World::DetectionType mType;
bool operator() (MWWorld::Ptr ptr)
bool operator() (const MWWorld::Ptr& ptr)
{
if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist)
return true;
@ -2930,7 +2958,7 @@ namespace MWWorld
return true;
}
bool needToAdd (MWWorld::Ptr ptr, MWWorld::Ptr detector)
bool needToAdd (const MWWorld::Ptr& ptr, const MWWorld::Ptr& detector)
{
if (mType == World::Detect_Creature)
{
@ -2970,13 +2998,13 @@ namespace MWWorld
dist = feetToGameUnits(dist);
AddDetectedReference functor (out, ptr, type, dist*dist);
AddDetectedReferenceVisitor visitor (out, ptr, type, dist*dist);
const Scene::CellStoreCollection& active = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it)
{
MWWorld::CellStore* cellStore = *it;
cellStore->forEach(functor);
cellStore->forEach(visitor);
}
}
@ -3232,7 +3260,7 @@ namespace MWWorld
interpreterContext.executeActivation(object, actor);
}
struct ResetActorsFunctor
struct ResetActorsVisitor
{
bool operator() (Ptr ptr)
{
@ -3254,8 +3282,8 @@ namespace MWWorld
iter!=mWorldScene->getActiveCells().end(); ++iter)
{
CellStore* cellstore = *iter;
ResetActorsFunctor functor;
cellstore->forEach(functor);
ResetActorsVisitor visitor;
cellstore->forEach(visitor);
}
}

@ -3,12 +3,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
void ESM::RefNum::load (ESMReader& esm, bool wide)
void ESM::RefNum::load (ESMReader& esm, bool wide, const std::string& tag)
{
if (wide)
esm.getHNT (*this, "FRMR", 8);
esm.getHNT (*this, tag.c_str(), 8);
else
esm.getHNT (mIndex, "FRMR");
esm.getHNT (mIndex, tag.c_str());
}
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const

@ -16,7 +16,7 @@ namespace ESM
unsigned int mIndex;
int mContentFile;
void load (ESMReader& esm, bool wide = false);
void load (ESMReader& esm, bool wide = false, const std::string& tag = "FRMR");
void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const;

Loading…
Cancel
Save