diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0c3a93e656..b32623b3f0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -78,7 +78,7 @@ add_openmw_dir (mwworld actionequip timestamp actionalchemy cellstore actionapply actioneat store esmstore fallback actionrepair actionsoulgem livecellref actiondoor contentloader esmloader actiontrap cellreflist cellref weather projectilemanager - cellpreloader datetimemanager groundcoverstore magiceffects cell + cellpreloader datetimemanager groundcoverstore magiceffects cell ptrregistry ) add_openmw_dir (mwphysics diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index fdb2a7274f..a7cfae503e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -208,7 +208,7 @@ namespace MWClass } newPtr.getCellRef().unsetRefNum(); newPtr.getRefData().setLuaScripts(nullptr); - MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(newPtr); return newPtr; } @@ -229,7 +229,7 @@ namespace MWClass newPtr = MWWorld::Ptr(cell.insert(ref), &cell); } ptr.getRefData().setLuaScripts(nullptr); - MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(newPtr); return newPtr; } diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 35f9af0f2b..83102df61f 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -83,7 +83,7 @@ namespace MWLua auto visitor = [&](const MWWorld::Ptr& ptr) { if (ptr.getRefData().isDeleted()) return true; - MWBase::Environment::get().getWorldModel()->registerPtr(ptr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(ptr); if (getLiveCellRefType(ptr.mRef) == ptr.getType()) res->push_back(getId(ptr)); return true; diff --git a/apps/openmw/mwlua/engineevents.cpp b/apps/openmw/mwlua/engineevents.cpp index 0c5abe6cef..7c1342aefe 100644 --- a/apps/openmw/mwlua/engineevents.cpp +++ b/apps/openmw/mwlua/engineevents.cpp @@ -74,7 +74,7 @@ namespace MWLua private: MWWorld::Ptr getPtr(const ESM::RefNum& id) const { - MWWorld::Ptr res = mWorldModel->getPtr(id); + MWWorld::Ptr res = mWorldModel->getPtrRegistry().getOrDefault(id); if (res.isEmpty() && Settings::lua().mLuaDebug) Log(Debug::Verbose) << "Can not find object" << id.toString() << " when calling engine hanglers"; return res; diff --git a/apps/openmw/mwlua/luaevents.cpp b/apps/openmw/mwlua/luaevents.cpp index b036fea3b6..d96ae63579 100644 --- a/apps/openmw/mwlua/luaevents.cpp +++ b/apps/openmw/mwlua/luaevents.cpp @@ -40,7 +40,7 @@ namespace MWLua mGlobalEventBatch.clear(); for (const Local& e : mLocalEventBatch) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorldModel()->getPtr(e.mDest); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(e.mDest); LocalScripts* scripts = ptr.isEmpty() ? nullptr : ptr.getRefData().getLuaScripts(); if (scripts) scripts->receiveEvent(e.mEventName, e.mEventData); diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 0447a24260..50d4d9c11d 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -136,7 +136,7 @@ namespace MWLua if (!mPlayer.isInCell() || !newPlayerPtr.isInCell() || mPlayer.getCell() != newPlayerPtr.getCell()) { mPlayer = newPlayerPtr; // player was moved to another cell, update ptr in registry - MWBase::Environment::get().getWorldModel()->registerPtr(mPlayer); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(mPlayer); } mWorldView.update(); @@ -299,7 +299,7 @@ namespace MWLua if (localScripts) { mActiveLocalScripts.erase(localScripts); - if (!MWBase::Environment::get().getWorldModel()->getPtr(getId(ptr)).isEmpty()) + if (!MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(getId(ptr)).isEmpty()) mEngineEvents.addToQueue(EngineEvents::OnInactive{ getId(ptr) }); } } @@ -401,7 +401,7 @@ namespace MWLua return; } - MWBase::Environment::get().getWorldModel()->registerPtr(ptr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(ptr); LocalScripts* scripts = createLocalScripts(ptr); scripts->setSerializer(mLocalSerializer.get()); @@ -409,7 +409,7 @@ namespace MWLua scripts->load(data); // LiveCellRef is usually copied after loading, so this Ptr will become invalid and should be deregistered. - MWBase::Environment::get().getWorldModel()->deregisterPtr(ptr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().remove(ptr); } void LuaManager::reloadAllScripts() @@ -430,7 +430,7 @@ namespace MWLua mGlobalScripts.load(data); } - for (const auto& [id, ptr] : MWBase::Environment::get().getWorldModel()->getAllPtrs()) + for (const auto& [id, ptr] : MWBase::Environment::get().getWorldModel()->getPtrRegistry()) { // Reload local scripts LocalScripts* scripts = ptr.getRefData().getLuaScripts(); if (scripts == nullptr) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 5e5c380469..5ad80c97eb 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -497,7 +497,7 @@ namespace MWLua while (it.getType() != -1) { const MWWorld::Ptr& item = *(it++); - MWBase::Environment::get().getWorldModel()->registerPtr(item); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(item); list->push_back(getId(item)); } return ObjectList{ list }; @@ -516,7 +516,7 @@ namespace MWLua { if (item.getCellRef().getRefId() == itemId) { - MWBase::Environment::get().getWorldModel()->registerPtr(item); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(item); return ObjectT(getId(item)); } } @@ -531,7 +531,7 @@ namespace MWLua { if (item.getCellRef().getRefId() == itemId) { - MWBase::Environment::get().getWorldModel()->registerPtr(item); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(item); list->push_back(getId(item)); } } diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index bf0866bc0f..d1f0e1ec8c 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -32,7 +32,8 @@ namespace MWLua MWWorld::Ptr itemPtr; if (std::holds_alternative(item)) { - itemPtr = MWBase::Environment::get().getWorldModel()->getPtr(std::get(item)); + itemPtr = MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault( + std::get(item)); if (old_it != store.end() && *old_it == itemPtr) return true; // already equipped if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0 @@ -217,7 +218,7 @@ namespace MWLua auto it = store.getSlot(slot); if (it == store.end()) continue; - MWBase::Environment::get().getWorldModel()->registerPtr(*it); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(*it); if (dynamic_cast(&o)) equipment[slot] = sol::make_object(lua, GObject(*it)); else @@ -233,7 +234,7 @@ namespace MWLua auto it = store.getSlot(slot); if (it == store.end()) return sol::nil; - MWBase::Environment::get().getWorldModel()->registerPtr(*it); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(*it); if (dynamic_cast(&o)) return sol::make_object(lua, GObject(*it)); else diff --git a/apps/openmw/mwlua/worldview.cpp b/apps/openmw/mwlua/worldview.cpp index f5699dff89..80f836c73b 100644 --- a/apps/openmw/mwlua/worldview.cpp +++ b/apps/openmw/mwlua/worldview.cpp @@ -58,7 +58,7 @@ namespace MWLua void WorldView::objectAddedToScene(const MWWorld::Ptr& ptr) { - MWBase::Environment::get().getWorldModel()->registerPtr(ptr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(ptr); ObjectGroup* group = chooseGroup(ptr); if (group) addToGroup(*group, ptr); @@ -81,13 +81,13 @@ namespace MWLua void WorldView::load(ESM::ESMReader& esm) { esm.getHNT(mSimulationTime, "LUAW"); - MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(esm.getFormId(true)); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().setLastGenerated(esm.getFormId(true)); } void WorldView::save(ESM::ESMWriter& esm) const { esm.writeHNT("LUAW", mSimulationTime); - esm.writeFormId(MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum(), true); + esm.writeFormId(MWBase::Environment::get().getWorldModel()->getPtrRegistry().getLastGenerated(), true); } void WorldView::ObjectGroup::updateList() diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 60bf58953a..d95f9c40ae 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -63,7 +63,7 @@ namespace if (pair.second.empty()) return MWWorld::Ptr(); else if (pair.first.hasContentFile()) - return MWBase::Environment::get().getWorldModel()->getPtr(pair.first); + return MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(pair.first); return MWBase::Environment::get().getWorld()->searchPtr(pair.second, false); } }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4036c378db..67242d9003 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -275,7 +275,7 @@ namespace iter->mData.enable(); MWBase::Environment::get().getWorld()->disable(ptr); } - MWBase::Environment::get().getWorldModel()->registerPtr(ptr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(ptr); return; } @@ -290,7 +290,7 @@ namespace collection.mList.push_back(ref); MWWorld::LiveCellRefBase* base = &collection.mList.back(); - MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(base, cellstore)); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(MWWorld::Ptr(base, cellstore)); } // this function allows us to link a CellRefList to the associated recNameInt, and apply a function @@ -443,7 +443,8 @@ namespace MWWorld throw std::runtime_error( "moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)"); - MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(object.getBase(), cellToMoveTo)); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert( + MWWorld::Ptr(object.getBase(), cellToMoveTo)); MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) @@ -1041,7 +1042,7 @@ namespace MWWorld } // Search for the reference. It might no longer exist if its content file was removed. - Ptr movedRef = MWBase::Environment::get().getWorldModel()->getPtr(refnum); + Ptr movedRef = MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(refnum); if (movedRef.isEmpty()) { Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << refnum.mIndex diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 28777656c8..ee6f3cc1ab 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -375,7 +375,7 @@ namespace MWWorld newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference newPtr.getRefData().setCount(count); newPtr.getRefData().setLuaScripts(nullptr); - MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(newPtr); if (hasInventoryStore(newPtr)) getInventoryStore(newPtr).setActor(newPtr); return newPtr; @@ -385,7 +385,7 @@ namespace MWWorld { Ptr newPtr = copyToCellImpl(ptr, cell); ptr.getRefData().setLuaScripts(nullptr); - MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(newPtr); if (hasInventoryStore(newPtr)) getInventoryStore(newPtr).setActor(newPtr); return newPtr; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5de939b6e9..62285c29a6 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -308,7 +308,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add( // The copy of the original item we just made MWWorld::Ptr item = *it; - MWBase::Environment::get().getWorldModel()->registerPtr(item); + MWBase::Environment::get().getWorldModel()->getPtrRegistry().insert(item); // we may have copied an item from the world, so reset a few things first item.getRefData().setBaseNode( diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index a0826474c5..5570856132 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -24,7 +24,7 @@ namespace MWWorld SafePtr::SafePtr(const Ptr& ptr) : mId(ptr.getCellRef().getRefNum()) , mPtr(ptr) - , mLastUpdate(MWBase::Environment::get().getWorldModel()->getPtrIndexUpdateCounter()) + , mLastUpdate(MWBase::Environment::get().getWorldModel()->getPtrRegistry().getRevision()) { } @@ -39,11 +39,11 @@ namespace MWWorld void SafePtr::update() const { - WorldModel& w = *MWBase::Environment::get().getWorldModel(); - if (mLastUpdate < w.getPtrIndexUpdateCounter()) + const PtrRegistry& registry = MWBase::Environment::get().getWorldModel()->getPtrRegistry(); + if (mLastUpdate < registry.getRevision()) { - mPtr = w.getPtr(mId); - mLastUpdate = w.getPtrIndexUpdateCounter(); + mPtr = registry.getOrDefault(mId); + mLastUpdate = registry.getRevision(); } } } diff --git a/apps/openmw/mwworld/ptrregistry.hpp b/apps/openmw/mwworld/ptrregistry.hpp new file mode 100644 index 0000000000..4ecde7b52f --- /dev/null +++ b/apps/openmw/mwworld/ptrregistry.hpp @@ -0,0 +1,59 @@ +#ifndef OPENMW_APPS_OPENMW_MWWORLD_PTRREGISTRY_H +#define OPENMW_APPS_OPENMW_MWWORLD_PTRREGISTRY_H + +#include "ptr.hpp" + +#include "components/esm3/cellref.hpp" + +#include + +namespace MWWorld +{ + class PtrRegistry + { + public: + std::size_t getRevision() const { return mRevision; } + + ESM::RefNum getLastGenerated() const { return mLastGenerated; } + + auto begin() const { return mIndex.cbegin(); } + + auto end() const { return mIndex.cend(); } + + Ptr getOrDefault(ESM::RefNum refNum) const + { + const auto it = mIndex.find(refNum); + if (it != mIndex.end()) + return it->second; + return Ptr(); + } + + void setLastGenerated(ESM::RefNum v) { mLastGenerated = v; } + + void clear() + { + mIndex.clear(); + mLastGenerated = ESM::RefNum{}; + mRevision = 0; + } + + void insert(const Ptr& ptr) + { + mIndex[ptr.getCellRef().getOrAssignRefNum(mLastGenerated)] = ptr; + ++mRevision; + } + + void remove(const Ptr& ptr) + { + mIndex.erase(ptr.getCellRef().getRefNum()); + ++mRevision; + } + + private: + std::size_t mRevision = 0; + std::unordered_map mIndex; + ESM::RefNum mLastGenerated; + }; +} + +#endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 349215460c..78a33bcdbf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1851,7 +1851,8 @@ namespace MWWorld facedObject = rayToObject.mHitObject; if (facedObject.isEmpty() && rayToObject.mHitRefnum.isSet()) - facedObject = MWBase::Environment::get().getWorldModel()->getPtr(rayToObject.mHitRefnum); + facedObject + = MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(rayToObject.mHitRefnum); if (rayToObject.mHit) mDistanceToFacedObject = (rayToObject.mRatio * maxDistance) - camDist; else @@ -1868,7 +1869,8 @@ namespace MWWorld res.mHitNormal = rayRes.mHitNormalWorld; res.mHitObject = rayRes.mHitObject; if (res.mHitObject.isEmpty() && rayRes.mHitRefnum.isSet()) - res.mHitObject = MWBase::Environment::get().getWorldModel()->getPtr(rayRes.mHitRefnum); + res.mHitObject + = MWBase::Environment::get().getWorldModel()->getPtrRegistry().getOrDefault(rayRes.mHitRefnum); return res.mHit; } diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index ca69a7ff39..3841cc6fdf 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -82,9 +82,7 @@ MWWorld::CellStore& MWWorld::WorldModel::insertCellStore(const ESM::Cell& cell) void MWWorld::WorldModel::clear() { - mPtrIndex.clear(); - mPtrIndexUpdateCounter = 0; - mLastGeneratedRefnum = ESM::RefNum{}; + mPtrRegistry.clear(); mInteriors.clear(); mExteriors.clear(); mCells.clear(); @@ -92,27 +90,6 @@ void MWWorld::WorldModel::clear() mIdCacheIndex = 0; } -void MWWorld::WorldModel::registerPtr(const MWWorld::Ptr& ptr) -{ - mPtrIndex[ptr.getCellRef().getOrAssignRefNum(mLastGeneratedRefnum)] = ptr; - mPtrIndexUpdateCounter++; -} - -void MWWorld::WorldModel::deregisterPtr(const MWWorld::Ptr& ptr) -{ - mPtrIndex.erase(ptr.getCellRef().getRefNum()); - mPtrIndexUpdateCounter++; -} - -MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefNum& refNum) const -{ - auto it = mPtrIndex.find(refNum); - if (it != mPtrIndex.end()) - return it->second; - else - return MWWorld::Ptr(); -} - MWWorld::Ptr MWWorld::WorldModel::getPtrAndCache(const ESM::RefId& name, CellStore& cellStore) { Ptr ptr = cellStore.getPtr(name); diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index a83e29dd83..53a46c78d1 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -12,6 +12,7 @@ #include "cellstore.hpp" #include "ptr.hpp" +#include "ptrregistry.hpp" namespace ESM { @@ -51,17 +52,10 @@ namespace MWWorld CellStore& getCell(std::string_view name, bool forceLoad = true); // interior or named exterior CellStore& getCell(const ESM::RefId& Id, bool forceLoad = true); - void registerPtr(const MWWorld::Ptr& ptr); - void deregisterPtr(const MWWorld::Ptr& ptr); - ESM::RefNum getLastGeneratedRefNum() const { return mLastGeneratedRefnum; } - void setLastGeneratedRefNum(ESM::RefNum v) { mLastGeneratedRefnum = v; } - size_t getPtrIndexUpdateCounter() const { return mPtrIndexUpdateCounter; } - const std::unordered_map& getAllPtrs() const { return mPtrIndex; } - - Ptr getPtr(const ESM::RefNum& refNum) const; - Ptr getPtr(const ESM::RefId& name); + PtrRegistry& getPtrRegistry() { return mPtrRegistry; } + template void forEachLoadedCellStore(Fn&& fn) { @@ -90,9 +84,7 @@ namespace MWWorld mutable std::map mExteriors; std::vector> mIdCache; std::size_t mIdCacheIndex = 0; - std::unordered_map mPtrIndex; - std::size_t mPtrIndexUpdateCounter = 0; - ESM::RefNum mLastGeneratedRefnum; + PtrRegistry mPtrRegistry; CellStore& getOrInsertCellStore(const ESM::Cell& cell);