Merge branch 'lua' into 'master'

LuaManager refactoring

See merge request OpenMW/openmw!2852
depth-refraction
psi29a 2 years ago
commit 76cba95a44

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

@ -23,6 +23,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -23,6 +23,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -86,6 +86,11 @@ namespace MWClass
return !name.empty() ? name : ref->mBase->mId.getRefIdString();
}
bool Light::isItem(const MWWorld::ConstPtr& ptr) const
{
return ptr.get<ESM::Light>()->mBase->mData.mFlags & ESM::Light::Carry;
}
std::unique_ptr<MWWorld::Action> Light::activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const
{
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))

@ -36,6 +36,8 @@ namespace MWClass
bool showsInInventory(const MWWorld::ConstPtr& ptr) const override;
bool isItem(const MWWorld::ConstPtr&) const override;
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -26,6 +26,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -21,6 +21,8 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
///< \return name or ID; can return an empty string.
bool isItem(const MWWorld::ConstPtr&) const override { return true; }
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
///< Generate action for activation

@ -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;
};
}

@ -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

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

@ -23,11 +23,6 @@ namespace MWLua
public:
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)
: mSetter(setter)
, mIndex(index)
@ -44,6 +39,11 @@ namespace MWLua
{
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)
@ -65,23 +65,9 @@ namespace MWLua
MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; }
const MWWorld::Ptr& getPtr() const { return mData.ptr(); }
struct OnActive
{
};
struct OnInactive
{
};
struct OnActivated
{
LObject mActivatingActor;
};
struct OnConsume
{
LObject mConsumable;
};
using EngineEvent = std::variant<OnActive, OnInactive, OnConsume, OnActivated>;
void receiveEngineEvent(const EngineEvent&);
void setActive(bool active);
void onConsume(const LObject& consumable) { callEngineHandlers(mOnConsumeHandlers, consumable); }
void onActivated(const LObject& actor) { callEngineHandlers(mOnActivatedHandlers, actor); }
void applyStatsCache();

@ -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);

@ -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

@ -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;
@ -137,7 +136,6 @@ namespace MWLua
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");
if (gcStepCount > 0)
lua_gc(mLua.sol(), LUA_GCSTEP, gcStepCount);
@ -165,10 +163,7 @@ namespace MWLua
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->statsNextFrame();
std::vector<GlobalEvent> globalEvents = std::move(mGlobalEvents);
std::vector<LocalEvent> localEvents = std::move(mLocalEvents);
mGlobalEvents = std::vector<GlobalEvent>();
mLocalEvents = std::vector<LocalEvent>();
mLuaEvents.finalizeEventBatch();
if (!mWorldView.isPaused())
{ // Update time and process timers
@ -181,83 +176,22 @@ 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";
}
// Run event handlers for events that were sent before `finalizeEventBatch`.
mLuaEvents.callEventHandlers();
// Run queued callbacks
for (CallbackWithData& c : mQueuedCallbacks)
c.mCallback.tryCall(c.mArg);
mQueuedCallbacks.clear();
// Engine handlers in local scripts
for (const LocalEngineEvent& e : mLocalEngineEvents)
{
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();
// Run engine handlers
mEngineEvents.callEngineHandlers();
if (!mWorldView.isPaused())
{
for (LocalScripts* scripts : mActiveLocalScripts)
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 (mWorldView.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);
}
}
void LuaManager::synchronizedUpdate()
@ -302,13 +236,9 @@ namespace MWLua
MWBase::Environment::get().getWindowManager()->setConsoleMode("");
MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders();
mActiveLocalScripts.clear();
mLocalEvents.clear();
mGlobalEvents.clear();
mLuaEvents.clear();
mEngineEvents.clear();
mInputEvents.clear();
mObjectAddedEvents.clear();
mLocalEngineEvents.clear();
mNewGameStarted = false;
mPlayerChanged = false;
mWorldView.clear();
mGlobalScripts.removeAllScripts();
mGlobalScriptsStarted = false;
@ -339,16 +269,15 @@ namespace MWLua
localScripts->addAutoStartedScripts();
}
mActiveLocalScripts.insert(localScripts);
mLocalEngineEvents.push_back({ getId(ptr), LocalScripts::OnActive{} });
mPlayerChanged = true;
mEngineEvents.addToQueue(EngineEvents::OnActive{ getId(ptr) });
}
void LuaManager::newGameStarted()
{
mNewGameStarted = true;
mInputEvents.clear();
mGlobalScripts.addAutoStartedScripts();
mGlobalScriptsStarted = true;
mEngineEvents.addToQueue(EngineEvents::OnNewGame{});
}
void LuaManager::gameLoaded()
@ -361,26 +290,16 @@ namespace MWLua
void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr)
{
mWorldView.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
mEngineEvents.addToQueue(EngineEvents::OnActive{ getId(ptr) });
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
if (!localScripts)
if (!ptr.getRefData().getLuaScripts())
{
LuaUtil::ScriptIdsWithInitializationData autoStartConf
= mConfiguration.getLocalConf(getLiveCellRefType(ptr.mRef), ptr.getCellRef().getRefId(), getId(ptr));
// TODO: put to a queue and apply `addAutoStartedScripts` on next `update()`
if (!autoStartConf.empty())
{
localScripts = createLocalScripts(ptr, std::move(autoStartConf));
localScripts->addAutoStartedScripts(); // TODO: put to a queue and apply on next `update()`
}
createLocalScripts(ptr, std::move(autoStartConf))->addAutoStartedScripts();
}
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)
@ -391,21 +310,10 @@ namespace MWLua
{
mActiveLocalScripts.erase(localScripts);
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
{
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
@ -470,7 +378,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 +391,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);
@ -547,7 +455,7 @@ namespace MWLua
scripts->load(data);
}
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->receiveEngineEvent(LocalScripts::OnActive());
scripts->setActive(true);
}
void LuaManager::handleConsoleCommand(

@ -14,9 +14,10 @@
#include "../mwbase/luamanager.hpp"
#include "eventqueue.hpp"
#include "engineevents.hpp"
#include "globalscripts.hpp"
#include "localscripts.hpp"
#include "luaevents.hpp"
#include "object.hpp"
#include "worldview.hpp"
@ -31,6 +32,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();
@ -62,8 +65,14 @@ namespace MWLua
void objectAddedToScene(const MWWorld::Ptr& ptr) override;
void objectRemovedFromScene(const MWWorld::Ptr& ptr) override;
void inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); }
void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) override;
void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override;
void itemConsumed(const MWWorld::Ptr& consumable, 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;
@ -161,12 +170,11 @@ namespace MWLua
std::set<LocalScripts*> mActiveLocalScripts;
WorldView mWorldView;
bool mPlayerChanged = false;
bool mNewGameStarted = false;
MWWorld::Ptr mPlayer;
GlobalEventQueue mGlobalEvents;
LocalEventQueue mLocalEvents;
LuaEvents mLuaEvents{ mGlobalScripts };
EngineEvents mEngineEvents{ mGlobalScripts };
std::vector<MWBase::LuaManager::InputEvent> mInputEvents;
std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalSerializer;
std::unique_ptr<LuaUtil::UserdataSerializer> mLocalSerializer;
@ -175,9 +183,6 @@ namespace MWLua
std::unique_ptr<LuaUtil::UserdataSerializer> mGlobalLoader;
std::unique_ptr<LuaUtil::UserdataSerializer> mLocalLoader;
std::vector<MWBase::LuaManager::InputEvent> mInputEvents;
std::vector<ObjectId> mObjectAddedEvents;
struct CallbackWithData
{
LuaUtil::Callback mCallback;
@ -185,13 +190,6 @@ namespace MWLua
};
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().
std::vector<std::unique_ptr<Action>> mActionQueue;
std::unique_ptr<Action> mTeleportPlayerAction;

@ -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) });
};

@ -11,6 +11,7 @@
#include "apps/openmw/mwworld/store.hpp"
#include "../context.hpp"
#include "../object.hpp"
namespace MWLua
{

@ -52,7 +52,7 @@ namespace MWLua
return &mDoorsInScene;
if (typeid(cls) == typeid(MWClass::Container))
return &mContainersInScene;
if (cls.hasToolTip(ptr))
if (cls.isItem(ptr))
return &mItemsInScene;
return nullptr;
}

@ -58,9 +58,6 @@ namespace MWLua
void load(ESM::ESMReader& esm);
void save(ESM::ESMWriter& esm) const;
// TODO: move this functionality to MWClass
bool isItem(const MWWorld::Ptr& ptr) { return chooseGroup(ptr) == &mItemsInScene; }
private:
struct ObjectGroup
{

@ -323,6 +323,9 @@ namespace MWWorld
virtual bool isDoor() const { return false; }
// True if it is an item that can be picked up.
virtual bool isItem(const MWWorld::ConstPtr& ptr) const { return false; }
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;

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

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

Loading…
Cancel
Save