mirror of https://github.com/OpenMW/openmw.git
Merge branch 'lua' into 'master'
LuaManager refactoring See merge request OpenMW/openmw!2852depth-refraction
commit
76cba95a44
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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 (const Global& e : mGlobalEventBatch)
|
||||
mGlobalScripts.receiveEvent(e.mEventName, e.mEventData);
|
||||
mGlobalEventBatch.clear();
|
||||
for (const 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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue