1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-30 07:21:12 +00:00

Make loaded but inactive objects available in Lua scripts.

This commit is contained in:
Petr Mikheev 2021-04-19 13:33:25 +02:00
parent 403d31313c
commit 1268597676
5 changed files with 56 additions and 36 deletions

View File

@ -31,6 +31,8 @@ namespace MWBase
virtual void newGameStarted() = 0; virtual void newGameStarted() = 0;
virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0; virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0;
virtual void objectRemovedFromScene(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; virtual void keyPressed(const SDL_KeyboardEvent &arg) = 0;
struct ActorControls { struct ActorControls {

View File

@ -134,6 +134,7 @@ namespace MWLua
scripts->processTimers(seconds, hours); scripts->processTimers(seconds, hours);
} }
// Receive events
for (GlobalEvent& e : globalEvents) for (GlobalEvent& e : globalEvents)
mGlobalScripts.receiveEvent(e.eventName, e.eventData); mGlobalScripts.receiveEvent(e.eventName, e.eventData);
for (LocalEvent& e : localEvents) for (LocalEvent& e : localEvents)
@ -147,12 +148,7 @@ namespace MWLua
<< ". Object not found or has no attached scripts"; << ". Object not found or has no attached scripts";
} }
if (mPlayerChanged) // Engine handlers in local scripts
{
mPlayerChanged = false;
mGlobalScripts.playerAdded(GObject(getId(mPlayer), mWorldView.getObjectRegistry()));
}
if (mPlayerScripts) if (mPlayerScripts)
{ {
for (const SDL_Keysym key : mKeyPressEvents) for (const SDL_Keysym key : mKeyPressEvents)
@ -167,13 +163,21 @@ namespace MWLua
mObjectActiveEvents.clear(); mObjectActiveEvents.clear();
mObjectInactiveEvents.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) for (ObjectId id : mActorAddedEvents)
mGlobalScripts.actorActive(GObject(id, mWorldView.getObjectRegistry())); mGlobalScripts.actorActive(GObject(id, mWorldView.getObjectRegistry()));
mActorAddedEvents.clear(); mActorAddedEvents.clear();
mGlobalScripts.update(dt); mGlobalScripts.update(dt);
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->update(dt);
} }
void LuaManager::applyQueuedChanges() 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) void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr)
{ {
mWorldView.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet. mWorldView.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
@ -227,21 +247,6 @@ namespace MWLua
mActorAddedEvents.push_back(getId(ptr)); 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) void LuaManager::objectRemovedFromScene(const MWWorld::Ptr& ptr)
{ {
mWorldView.objectRemovedFromScene(ptr); mWorldView.objectRemovedFromScene(ptr);
@ -249,10 +254,19 @@ namespace MWLua
if (localScripts) if (localScripts)
{ {
mActiveLocalScripts.erase(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) void LuaManager::keyPressed(const SDL_KeyboardEvent& arg)
@ -349,6 +363,9 @@ namespace MWLua
scripts->setSerializer(mLocalLoader.get()); scripts->setSerializer(mLocalLoader.get());
scripts->load(data, true); scripts->load(data, true);
scripts->setSerializer(mLocalSerializer.get()); 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() void LuaManager::reloadAllScripts()

View File

@ -40,6 +40,8 @@ namespace MWLua
void newGameStarted() override { mGlobalScripts.newGameStarted(); } void newGameStarted() override { mGlobalScripts.newGameStarted(); }
void objectAddedToScene(const MWWorld::Ptr& ptr) override; void objectAddedToScene(const MWWorld::Ptr& ptr) override;
void objectRemovedFromScene(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; void keyPressed(const SDL_KeyboardEvent &arg) override;
MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override;

View File

@ -18,6 +18,7 @@
#include <components/esm/doorstate.hpp> #include <components/esm/doorstate.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -195,6 +196,8 @@ namespace
iter->mData.enable(); iter->mData.enable();
MWBase::Environment::get().getWorld()->disable(MWWorld::Ptr(&*iter, cellstore)); MWBase::Environment::get().getWorld()->disable(MWWorld::Ptr(&*iter, cellstore));
} }
else
MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(&*iter, cellstore));
return; return;
} }
@ -206,6 +209,9 @@ namespace
MWWorld::LiveCellRef<T> ref (record); MWWorld::LiveCellRef<T> ref (record);
ref.load (state); ref.load (state);
collection.mList.push_back (ref); 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()) if (searchViaRefNum(object.getCellRef().getRefNum()).isEmpty())
throw std::runtime_error("moveTo: object is not in this cell"); throw std::runtime_error("moveTo: object is not in this cell");
MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(object.getBase(), cellToMoveTo));
// 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;
}
MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end()) if (found != mMovedHere.end())

View File

@ -813,7 +813,8 @@ namespace MWWorld
void World::enable (const Ptr& reference) void World::enable (const Ptr& reference)
{ {
// enable is a no-op for items in containers MWBase::Environment::get().getLuaManager()->registerObject(reference);
if (!reference.isInCell()) if (!reference.isInCell())
return; return;
@ -864,6 +865,7 @@ namespace MWWorld
if (reference == getPlayerPtr()) if (reference == getPlayerPtr())
throw std::runtime_error("can not disable player object"); throw std::runtime_error("can not disable player object");
MWBase::Environment::get().getLuaManager()->deregisterObject(reference);
reference.getRefData().disable(); reference.getRefData().disable();
if (reference.getCellRef().getRefNum().hasContentFile()) if (reference.getCellRef().getRefNum().hasContentFile())