From a2fa1fe0a53850b89feddc3082df041e6ccf37db Mon Sep 17 00:00:00 2001 From: uramer Date: Sun, 2 Oct 2022 12:47:33 +0200 Subject: [PATCH] Execute async callbacks on the main Lua stack --- apps/openmw/mwlua/asyncbindings.cpp | 28 ++++++++++++++-------------- apps/openmw/mwlua/luamanagerimp.hpp | 7 ++++--- apps/openmw/mwlua/nearbybindings.cpp | 8 ++++---- components/lua/scriptscontainer.cpp | 11 +++++++---- components/lua/scriptscontainer.hpp | 14 +++++++------- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwlua/asyncbindings.cpp b/apps/openmw/mwlua/asyncbindings.cpp index 00ca7b75ec..481cce74c9 100644 --- a/apps/openmw/mwlua/asyncbindings.cpp +++ b/apps/openmw/mwlua/asyncbindings.cpp @@ -29,32 +29,32 @@ namespace MWLua using TimerType = LuaUtil::ScriptsContainer::TimerType; sol::usertype api = context.mLua->sol().new_usertype("AsyncPackage"); api["registerTimerCallback"] - = [](const AsyncPackageId& asyncId, std::string_view name, sol::function callback) { + = [](const AsyncPackageId& asyncId, std::string_view name, sol::main_protected_function callback) { asyncId.mContainer->registerTimerCallback(asyncId.mScriptId, name, std::move(callback)); return TimerCallback{ asyncId, std::string(name) }; }; api["newSimulationTimer"] = [world = context.mWorldView](const AsyncPackageId&, double delay, - const TimerCallback& callback, sol::object callbackArg) { + const TimerCallback& callback, sol::main_object callbackArg) { callback.mAsyncId.mContainer->setupSerializableTimer(TimerType::SIMULATION_TIME, world->getSimulationTime() + delay, callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg)); }; api["newGameTimer"] = [world = context.mWorldView](const AsyncPackageId&, double delay, - const TimerCallback& callback, sol::object callbackArg) { + const TimerCallback& callback, sol::main_object callbackArg) { callback.mAsyncId.mContainer->setupSerializableTimer(TimerType::GAME_TIME, world->getGameTime() + delay, callback.mAsyncId.mScriptId, callback.mName, std::move(callbackArg)); }; - api["newUnsavableSimulationTimer"] - = [world = context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback) { - asyncId.mContainer->setupUnsavableTimer(TimerType::SIMULATION_TIME, - world->getSimulationTime() + delay, asyncId.mScriptId, std::move(callback)); - }; - api["newUnsavableGameTimer"] - = [world = context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback) { - asyncId.mContainer->setupUnsavableTimer( - TimerType::GAME_TIME, world->getGameTime() + delay, asyncId.mScriptId, std::move(callback)); - }; - api["callback"] = [](const AsyncPackageId& asyncId, sol::function fn) -> LuaUtil::Callback { + api["newUnsavableSimulationTimer"] = [world = context.mWorldView](const AsyncPackageId& asyncId, double delay, + sol::main_protected_function callback) { + asyncId.mContainer->setupUnsavableTimer( + TimerType::SIMULATION_TIME, world->getSimulationTime() + delay, asyncId.mScriptId, std::move(callback)); + }; + api["newUnsavableGameTimer"] = [world = context.mWorldView](const AsyncPackageId& asyncId, double delay, + sol::main_protected_function callback) { + asyncId.mContainer->setupUnsavableTimer( + TimerType::GAME_TIME, world->getGameTime() + delay, asyncId.mScriptId, std::move(callback)); + }; + api["callback"] = [](const AsyncPackageId& asyncId, sol::main_protected_function fn) -> LuaUtil::Callback { return LuaUtil::Callback{ std::move(fn), asyncId.mHiddenData }; }; diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 1d88d97957..c599c95a53 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -103,7 +103,7 @@ namespace MWLua const std::string& consoleMode, const std::string& command, const MWWorld::Ptr& selectedPtr) override; // Used to call Lua callbacks from C++ - void queueCallback(LuaUtil::Callback callback, sol::object arg) + void queueCallback(LuaUtil::Callback callback, sol::main_object arg) { mQueuedCallbacks.push_back({ std::move(callback), std::move(arg) }); } @@ -114,7 +114,8 @@ namespace MWLua template std::function wrapLuaCallback(const LuaUtil::Callback& c) { - return [this, c](Arg arg) { this->queueCallback(c, sol::make_object(c.mFunc.lua_state(), arg)); }; + return + [this, c](Arg arg) { this->queueCallback(c, sol::main_object(this->mLua.sol(), sol::in_place, arg)); }; } LuaUi::ResourceManager* uiResourceManager() { return &mUiResourceManager; } @@ -167,7 +168,7 @@ namespace MWLua struct CallbackWithData { LuaUtil::Callback mCallback; - sol::object mArg; + sol::main_object mArg; }; std::vector mQueuedCallbacks; diff --git a/apps/openmw/mwlua/nearbybindings.cpp b/apps/openmw/mwlua/nearbybindings.cpp index df1fafc9d7..10507e3746 100644 --- a/apps/openmw/mwlua/nearbybindings.cpp +++ b/apps/openmw/mwlua/nearbybindings.cpp @@ -115,12 +115,12 @@ namespace MWLua MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); return res; }; - api["asyncCastRenderingRay"] = [manager = context.mLuaManager](const LuaUtil::Callback& callback, - const osg::Vec3f& from, const osg::Vec3f& to) { - manager->addAction([manager, callback, from, to] { + api["asyncCastRenderingRay"] = [context](const LuaUtil::Callback& callback, const osg::Vec3f& from, + const osg::Vec3f& to) { + context.mLuaManager->addAction([context, callback, from, to] { MWPhysics::RayCastingResult res; MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); - manager->queueCallback(callback, sol::make_object(callback.mFunc.lua_state(), res)); + context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res)); }); }; diff --git a/components/lua/scriptscontainer.cpp b/components/lua/scriptscontainer.cpp index aa669b0fe4..057fcd66f9 100644 --- a/components/lua/scriptscontainer.cpp +++ b/components/lua/scriptscontainer.cpp @@ -438,7 +438,8 @@ namespace LuaUtil try { - timer.mArg = deserialize(mLua.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer); + timer.mArg = sol::main_object( + deserialize(mLua.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer)); // It is important if the order of content files was changed. The deserialize-serialize procedure // updates refnums, so timer.mSerializedArg may be not equal to savedTimer.mCallbackArgument. timer.mSerializedArg = serialize(timer.mArg, mSerializer); @@ -488,7 +489,8 @@ namespace LuaUtil return it->second; } - void ScriptsContainer::registerTimerCallback(int scriptId, std::string_view callbackName, sol::function callback) + void ScriptsContainer::registerTimerCallback( + int scriptId, std::string_view callbackName, sol::main_protected_function callback) { getScript(scriptId).mRegisteredCallbacks.emplace(std::string(callbackName), std::move(callback)); } @@ -500,7 +502,7 @@ namespace LuaUtil } void ScriptsContainer::setupSerializableTimer( - TimerType type, double time, int scriptId, std::string_view callbackName, sol::object callbackArg) + TimerType type, double time, int scriptId, std::string_view callbackName, sol::main_object callbackArg) { Timer t; t.mCallback = std::string(callbackName); @@ -512,7 +514,8 @@ namespace LuaUtil insertTimer(type == TimerType::GAME_TIME ? mGameTimersQueue : mSimulationTimersQueue, std::move(t)); } - void ScriptsContainer::setupUnsavableTimer(TimerType type, double time, int scriptId, sol::function callback) + void ScriptsContainer::setupUnsavableTimer( + TimerType type, double time, int scriptId, sol::main_protected_function callback) { Timer t; t.mScriptId = scriptId; diff --git a/components/lua/scriptscontainer.hpp b/components/lua/scriptscontainer.hpp index 04a5af2e5e..5fdbb5c1ef 100644 --- a/components/lua/scriptscontainer.hpp +++ b/components/lua/scriptscontainer.hpp @@ -136,7 +136,7 @@ namespace LuaUtil // Callbacks for serializable timers should be registered in advance. // The script with the given path should already present in the container. - void registerTimerCallback(int scriptId, std::string_view callbackName, sol::function callback); + void registerTimerCallback(int scriptId, std::string_view callbackName, sol::main_protected_function callback); // Sets up a timer, that can be automatically saved and loaded. // type - the type of timer, either SIMULATION_TIME or GAME_TIME. @@ -145,11 +145,11 @@ namespace LuaUtil // in the container. callbackName - callback (should be registered in advance) for this timer. callbackArg - // parameter for the callback (should be serializable). void setupSerializableTimer( - TimerType type, double time, int scriptId, std::string_view callbackName, sol::object callbackArg); + TimerType type, double time, int scriptId, std::string_view callbackName, sol::main_object callbackArg); // Creates a timer. `callback` is an arbitrary Lua function. These timers are called "unsavable" // because they can not be stored in saves. I.e. loading a saved game will not fully restore the state. - void setupUnsavableTimer(TimerType type, double time, int scriptId, sol::function callback); + void setupUnsavableTimer(TimerType type, double time, int scriptId, sol::main_protected_function callback); protected: struct Handler @@ -203,8 +203,8 @@ namespace LuaUtil std::optional mInterface; std::string mInterfaceName; sol::table mHiddenData; - std::map mRegisteredCallbacks; - std::map mTemporaryCallbacks; + std::map mRegisteredCallbacks; + std::map mTemporaryCallbacks; std::string mPath; }; struct Timer @@ -213,7 +213,7 @@ namespace LuaUtil bool mSerializable; int mScriptId; std::variant mCallback; // string if serializable, integer otherwise - sol::object mArg; + sol::main_object mArg; std::string mSerializedArg; bool operator<(const Timer& t) const { return mTime > t.mTime; } @@ -259,7 +259,7 @@ namespace LuaUtil // Needed to prevent callback calls if the script was removed. struct Callback { - sol::function mFunc; + sol::main_protected_function mFunc; sol::table mHiddenData; // same object as Script::mHiddenData in ScriptsContainer bool isValid() const { return mHiddenData[ScriptsContainer::sScriptIdKey] != sol::nil; }