diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f9f4905421..2da93de653 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -59,7 +59,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwlua - luamanagerimp object worldview userdataserializer eventqueue objectvariant + luamanagerimp object worldview userdataserializer luaevents objectvariant luabindings localscripts playerscripts objectbindings cellbindings 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 diff --git a/apps/openmw/mwlua/context.hpp b/apps/openmw/mwlua/context.hpp index b3e3703a46..e743bfa50a 100644 --- a/apps/openmw/mwlua/context.hpp +++ b/apps/openmw/mwlua/context.hpp @@ -1,8 +1,6 @@ #ifndef MWLUA_CONTEXT_H #define MWLUA_CONTEXT_H -#include "eventqueue.hpp" - namespace LuaUtil { class LuaState; @@ -11,6 +9,7 @@ namespace LuaUtil namespace MWLua { + class LuaEvents; class LuaManager; class WorldView; @@ -21,8 +20,7 @@ namespace MWLua LuaUtil::LuaState* mLua; LuaUtil::UserdataSerializer* mSerializer; WorldView* mWorldView; - LocalEventQueue* mLocalEventQueue; - GlobalEventQueue* mGlobalEventQueue; + LuaEvents* mLuaEvents; }; } diff --git a/apps/openmw/mwlua/eventqueue.cpp b/apps/openmw/mwlua/eventqueue.cpp deleted file mode 100644 index ebd4a82802..0000000000 --- a/apps/openmw/mwlua/eventqueue.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "eventqueue.hpp" - -#include - -#include -#include -#include - -#include - -namespace MWLua -{ - - template - void saveEvent(ESM::ESMWriter& esm, const ObjectId& dest, const Event& event) - { - esm.writeHNString("LUAE", event.mEventName); - dest.save(esm, true); - if (!event.mEventData.empty()) - saveLuaBinaryData(esm, event.mEventData); - } - - void loadEvents(sol::state_view& lua, ESM::ESMReader& esm, GlobalEventQueue& globalEvents, - LocalEventQueue& localEvents, const std::map& contentFileMapping, - const LuaUtil::UserdataSerializer* serializer) - { - while (esm.isNextSub("LUAE")) - { - std::string name = esm.getHString(); - ObjectId dest; - dest.load(esm, true); - std::string data = loadLuaBinaryData(esm); - try - { - data = LuaUtil::serialize(LuaUtil::deserialize(lua, data, serializer), serializer); - } - catch (std::exception& e) - { - Log(Debug::Error) << "loadEvent: invalid event data: " << e.what(); - } - if (dest.isSet()) - { - auto it = contentFileMapping.find(dest.mContentFile); - if (it != contentFileMapping.end()) - dest.mContentFile = it->second; - localEvents.push_back({ dest, std::move(name), std::move(data) }); - } - else - globalEvents.push_back({ std::move(name), std::move(data) }); - } - } - - void saveEvents(ESM::ESMWriter& esm, const GlobalEventQueue& globalEvents, const LocalEventQueue& localEvents) - { - // Used as a marker of a global event. - constexpr ObjectId globalId; - - for (const GlobalEvent& e : globalEvents) - saveEvent(esm, globalId, e); - for (const LocalEvent& e : localEvents) - saveEvent(esm, e.mDest, e); - } - -} diff --git a/apps/openmw/mwlua/eventqueue.hpp b/apps/openmw/mwlua/eventqueue.hpp deleted file mode 100644 index 8854aa12a5..0000000000 --- a/apps/openmw/mwlua/eventqueue.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MWLUA_EVENTQUEUE_H -#define MWLUA_EVENTQUEUE_H - -#include "object.hpp" - -namespace ESM -{ - class ESMReader; - class ESMWriter; -} - -namespace LuaUtil -{ - class UserdataSerializer; -} - -namespace sol -{ - class state; -} - -namespace MWLua -{ - struct GlobalEvent - { - std::string mEventName; - std::string mEventData; - }; - struct LocalEvent - { - ObjectId mDest; - std::string mEventName; - std::string mEventData; - }; - using GlobalEventQueue = std::vector; - using LocalEventQueue = std::vector; - - void loadEvents(sol::state_view& lua, ESM::ESMReader& esm, GlobalEventQueue&, LocalEventQueue&, - const std::map& contentFileMapping, const LuaUtil::UserdataSerializer* serializer); - void saveEvents(ESM::ESMWriter& esm, const GlobalEventQueue&, const LocalEventQueue&); -} - -#endif // MWLUA_EVENTQUEUE_H diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 24b47481b0..7c9691e6d0 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -13,7 +13,7 @@ #include "../mwworld/scene.hpp" #include "../mwworld/store.hpp" -#include "eventqueue.hpp" +#include "luaevents.hpp" #include "luamanagerimp.hpp" #include "worldview.hpp" @@ -57,7 +57,7 @@ namespace MWLua MWBase::Environment::get().getStateManager()->requestQuit(); }; api["sendGlobalEvent"] = [context](std::string eventName, const sol::object& eventData) { - context.mGlobalEventQueue->push_back( + context.mLuaEvents->addGlobalEvent( { std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; addTimeBindings(api, context, false); diff --git a/apps/openmw/mwlua/luaevents.cpp b/apps/openmw/mwlua/luaevents.cpp new file mode 100644 index 0000000000..2013bfe6b0 --- /dev/null +++ b/apps/openmw/mwlua/luaevents.cpp @@ -0,0 +1,108 @@ +#include "luaevents.hpp" + +#include + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/worldmodel.hpp" + +#include "globalscripts.hpp" +#include "localscripts.hpp" + +namespace MWLua +{ + + void LuaEvents::clear() + { + mGlobalEventBatch.clear(); + mLocalEventBatch.clear(); + mNewGlobalEventBatch.clear(); + mNewLocalEventBatch.clear(); + } + + void LuaEvents::finalizeEventBatch() + { + mNewGlobalEventBatch.swap(mGlobalEventBatch); + mNewLocalEventBatch.swap(mLocalEventBatch); + mNewGlobalEventBatch.clear(); + mNewLocalEventBatch.clear(); + } + + void LuaEvents::callEventHandlers() + { + for (Global& e : mGlobalEventBatch) + mGlobalScripts->receiveEvent(e.mEventName, e.mEventData); + mGlobalEventBatch.clear(); + for (Local& e : mLocalEventBatch) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorldModel()->getPtr(e.mDest); + LocalScripts* scripts = ptr.isEmpty() ? nullptr : ptr.getRefData().getLuaScripts(); + if (scripts) + scripts->receiveEvent(e.mEventName, e.mEventData); + else + Log(Debug::Debug) << "Ignored event " << e.mEventName << " to L" << e.mDest.toString() + << ". Object not found or has no attached scripts"; + } + mLocalEventBatch.clear(); + } + + template + static void saveEvent(ESM::ESMWriter& esm, const ESM::RefNum& dest, const Event& event) + { + esm.writeHNString("LUAE", event.mEventName); + dest.save(esm, true); + if (!event.mEventData.empty()) + saveLuaBinaryData(esm, event.mEventData); + } + + void LuaEvents::load(lua_State* lua, ESM::ESMReader& esm, const std::map& contentFileMapping, + const LuaUtil::UserdataSerializer* serializer) + { + clear(); + while (esm.isNextSub("LUAE")) + { + std::string name = esm.getHString(); + ESM::RefNum dest; + dest.load(esm, true); + std::string data = loadLuaBinaryData(esm); + try + { + data = LuaUtil::serialize(LuaUtil::deserialize(lua, data, serializer), serializer); + } + catch (std::exception& e) + { + Log(Debug::Error) << "loadEvent: invalid event data: " << e.what(); + } + if (dest.isSet()) + { + auto it = contentFileMapping.find(dest.mContentFile); + if (it != contentFileMapping.end()) + dest.mContentFile = it->second; + mLocalEventBatch.push_back({ dest, std::move(name), std::move(data) }); + } + else + mGlobalEventBatch.push_back({ std::move(name), std::move(data) }); + } + } + + void LuaEvents::save(ESM::ESMWriter& esm) const + { + // Used as a marker of a global event. + constexpr ESM::RefNum globalId; + + for (const Global& e : mGlobalEventBatch) + saveEvent(esm, globalId, e); + for (const Global& e : mNewGlobalEventBatch) + saveEvent(esm, globalId, e); + for (const Local& e : mLocalEventBatch) + saveEvent(esm, e.mDest, e); + for (const Local& e : mNewLocalEventBatch) + saveEvent(esm, e.mDest, e); + } + +} diff --git a/apps/openmw/mwlua/luaevents.hpp b/apps/openmw/mwlua/luaevents.hpp new file mode 100644 index 0000000000..9cc9d5b399 --- /dev/null +++ b/apps/openmw/mwlua/luaevents.hpp @@ -0,0 +1,68 @@ +#ifndef MWLUA_LUAEVENTS_H +#define MWLUA_LUAEVENTS_H + +#include +#include + +#include // defines RefNum that is used as a unique id + +struct lua_State; + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + +namespace LuaUtil +{ + class UserdataSerializer; +} + +namespace MWLua +{ + + class GlobalScripts; + + class LuaEvents + { + public: + explicit LuaEvents(GlobalScripts* globalScripts) + : mGlobalScripts(globalScripts) + { + } + + struct Global + { + std::string mEventName; + std::string mEventData; + }; + struct Local + { + ESM::RefNum mDest; + std::string mEventName; + std::string mEventData; + }; + + void addGlobalEvent(Global event) { mNewGlobalEventBatch.push_back(std::move(event)); } + void addLocalEvent(Local event) { mNewLocalEventBatch.push_back(std::move(event)); } + + void clear(); + void finalizeEventBatch(); + void callEventHandlers(); + + void load(lua_State* lua, ESM::ESMReader& esm, const std::map& contentFileMapping, + const LuaUtil::UserdataSerializer* serializer); + void save(ESM::ESMWriter& esm) const; + + private: + GlobalScripts* mGlobalScripts; + std::vector mNewGlobalEventBatch; + std::vector mNewLocalEventBatch; + std::vector mGlobalEventBatch; + std::vector mLocalEventBatch; + }; + +} + +#endif // MWLUA_LUAEVENTS_H diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 4c1a7ab35b..2b3c900959 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -81,8 +81,7 @@ namespace MWLua context.mLuaManager = this; context.mLua = &mLua; context.mWorldView = &mWorldView; - context.mLocalEventQueue = &mLocalEvents; - context.mGlobalEventQueue = &mGlobalEvents; + context.mLuaEvents = &mLuaEvents; context.mSerializer = mGlobalSerializer.get(); Context localContext = context; @@ -165,10 +164,7 @@ namespace MWLua for (LocalScripts* scripts : mActiveLocalScripts) scripts->statsNextFrame(); - std::vector globalEvents = std::move(mGlobalEvents); - std::vector localEvents = std::move(mLocalEvents); - mGlobalEvents = std::vector(); - mLocalEvents = std::vector(); + mLuaEvents.finalizeEventBatch(); if (!mWorldView.isPaused()) { // Update time and process timers @@ -181,20 +177,7 @@ namespace MWLua scripts->processTimers(simulationTime, gameTime); } - // Receive events - for (GlobalEvent& e : globalEvents) - mGlobalScripts.receiveEvent(e.mEventName, e.mEventData); - for (LocalEvent& e : localEvents) - { - LObject obj(e.mDest); - const MWWorld::Ptr& ptr = obj.ptrOrNull(); - LocalScripts* scripts = ptr.isEmpty() ? nullptr : ptr.getRefData().getLuaScripts(); - if (scripts) - scripts->receiveEvent(e.mEventName, e.mEventData); - else - Log(Debug::Debug) << "Ignored event " << e.mEventName << " to L" << e.mDest.toString() - << ". Object not found or has no attached scripts"; - } + mLuaEvents.callEventHandlers(); // Run queued callbacks for (CallbackWithData& c : mQueuedCallbacks) @@ -302,8 +285,7 @@ namespace MWLua MWBase::Environment::get().getWindowManager()->setConsoleMode(""); MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders(); mActiveLocalScripts.clear(); - mLocalEvents.clear(); - mGlobalEvents.clear(); + mLuaEvents.clear(); mInputEvents.clear(); mObjectAddedEvents.clear(); mLocalEngineEvents.clear(); @@ -470,7 +452,7 @@ namespace MWLua ESM::LuaScripts globalScripts; mGlobalScripts.save(globalScripts); globalScripts.save(writer); - saveEvents(writer, mGlobalEvents, mLocalEvents); + mLuaEvents.save(writer); writer.endRecord(ESM::REC_LUAM); } @@ -483,7 +465,7 @@ namespace MWLua mWorldView.load(reader); ESM::LuaScripts globalScripts; globalScripts.load(reader); - loadEvents(mLua.sol(), reader, mGlobalEvents, mLocalEvents, mContentFileMapping, mGlobalLoader.get()); + mLuaEvents.load(mLua.sol(), reader, mContentFileMapping, mGlobalLoader.get()); mGlobalScripts.setSavedDataDeserializer(mGlobalLoader.get()); mGlobalScripts.load(globalScripts); diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 3ed8d8b213..3adf97ab6f 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -14,9 +14,9 @@ #include "../mwbase/luamanager.hpp" -#include "eventqueue.hpp" #include "globalscripts.hpp" #include "localscripts.hpp" +#include "luaevents.hpp" #include "object.hpp" #include "worldview.hpp" @@ -31,6 +31,8 @@ namespace MWLua { public: LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir); + LuaManager(const LuaManager&) = delete; + LuaManager(LuaManager&&) = delete; // Called by engine.cpp when the environment is fully initialized. void init(); @@ -165,8 +167,7 @@ namespace MWLua bool mNewGameStarted = false; MWWorld::Ptr mPlayer; - GlobalEventQueue mGlobalEvents; - LocalEventQueue mLocalEvents; + LuaEvents mLuaEvents{ &mGlobalScripts }; std::unique_ptr mGlobalSerializer; std::unique_ptr mLocalSerializer; diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 5a7791c635..45a51306a1 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -11,7 +11,7 @@ #include "../mwmechanics/creaturestats.hpp" -#include "eventqueue.hpp" +#include "luaevents.hpp" #include "luamanagerimp.hpp" #include "types/types.hpp" @@ -188,7 +188,7 @@ namespace MWLua objectT[sol::meta_function::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); }; objectT[sol::meta_function::to_string] = &ObjectT::toString; objectT["sendEvent"] = [context](const ObjectT& dest, std::string eventName, const sol::object& eventData) { - context.mLocalEventQueue->push_back( + context.mLuaEvents->addLocalEvent( { dest.id(), std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index 2ce6d3e9a2..c71edfa24a 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -6,6 +6,7 @@ #include #include "../context.hpp" +#include "../object.hpp" namespace MWLua {