diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1873583c1..8cfc6bfc8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -145,6 +145,7 @@ set(GAMEWORLD_HEADER mwworld/containerutil.hpp mwworld/player.hpp mwworld/doingphysics.hpp + mwworld/cellfunctors.hpp ) source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp new file mode 100644 index 000000000..5ff801f01 --- /dev/null +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -0,0 +1,31 @@ +#ifndef GAME_MWWORLD_CELLFUNCTORS_H +#define GAME_MWWORLD_CELLFUNCTORS_H + +#include +#include + +#include "refdata.hpp" + +namespace ESM +{ + class CellRef; +} + +namespace MWWorld +{ + /// List all (Ogre-)handles. + struct ListHandles + { + std::vector mHandles; + + bool operator() (ESM::CellRef& ref, RefData& data) + { + std::string handle = data.getHandle(); + if (!handle.empty()) + mHandles.push_back (handle); + return true; + } + }; +} + +#endif diff --git a/apps/openmw/mwworld/doingphysics.cpp b/apps/openmw/mwworld/doingphysics.cpp index 63c6244e9..27fb27c57 100644 --- a/apps/openmw/mwworld/doingphysics.cpp +++ b/apps/openmw/mwworld/doingphysics.cpp @@ -4,6 +4,7 @@ namespace MWWorld { int DoingPhysics::sCounter = 0; + int DoingPhysics::sSuppress = 0; DoingPhysics::DoingPhysics() { @@ -17,6 +18,16 @@ namespace MWWorld bool DoingPhysics::isDoingPhysics() { - return sCounter>0; + return sCounter>0 || sSuppress>0; + } + + SuppressDoingPhysics::SuppressDoingPhysics() + { + ++DoingPhysics::sSuppress; + } + + SuppressDoingPhysics::~SuppressDoingPhysics() + { + --DoingPhysics::sSuppress; } } diff --git a/apps/openmw/mwworld/doingphysics.hpp b/apps/openmw/mwworld/doingphysics.hpp index 7ea2b0f41..d38e4bb15 100644 --- a/apps/openmw/mwworld/doingphysics.hpp +++ b/apps/openmw/mwworld/doingphysics.hpp @@ -3,10 +3,13 @@ namespace MWWorld { - ///< Scope guard for blocking physics updates during physics simulation. + class SuppressDoingPhysics; + + /// Scope guard for blocking physics updates during physics simulation. class DoingPhysics { static int sCounter; + static int sSuppress; private: @@ -20,6 +23,23 @@ namespace MWWorld ~DoingPhysics(); static bool isDoingPhysics(); + + friend class SuppressDoingPhysics; + }; + + /// Scope guard for temporarily lifting the block issues by DoingPhysics + class SuppressDoingPhysics + { + private: + + SuppressDoingPhysics (const SuppressDoingPhysics&); + SuppressDoingPhysics& operator= (const SuppressDoingPhysics&); + + public: + + SuppressDoingPhysics(); + + ~SuppressDoingPhysics(); }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 52547adc2..9ec5ea52c 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -22,6 +22,7 @@ #include "refdata.hpp" #include "globals.hpp" #include "doingphysics.hpp" +#include "cellfunctors.hpp" namespace { @@ -271,6 +272,15 @@ namespace MWWorld void World::unloadCell (CellRenderCollection::iterator iter) { + ListHandles functor; + iter->first->forEach (functor); + + { // silence annoying g++ warning + for (std::vector::const_iterator iter (functor.mHandles.begin()); + iter!=functor.mHandles.end(); ++iter) + mScene.removeObject (*iter); + } + removeScripts (iter->first); mEnvironment.mMechanicsManager->dropActors (iter->first); iter->second->destroy(); @@ -616,6 +626,8 @@ namespace MWWorld void World::changeCell (int X, int Y, const ESM::Position& position) { + SuppressDoingPhysics scopeGuard; + // remove active CellRenderCollection::iterator active = mActiveCells.begin(); @@ -782,10 +794,10 @@ namespace MWWorld if (mCurrentCell->cell->data.gridX!=cellX || mCurrentCell->cell->data.gridY!=cellY) { changeCell (cellX, cellY, mPlayer->getPlayer().getCellRef().pos); - - if (!DoingPhysics::isDoingPhysics()) - mScene.moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z)); } + + if (!DoingPhysics::isDoingPhysics()) + mScene.moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z)); } } } diff --git a/components/esm_store/cell_store.hpp b/components/esm_store/cell_store.hpp index 6acd81dce..43860dff3 100644 --- a/components/esm_store/cell_store.hpp +++ b/components/esm_store/cell_store.hpp @@ -133,7 +133,48 @@ namespace ESMS loadRefs(store, esm); } + /// Call functor (ref) for each reference. functor must return a bool. Returning + /// false will abort the iteration. + /// \return Iteration completed? + template + bool forEach (Functor& functor) + { + return + forEachImp (functor, activators) && + forEachImp (functor, potions) && + forEachImp (functor, appas) && + forEachImp (functor, armors) && + forEachImp (functor, books) && + forEachImp (functor, clothes) && + forEachImp (functor, containers) && + forEachImp (functor, creatures) && + forEachImp (functor, doors) && + forEachImp (functor, ingreds) && + forEachImp (functor, creatureLists) && + forEachImp (functor, itemLists) && + forEachImp (functor, lights) && + forEachImp (functor, lockpicks) && + forEachImp (functor, miscItems) && + forEachImp (functor, npcs) && + forEachImp (functor, probes) && + forEachImp (functor, repairs) && + forEachImp (functor, statics) && + forEachImp (functor, weapons); + } + private: + + template + bool forEachImp (Functor& functor, List& list) + { + for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); + ++iter) + if (!functor (iter->ref, iter->mData)) + return false; + + return true; + } + void loadRefs(const ESMStore &store, ESMReader &esm) { assert (cell);