mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-19 19:53:53 +00:00
Merge branch 'lua' into 'master'
LuaManager refactoring See merge request OpenMW/openmw!2852
This commit is contained in:
commit
76cba95a44
33 changed files with 435 additions and 300 deletions
|
@ -59,8 +59,8 @@ add_openmw_dir (mwscript
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwlua
|
add_openmw_dir (mwlua
|
||||||
luamanagerimp object worldview userdataserializer eventqueue 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
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,11 @@ namespace MWClass
|
||||||
return !name.empty() ? name : ref->mBase->mId.getRefIdString();
|
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
|
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))
|
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace MWClass
|
||||||
|
|
||||||
bool showsInInventory(const MWWorld::ConstPtr& ptr) const override;
|
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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace MWClass
|
||||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \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;
|
std::unique_ptr<MWWorld::Action> activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
105
apps/openmw/mwlua/engineevents.cpp
Normal file
105
apps/openmw/mwlua/engineevents.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
56
apps/openmw/mwlua/engineevents.hpp
Normal file
56
apps/openmw/mwlua/engineevents.hpp
Normal 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
|
|
@ -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 });
|
{ &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)>;
|
|
||||||
if constexpr (std::is_same_v<EventT, OnActive>)
|
|
||||||
{
|
|
||||||
mData.mIsActive = true;
|
|
||||||
callEngineHandlers(mOnActiveHandlers);
|
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
|
else
|
||||||
{
|
callEngineHandlers(mOnInactiveHandlers);
|
||||||
static_assert(std::is_same_v<EventT, OnConsume>);
|
|
||||||
callEngineHandlers(mOnConsumeHandlers, arg.mConsumable);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalScripts::applyStatsCache()
|
void LocalScripts::applyStatsCache()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
108
apps/openmw/mwlua/luaevents.cpp
Normal file
108
apps/openmw/mwlua/luaevents.cpp
Normal 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 (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
apps/openmw/mwlua/luaevents.hpp
Normal file
68
apps/openmw/mwlua/luaevents.hpp
Normal 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
|
|
@ -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;
|
||||||
|
@ -137,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);
|
||||||
|
@ -165,10 +163,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,84 +176,23 @@ namespace MWLua
|
||||||
scripts->processTimers(simulationTime, gameTime);
|
scripts->processTimers(simulationTime, gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive events
|
// Run event handlers for events that were sent before `finalizeEventBatch`.
|
||||||
for (GlobalEvent& e : globalEvents)
|
mLuaEvents.callEventHandlers();
|
||||||
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)
|
||||||
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 (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);
|
mGlobalScripts.update(frameDuration);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LuaManager::synchronizedUpdate()
|
void LuaManager::synchronizedUpdate()
|
||||||
{
|
{
|
||||||
|
@ -302,13 +236,9 @@ 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();
|
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;
|
||||||
|
@ -339,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()
|
||||||
|
@ -361,27 +290,17 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -391,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();
|
||||||
|
@ -470,7 +378,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 +391,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);
|
||||||
|
@ -547,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(
|
||||||
|
|
|
@ -14,9 +14,10 @@
|
||||||
|
|
||||||
#include "../mwbase/luamanager.hpp"
|
#include "../mwbase/luamanager.hpp"
|
||||||
|
|
||||||
#include "eventqueue.hpp"
|
#include "engineevents.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 +32,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();
|
||||||
|
@ -62,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;
|
||||||
|
|
||||||
|
@ -161,12 +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;
|
||||||
|
|
||||||
GlobalEventQueue mGlobalEvents;
|
LuaEvents mLuaEvents{ mGlobalScripts };
|
||||||
LocalEventQueue mLocalEvents;
|
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;
|
||||||
|
@ -175,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;
|
||||||
|
@ -185,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;
|
||||||
|
|
|
@ -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) });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "apps/openmw/mwworld/store.hpp"
|
#include "apps/openmw/mwworld/store.hpp"
|
||||||
|
|
||||||
#include "../context.hpp"
|
#include "../context.hpp"
|
||||||
|
#include "../object.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace MWLua
|
||||||
return &mDoorsInScene;
|
return &mDoorsInScene;
|
||||||
if (typeid(cls) == typeid(MWClass::Container))
|
if (typeid(cls) == typeid(MWClass::Container))
|
||||||
return &mContainersInScene;
|
return &mContainersInScene;
|
||||||
if (cls.hasToolTip(ptr))
|
if (cls.isItem(ptr))
|
||||||
return &mItemsInScene;
|
return &mItemsInScene;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,9 +58,6 @@ namespace MWLua
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm);
|
||||||
void save(ESM::ESMWriter& esm) const;
|
void save(ESM::ESMWriter& esm) const;
|
||||||
|
|
||||||
// TODO: move this functionality to MWClass
|
|
||||||
bool isItem(const MWWorld::Ptr& ptr) { return chooseGroup(ptr) == &mItemsInScene; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ObjectGroup
|
struct ObjectGroup
|
||||||
{
|
{
|
||||||
|
|
|
@ -323,6 +323,9 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual bool isDoor() const { return false; }
|
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 isBipedal(const MWWorld::ConstPtr& ptr) const;
|
||||||
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
|
||||||
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue