From ce3bba0cdc02a0f58bb67f7f1e12d62619c7deb3 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 18 May 2022 19:40:54 +0200 Subject: [PATCH] Use std::list to store mechanics objects To make the order of elements deterministic. Using memory address based objects as map key makes order of elements there nondeterministic. Later it can be replaced with vector when there are no indirect munipulations with container inside iteration loops. Change map key to const MWWorld::LiveCellRefBase* to avoid erasing and inserting elements on MWWorld::Ptr update. Store CharacterController by value instead of pointer to avoid redundant memory allocation. --- apps/openmw/mwmechanics/character.hpp | 2 + apps/openmw/mwmechanics/objects.cpp | 88 +++++++++++---------------- apps/openmw/mwmechanics/objects.hpp | 14 ++--- 3 files changed, 45 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index e7f445054e..e8e7f2b721 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,8 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); + const MWWorld::Ptr& getPtr() const { return mPtr; }; + void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override; // Be careful when to call this, see comment in Actors diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 2b5157b4ec..c77521d06e 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -13,55 +13,43 @@ namespace MWMechanics { -Objects::~Objects() -{ - for(auto& object : mObjects) - { - delete object.second; - object.second = nullptr; - } -} - void Objects::addObject(const MWWorld::Ptr& ptr) { removeObject(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(anim) mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim))); + if (anim == nullptr) + return; + + const auto it = mObjects.emplace(mObjects.end(), ptr, anim); + mIndex.emplace(ptr.getBase(), it); } void Objects::removeObject(const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mObjects.find(ptr); - if(iter != mObjects.end()) + const auto iter = mIndex.find(ptr.getBase()); + if (iter != mIndex.end()) { - delete iter->second; - mObjects.erase(iter); + mObjects.erase(iter->second); + mIndex.erase(iter); } } void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mObjects.find(old); - if(iter != mObjects.end()) - { - CharacterController *ctrl = iter->second; - mObjects.erase(iter); - - ctrl->updatePtr(ptr); - mObjects.insert(std::make_pair(ptr, ctrl)); - } + const auto iter = mIndex.find(old.getBase()); + if (iter != mIndex.end()) + iter->second->updatePtr(ptr); } void Objects::dropObjects (const MWWorld::CellStore *cellStore) { - PtrControllerMap::iterator iter = mObjects.begin(); - while(iter != mObjects.end()) + for (auto iter = mObjects.begin(); iter != mObjects.end();) { - if(iter->first.getCell()==cellStore) + if (iter->getPtr().getCell() == cellStore) { - delete iter->second; - mObjects.erase(iter++); + mIndex.erase(iter->getPtr().getBase()); + iter = mObjects.erase(iter); } else ++iter; @@ -72,8 +60,8 @@ void Objects::update(float duration, bool paused) { if(!paused) { - for(auto& object : mObjects) - object.second->update(duration); + for (CharacterController& object : mObjects) + object.update(duration); } else { @@ -82,15 +70,15 @@ void Objects::update(float duration, bool paused) if(mode != MWGui::GM_Container) return; - for(auto& object : mObjects) + for (CharacterController& object : mObjects) { - if (object.first.getType() != ESM::Container::sRecordId) + if (object.getPtr().getType() != ESM::Container::sRecordId) continue; - if (object.second->isAnimPlaying("containeropen")) + if (object.isAnimPlaying("containeropen")) { - object.second->update(duration); - MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(object.first); + object.update(duration); + MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(object.getPtr()); } } } @@ -98,23 +86,23 @@ void Objects::update(float duration, bool paused) bool Objects::onOpen(const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mObjects.find(ptr); - if(iter != mObjects.end()) + const auto iter = mIndex.find(ptr.getBase()); + if (iter != mIndex.end()) return iter->second->onOpen(); return true; } void Objects::onClose(const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mObjects.find(ptr); - if(iter != mObjects.end()) + const auto iter = mIndex.find(ptr.getBase()); + if (iter != mIndex.end()) iter->second->onClose(); } bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) { - PtrControllerMap::iterator iter = mObjects.find(ptr); - if(iter != mObjects.end()) + const auto iter = mIndex.find(ptr.getBase()); + if (iter != mIndex.end()) { return iter->second->playGroup(groupName, mode, number, persist); } @@ -126,24 +114,22 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro } void Objects::skipAnimation(const MWWorld::Ptr& ptr) { - PtrControllerMap::iterator iter = mObjects.find(ptr); - if(iter != mObjects.end()) + const auto iter = mIndex.find(ptr.getBase()); + if (iter != mIndex.end()) iter->second->skipAnim(); } void Objects::persistAnimationStates() { - for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) - iter->second->persistAnimationState(); + for (CharacterController& object : mObjects) + object.persistAnimationState(); } -void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) +void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) const { - for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) - { - if ((position - iter->first.getRefData().getPosition().asVec3()).length2() <= radius*radius) - out.push_back(iter->first); - } + for (const CharacterController& object : mObjects) + if ((position - object.getPtr().getRefData().getPosition().asVec3()).length2() <= radius * radius) + out.push_back(object.getPtr()); } } diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index ba39fdbd4f..a6b2d7c675 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,9 +1,12 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H #define GAME_MWMECHANICS_ACTIVATORS_H +#include "character.hpp" + #include #include #include +#include namespace osg { @@ -18,17 +21,12 @@ namespace MWWorld namespace MWMechanics { - class CharacterController; - class Objects { - typedef std::map PtrControllerMap; - PtrControllerMap mObjects; + std::list mObjects; + std::map::iterator> mIndex; public: - Objects() = default; - ~Objects(); - void addObject (const MWWorld::Ptr& ptr); ///< Register an animated object @@ -51,7 +49,7 @@ namespace MWMechanics void skipAnimation(const MWWorld::Ptr& ptr); void persistAnimationStates(); - void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); + void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) const; std::size_t size() const {