1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-22 03:40:49 +00:00

Extract engine handlers processing from LuaManager to a new class EngineEvents

This commit is contained in:
Petr Mikheev 2023-03-22 01:27:22 +01:00
parent 7ef759c78b
commit 8d1e52ed51
9 changed files with 209 additions and 154 deletions

View File

@ -59,8 +59,8 @@ add_openmw_dir (mwscript
) )
add_openmw_dir (mwlua add_openmw_dir (mwlua
luamanagerimp object worldview userdataserializer luaevents objectvariant luamanagerimp object worldview userdataserializer luaevents engineevents objectvariant
luabindings localscripts playerscripts objectbindings cellbindings context globalscripts localscripts playerscripts luabindings objectbindings cellbindings
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing
worker worker

View File

@ -0,0 +1,105 @@
#include "engineevents.hpp"
#include <components/debug/debuglog.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/worldmodel.hpp"
#include "globalscripts.hpp"
#include "localscripts.hpp"
#include "object.hpp"
namespace MWLua
{
class EngineEvents::Visitor
{
public:
explicit Visitor(GlobalScripts* globalScripts)
: mGlobalScripts(globalScripts)
{
}
void operator()(const OnNewGame&) const { mGlobalScripts->newGameStarted(); }
void operator()(const OnActive& event) const
{
MWWorld::Ptr ptr = getPtr(event.mObject);
if (ptr.isEmpty())
return;
if (ptr.getCellRef().getRefId() == "player")
mGlobalScripts->playerAdded(GObject(ptr));
else
{
mGlobalScripts->objectActive(GObject(ptr));
const MWWorld::Class& objClass = ptr.getClass();
if (objClass.isActor())
mGlobalScripts->actorActive(GObject(ptr));
if (objClass.isItem(ptr))
mGlobalScripts->itemActive(GObject(ptr));
}
if (auto* scripts = getLocalScripts(ptr))
scripts->setActive(true);
}
void operator()(const OnInactive& event) const
{
if (auto* scripts = getLocalScripts(event.mObject))
scripts->setActive(false);
}
void operator()(const OnActivate& event) const
{
MWWorld::Ptr obj = getPtr(event.mObject);
MWWorld::Ptr actor = getPtr(event.mActor);
if (actor.isEmpty() || obj.isEmpty())
return;
if (auto* scripts = getLocalScripts(obj))
scripts->onActivated(LObject(actor));
}
void operator()(const OnConsume& event) const
{
MWWorld::Ptr actor = getPtr(event.mActor);
MWWorld::Ptr consumable = getPtr(event.mConsumable);
if (actor.isEmpty() || consumable.isEmpty())
return;
if (auto* scripts = getLocalScripts(actor))
scripts->onConsume(LObject(consumable));
}
private:
MWWorld::Ptr getPtr(const ESM::RefNum& id) const
{
MWWorld::Ptr res = mWorldModel->getPtr(id);
if (res.isEmpty() && mLuaDebug)
Log(Debug::Verbose) << "Can not find object" << id.toString() << " when calling engine hanglers";
return res;
}
LocalScripts* getLocalScripts(const MWWorld::Ptr& ptr) const
{
if (ptr.isEmpty())
return nullptr;
else
return ptr.getRefData().getLuaScripts();
}
LocalScripts* getLocalScripts(const ESM::RefNum& id) const { return getLocalScripts(getPtr(id)); }
GlobalScripts* mGlobalScripts;
bool mLuaDebug = Settings::Manager::getBool("lua debug", "Lua");
MWWorld::WorldModel* mWorldModel = MWBase::Environment::get().getWorldModel();
};
void EngineEvents::callEngineHandlers()
{
Visitor vis(mGlobalScripts);
for (const Event& event : mQueue)
std::visit(vis, event);
mQueue.clear();
}
}

View File

@ -0,0 +1,56 @@
#ifndef MWLUA_ENGINEEVENTS_H
#define MWLUA_ENGINEEVENTS_H
#include <variant>
#include <components/esm3/cellref.hpp> // defines RefNum that is used as a unique id
namespace MWLua
{
class GlobalScripts;
class EngineEvents
{
public:
explicit EngineEvents(GlobalScripts* globalScripts)
: mGlobalScripts(globalScripts)
{
}
struct OnNewGame
{
};
struct OnActive
{
ESM::RefNum mObject;
};
struct OnInactive
{
ESM::RefNum mObject;
};
struct OnActivate
{
ESM::RefNum mActor;
ESM::RefNum mObject;
};
struct OnConsume
{
ESM::RefNum mActor;
ESM::RefNum mConsumable;
};
using Event = std::variant<OnNewGame, OnActive, OnInactive, OnConsume, OnActivate>;
void clear() { mQueue.clear(); }
void addToQueue(Event e) { mQueue.push_back(std::move(e)); }
void callEngineHandlers();
private:
class Visitor;
GlobalScripts* mGlobalScripts;
std::vector<Event> mQueue;
};
}
#endif // MWLUA_ENGINEEVENTS_H

View File

@ -206,32 +206,13 @@ namespace MWLua
{ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers }); { &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers });
} }
void LocalScripts::receiveEngineEvent(const EngineEvent& event) void LocalScripts::setActive(bool active)
{ {
std::visit( mData.mIsActive = active;
[this](auto&& arg) { if (active)
using EventT = std::decay_t<decltype(arg)>; callEngineHandlers(mOnActiveHandlers);
if constexpr (std::is_same_v<EventT, OnActive>) else
{ callEngineHandlers(mOnInactiveHandlers);
mData.mIsActive = true;
callEngineHandlers(mOnActiveHandlers);
}
else if constexpr (std::is_same_v<EventT, OnInactive>)
{
mData.mIsActive = false;
callEngineHandlers(mOnInactiveHandlers);
}
else if constexpr (std::is_same_v<EventT, OnActivated>)
{
callEngineHandlers(mOnActivatedHandlers, arg.mActivatingActor);
}
else
{
static_assert(std::is_same_v<EventT, OnConsume>);
callEngineHandlers(mOnConsumeHandlers, arg.mConsumable);
}
},
event);
} }
void LocalScripts::applyStatsCache() void LocalScripts::applyStatsCache()

View File

@ -23,11 +23,6 @@ namespace MWLua
public: public:
using Setter = void (*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&); using Setter = void (*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&);
private:
Setter mSetter; // Function that updates a stat's property
int mIndex; // Optional index to disambiguate the stat
std::string_view mProp; // Name of the stat's property
public:
CachedStat(Setter setter, int index, std::string_view prop) CachedStat(Setter setter, int index, std::string_view prop)
: mSetter(setter) : mSetter(setter)
, mIndex(index) , mIndex(index)
@ -44,6 +39,11 @@ namespace MWLua
{ {
return std::tie(mSetter, mIndex, mProp) < std::tie(other.mSetter, other.mIndex, other.mProp); return std::tie(mSetter, mIndex, mProp) < std::tie(other.mSetter, other.mIndex, other.mProp);
} }
private:
Setter mSetter; // Function that updates a stat's property
int mIndex; // Optional index to disambiguate the stat
std::string_view mProp; // Name of the stat's property
}; };
SelfObject(const LObject& obj) SelfObject(const LObject& obj)
@ -65,23 +65,9 @@ namespace MWLua
MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; } MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; }
const MWWorld::Ptr& getPtr() const { return mData.ptr(); } const MWWorld::Ptr& getPtr() const { return mData.ptr(); }
struct OnActive void setActive(bool active);
{ void onConsume(const LObject& consumable) { callEngineHandlers(mOnConsumeHandlers, consumable); }
}; void onActivated(const LObject& actor) { callEngineHandlers(mOnActivatedHandlers, actor); }
struct OnInactive
{
};
struct OnActivated
{
LObject mActivatingActor;
};
struct OnConsume
{
LObject mConsumable;
};
using EngineEvent = std::variant<OnActive, OnInactive, OnConsume, OnActivated>;
void receiveEngineEvent(const EngineEvent&);
void applyStatsCache(); void applyStatsCache();

View File

@ -136,7 +136,6 @@ namespace MWLua
void LuaManager::update() void LuaManager::update()
{ {
static const bool luaDebug = Settings::Manager::getBool("lua debug", "Lua");
static const int gcStepCount = Settings::Manager::getInt("gc steps per frame", "Lua"); static const int gcStepCount = Settings::Manager::getInt("gc steps per frame", "Lua");
if (gcStepCount > 0) if (gcStepCount > 0)
lua_gc(mLua.sol(), LUA_GCSTEP, gcStepCount); lua_gc(mLua.sol(), LUA_GCSTEP, gcStepCount);
@ -177,6 +176,7 @@ namespace MWLua
scripts->processTimers(simulationTime, gameTime); scripts->processTimers(simulationTime, gameTime);
} }
// Run event handlers for events that were sent before `finalizeEventBatch`.
mLuaEvents.callEventHandlers(); mLuaEvents.callEventHandlers();
// Run queued callbacks // Run queued callbacks
@ -184,63 +184,14 @@ namespace MWLua
c.mCallback.tryCall(c.mArg); c.mCallback.tryCall(c.mArg);
mQueuedCallbacks.clear(); mQueuedCallbacks.clear();
// Engine handlers in local scripts // Run engine handlers
for (const LocalEngineEvent& e : mLocalEngineEvents) mEngineEvents.callEngineHandlers();
{
LObject obj(e.mDest);
const MWWorld::Ptr& ptr = obj.ptrOrNull();
if (ptr.isEmpty())
{
if (luaDebug)
Log(Debug::Verbose) << "Can not call engine handlers: object" << e.mDest.toString()
<< " is not found";
continue;
}
LocalScripts* scripts = ptr.getRefData().getLuaScripts();
if (scripts)
scripts->receiveEngineEvent(e.mEvent);
}
mLocalEngineEvents.clear();
if (!mWorldView.isPaused()) if (!mWorldView.isPaused())
{ {
for (LocalScripts* scripts : mActiveLocalScripts) for (LocalScripts* scripts : mActiveLocalScripts)
scripts->update(frameDuration); scripts->update(frameDuration);
}
// Engine handlers in global scripts
if (mPlayerChanged)
{
mPlayerChanged = false;
mGlobalScripts.playerAdded(GObject(getId(mPlayer)));
}
if (mNewGameStarted)
{
mNewGameStarted = false;
mGlobalScripts.newGameStarted();
}
for (ObjectId id : mObjectAddedEvents)
{
GObject obj(id);
const MWWorld::Ptr& ptr = obj.ptrOrNull();
if (!ptr.isEmpty())
{
mGlobalScripts.objectActive(obj);
const MWWorld::Class& objClass = ptr.getClass();
if (objClass.isActor())
mGlobalScripts.actorActive(obj);
if (objClass.isItem(ptr))
mGlobalScripts.itemActive(obj);
}
else if (luaDebug)
Log(Debug::Verbose) << "Could not resolve a Lua object added event: object" << id.toString()
<< " is already removed";
}
mObjectAddedEvents.clear();
if (!mWorldView.isPaused())
mGlobalScripts.update(frameDuration); mGlobalScripts.update(frameDuration);
}
} }
void LuaManager::synchronizedUpdate() void LuaManager::synchronizedUpdate()
@ -286,11 +237,8 @@ namespace MWLua
MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders(); MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders();
mActiveLocalScripts.clear(); mActiveLocalScripts.clear();
mLuaEvents.clear(); mLuaEvents.clear();
mEngineEvents.clear();
mInputEvents.clear(); mInputEvents.clear();
mObjectAddedEvents.clear();
mLocalEngineEvents.clear();
mNewGameStarted = false;
mPlayerChanged = false;
mWorldView.clear(); mWorldView.clear();
mGlobalScripts.removeAllScripts(); mGlobalScripts.removeAllScripts();
mGlobalScriptsStarted = false; mGlobalScriptsStarted = false;
@ -321,16 +269,15 @@ namespace MWLua
localScripts->addAutoStartedScripts(); localScripts->addAutoStartedScripts();
} }
mActiveLocalScripts.insert(localScripts); mActiveLocalScripts.insert(localScripts);
mLocalEngineEvents.push_back({ getId(ptr), LocalScripts::OnActive{} }); mEngineEvents.addToQueue(EngineEvents::OnActive{ getId(ptr) });
mPlayerChanged = true;
} }
void LuaManager::newGameStarted() void LuaManager::newGameStarted()
{ {
mNewGameStarted = true;
mInputEvents.clear(); mInputEvents.clear();
mGlobalScripts.addAutoStartedScripts(); mGlobalScripts.addAutoStartedScripts();
mGlobalScriptsStarted = true; mGlobalScriptsStarted = true;
mEngineEvents.addToQueue(EngineEvents::OnNewGame{});
} }
void LuaManager::gameLoaded() void LuaManager::gameLoaded()
@ -343,26 +290,16 @@ namespace MWLua
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.
mEngineEvents.addToQueue(EngineEvents::OnActive{ getId(ptr) });
LocalScripts* localScripts = ptr.getRefData().getLuaScripts(); if (!ptr.getRefData().getLuaScripts())
if (!localScripts)
{ {
LuaUtil::ScriptIdsWithInitializationData autoStartConf LuaUtil::ScriptIdsWithInitializationData autoStartConf
= mConfiguration.getLocalConf(getLiveCellRefType(ptr.mRef), ptr.getCellRef().getRefId(), getId(ptr)); = mConfiguration.getLocalConf(getLiveCellRefType(ptr.mRef), ptr.getCellRef().getRefId(), getId(ptr));
// TODO: put to a queue and apply `addAutoStartedScripts` on next `update()`
if (!autoStartConf.empty()) if (!autoStartConf.empty())
{ createLocalScripts(ptr, std::move(autoStartConf))->addAutoStartedScripts();
localScripts = createLocalScripts(ptr, std::move(autoStartConf));
localScripts->addAutoStartedScripts(); // TODO: put to a queue and apply on next `update()`
}
} }
if (localScripts)
{
mActiveLocalScripts.insert(localScripts);
mLocalEngineEvents.push_back({ getId(ptr), LocalScripts::OnActive{} });
}
if (ptr != mPlayer)
mObjectAddedEvents.push_back(getId(ptr));
} }
void LuaManager::objectRemovedFromScene(const MWWorld::Ptr& ptr) void LuaManager::objectRemovedFromScene(const MWWorld::Ptr& ptr)
@ -373,21 +310,10 @@ namespace MWLua
{ {
mActiveLocalScripts.erase(localScripts); mActiveLocalScripts.erase(localScripts);
if (!MWBase::Environment::get().getWorldModel()->getPtr(getId(ptr)).isEmpty()) if (!MWBase::Environment::get().getWorldModel()->getPtr(getId(ptr)).isEmpty())
mLocalEngineEvents.push_back({ getId(ptr), LocalScripts::OnInactive{} }); mEngineEvents.addToQueue(EngineEvents::OnInactive{ getId(ptr) });
} }
} }
void LuaManager::itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor)
{
MWBase::Environment::get().getWorldModel()->registerPtr(consumable);
mLocalEngineEvents.push_back({ getId(actor), LocalScripts::OnConsume{ LObject(getId(consumable)) } });
}
void LuaManager::objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor)
{
mLocalEngineEvents.push_back({ getId(object), LocalScripts::OnActivated{ LObject(getId(actor)) } });
}
MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const
{ {
LocalScripts* localScripts = ptr.getRefData().getLuaScripts(); LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
@ -529,7 +455,7 @@ namespace MWLua
scripts->load(data); scripts->load(data);
} }
for (LocalScripts* scripts : mActiveLocalScripts) for (LocalScripts* scripts : mActiveLocalScripts)
scripts->receiveEngineEvent(LocalScripts::OnActive()); scripts->setActive(true);
} }
void LuaManager::handleConsoleCommand( void LuaManager::handleConsoleCommand(

View File

@ -14,6 +14,7 @@
#include "../mwbase/luamanager.hpp" #include "../mwbase/luamanager.hpp"
#include "engineevents.hpp"
#include "globalscripts.hpp" #include "globalscripts.hpp"
#include "localscripts.hpp" #include "localscripts.hpp"
#include "luaevents.hpp" #include "luaevents.hpp"
@ -64,8 +65,14 @@ namespace MWLua
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 inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); } void inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); }
void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) override; void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) override
void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; {
mEngineEvents.addToQueue(EngineEvents::OnConsume{ getId(actor), getId(consumable) });
}
void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override
{
mEngineEvents.addToQueue(EngineEvents::OnActivate{ getId(actor), getId(object) });
}
MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override;
@ -163,11 +170,11 @@ namespace MWLua
std::set<LocalScripts*> mActiveLocalScripts; std::set<LocalScripts*> mActiveLocalScripts;
WorldView mWorldView; WorldView mWorldView;
bool mPlayerChanged = false;
bool mNewGameStarted = false;
MWWorld::Ptr mPlayer; MWWorld::Ptr mPlayer;
LuaEvents mLuaEvents{ &mGlobalScripts }; LuaEvents mLuaEvents{ &mGlobalScripts };
EngineEvents mEngineEvents{ &mGlobalScripts };
std::vector<MWBase::LuaManager::InputEvent> mInputEvents;
std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalSerializer; std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalSerializer;
std::unique_ptr<LuaUtil::UserdataSerializer> mLocalSerializer; std::unique_ptr<LuaUtil::UserdataSerializer> mLocalSerializer;
@ -176,9 +183,6 @@ namespace MWLua
std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalLoader; std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalLoader;
std::unique_ptr<LuaUtil::UserdataSerializer> mLocalLoader; std::unique_ptr<LuaUtil::UserdataSerializer> mLocalLoader;
std::vector<MWBase::LuaManager::InputEvent> mInputEvents;
std::vector<ObjectId> mObjectAddedEvents;
struct CallbackWithData struct CallbackWithData
{ {
LuaUtil::Callback mCallback; LuaUtil::Callback mCallback;
@ -186,13 +190,6 @@ namespace MWLua
}; };
std::vector<CallbackWithData> mQueuedCallbacks; std::vector<CallbackWithData> mQueuedCallbacks;
struct LocalEngineEvent
{
ObjectId mDest;
LocalScripts::EngineEvent mEvent;
};
std::vector<LocalEngineEvent> mLocalEngineEvents;
// Queued actions that should be done in main thread. Processed by applyQueuedChanges(). // Queued actions that should be done in main thread. Processed by applyQueuedChanges().
std::vector<std::unique_ptr<Action>> mActionQueue; std::vector<std::unique_ptr<Action>> mActionQueue;
std::unique_ptr<Action> mTeleportPlayerAction; std::unique_ptr<Action> mTeleportPlayerAction;

View File

@ -21,6 +21,13 @@ namespace MWWorld
return res; return res;
} }
SafePtr::SafePtr(const Ptr& ptr)
: mId(ptr.getCellRef().getRefNum())
, mPtr(ptr)
, mLastUpdate(MWBase::Environment::get().getWorldModel()->getPtrIndexUpdateCounter())
{
}
std::string SafePtr::toString() const std::string SafePtr::toString() const
{ {
update(); update();

View File

@ -159,10 +159,7 @@ namespace MWWorld
: mId(id) : mId(id)
{ {
} }
explicit SafePtr(const Ptr& ptr) explicit SafePtr(const Ptr& ptr);
: SafePtr(ptr.getCellRef().getRefNum())
{
}
virtual ~SafePtr() = default; virtual ~SafePtr() = default;
Id id() const { return mId; } Id id() const { return mId; }