diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp index 0d6aee38f1..52d3102a45 100644 --- a/apps/openmw/mwbase/luamanager.hpp +++ b/apps/openmw/mwbase/luamanager.hpp @@ -31,6 +31,8 @@ namespace MWBase virtual void newGameStarted() = 0; virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0; virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0; + virtual void registerObject(const MWWorld::Ptr& ptr) = 0; + virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0; virtual void keyPressed(const SDL_KeyboardEvent &arg) = 0; struct ActorControls { diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 15e45eba1a..f695e1245b 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -134,6 +134,7 @@ namespace MWLua scripts->processTimers(seconds, hours); } + // Receive events for (GlobalEvent& e : globalEvents) mGlobalScripts.receiveEvent(e.eventName, e.eventData); for (LocalEvent& e : localEvents) @@ -147,12 +148,7 @@ namespace MWLua << ". Object not found or has no attached scripts"; } - if (mPlayerChanged) - { - mPlayerChanged = false; - mGlobalScripts.playerAdded(GObject(getId(mPlayer), mWorldView.getObjectRegistry())); - } - + // Engine handlers in local scripts if (mPlayerScripts) { for (const SDL_Keysym key : mKeyPressEvents) @@ -167,13 +163,21 @@ namespace MWLua mObjectActiveEvents.clear(); mObjectInactiveEvents.clear(); + for (LocalScripts* scripts : mActiveLocalScripts) + scripts->update(dt); + + // Engine handlers in global scripts + if (mPlayerChanged) + { + mPlayerChanged = false; + mGlobalScripts.playerAdded(GObject(getId(mPlayer), mWorldView.getObjectRegistry())); + } + for (ObjectId id : mActorAddedEvents) mGlobalScripts.actorActive(GObject(id, mWorldView.getObjectRegistry())); mActorAddedEvents.clear(); mGlobalScripts.update(dt); - for (LocalScripts* scripts : mActiveLocalScripts) - scripts->update(dt); } void LuaManager::applyQueuedChanges() @@ -212,6 +216,22 @@ namespace MWLua } } + void LuaManager::setupPlayer(const MWWorld::Ptr& ptr) + { + if (!mPlayer.isEmpty()) + throw std::logic_error("Player is initialized twice"); + mWorldView.objectAddedToScene(ptr); + mPlayer = ptr; + MWWorld::RefData& refData = ptr.getRefData(); + if (!refData.getLuaScripts()) + createLocalScripts(ptr); + if (!mPlayerScripts) + throw std::logic_error("mPlayerScripts not initialized"); + mActiveLocalScripts.insert(mPlayerScripts); + mObjectActiveEvents.push_back(mPlayerScripts); + mPlayerChanged = true; + } + void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr) { mWorldView.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet. @@ -227,21 +247,6 @@ namespace MWLua mActorAddedEvents.push_back(getId(ptr)); } - void LuaManager::setupPlayer(const MWWorld::Ptr& ptr) - { - if (!mPlayer.isEmpty()) - throw std::logic_error("Player is initialized twice"); - mWorldView.objectAddedToScene(ptr); - mPlayer = ptr; - MWWorld::RefData& refData = ptr.getRefData(); - if (!refData.getLuaScripts()) - createLocalScripts(ptr); - if (!mPlayerScripts) - throw std::logic_error("mPlayerScripts not initialized"); - mActiveLocalScripts.insert(mPlayerScripts); - mPlayerChanged = true; - } - void LuaManager::objectRemovedFromScene(const MWWorld::Ptr& ptr) { mWorldView.objectRemovedFromScene(ptr); @@ -249,10 +254,19 @@ namespace MWLua if (localScripts) { mActiveLocalScripts.erase(localScripts); - mObjectInactiveEvents.push_back(localScripts); + if (!mWorldView.getObjectRegistry()->getPtr(getId(ptr), true).isEmpty()) + mObjectInactiveEvents.push_back(localScripts); } + } - // TODO: call mWorldView.objectUnloaded if object is unloaded from memory (does it ever happen?) and ptr becomes invalid. + void LuaManager::registerObject(const MWWorld::Ptr& ptr) + { + mWorldView.getObjectRegistry()->registerPtr(ptr); + } + + void LuaManager::deregisterObject(const MWWorld::Ptr& ptr) + { + mWorldView.getObjectRegistry()->deregisterPtr(ptr); } void LuaManager::keyPressed(const SDL_KeyboardEvent& arg) @@ -349,6 +363,9 @@ namespace MWLua scripts->setSerializer(mLocalLoader.get()); scripts->load(data, true); scripts->setSerializer(mLocalSerializer.get()); + + // LiveCellRef is usually copied after loading, so this Ptr will become invalid and should be deregistered. + mWorldView.getObjectRegistry()->deregisterPtr(ptr); } void LuaManager::reloadAllScripts() diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index c0b08ee546..d3191e8428 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -40,6 +40,8 @@ namespace MWLua void newGameStarted() override { mGlobalScripts.newGameStarted(); } void objectAddedToScene(const MWWorld::Ptr& ptr) override; void objectRemovedFromScene(const MWWorld::Ptr& ptr) override; + void registerObject(const MWWorld::Ptr& ptr) override; + void deregisterObject(const MWWorld::Ptr& ptr) override; void keyPressed(const SDL_KeyboardEvent &arg) override; MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0d2ee85deb..53245be247 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -18,6 +18,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/luamanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" @@ -195,6 +196,8 @@ namespace iter->mData.enable(); MWBase::Environment::get().getWorld()->disable(MWWorld::Ptr(&*iter, cellstore)); } + else + MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(&*iter, cellstore)); return; } @@ -206,6 +209,9 @@ namespace MWWorld::LiveCellRef ref (record); ref.load (state); collection.mList.push_back (ref); + + MWWorld::LiveCellRefBase* base = &collection.mList.back(); + MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(base, cellstore)); } } @@ -286,16 +292,7 @@ namespace MWWorld if (searchViaRefNum(object.getCellRef().getRefNum()).isEmpty()) 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().getCount()); - object.getRefData().setCount(0); - object.getRefData().setBaseNode(nullptr); - return copied; - } + MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(object.getBase(), cellToMoveTo)); MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a7915dd30d..99bd53ef3f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -813,7 +813,8 @@ namespace MWWorld void World::enable (const Ptr& reference) { - // enable is a no-op for items in containers + MWBase::Environment::get().getLuaManager()->registerObject(reference); + if (!reference.isInCell()) return; @@ -864,6 +865,7 @@ namespace MWWorld if (reference == getPlayerPtr()) throw std::runtime_error("can not disable player object"); + MWBase::Environment::get().getLuaManager()->deregisterObject(reference); reference.getRefData().disable(); if (reference.getCellRef().getRefNum().hasContentFile())