1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-05-05 19:11:25 +00:00

Refactor mwlua/eventqueue and extract some code out of LuaManager

This commit is contained in:
Petr Mikheev 2023-03-19 21:32:16 +01:00
parent 4fd07cb58d
commit 7ef759c78b
11 changed files with 194 additions and 143 deletions

View file

@ -59,7 +59,7 @@ add_openmw_dir (mwscript
) )
add_openmw_dir (mwlua add_openmw_dir (mwlua
luamanagerimp object worldview userdataserializer eventqueue objectvariant luamanagerimp object worldview userdataserializer luaevents objectvariant
luabindings localscripts playerscripts objectbindings cellbindings luabindings localscripts playerscripts 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

View file

@ -1,8 +1,6 @@
#ifndef MWLUA_CONTEXT_H #ifndef MWLUA_CONTEXT_H
#define MWLUA_CONTEXT_H #define MWLUA_CONTEXT_H
#include "eventqueue.hpp"
namespace LuaUtil namespace LuaUtil
{ {
class LuaState; class LuaState;
@ -11,6 +9,7 @@ namespace LuaUtil
namespace MWLua namespace MWLua
{ {
class LuaEvents;
class LuaManager; class LuaManager;
class WorldView; class WorldView;
@ -21,8 +20,7 @@ namespace MWLua
LuaUtil::LuaState* mLua; LuaUtil::LuaState* mLua;
LuaUtil::UserdataSerializer* mSerializer; LuaUtil::UserdataSerializer* mSerializer;
WorldView* mWorldView; WorldView* mWorldView;
LocalEventQueue* mLocalEventQueue; LuaEvents* mLuaEvents;
GlobalEventQueue* mGlobalEventQueue;
}; };
} }

View file

@ -1,64 +0,0 @@
#include "eventqueue.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/luascripts.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/lua/serialization.hpp>
namespace MWLua
{
template <typename Event>
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<int, int>& 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);
}
}

View file

@ -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<GlobalEvent>;
using LocalEventQueue = std::vector<LocalEvent>;
void loadEvents(sol::state_view& lua, ESM::ESMReader& esm, GlobalEventQueue&, LocalEventQueue&,
const std::map<int, int>& contentFileMapping, const LuaUtil::UserdataSerializer* serializer);
void saveEvents(ESM::ESMWriter& esm, const GlobalEventQueue&, const LocalEventQueue&);
}
#endif // MWLUA_EVENTQUEUE_H

View file

@ -13,7 +13,7 @@
#include "../mwworld/scene.hpp" #include "../mwworld/scene.hpp"
#include "../mwworld/store.hpp" #include "../mwworld/store.hpp"
#include "eventqueue.hpp" #include "luaevents.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "worldview.hpp" #include "worldview.hpp"
@ -57,7 +57,7 @@ namespace MWLua
MWBase::Environment::get().getStateManager()->requestQuit(); MWBase::Environment::get().getStateManager()->requestQuit();
}; };
api["sendGlobalEvent"] = [context](std::string eventName, const sol::object& eventData) { 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) }); { std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
}; };
addTimeBindings(api, context, false); addTimeBindings(api, context, false);

View file

@ -0,0 +1,108 @@
#include "luaevents.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/luascripts.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/lua/serialization.hpp>
#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 <typename Event>
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<int, int>& 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);
}
}

View file

@ -0,0 +1,68 @@
#ifndef MWLUA_LUAEVENTS_H
#define MWLUA_LUAEVENTS_H
#include <map>
#include <string>
#include <components/esm3/cellref.hpp> // 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<int, int>& contentFileMapping,
const LuaUtil::UserdataSerializer* serializer);
void save(ESM::ESMWriter& esm) const;
private:
GlobalScripts* mGlobalScripts;
std::vector<Global> mNewGlobalEventBatch;
std::vector<Local> mNewLocalEventBatch;
std::vector<Global> mGlobalEventBatch;
std::vector<Local> mLocalEventBatch;
};
}
#endif // MWLUA_LUAEVENTS_H

View file

@ -81,8 +81,7 @@ namespace MWLua
context.mLuaManager = this; context.mLuaManager = this;
context.mLua = &mLua; context.mLua = &mLua;
context.mWorldView = &mWorldView; context.mWorldView = &mWorldView;
context.mLocalEventQueue = &mLocalEvents; context.mLuaEvents = &mLuaEvents;
context.mGlobalEventQueue = &mGlobalEvents;
context.mSerializer = mGlobalSerializer.get(); context.mSerializer = mGlobalSerializer.get();
Context localContext = context; Context localContext = context;
@ -165,10 +164,7 @@ namespace MWLua
for (LocalScripts* scripts : mActiveLocalScripts) for (LocalScripts* scripts : mActiveLocalScripts)
scripts->statsNextFrame(); scripts->statsNextFrame();
std::vector<GlobalEvent> globalEvents = std::move(mGlobalEvents); mLuaEvents.finalizeEventBatch();
std::vector<LocalEvent> localEvents = std::move(mLocalEvents);
mGlobalEvents = std::vector<GlobalEvent>();
mLocalEvents = std::vector<LocalEvent>();
if (!mWorldView.isPaused()) if (!mWorldView.isPaused())
{ // Update time and process timers { // Update time and process timers
@ -181,20 +177,7 @@ namespace MWLua
scripts->processTimers(simulationTime, gameTime); scripts->processTimers(simulationTime, gameTime);
} }
// Receive events mLuaEvents.callEventHandlers();
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";
}
// Run queued callbacks // Run queued callbacks
for (CallbackWithData& c : mQueuedCallbacks) for (CallbackWithData& c : mQueuedCallbacks)
@ -302,8 +285,7 @@ namespace MWLua
MWBase::Environment::get().getWindowManager()->setConsoleMode(""); MWBase::Environment::get().getWindowManager()->setConsoleMode("");
MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders(); MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders();
mActiveLocalScripts.clear(); mActiveLocalScripts.clear();
mLocalEvents.clear(); mLuaEvents.clear();
mGlobalEvents.clear();
mInputEvents.clear(); mInputEvents.clear();
mObjectAddedEvents.clear(); mObjectAddedEvents.clear();
mLocalEngineEvents.clear(); mLocalEngineEvents.clear();
@ -470,7 +452,7 @@ namespace MWLua
ESM::LuaScripts globalScripts; ESM::LuaScripts globalScripts;
mGlobalScripts.save(globalScripts); mGlobalScripts.save(globalScripts);
globalScripts.save(writer); globalScripts.save(writer);
saveEvents(writer, mGlobalEvents, mLocalEvents); mLuaEvents.save(writer);
writer.endRecord(ESM::REC_LUAM); writer.endRecord(ESM::REC_LUAM);
} }
@ -483,7 +465,7 @@ namespace MWLua
mWorldView.load(reader); mWorldView.load(reader);
ESM::LuaScripts globalScripts; ESM::LuaScripts globalScripts;
globalScripts.load(reader); 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.setSavedDataDeserializer(mGlobalLoader.get());
mGlobalScripts.load(globalScripts); mGlobalScripts.load(globalScripts);

View file

@ -14,9 +14,9 @@
#include "../mwbase/luamanager.hpp" #include "../mwbase/luamanager.hpp"
#include "eventqueue.hpp"
#include "globalscripts.hpp" #include "globalscripts.hpp"
#include "localscripts.hpp" #include "localscripts.hpp"
#include "luaevents.hpp"
#include "object.hpp" #include "object.hpp"
#include "worldview.hpp" #include "worldview.hpp"
@ -31,6 +31,8 @@ namespace MWLua
{ {
public: public:
LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir); 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. // Called by engine.cpp when the environment is fully initialized.
void init(); void init();
@ -165,8 +167,7 @@ namespace MWLua
bool mNewGameStarted = false; bool mNewGameStarted = false;
MWWorld::Ptr mPlayer; MWWorld::Ptr mPlayer;
GlobalEventQueue mGlobalEvents; LuaEvents mLuaEvents{ &mGlobalScripts };
LocalEventQueue mLocalEvents;
std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalSerializer; std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalSerializer;
std::unique_ptr<LuaUtil::UserdataSerializer> mLocalSerializer; std::unique_ptr<LuaUtil::UserdataSerializer> mLocalSerializer;

View file

@ -11,7 +11,7 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "eventqueue.hpp" #include "luaevents.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "types/types.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::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); };
objectT[sol::meta_function::to_string] = &ObjectT::toString; objectT[sol::meta_function::to_string] = &ObjectT::toString;
objectT["sendEvent"] = [context](const ObjectT& dest, std::string eventName, const sol::object& eventData) { 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) }); { dest.id(), std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
}; };

View file

@ -6,6 +6,7 @@
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include "../context.hpp" #include "../context.hpp"
#include "../object.hpp"
namespace MWLua namespace MWLua
{ {