From c9783344a0b9256d69020cf11d5ce262bad030c1 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 22 Aug 2024 22:22:28 +0200 Subject: [PATCH 1/3] Wrap all memory allocating Lua functions in protected calls --- apps/openmw/mwlua/animationbindings.cpp | 70 +-- apps/openmw/mwlua/birthsignbindings.cpp | 4 +- apps/openmw/mwlua/camerabindings.cpp | 2 +- apps/openmw/mwlua/camerabindings.hpp | 2 +- apps/openmw/mwlua/cellbindings.cpp | 6 +- apps/openmw/mwlua/classbindings.cpp | 4 +- apps/openmw/mwlua/context.hpp | 15 +- apps/openmw/mwlua/corebindings.cpp | 19 +- apps/openmw/mwlua/debugbindings.cpp | 33 +- apps/openmw/mwlua/dialoguebindings.cpp | 4 +- apps/openmw/mwlua/factionbindings.cpp | 2 +- apps/openmw/mwlua/inputbindings.cpp | 435 ++++++++++--------- apps/openmw/mwlua/itemdata.cpp | 15 +- apps/openmw/mwlua/localscripts.cpp | 49 ++- apps/openmw/mwlua/luabindings.cpp | 4 +- apps/openmw/mwlua/luamanagerimp.cpp | 173 ++++---- apps/openmw/mwlua/luamanagerimp.hpp | 9 +- apps/openmw/mwlua/magicbindings.cpp | 64 +-- apps/openmw/mwlua/markupbindings.cpp | 12 +- apps/openmw/mwlua/menuscripts.cpp | 13 +- apps/openmw/mwlua/mwscriptbindings.cpp | 9 +- apps/openmw/mwlua/nearbybindings.cpp | 90 ++-- apps/openmw/mwlua/objectbindings.cpp | 17 +- apps/openmw/mwlua/postprocessingbindings.cpp | 5 +- apps/openmw/mwlua/racebindings.cpp | 4 +- apps/openmw/mwlua/recordstore.hpp | 2 +- apps/openmw/mwlua/soundbindings.cpp | 4 +- apps/openmw/mwlua/stats.cpp | 41 +- apps/openmw/mwlua/types/activator.cpp | 2 +- apps/openmw/mwlua/types/actor.cpp | 14 +- apps/openmw/mwlua/types/actor.hpp | 4 +- apps/openmw/mwlua/types/apparatus.cpp | 16 +- apps/openmw/mwlua/types/armor.cpp | 30 +- apps/openmw/mwlua/types/book.cpp | 5 +- apps/openmw/mwlua/types/clothing.cpp | 28 +- apps/openmw/mwlua/types/container.cpp | 2 +- apps/openmw/mwlua/types/creature.cpp | 19 +- apps/openmw/mwlua/types/door.cpp | 16 +- apps/openmw/mwlua/types/ingredient.cpp | 6 +- apps/openmw/mwlua/types/levelledlist.cpp | 2 +- apps/openmw/mwlua/types/light.cpp | 2 +- apps/openmw/mwlua/types/lockpick.cpp | 2 +- apps/openmw/mwlua/types/misc.cpp | 3 +- apps/openmw/mwlua/types/npc.cpp | 2 +- apps/openmw/mwlua/types/player.cpp | 24 +- apps/openmw/mwlua/types/potion.cpp | 6 +- apps/openmw/mwlua/types/probe.cpp | 2 +- apps/openmw/mwlua/types/repair.cpp | 2 +- apps/openmw/mwlua/types/static.cpp | 2 +- apps/openmw/mwlua/types/terminal.cpp | 2 +- apps/openmw/mwlua/types/types.cpp | 20 +- apps/openmw/mwlua/types/weapon.cpp | 36 +- apps/openmw/mwlua/uibindings.cpp | 30 +- apps/openmw/mwlua/vfsbindings.cpp | 56 +-- apps/openmw/mwlua/worldbindings.cpp | 9 +- components/lua/luastate.cpp | 208 ++++----- components/lua/luastate.hpp | 85 +++- components/lua/scriptscontainer.cpp | 173 ++++---- components/lua/scriptscontainer.hpp | 5 +- components/lua/storage.cpp | 109 ++--- components/lua/storage.hpp | 42 +- 61 files changed, 1109 insertions(+), 962 deletions(-) diff --git a/apps/openmw/mwlua/animationbindings.cpp b/apps/openmw/mwlua/animationbindings.cpp index d959e6b478..95294f46cb 100644 --- a/apps/openmw/mwlua/animationbindings.cpp +++ b/apps/openmw/mwlua/animationbindings.cpp @@ -99,45 +99,48 @@ namespace MWLua sol::table initAnimationPackage(const Context& context) { - auto* lua = context.mLua; + auto view = context.sol(); auto mechanics = MWBase::Environment::get().getMechanicsManager(); auto world = MWBase::Environment::get().getWorld(); - sol::table api(lua->sol(), sol::create); + sol::table api(view, sol::create); api["PRIORITY"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Default", MWMechanics::Priority::Priority_Default }, - { "WeaponLowerBody", MWMechanics::Priority::Priority_WeaponLowerBody }, - { "SneakIdleLowerBody", MWMechanics::Priority::Priority_SneakIdleLowerBody }, - { "SwimIdle", MWMechanics::Priority::Priority_SwimIdle }, - { "Jump", MWMechanics::Priority::Priority_Jump }, - { "Movement", MWMechanics::Priority::Priority_Movement }, - { "Hit", MWMechanics::Priority::Priority_Hit }, - { "Weapon", MWMechanics::Priority::Priority_Weapon }, - { "Block", MWMechanics::Priority::Priority_Block }, - { "Knockdown", MWMechanics::Priority::Priority_Knockdown }, - { "Torch", MWMechanics::Priority::Priority_Torch }, - { "Storm", MWMechanics::Priority::Priority_Storm }, - { "Death", MWMechanics::Priority::Priority_Death }, - { "Scripted", MWMechanics::Priority::Priority_Scripted }, + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(view, + { + { "Default", MWMechanics::Priority::Priority_Default }, + { "WeaponLowerBody", MWMechanics::Priority::Priority_WeaponLowerBody }, + { "SneakIdleLowerBody", MWMechanics::Priority::Priority_SneakIdleLowerBody }, + { "SwimIdle", MWMechanics::Priority::Priority_SwimIdle }, + { "Jump", MWMechanics::Priority::Priority_Jump }, + { "Movement", MWMechanics::Priority::Priority_Movement }, + { "Hit", MWMechanics::Priority::Priority_Hit }, + { "Weapon", MWMechanics::Priority::Priority_Weapon }, + { "Block", MWMechanics::Priority::Priority_Block }, + { "Knockdown", MWMechanics::Priority::Priority_Knockdown }, + { "Torch", MWMechanics::Priority::Priority_Torch }, + { "Storm", MWMechanics::Priority::Priority_Storm }, + { "Death", MWMechanics::Priority::Priority_Death }, + { "Scripted", MWMechanics::Priority::Priority_Scripted }, + })); + + api["BLEND_MASK"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(view, + { + { "LowerBody", BlendMask::BlendMask_LowerBody }, + { "Torso", BlendMask::BlendMask_Torso }, + { "LeftArm", BlendMask::BlendMask_LeftArm }, + { "RightArm", BlendMask::BlendMask_RightArm }, + { "UpperBody", BlendMask::BlendMask_UpperBody }, + { "All", BlendMask::BlendMask_All }, })); - api["BLEND_MASK"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "LowerBody", BlendMask::BlendMask_LowerBody }, - { "Torso", BlendMask::BlendMask_Torso }, - { "LeftArm", BlendMask::BlendMask_LeftArm }, - { "RightArm", BlendMask::BlendMask_RightArm }, - { "UpperBody", BlendMask::BlendMask_UpperBody }, - { "All", BlendMask::BlendMask_All }, - })); - - api["BONE_GROUP"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "LowerBody", BoneGroup::BoneGroup_LowerBody }, - { "Torso", BoneGroup::BoneGroup_Torso }, - { "LeftArm", BoneGroup::BoneGroup_LeftArm }, - { "RightArm", BoneGroup::BoneGroup_RightArm }, - })); + api["BONE_GROUP"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(view, + { + { "LowerBody", BoneGroup::BoneGroup_LowerBody }, + { "Torso", BoneGroup::BoneGroup_Torso }, + { "LeftArm", BoneGroup::BoneGroup_LeftArm }, + { "RightArm", BoneGroup::BoneGroup_RightArm }, + })); api["hasAnimation"] = [world](const sol::object& object) -> bool { return world->getAnimation(getPtrOrThrow(ObjectVariant(object))) != nullptr; @@ -305,8 +308,7 @@ namespace MWLua sol::table initWorldVfxBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); - sol::table api(lua, sol::create); + sol::table api(context.mLua->unsafeState(), sol::create); auto world = MWBase::Environment::get().getWorld(); api["spawn"] diff --git a/apps/openmw/mwlua/birthsignbindings.cpp b/apps/openmw/mwlua/birthsignbindings.cpp index f65d50bc5a..218d05b804 100644 --- a/apps/openmw/mwlua/birthsignbindings.cpp +++ b/apps/openmw/mwlua/birthsignbindings.cpp @@ -22,8 +22,8 @@ namespace MWLua { sol::table initBirthSignRecordBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); - sol::table birthSigns(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table birthSigns(lua, sol::create); addRecordFunctionBinding(birthSigns, context); auto signT = lua.new_usertype("ESM3_BirthSign"); diff --git a/apps/openmw/mwlua/camerabindings.cpp b/apps/openmw/mwlua/camerabindings.cpp index ed75b4b198..d64110ea98 100644 --- a/apps/openmw/mwlua/camerabindings.cpp +++ b/apps/openmw/mwlua/camerabindings.cpp @@ -14,7 +14,7 @@ namespace MWLua using CameraMode = MWRender::Camera::Mode; - sol::table initCameraPackage(sol::state_view& lua) + sol::table initCameraPackage(sol::state_view lua) { MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera(); MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager(); diff --git a/apps/openmw/mwlua/camerabindings.hpp b/apps/openmw/mwlua/camerabindings.hpp index be468495e1..001ef32167 100644 --- a/apps/openmw/mwlua/camerabindings.hpp +++ b/apps/openmw/mwlua/camerabindings.hpp @@ -5,7 +5,7 @@ namespace MWLua { - sol::table initCameraPackage(sol::state_view& lua); + sol::table initCameraPackage(sol::state_view lua); } #endif // MWLUA_CAMERABINDINGS_H diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index eded0d0387..933dba3fda 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -69,7 +69,8 @@ namespace MWLua template static void initCellBindings(const std::string& prefix, const Context& context) { - sol::usertype cellT = context.mLua->sol().new_usertype(prefix + "Cell"); + auto view = context.sol(); + sol::usertype cellT = view.new_usertype(prefix + "Cell"); cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; }; cellT[sol::meta_function::to_string] = [](const CellT& c) { @@ -127,8 +128,7 @@ namespace MWLua if constexpr (std::is_same_v) { // only for global scripts - cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())]( - const CellT& cell, sol::optional type) { + cellT["getAll"] = [ids = getPackageToTypeTable(view)](const CellT& cell, sol::optional type) { if (cell.mStore->getState() != MWWorld::CellStore::State_Loaded) cell.mStore->load(); ObjectIdList res = std::make_shared>(); diff --git a/apps/openmw/mwlua/classbindings.cpp b/apps/openmw/mwlua/classbindings.cpp index 84864781d2..c94631fb3c 100644 --- a/apps/openmw/mwlua/classbindings.cpp +++ b/apps/openmw/mwlua/classbindings.cpp @@ -19,8 +19,8 @@ namespace MWLua sol::table initClassRecordBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); - sol::table classes(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table classes(lua, sol::create); addRecordFunctionBinding(classes, context); auto classT = lua.new_usertype("ESM3_Class"); diff --git a/apps/openmw/mwlua/context.hpp b/apps/openmw/mwlua/context.hpp index 0bda4ca4e3..363507bdc9 100644 --- a/apps/openmw/mwlua/context.hpp +++ b/apps/openmw/mwlua/context.hpp @@ -48,7 +48,7 @@ namespace MWLua template sol::object getCachedPackage(std::string_view first, const Str&... str) const { - sol::object package = mLua->sol()[first]; + sol::object package = sol()[first]; if constexpr (sizeof...(str) == 0) return package; else @@ -58,7 +58,7 @@ namespace MWLua template const sol::object& setCachedPackage(const sol::object& value, std::string_view first, const Str&... str) const { - sol::state_view& lua = mLua->sol(); + sol::state_view lua = sol(); if constexpr (sizeof...(str) == 0) lua[first] = value; else @@ -90,10 +90,17 @@ namespace MWLua bool initializeOnce(std::string_view key) const { - sol::object flag = mLua->sol()[key]; - mLua->sol()[key] = sol::make_object(mLua->sol(), true); + auto view = sol(); + sol::object flag = view[key]; + view[key] = sol::make_object(view, true); return flag == sol::nil; } + + sol::state_view sol() const + { + // Bindings are initialized in a safe context + return mLua->unsafeState(); + } }; } diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 7ac88e1e0b..445bcdd617 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -70,19 +70,18 @@ namespace MWLua sol::table initCorePackage(const Context& context) { - auto* lua = context.mLua; - + auto lua = context.sol(); sol::object cached = context.getTypePackage("openmw_core"); if (cached != sol::nil) return cached; - sol::table api(lua->sol(), sol::create); + sol::table api(lua, sol::create); api["API_REVISION"] = Version::getLuaApiRevision(); // specified in CMakeLists.txt - api["quit"] = [lua]() { + api["quit"] = [lua = context.mLua]() { Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); MWBase::Environment::get().getStateManager()->requestQuit(); }; - api["contentFiles"] = initContentFilesBindings(lua->sol()); + api["contentFiles"] = initContentFilesBindings(lua); api["getFormId"] = [](std::string_view contentFile, unsigned int index) -> std::string { const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); for (size_t i = 0; i < contentList.size(); ++i) @@ -103,10 +102,10 @@ namespace MWLua api["dialogue"] = context.cachePackage("openmw_core_dialogue", [context]() { return initCoreDialogueBindings(context); }); api["l10n"] = context.cachePackage("openmw_core_l10n", - [lua]() { return LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager()); }); + [lua]() { return LuaUtil::initL10nLoader(lua, MWBase::Environment::get().getL10nManager()); }); const MWWorld::Store* gmstStore = &MWBase::Environment::get().getESMStore()->get(); - api["getGMST"] = [lua = context.mLua, gmstStore](const std::string& setting) -> sol::object { + api["getGMST"] = [lua, gmstStore](const std::string& setting) -> sol::object { const ESM::GameSetting* gmst = gmstStore->search(setting); if (gmst == nullptr) return sol::nil; @@ -114,13 +113,13 @@ namespace MWLua switch (value.getType()) { case ESM::VT_Float: - return sol::make_object(lua->sol(), value.getFloat()); + return sol::make_object(lua, value.getFloat()); case ESM::VT_Short: case ESM::VT_Long: case ESM::VT_Int: - return sol::make_object(lua->sol(), value.getInteger()); + return sol::make_object(lua, value.getInteger()); case ESM::VT_String: - return sol::make_object(lua->sol(), value.getString()); + return sol::make_object(lua, value.getString()); case ESM::VT_Unknown: case ESM::VT_None: break; diff --git a/apps/openmw/mwlua/debugbindings.cpp b/apps/openmw/mwlua/debugbindings.cpp index 97ca080e5c..dcb77580ce 100644 --- a/apps/openmw/mwlua/debugbindings.cpp +++ b/apps/openmw/mwlua/debugbindings.cpp @@ -20,19 +20,21 @@ namespace MWLua { sol::table initDebugPackage(const Context& context) { - sol::table api = context.mLua->newTable(); + auto view = context.sol(); + sol::table api(view, sol::create); api["RENDER_MODE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "CollisionDebug", MWRender::Render_CollisionDebug }, - { "Wireframe", MWRender::Render_Wireframe }, - { "Pathgrid", MWRender::Render_Pathgrid }, - { "Water", MWRender::Render_Water }, - { "Scene", MWRender::Render_Scene }, - { "NavMesh", MWRender::Render_NavMesh }, - { "ActorsPaths", MWRender::Render_ActorsPaths }, - { "RecastMesh", MWRender::Render_RecastMesh }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(view, + { + { "CollisionDebug", MWRender::Render_CollisionDebug }, + { "Wireframe", MWRender::Render_Wireframe }, + { "Pathgrid", MWRender::Render_Pathgrid }, + { "Water", MWRender::Render_Water }, + { "Scene", MWRender::Render_Scene }, + { "NavMesh", MWRender::Render_NavMesh }, + { "ActorsPaths", MWRender::Render_ActorsPaths }, + { "RecastMesh", MWRender::Render_RecastMesh }, + })); api["toggleRenderMode"] = [context](MWRender::RenderMode value) { context.mLuaManager->addAction([value] { MWBase::Environment::get().getWorld()->toggleRenderMode(value); }); @@ -56,10 +58,11 @@ namespace MWLua api["reloadLua"] = []() { MWBase::Environment::get().getLuaManager()->reloadAllScripts(); }; api["NAV_MESH_RENDER_MODE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "AreaType", Settings::NavMeshRenderMode::AreaType }, - { "UpdateFrequency", Settings::NavMeshRenderMode::UpdateFrequency }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(view, + { + { "AreaType", Settings::NavMeshRenderMode::AreaType }, + { "UpdateFrequency", Settings::NavMeshRenderMode::UpdateFrequency }, + })); api["setNavMeshRenderMode"] = [context](Settings::NavMeshRenderMode value) { context.mLuaManager->addAction( diff --git a/apps/openmw/mwlua/dialoguebindings.cpp b/apps/openmw/mwlua/dialoguebindings.cpp index 47e3dc941e..d0ca799cb6 100644 --- a/apps/openmw/mwlua/dialoguebindings.cpp +++ b/apps/openmw/mwlua/dialoguebindings.cpp @@ -59,7 +59,7 @@ namespace { using StoreT = FilteredDialogueStore; - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::usertype storeBindingsClass = lua.new_usertype("ESM3_Dialogue_Type" + std::to_string(filter) + " Store"); storeBindingsClass[sol::meta_function::to_string] = [](const StoreT& store) { @@ -317,7 +317,7 @@ namespace MWLua { sol::table initCoreDialogueBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table api(lua, sol::create); sol::table journalTable(lua, sol::create); diff --git a/apps/openmw/mwlua/factionbindings.cpp b/apps/openmw/mwlua/factionbindings.cpp index 701e56f1d3..2116752647 100644 --- a/apps/openmw/mwlua/factionbindings.cpp +++ b/apps/openmw/mwlua/factionbindings.cpp @@ -46,7 +46,7 @@ namespace MWLua { sol::table initCoreFactionBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table factions(lua, sol::create); addRecordFunctionBinding(factions, context); // Faction record diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index d26de4336a..b9affcdfca 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -38,13 +38,13 @@ namespace MWLua sol::table initInputPackage(const Context& context) { + sol::state_view lua = context.sol(); { - sol::state_view& lua = context.mLua->sol(); if (lua["openmw_input"] != sol::nil) return lua["openmw_input"]; } - sol::usertype keyEvent = context.mLua->sol().new_usertype("KeyEvent"); + sol::usertype keyEvent = lua.new_usertype("KeyEvent"); keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) { if (e.sym > 0 && e.sym <= 255) return std::string(1, static_cast(e.sym)); @@ -57,7 +57,7 @@ namespace MWLua keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; }); keyEvent["withSuper"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; }); - auto touchpadEvent = context.mLua->sol().new_usertype("TouchpadEvent"); + auto touchpadEvent = lua.new_usertype("TouchpadEvent"); touchpadEvent["device"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; }); touchpadEvent["finger"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; }); touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f { @@ -66,7 +66,7 @@ namespace MWLua touchpadEvent["pressure"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; }); - auto inputActions = context.mLua->sol().new_usertype("InputActions"); + auto inputActions = lua.new_usertype("InputActions"); inputActions[sol::meta_function::index] = [](LuaUtil::InputAction::Registry& registry, std::string_view key) { return registry[key]; }; { @@ -85,7 +85,7 @@ namespace MWLua inputActions[sol::meta_function::pairs] = pairs; } - auto actionInfo = context.mLua->sol().new_usertype("ActionInfo"); + auto actionInfo = lua.new_usertype("ActionInfo"); actionInfo["key"] = sol::readonly_property( [](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mKey; }); actionInfo["name"] = sol::readonly_property( @@ -98,7 +98,7 @@ namespace MWLua actionInfo["defaultValue"] = sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mDefaultValue; }); - auto inputTriggers = context.mLua->sol().new_usertype("InputTriggers"); + auto inputTriggers = lua.new_usertype("InputTriggers"); inputTriggers[sol::meta_function::index] = [](LuaUtil::InputTrigger::Registry& registry, std::string_view key) { return registry[key]; }; { @@ -117,7 +117,7 @@ namespace MWLua inputTriggers[sol::meta_function::pairs] = pairs; } - auto triggerInfo = context.mLua->sol().new_usertype("TriggerInfo"); + auto triggerInfo = lua.new_usertype("TriggerInfo"); triggerInfo["key"] = sol::readonly_property( [](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mKey; }); triggerInfo["name"] = sol::readonly_property( @@ -128,14 +128,15 @@ namespace MWLua [](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mL10n; }); MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); - sol::table api(context.mLua->sol(), sol::create); + sol::table api(lua, sol::create); api["ACTION_TYPE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Boolean", LuaUtil::InputAction::Type::Boolean }, - { "Number", LuaUtil::InputAction::Type::Number }, - { "Range", LuaUtil::InputAction::Type::Range }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Boolean", LuaUtil::InputAction::Type::Boolean }, + { "Number", LuaUtil::InputAction::Type::Number }, + { "Range", LuaUtil::InputAction::Type::Range }, + })); api["actions"] = std::ref(context.mLuaManager->inputActions()); api["registerAction"] = [manager = context.mLuaManager](sol::table options) { @@ -231,215 +232,219 @@ namespace MWLua api["getKeyName"] = [](SDL_Scancode code) { return SDL_GetScancodeName(code); }; - api["ACTION"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "GameMenu", MWInput::A_GameMenu }, - { "Screenshot", MWInput::A_Screenshot }, - { "Inventory", MWInput::A_Inventory }, - { "Console", MWInput::A_Console }, - - { "MoveLeft", MWInput::A_MoveLeft }, - { "MoveRight", MWInput::A_MoveRight }, - { "MoveForward", MWInput::A_MoveForward }, - { "MoveBackward", MWInput::A_MoveBackward }, - - { "Activate", MWInput::A_Activate }, - { "Use", MWInput::A_Use }, - { "Jump", MWInput::A_Jump }, - { "AutoMove", MWInput::A_AutoMove }, - { "Rest", MWInput::A_Rest }, - { "Journal", MWInput::A_Journal }, - { "Run", MWInput::A_Run }, - { "CycleSpellLeft", MWInput::A_CycleSpellLeft }, - { "CycleSpellRight", MWInput::A_CycleSpellRight }, - { "CycleWeaponLeft", MWInput::A_CycleWeaponLeft }, - { "CycleWeaponRight", MWInput::A_CycleWeaponRight }, - { "AlwaysRun", MWInput::A_AlwaysRun }, - { "Sneak", MWInput::A_Sneak }, - - { "QuickSave", MWInput::A_QuickSave }, - { "QuickLoad", MWInput::A_QuickLoad }, - { "QuickMenu", MWInput::A_QuickMenu }, - { "ToggleWeapon", MWInput::A_ToggleWeapon }, - { "ToggleSpell", MWInput::A_ToggleSpell }, - { "TogglePOV", MWInput::A_TogglePOV }, - - { "QuickKey1", MWInput::A_QuickKey1 }, - { "QuickKey2", MWInput::A_QuickKey2 }, - { "QuickKey3", MWInput::A_QuickKey3 }, - { "QuickKey4", MWInput::A_QuickKey4 }, - { "QuickKey5", MWInput::A_QuickKey5 }, - { "QuickKey6", MWInput::A_QuickKey6 }, - { "QuickKey7", MWInput::A_QuickKey7 }, - { "QuickKey8", MWInput::A_QuickKey8 }, - { "QuickKey9", MWInput::A_QuickKey9 }, - { "QuickKey10", MWInput::A_QuickKey10 }, - { "QuickKeysMenu", MWInput::A_QuickKeysMenu }, - - { "ToggleHUD", MWInput::A_ToggleHUD }, - { "ToggleDebug", MWInput::A_ToggleDebug }, - { "TogglePostProcessorHUD", MWInput::A_TogglePostProcessorHUD }, - - { "ZoomIn", MWInput::A_ZoomIn }, - { "ZoomOut", MWInput::A_ZoomOut }, - })); + api["ACTION"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "GameMenu", MWInput::A_GameMenu }, + { "Screenshot", MWInput::A_Screenshot }, + { "Inventory", MWInput::A_Inventory }, + { "Console", MWInput::A_Console }, + + { "MoveLeft", MWInput::A_MoveLeft }, + { "MoveRight", MWInput::A_MoveRight }, + { "MoveForward", MWInput::A_MoveForward }, + { "MoveBackward", MWInput::A_MoveBackward }, + + { "Activate", MWInput::A_Activate }, + { "Use", MWInput::A_Use }, + { "Jump", MWInput::A_Jump }, + { "AutoMove", MWInput::A_AutoMove }, + { "Rest", MWInput::A_Rest }, + { "Journal", MWInput::A_Journal }, + { "Run", MWInput::A_Run }, + { "CycleSpellLeft", MWInput::A_CycleSpellLeft }, + { "CycleSpellRight", MWInput::A_CycleSpellRight }, + { "CycleWeaponLeft", MWInput::A_CycleWeaponLeft }, + { "CycleWeaponRight", MWInput::A_CycleWeaponRight }, + { "AlwaysRun", MWInput::A_AlwaysRun }, + { "Sneak", MWInput::A_Sneak }, + + { "QuickSave", MWInput::A_QuickSave }, + { "QuickLoad", MWInput::A_QuickLoad }, + { "QuickMenu", MWInput::A_QuickMenu }, + { "ToggleWeapon", MWInput::A_ToggleWeapon }, + { "ToggleSpell", MWInput::A_ToggleSpell }, + { "TogglePOV", MWInput::A_TogglePOV }, + + { "QuickKey1", MWInput::A_QuickKey1 }, + { "QuickKey2", MWInput::A_QuickKey2 }, + { "QuickKey3", MWInput::A_QuickKey3 }, + { "QuickKey4", MWInput::A_QuickKey4 }, + { "QuickKey5", MWInput::A_QuickKey5 }, + { "QuickKey6", MWInput::A_QuickKey6 }, + { "QuickKey7", MWInput::A_QuickKey7 }, + { "QuickKey8", MWInput::A_QuickKey8 }, + { "QuickKey9", MWInput::A_QuickKey9 }, + { "QuickKey10", MWInput::A_QuickKey10 }, + { "QuickKeysMenu", MWInput::A_QuickKeysMenu }, + + { "ToggleHUD", MWInput::A_ToggleHUD }, + { "ToggleDebug", MWInput::A_ToggleDebug }, + { "TogglePostProcessorHUD", MWInput::A_TogglePostProcessorHUD }, + + { "ZoomIn", MWInput::A_ZoomIn }, + { "ZoomOut", MWInput::A_ZoomOut }, + })); // input.CONTROL_SWITCH is deprecated, remove after releasing 0.49 api["CONTROL_SWITCH"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Controls", "playercontrols" }, - { "Fighting", "playerfighting" }, - { "Jumping", "playerjumping" }, - { "Looking", "playerlooking" }, - { "Magic", "playermagic" }, - { "ViewMode", "playerviewswitch" }, - { "VanityMode", "vanitymode" }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Controls", "playercontrols" }, + { "Fighting", "playerfighting" }, + { "Jumping", "playerjumping" }, + { "Looking", "playerlooking" }, + { "Magic", "playermagic" }, + { "ViewMode", "playerviewswitch" }, + { "VanityMode", "vanitymode" }, + })); api["CONTROLLER_BUTTON"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "A", SDL_CONTROLLER_BUTTON_A }, - { "B", SDL_CONTROLLER_BUTTON_B }, - { "X", SDL_CONTROLLER_BUTTON_X }, - { "Y", SDL_CONTROLLER_BUTTON_Y }, - { "Back", SDL_CONTROLLER_BUTTON_BACK }, - { "Guide", SDL_CONTROLLER_BUTTON_GUIDE }, - { "Start", SDL_CONTROLLER_BUTTON_START }, - { "LeftStick", SDL_CONTROLLER_BUTTON_LEFTSTICK }, - { "RightStick", SDL_CONTROLLER_BUTTON_RIGHTSTICK }, - { "LeftShoulder", SDL_CONTROLLER_BUTTON_LEFTSHOULDER }, - { "RightShoulder", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER }, - { "DPadUp", SDL_CONTROLLER_BUTTON_DPAD_UP }, - { "DPadDown", SDL_CONTROLLER_BUTTON_DPAD_DOWN }, - { "DPadLeft", SDL_CONTROLLER_BUTTON_DPAD_LEFT }, - { "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT }, + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "A", SDL_CONTROLLER_BUTTON_A }, + { "B", SDL_CONTROLLER_BUTTON_B }, + { "X", SDL_CONTROLLER_BUTTON_X }, + { "Y", SDL_CONTROLLER_BUTTON_Y }, + { "Back", SDL_CONTROLLER_BUTTON_BACK }, + { "Guide", SDL_CONTROLLER_BUTTON_GUIDE }, + { "Start", SDL_CONTROLLER_BUTTON_START }, + { "LeftStick", SDL_CONTROLLER_BUTTON_LEFTSTICK }, + { "RightStick", SDL_CONTROLLER_BUTTON_RIGHTSTICK }, + { "LeftShoulder", SDL_CONTROLLER_BUTTON_LEFTSHOULDER }, + { "RightShoulder", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER }, + { "DPadUp", SDL_CONTROLLER_BUTTON_DPAD_UP }, + { "DPadDown", SDL_CONTROLLER_BUTTON_DPAD_DOWN }, + { "DPadLeft", SDL_CONTROLLER_BUTTON_DPAD_LEFT }, + { "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT }, + })); + + api["CONTROLLER_AXIS"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "LeftX", SDL_CONTROLLER_AXIS_LEFTX }, + { "LeftY", SDL_CONTROLLER_AXIS_LEFTY }, + { "RightX", SDL_CONTROLLER_AXIS_RIGHTX }, + { "RightY", SDL_CONTROLLER_AXIS_RIGHTY }, + { "TriggerLeft", SDL_CONTROLLER_AXIS_TRIGGERLEFT }, + { "TriggerRight", SDL_CONTROLLER_AXIS_TRIGGERRIGHT }, + + { "LookUpDown", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_LookUpDown) }, + { "LookLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_LookLeftRight) }, + { "MoveForwardBackward", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_MoveForwardBackward) }, + { "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_MoveLeftRight) }, + })); + + api["KEY"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "_0", SDL_SCANCODE_0 }, + { "_1", SDL_SCANCODE_1 }, + { "_2", SDL_SCANCODE_2 }, + { "_3", SDL_SCANCODE_3 }, + { "_4", SDL_SCANCODE_4 }, + { "_5", SDL_SCANCODE_5 }, + { "_6", SDL_SCANCODE_6 }, + { "_7", SDL_SCANCODE_7 }, + { "_8", SDL_SCANCODE_8 }, + { "_9", SDL_SCANCODE_9 }, + + { "NP_0", SDL_SCANCODE_KP_0 }, + { "NP_1", SDL_SCANCODE_KP_1 }, + { "NP_2", SDL_SCANCODE_KP_2 }, + { "NP_3", SDL_SCANCODE_KP_3 }, + { "NP_4", SDL_SCANCODE_KP_4 }, + { "NP_5", SDL_SCANCODE_KP_5 }, + { "NP_6", SDL_SCANCODE_KP_6 }, + { "NP_7", SDL_SCANCODE_KP_7 }, + { "NP_8", SDL_SCANCODE_KP_8 }, + { "NP_9", SDL_SCANCODE_KP_9 }, + { "NP_Divide", SDL_SCANCODE_KP_DIVIDE }, + { "NP_Enter", SDL_SCANCODE_KP_ENTER }, + { "NP_Minus", SDL_SCANCODE_KP_MINUS }, + { "NP_Multiply", SDL_SCANCODE_KP_MULTIPLY }, + { "NP_Delete", SDL_SCANCODE_KP_PERIOD }, + { "NP_Plus", SDL_SCANCODE_KP_PLUS }, + + { "F1", SDL_SCANCODE_F1 }, + { "F2", SDL_SCANCODE_F2 }, + { "F3", SDL_SCANCODE_F3 }, + { "F4", SDL_SCANCODE_F4 }, + { "F5", SDL_SCANCODE_F5 }, + { "F6", SDL_SCANCODE_F6 }, + { "F7", SDL_SCANCODE_F7 }, + { "F8", SDL_SCANCODE_F8 }, + { "F9", SDL_SCANCODE_F9 }, + { "F10", SDL_SCANCODE_F10 }, + { "F11", SDL_SCANCODE_F11 }, + { "F12", SDL_SCANCODE_F12 }, + + { "A", SDL_SCANCODE_A }, + { "B", SDL_SCANCODE_B }, + { "C", SDL_SCANCODE_C }, + { "D", SDL_SCANCODE_D }, + { "E", SDL_SCANCODE_E }, + { "F", SDL_SCANCODE_F }, + { "G", SDL_SCANCODE_G }, + { "H", SDL_SCANCODE_H }, + { "I", SDL_SCANCODE_I }, + { "J", SDL_SCANCODE_J }, + { "K", SDL_SCANCODE_K }, + { "L", SDL_SCANCODE_L }, + { "M", SDL_SCANCODE_M }, + { "N", SDL_SCANCODE_N }, + { "O", SDL_SCANCODE_O }, + { "P", SDL_SCANCODE_P }, + { "Q", SDL_SCANCODE_Q }, + { "R", SDL_SCANCODE_R }, + { "S", SDL_SCANCODE_S }, + { "T", SDL_SCANCODE_T }, + { "U", SDL_SCANCODE_U }, + { "V", SDL_SCANCODE_V }, + { "W", SDL_SCANCODE_W }, + { "X", SDL_SCANCODE_X }, + { "Y", SDL_SCANCODE_Y }, + { "Z", SDL_SCANCODE_Z }, + + { "LeftArrow", SDL_SCANCODE_LEFT }, + { "RightArrow", SDL_SCANCODE_RIGHT }, + { "UpArrow", SDL_SCANCODE_UP }, + { "DownArrow", SDL_SCANCODE_DOWN }, + + { "LeftAlt", SDL_SCANCODE_LALT }, + { "LeftCtrl", SDL_SCANCODE_LCTRL }, + { "LeftBracket", SDL_SCANCODE_LEFTBRACKET }, + { "LeftSuper", SDL_SCANCODE_LGUI }, + { "LeftShift", SDL_SCANCODE_LSHIFT }, + { "RightAlt", SDL_SCANCODE_RALT }, + { "RightCtrl", SDL_SCANCODE_RCTRL }, + { "RightSuper", SDL_SCANCODE_RGUI }, + { "RightBracket", SDL_SCANCODE_RIGHTBRACKET }, + { "RightShift", SDL_SCANCODE_RSHIFT }, + + { "Apostrophe", SDL_SCANCODE_APOSTROPHE }, + { "BackSlash", SDL_SCANCODE_BACKSLASH }, + { "Backspace", SDL_SCANCODE_BACKSPACE }, + { "CapsLock", SDL_SCANCODE_CAPSLOCK }, + { "Comma", SDL_SCANCODE_COMMA }, + { "Delete", SDL_SCANCODE_DELETE }, + { "End", SDL_SCANCODE_END }, + { "Enter", SDL_SCANCODE_RETURN }, + { "Equals", SDL_SCANCODE_EQUALS }, + { "Escape", SDL_SCANCODE_ESCAPE }, + { "Home", SDL_SCANCODE_HOME }, + { "Insert", SDL_SCANCODE_INSERT }, + { "Minus", SDL_SCANCODE_MINUS }, + { "NumLock", SDL_SCANCODE_NUMLOCKCLEAR }, + { "PageDown", SDL_SCANCODE_PAGEDOWN }, + { "PageUp", SDL_SCANCODE_PAGEUP }, + { "Period", SDL_SCANCODE_PERIOD }, + { "Pause", SDL_SCANCODE_PAUSE }, + { "PrintScreen", SDL_SCANCODE_PRINTSCREEN }, + { "ScrollLock", SDL_SCANCODE_SCROLLLOCK }, + { "Semicolon", SDL_SCANCODE_SEMICOLON }, + { "Slash", SDL_SCANCODE_SLASH }, + { "Space", SDL_SCANCODE_SPACE }, + { "Tab", SDL_SCANCODE_TAB }, })); - api["CONTROLLER_AXIS"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "LeftX", SDL_CONTROLLER_AXIS_LEFTX }, - { "LeftY", SDL_CONTROLLER_AXIS_LEFTY }, - { "RightX", SDL_CONTROLLER_AXIS_RIGHTX }, - { "RightY", SDL_CONTROLLER_AXIS_RIGHTY }, - { "TriggerLeft", SDL_CONTROLLER_AXIS_TRIGGERLEFT }, - { "TriggerRight", SDL_CONTROLLER_AXIS_TRIGGERRIGHT }, - - { "LookUpDown", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_LookUpDown) }, - { "LookLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_LookLeftRight) }, - { "MoveForwardBackward", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_MoveForwardBackward) }, - { "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast(MWInput::A_MoveLeftRight) }, - })); - - api["KEY"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "_0", SDL_SCANCODE_0 }, - { "_1", SDL_SCANCODE_1 }, - { "_2", SDL_SCANCODE_2 }, - { "_3", SDL_SCANCODE_3 }, - { "_4", SDL_SCANCODE_4 }, - { "_5", SDL_SCANCODE_5 }, - { "_6", SDL_SCANCODE_6 }, - { "_7", SDL_SCANCODE_7 }, - { "_8", SDL_SCANCODE_8 }, - { "_9", SDL_SCANCODE_9 }, - - { "NP_0", SDL_SCANCODE_KP_0 }, - { "NP_1", SDL_SCANCODE_KP_1 }, - { "NP_2", SDL_SCANCODE_KP_2 }, - { "NP_3", SDL_SCANCODE_KP_3 }, - { "NP_4", SDL_SCANCODE_KP_4 }, - { "NP_5", SDL_SCANCODE_KP_5 }, - { "NP_6", SDL_SCANCODE_KP_6 }, - { "NP_7", SDL_SCANCODE_KP_7 }, - { "NP_8", SDL_SCANCODE_KP_8 }, - { "NP_9", SDL_SCANCODE_KP_9 }, - { "NP_Divide", SDL_SCANCODE_KP_DIVIDE }, - { "NP_Enter", SDL_SCANCODE_KP_ENTER }, - { "NP_Minus", SDL_SCANCODE_KP_MINUS }, - { "NP_Multiply", SDL_SCANCODE_KP_MULTIPLY }, - { "NP_Delete", SDL_SCANCODE_KP_PERIOD }, - { "NP_Plus", SDL_SCANCODE_KP_PLUS }, - - { "F1", SDL_SCANCODE_F1 }, - { "F2", SDL_SCANCODE_F2 }, - { "F3", SDL_SCANCODE_F3 }, - { "F4", SDL_SCANCODE_F4 }, - { "F5", SDL_SCANCODE_F5 }, - { "F6", SDL_SCANCODE_F6 }, - { "F7", SDL_SCANCODE_F7 }, - { "F8", SDL_SCANCODE_F8 }, - { "F9", SDL_SCANCODE_F9 }, - { "F10", SDL_SCANCODE_F10 }, - { "F11", SDL_SCANCODE_F11 }, - { "F12", SDL_SCANCODE_F12 }, - - { "A", SDL_SCANCODE_A }, - { "B", SDL_SCANCODE_B }, - { "C", SDL_SCANCODE_C }, - { "D", SDL_SCANCODE_D }, - { "E", SDL_SCANCODE_E }, - { "F", SDL_SCANCODE_F }, - { "G", SDL_SCANCODE_G }, - { "H", SDL_SCANCODE_H }, - { "I", SDL_SCANCODE_I }, - { "J", SDL_SCANCODE_J }, - { "K", SDL_SCANCODE_K }, - { "L", SDL_SCANCODE_L }, - { "M", SDL_SCANCODE_M }, - { "N", SDL_SCANCODE_N }, - { "O", SDL_SCANCODE_O }, - { "P", SDL_SCANCODE_P }, - { "Q", SDL_SCANCODE_Q }, - { "R", SDL_SCANCODE_R }, - { "S", SDL_SCANCODE_S }, - { "T", SDL_SCANCODE_T }, - { "U", SDL_SCANCODE_U }, - { "V", SDL_SCANCODE_V }, - { "W", SDL_SCANCODE_W }, - { "X", SDL_SCANCODE_X }, - { "Y", SDL_SCANCODE_Y }, - { "Z", SDL_SCANCODE_Z }, - - { "LeftArrow", SDL_SCANCODE_LEFT }, - { "RightArrow", SDL_SCANCODE_RIGHT }, - { "UpArrow", SDL_SCANCODE_UP }, - { "DownArrow", SDL_SCANCODE_DOWN }, - - { "LeftAlt", SDL_SCANCODE_LALT }, - { "LeftCtrl", SDL_SCANCODE_LCTRL }, - { "LeftBracket", SDL_SCANCODE_LEFTBRACKET }, - { "LeftSuper", SDL_SCANCODE_LGUI }, - { "LeftShift", SDL_SCANCODE_LSHIFT }, - { "RightAlt", SDL_SCANCODE_RALT }, - { "RightCtrl", SDL_SCANCODE_RCTRL }, - { "RightSuper", SDL_SCANCODE_RGUI }, - { "RightBracket", SDL_SCANCODE_RIGHTBRACKET }, - { "RightShift", SDL_SCANCODE_RSHIFT }, - - { "Apostrophe", SDL_SCANCODE_APOSTROPHE }, - { "BackSlash", SDL_SCANCODE_BACKSLASH }, - { "Backspace", SDL_SCANCODE_BACKSPACE }, - { "CapsLock", SDL_SCANCODE_CAPSLOCK }, - { "Comma", SDL_SCANCODE_COMMA }, - { "Delete", SDL_SCANCODE_DELETE }, - { "End", SDL_SCANCODE_END }, - { "Enter", SDL_SCANCODE_RETURN }, - { "Equals", SDL_SCANCODE_EQUALS }, - { "Escape", SDL_SCANCODE_ESCAPE }, - { "Home", SDL_SCANCODE_HOME }, - { "Insert", SDL_SCANCODE_INSERT }, - { "Minus", SDL_SCANCODE_MINUS }, - { "NumLock", SDL_SCANCODE_NUMLOCKCLEAR }, - { "PageDown", SDL_SCANCODE_PAGEDOWN }, - { "PageUp", SDL_SCANCODE_PAGEUP }, - { "Period", SDL_SCANCODE_PERIOD }, - { "Pause", SDL_SCANCODE_PAUSE }, - { "PrintScreen", SDL_SCANCODE_PRINTSCREEN }, - { "ScrollLock", SDL_SCANCODE_SCROLLLOCK }, - { "Semicolon", SDL_SCANCODE_SEMICOLON }, - { "Slash", SDL_SCANCODE_SLASH }, - { "Space", SDL_SCANCODE_SPACE }, - { "Tab", SDL_SCANCODE_TAB }, - })); - - sol::state_view& lua = context.mLua->sol(); lua["openmw_input"] = LuaUtil::makeReadOnly(api); return lua["openmw_input"]; } diff --git a/apps/openmw/mwlua/itemdata.cpp b/apps/openmw/mwlua/itemdata.cpp index 9ae9f57b34..38415ea25e 100644 --- a/apps/openmw/mwlua/itemdata.cpp +++ b/apps/openmw/mwlua/itemdata.cpp @@ -60,7 +60,7 @@ namespace MWLua if (it != self->mStatsCache.end()) return it->second; } - return sol::make_object(context.mLua->sol(), getValue(context, prop, mObject.ptr())); + return sol::make_object(context.mLua->unsafeState(), getValue(context, prop, mObject.ptr())); } void set(const Context& context, std::string_view prop, const sol::object& value) const @@ -82,9 +82,9 @@ namespace MWLua if (prop == "condition") { if (ptr.mRef->getType() == ESM::REC_LIGH) - return sol::make_object(context.mLua->sol(), ptr.getClass().getRemainingUsageTime(ptr)); + return sol::make_object(context.mLua->unsafeState(), ptr.getClass().getRemainingUsageTime(ptr)); else if (ptr.getClass().hasItemHealth(ptr)) - return sol::make_object(context.mLua->sol(), + return sol::make_object(context.mLua->unsafeState(), ptr.getClass().getItemHealth(ptr) + ptr.getCellRef().getChargeIntRemainder()); } else if (prop == "enchantmentCharge") @@ -99,9 +99,10 @@ namespace MWLua const auto* enchantment = store->get().find(enchantmentName); if (charge == -1) // return the full charge - return sol::make_object(context.mLua->sol(), MWMechanics::getEnchantmentCharge(*enchantment)); + return sol::make_object( + context.mLua->unsafeState(), MWMechanics::getEnchantmentCharge(*enchantment)); - return sol::make_object(context.mLua->sol(), charge); + return sol::make_object(context.mLua->unsafeState(), charge); } else if (prop == "soul") { @@ -109,7 +110,7 @@ namespace MWLua if (soul.empty()) return sol::lua_nil; - return sol::make_object(context.mLua->sol(), soul.serializeText()); + return sol::make_object(context.mLua->unsafeState(), soul.serializeText()); } return sol::lua_nil; @@ -185,7 +186,7 @@ namespace MWLua return {}; }; - sol::usertype itemData = context.mLua->sol().new_usertype("ItemData"); + sol::usertype itemData = context.sol().new_usertype("ItemData"); itemData[sol::meta_function::new_index] = [](const ItemData& stat, const sol::variadic_args args) { throw std::runtime_error("Unknown ItemData property '" + args.get() + "'"); }; diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 1230c6fa91..d57ac8da9b 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -38,8 +38,9 @@ namespace MWLua void LocalScripts::initializeSelfPackage(const Context& context) { + auto lua = context.sol(); using ActorControls = MWBase::LuaManager::ActorControls; - sol::usertype controls = context.mLua->sol().new_usertype("ActorControls"); + sol::usertype controls = lua.new_usertype("ActorControls"); #define CONTROL(TYPE, FIELD) \ sol::property([](const ActorControls& c) { return c.FIELD; }, \ @@ -57,8 +58,8 @@ namespace MWLua controls["use"] = CONTROL(int, mUse); #undef CONTROL - sol::usertype selfAPI = context.mLua->sol().new_usertype( - "SelfObject", sol::base_classes, sol::bases()); + sol::usertype selfAPI + = lua.new_usertype("SelfObject", sol::base_classes, sol::bases()); selfAPI[sol::meta_function::to_string] = [](SelfObject& self) { return "openmw.self[" + self.toString() + "]"; }; selfAPI["object"] = sol::readonly_property([](SelfObject& self) -> LObject { return LObject(self); }); @@ -66,13 +67,13 @@ namespace MWLua selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; }; selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; }; selfAPI["ATTACK_TYPE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs( + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, { { "NoAttack", MWMechanics::AttackType::NoAttack }, { "Any", MWMechanics::AttackType::Any }, { "Chop", MWMechanics::AttackType::Chop }, { "Slash", MWMechanics::AttackType::Slash }, { "Thrust", MWMechanics::AttackType::Thrust } })); using AiPackage = MWMechanics::AiPackage; - sol::usertype aiPackage = context.mLua->sol().new_usertype("AiPackage"); + sol::usertype aiPackage = lua.new_usertype("AiPackage"); aiPackage["type"] = sol::readonly_property([](const AiPackage& p) -> std::string_view { switch (p.getTypeId()) { @@ -113,23 +114,24 @@ namespace MWLua aiPackage["destPosition"] = sol::readonly_property([](const AiPackage& p) { return p.getDestination(); }); aiPackage["distance"] = sol::readonly_property([](const AiPackage& p) { return p.getDistance(); }); aiPackage["duration"] = sol::readonly_property([](const AiPackage& p) { return p.getDuration(); }); - aiPackage["idle"] = sol::readonly_property([context](const AiPackage& p) -> sol::optional { - if (p.getTypeId() == MWMechanics::AiPackageTypeId::Wander) - { - sol::table idles(context.mLua->sol(), sol::create); - const std::vector& idle = static_cast(p).getIdle(); - if (!idle.empty()) - { - for (size_t i = 0; i < idle.size(); ++i) - { - std::string_view groupName = MWMechanics::AiWander::getIdleGroupName(i); - idles[groupName] = idle[i]; - } - return idles; - } - } - return sol::nullopt; - }); + aiPackage["idle"] + = sol::readonly_property([](sol::this_state lua, const AiPackage& p) -> sol::optional { + if (p.getTypeId() == MWMechanics::AiPackageTypeId::Wander) + { + sol::table idles(lua, sol::create); + const std::vector& idle = static_cast(p).getIdle(); + if (!idle.empty()) + { + for (size_t i = 0; i < idle.size(); ++i) + { + std::string_view groupName = MWMechanics::AiWander::getIdleGroupName(i); + idles[groupName] = idle[i]; + } + return idles; + } + } + return sol::nullopt; + }); aiPackage["isRepeat"] = sol::readonly_property([](const AiPackage& p) { return p.getRepeat(); }); @@ -226,7 +228,8 @@ namespace MWLua : LuaUtil::ScriptsContainer(lua, "L" + obj.id().toString()) , mData(obj) { - this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData)); + lua->protectedCall( + [&](LuaUtil::LuaView& view) { addPackage("openmw.self", sol::make_object(view.sol(), &mData)); }); registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers, &mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers, &mOnSkillUse, &mOnSkillLevelUp }); diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 5b4357ae8e..8debbe153d 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -29,7 +29,7 @@ namespace MWLua { std::map initCommonPackages(const Context& context) { - sol::state_view lua = context.mLua->sol(); + sol::state_view lua = context.mLua->unsafeState(); MWWorld::DateTimeManager* tm = MWBase::Environment::get().getWorld()->getTimeManager(); return { { "openmw.animation", initAnimationPackage(context) }, @@ -69,7 +69,7 @@ namespace MWLua { return { { "openmw.ambient", initAmbientPackage(context) }, - { "openmw.camera", initCameraPackage(context.mLua->sol()) }, + { "openmw.camera", initCameraPackage(context.sol()) }, { "openmw.debug", initDebugPackage(context) }, { "openmw.input", initInputPackage(context) }, { "openmw.postprocessing", initPostprocessingPackage(context) }, diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index cba34e43f3..658652f793 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -83,47 +83,49 @@ namespace MWLua void LuaManager::init() { - Context globalContext; - globalContext.mType = Context::Global; - globalContext.mLuaManager = this; - globalContext.mLua = &mLua; - globalContext.mObjectLists = &mObjectLists; - globalContext.mLuaEvents = &mLuaEvents; - globalContext.mSerializer = mGlobalSerializer.get(); - - Context localContext = globalContext; - localContext.mType = Context::Local; - localContext.mSerializer = mLocalSerializer.get(); - - Context menuContext = globalContext; - menuContext.mType = Context::Menu; - - for (const auto& [name, package] : initCommonPackages(globalContext)) - mLua.addCommonPackage(name, package); - for (const auto& [name, package] : initGlobalPackages(globalContext)) - mGlobalScripts.addPackage(name, package); - for (const auto& [name, package] : initMenuPackages(menuContext)) - mMenuScripts.addPackage(name, package); - - mLocalPackages = initLocalPackages(localContext); - - mPlayerPackages = initPlayerPackages(localContext); - mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end()); - - LuaUtil::LuaStorage::initLuaBindings(mLua.sol()); - mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua, &mGlobalStorage)); - mMenuScripts.addPackage( - "openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua, &mGlobalStorage, &mPlayerStorage)); - mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua, &mGlobalStorage); - mPlayerPackages["openmw.storage"] - = LuaUtil::LuaStorage::initPlayerPackage(mLua, &mGlobalStorage, &mPlayerStorage); - - mPlayerStorage.setActive(true); - mGlobalStorage.setActive(false); - - initConfiguration(); - mInitialized = true; - mMenuScripts.addAutoStartedScripts(); + mLua.protectedCall([&](LuaUtil::LuaView& view) { + Context globalContext; + globalContext.mType = Context::Global; + globalContext.mLuaManager = this; + globalContext.mLua = &mLua; + globalContext.mObjectLists = &mObjectLists; + globalContext.mLuaEvents = &mLuaEvents; + globalContext.mSerializer = mGlobalSerializer.get(); + + Context localContext = globalContext; + localContext.mType = Context::Local; + localContext.mSerializer = mLocalSerializer.get(); + + Context menuContext = globalContext; + menuContext.mType = Context::Menu; + + for (const auto& [name, package] : initCommonPackages(globalContext)) + mLua.addCommonPackage(name, package); + for (const auto& [name, package] : initGlobalPackages(globalContext)) + mGlobalScripts.addPackage(name, package); + for (const auto& [name, package] : initMenuPackages(menuContext)) + mMenuScripts.addPackage(name, package); + + mLocalPackages = initLocalPackages(localContext); + + mPlayerPackages = initPlayerPackages(localContext); + mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end()); + + LuaUtil::LuaStorage::initLuaBindings(view); + mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(view, &mGlobalStorage)); + mMenuScripts.addPackage( + "openmw.storage", LuaUtil::LuaStorage::initMenuPackage(view, &mGlobalStorage, &mPlayerStorage)); + mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(view, &mGlobalStorage); + mPlayerPackages["openmw.storage"] + = LuaUtil::LuaStorage::initPlayerPackage(view, &mGlobalStorage, &mPlayerStorage); + + mPlayerStorage.setActive(true); + mGlobalStorage.setActive(false); + + initConfiguration(); + mInitialized = true; + mMenuScripts.addAutoStartedScripts(); + }); } void LuaManager::loadPermanentStorage(const std::filesystem::path& userConfigPath) @@ -132,23 +134,28 @@ namespace MWLua mGlobalStorage.setActive(true); const auto globalPath = userConfigPath / "global_storage.bin"; const auto playerPath = userConfigPath / "player_storage.bin"; - if (std::filesystem::exists(globalPath)) - mGlobalStorage.load(globalPath); - if (std::filesystem::exists(playerPath)) - mPlayerStorage.load(playerPath); + + mLua.protectedCall([&](LuaUtil::LuaView& view) { + if (std::filesystem::exists(globalPath)) + mGlobalStorage.load(view.sol(), globalPath); + if (std::filesystem::exists(playerPath)) + mPlayerStorage.load(view.sol(), playerPath); + }); } void LuaManager::savePermanentStorage(const std::filesystem::path& userConfigPath) { - if (mGlobalScriptsStarted) - mGlobalStorage.save(userConfigPath / "global_storage.bin"); - mPlayerStorage.save(userConfigPath / "player_storage.bin"); + mLua.protectedCall([&](LuaUtil::LuaView& view) { + if (mGlobalScriptsStarted) + mGlobalStorage.save(view.sol(), userConfigPath / "global_storage.bin"); + mPlayerStorage.save(view.sol(), userConfigPath / "player_storage.bin"); + }); } void LuaManager::update() { if (const int steps = Settings::lua().mGcStepsPerFrame; steps > 0) - lua_gc(mLua.sol(), LUA_GCSTEP, steps); + lua_gc(mLua.unsafeState(), LUA_GCSTEP, steps); if (mPlayer.isEmpty()) return; // The game is not started yet. @@ -330,7 +337,7 @@ namespace MWLua mInputActions.clear(); mInputTriggers.clear(); for (int i = 0; i < 5; ++i) - lua_gc(mLua.sol(), LUA_GCCOLLECT, 0); + lua_gc(mLua.unsafeState(), LUA_GCCOLLECT, 0); } void LuaManager::setupPlayer(const MWWorld::Ptr& ptr) @@ -424,35 +431,37 @@ namespace MWLua const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult, std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback) { - sol::table options = mLua.newTable(); - options["blendMask"] = blendMask; - options["autoDisable"] = autodisable; - options["speed"] = speedmult; - options["startKey"] = start; - options["stopKey"] = stop; - options["startPoint"] = startpoint; - options["loops"] = loops; - options["forceLoop"] = loopfallback; - - bool priorityAsTable = false; - for (uint32_t i = 1; i < MWRender::sNumBlendMasks; i++) - if (priority[static_cast(i)] != priority[static_cast(0)]) - priorityAsTable = true; - if (priorityAsTable) - { - sol::table priorityTable = mLua.newTable(); - for (uint32_t i = 0; i < MWRender::sNumBlendMasks; i++) - priorityTable[static_cast(i)] = priority[static_cast(i)]; - options["priority"] = priorityTable; - } - else - options["priority"] = priority[MWRender::BoneGroup_LowerBody]; + mLua.protectedCall([&](LuaUtil::LuaView& view) { + sol::table options = view.newTable(); + options["blendMask"] = blendMask; + options["autoDisable"] = autodisable; + options["speed"] = speedmult; + options["startKey"] = start; + options["stopKey"] = stop; + options["startPoint"] = startpoint; + options["loops"] = loops; + options["forceLoop"] = loopfallback; + + bool priorityAsTable = false; + for (uint32_t i = 1; i < MWRender::sNumBlendMasks; i++) + if (priority[static_cast(i)] != priority[static_cast(0)]) + priorityAsTable = true; + if (priorityAsTable) + { + sol::table priorityTable = view.newTable(); + for (uint32_t i = 0; i < MWRender::sNumBlendMasks; i++) + priorityTable[static_cast(i)] = priority[static_cast(i)]; + options["priority"] = priorityTable; + } + else + options["priority"] = priority[MWRender::BoneGroup_LowerBody]; - // mEngineEvents.addToQueue(event); - // Has to be called immediately, otherwise engine details that depend on animations playing immediately - // break. - if (auto* scripts = actor.getRefData().getLuaScripts()) - scripts->onPlayAnimation(groupname, options); + // mEngineEvents.addToQueue(event); + // Has to be called immediately, otherwise engine details that depend on animations playing immediately + // break. + if (auto* scripts = actor.getRefData().getLuaScripts()) + scripts->onPlayAnimation(groupname, options); + }); } void LuaManager::skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) @@ -593,7 +602,9 @@ namespace MWLua ESM::LuaScripts globalScripts; globalScripts.load(reader); - mLuaEvents.load(mLua.sol(), reader, mContentFileMapping, mGlobalLoader.get()); + mLua.protectedCall([&](LuaUtil::LuaView& view) { + mLuaEvents.load(view.sol(), reader, mContentFileMapping, mGlobalLoader.get()); + }); mGlobalScripts.setSavedDataDeserializer(mGlobalLoader.get()); mGlobalScripts.load(globalScripts); @@ -696,7 +707,9 @@ namespace MWLua { sol::object selected = sol::nil; if (!selectedPtr.isEmpty()) - selected = sol::make_object(mLua.sol(), LObject(getId(selectedPtr))); + mLua.protectedCall([&](LuaUtil::LuaView& view) { + selected = sol::make_object(view.sol(), LObject(getId(selectedPtr))); + }); if (playerScripts->consoleCommand(consoleMode, command, selected)) processed = true; } diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 3238365ad5..5fa20d377f 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -150,8 +150,9 @@ namespace MWLua template std::function wrapLuaCallback(const LuaUtil::Callback& c) { - return - [this, c](Arg arg) { this->queueCallback(c, sol::main_object(this->mLua.sol(), sol::in_place, arg)); }; + return [this, c](Arg arg) { + this->queueCallback(c, sol::main_object(this->mLua.unsafeState(), sol::in_place, arg)); + }; } LuaUi::ResourceManager* uiResourceManager() { return &mUiResourceManager; } @@ -227,8 +228,8 @@ namespace MWLua std::vector> mInGameConsoleMessages; std::optional mDelayedUiModeChangedArg; - LuaUtil::LuaStorage mGlobalStorage{ mLua.sol() }; - LuaUtil::LuaStorage mPlayerStorage{ mLua.sol() }; + LuaUtil::LuaStorage mGlobalStorage; + LuaUtil::LuaStorage mPlayerStorage; LuaUtil::InputAction::Registry mInputActions; LuaUtil::InputTrigger::Registry mInputTriggers; diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index a894ed07ff..e75717d6f2 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -214,33 +214,36 @@ namespace MWLua sol::table initCoreMagicBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table magicApi(lua, sol::create); // Constants - magicApi["RANGE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Self", ESM::RT_Self }, - { "Touch", ESM::RT_Touch }, - { "Target", ESM::RT_Target }, - })); - magicApi["SPELL_TYPE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Spell", ESM::Spell::ST_Spell }, - { "Ability", ESM::Spell::ST_Ability }, - { "Blight", ESM::Spell::ST_Blight }, - { "Disease", ESM::Spell::ST_Disease }, - { "Curse", ESM::Spell::ST_Curse }, - { "Power", ESM::Spell::ST_Power }, + magicApi["RANGE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Self", ESM::RT_Self }, + { "Touch", ESM::RT_Touch }, + { "Target", ESM::RT_Target }, })); + magicApi["SPELL_TYPE"] + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Spell", ESM::Spell::ST_Spell }, + { "Ability", ESM::Spell::ST_Ability }, + { "Blight", ESM::Spell::ST_Blight }, + { "Disease", ESM::Spell::ST_Disease }, + { "Curse", ESM::Spell::ST_Curse }, + { "Power", ESM::Spell::ST_Power }, + })); magicApi["ENCHANTMENT_TYPE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "CastOnce", ESM::Enchantment::Type::CastOnce }, - { "CastOnStrike", ESM::Enchantment::Type::WhenStrikes }, - { "CastOnUse", ESM::Enchantment::Type::WhenUsed }, - { "ConstantEffect", ESM::Enchantment::Type::ConstantEffect }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "CastOnce", ESM::Enchantment::Type::CastOnce }, + { "CastOnStrike", ESM::Enchantment::Type::WhenStrikes }, + { "CastOnUse", ESM::Enchantment::Type::WhenUsed }, + { "ConstantEffect", ESM::Enchantment::Type::ConstantEffect }, + })); - sol::table effect(context.mLua->sol(), sol::create); + sol::table effect(lua, sol::create); magicApi["EFFECT_TYPE"] = LuaUtil::makeStrictReadOnly(effect); for (const auto& name : ESM::MagicEffect::sIndexNames) { @@ -369,7 +372,7 @@ namespace MWLua = sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> int { return params.mIndex; }); // MagicEffect record - auto magicEffectT = context.mLua->sol().new_usertype("ESM3_MagicEffect"); + auto magicEffectT = lua.new_usertype("ESM3_MagicEffect"); magicEffectT[sol::meta_function::to_string] = [](const ESM::MagicEffect& rec) { return "ESM3_MagicEffect[" + ESM::MagicEffect::indexToGmstString(rec.mIndex) + "]"; @@ -437,7 +440,7 @@ namespace MWLua // magicEffectT["projectileSpeed"] // = sol::readonly_property([](const ESM::MagicEffect& rec) -> float { return rec.mData.mSpeed; }); - auto activeSpellEffectT = context.mLua->sol().new_usertype("ActiveSpellEffect"); + auto activeSpellEffectT = lua.new_usertype("ActiveSpellEffect"); activeSpellEffectT[sol::meta_function::to_string] = [](const ESM::ActiveEffect& effect) { return "ActiveSpellEffect[" + ESM::MagicEffect::indexToGmstString(effect.mEffectId) + "]"; }; @@ -508,7 +511,7 @@ namespace MWLua return effect.mDuration; }); - auto activeSpellT = context.mLua->sol().new_usertype("ActiveSpellParams"); + auto activeSpellT = lua.new_usertype("ActiveSpellParams"); activeSpellT[sol::meta_function::to_string] = [](const ActiveSpell& activeSpell) { return "ActiveSpellParams[" + activeSpell.mParams.getSourceSpellId().serializeText() + "]"; }; @@ -569,7 +572,7 @@ namespace MWLua return activeSpell.mParams.getActiveSpellId().serializeText(); }); - auto activeEffectT = context.mLua->sol().new_usertype("ActiveEffect"); + auto activeEffectT = lua.new_usertype("ActiveEffect"); activeEffectT[sol::meta_function::to_string] = [](const ActiveEffect& effect) { return "ActiveEffect[" + ESM::MagicEffect::indexToGmstString(effect.key.mId) + "]"; @@ -680,23 +683,24 @@ namespace MWLua void addActorMagicBindings(sol::table& actor, const Context& context) { + auto lua = context.sol(); const MWWorld::Store* spellStore = &MWBase::Environment::get().getWorld()->getStore().get(); // types.Actor.spells(o) actor["spells"] = [](const sol::object& actor) { return ActorSpells{ actor }; }; - auto spellsT = context.mLua->sol().new_usertype("ActorSpells"); + auto spellsT = lua.new_usertype("ActorSpells"); spellsT[sol::meta_function::to_string] = [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString() + "]"; }; actor["activeSpells"] = [](const sol::object& actor) { return ActorActiveSpells{ actor }; }; - auto activeSpellsT = context.mLua->sol().new_usertype("ActorActiveSpells"); + auto activeSpellsT = lua.new_usertype("ActorActiveSpells"); activeSpellsT[sol::meta_function::to_string] = [](const ActorActiveSpells& spells) { return "ActorActiveSpells[" + spells.mActor.object().toString() + "]"; }; actor["activeEffects"] = [](const sol::object& actor) { return ActorActiveEffects{ actor }; }; - auto activeEffectsT = context.mLua->sol().new_usertype("ActorActiveEffects"); + auto activeEffectsT = lua.new_usertype("ActorActiveEffects"); activeEffectsT[sol::meta_function::to_string] = [](const ActorActiveEffects& effects) { return "ActorActiveEffects[" + effects.mActor.object().toString() + "]"; }; @@ -798,10 +802,10 @@ namespace MWLua }); // pairs(types.Actor.spells(o)) - spellsT[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get(); + spellsT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); // ipairs(types.Actor.spells(o)) - spellsT[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get(); + spellsT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); // types.Actor.spells(o):add(id) spellsT["add"] = [context](const ActorSpells& spells, const sol::object& spellOrId) { diff --git a/apps/openmw/mwlua/markupbindings.cpp b/apps/openmw/mwlua/markupbindings.cpp index f0b9d67a51..9a3142cc3b 100644 --- a/apps/openmw/mwlua/markupbindings.cpp +++ b/apps/openmw/mwlua/markupbindings.cpp @@ -14,17 +14,17 @@ namespace MWLua { sol::table initMarkupPackage(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table api(lua, sol::create); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - api["loadYaml"] = [lua = context.mLua, vfs](std::string_view fileName) { + api["loadYaml"] = [lua, vfs](std::string_view fileName) { Files::IStreamPtr file = vfs->get(VFS::Path::Normalized(fileName)); - return LuaUtil::loadYaml(*file, lua->sol()); - }; - api["decodeYaml"] = [lua = context.mLua](std::string_view inputData) { - return LuaUtil::loadYaml(std::string(inputData), lua->sol()); + return LuaUtil::loadYaml(*file, lua); }; + api["decodeYaml"] + = [lua](std::string_view inputData) { return LuaUtil::loadYaml(std::string(inputData), lua); }; return LuaUtil::makeReadOnly(api); } diff --git a/apps/openmw/mwlua/menuscripts.cpp b/apps/openmw/mwlua/menuscripts.cpp index e433284865..32520c0822 100644 --- a/apps/openmw/mwlua/menuscripts.cpp +++ b/apps/openmw/mwlua/menuscripts.cpp @@ -30,15 +30,16 @@ namespace MWLua sol::table initMenuPackage(const Context& context) { - sol::state_view lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table api(lua, sol::create); api["STATE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "NoGame", MWBase::StateManager::State_NoGame }, - { "Running", MWBase::StateManager::State_Running }, - { "Ended", MWBase::StateManager::State_Ended }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "NoGame", MWBase::StateManager::State_NoGame }, + { "Running", MWBase::StateManager::State_Running }, + { "Ended", MWBase::StateManager::State_Ended }, + })); api["getState"] = []() -> int { return MWBase::Environment::get().getStateManager()->getState(); }; diff --git a/apps/openmw/mwlua/mwscriptbindings.cpp b/apps/openmw/mwlua/mwscriptbindings.cpp index e8033d6c07..2a92a6c5af 100644 --- a/apps/openmw/mwlua/mwscriptbindings.cpp +++ b/apps/openmw/mwlua/mwscriptbindings.cpp @@ -95,7 +95,8 @@ namespace MWLua sol::table initMWScriptBindings(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::state_view lua = lua; + sol::table api(lua, sol::create); api["getGlobalScript"] = [](std::string_view recordId, sol::optional player) -> sol::optional { @@ -121,10 +122,8 @@ namespace MWLua // api["getGlobalScripts"] = [](std::string_view recordId) -> list of scripts // api["getLocalScripts"] = [](const GObject& obj) -> list of scripts - sol::state_view& lua = context.mLua->sol(); - sol::usertype mwscript = context.mLua->sol().new_usertype("MWScript"); - sol::usertype mwscriptVars - = context.mLua->sol().new_usertype("MWScriptVariables"); + sol::usertype mwscript = lua.new_usertype("MWScript"); + sol::usertype mwscriptVars = lua.new_usertype("MWScriptVariables"); mwscript[sol::meta_function::to_string] = [](const MWScriptRef& s) { return std::string("MWScript{") + s.mId.toDebugString() + "}"; }; mwscript["isRunning"] = sol::readonly_property([](const MWScriptRef& s) { return s.isRunning(); }); diff --git a/apps/openmw/mwlua/nearbybindings.cpp b/apps/openmw/mwlua/nearbybindings.cpp index af6980fb7f..40367ea45f 100644 --- a/apps/openmw/mwlua/nearbybindings.cpp +++ b/apps/openmw/mwlua/nearbybindings.cpp @@ -53,11 +53,12 @@ namespace MWLua { sol::table initNearbyPackage(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table api(lua, sol::create); ObjectLists* objectLists = context.mObjectLists; sol::usertype rayResult - = context.mLua->sol().new_usertype("RayCastingResult"); + = lua.new_usertype("RayCastingResult"); rayResult["hit"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) { return r.mHit; }); rayResult["hitPos"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) -> sol::optional { @@ -82,18 +83,19 @@ namespace MWLua }); api["COLLISION_TYPE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "World", MWPhysics::CollisionType_World }, - { "Door", MWPhysics::CollisionType_Door }, - { "Actor", MWPhysics::CollisionType_Actor }, - { "HeightMap", MWPhysics::CollisionType_HeightMap }, - { "Projectile", MWPhysics::CollisionType_Projectile }, - { "Water", MWPhysics::CollisionType_Water }, - { "Default", MWPhysics::CollisionType_Default }, - { "AnyPhysical", MWPhysics::CollisionType_AnyPhysical }, - { "Camera", MWPhysics::CollisionType_CameraOnly }, - { "VisualOnly", MWPhysics::CollisionType_VisualOnly }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "World", MWPhysics::CollisionType_World }, + { "Door", MWPhysics::CollisionType_Door }, + { "Actor", MWPhysics::CollisionType_Actor }, + { "HeightMap", MWPhysics::CollisionType_HeightMap }, + { "Projectile", MWPhysics::CollisionType_Projectile }, + { "Water", MWPhysics::CollisionType_Water }, + { "Default", MWPhysics::CollisionType_Default }, + { "AnyPhysical", MWPhysics::CollisionType_AnyPhysical }, + { "Camera", MWPhysics::CollisionType_CameraOnly }, + { "VisualOnly", MWPhysics::CollisionType_VisualOnly }, + })); api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional options) { std::vector ignore; @@ -163,12 +165,13 @@ namespace MWLua ignore = parseIgnoreList(*options); } - context.mLuaManager->addAction([context, ignore = std::move(ignore), - callback = LuaUtil::Callback::fromLua(callback), from, to] { - MWPhysics::RayCastingResult res; - MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore); - context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res)); - }); + context.mLuaManager->addAction( + [context, ignore = std::move(ignore), callback = LuaUtil::Callback::fromLua(callback), from, to] { + MWPhysics::RayCastingResult res; + MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore); + context.mLuaManager->queueCallback( + callback, sol::main_object(context.mLua->unsafeState(), sol::in_place, res)); + }); }; api["getObjectByFormId"] = [](std::string_view formIdStr) -> LObject { @@ -186,32 +189,35 @@ namespace MWLua api["players"] = LObjectList{ objectLists->getPlayers() }; api["NAVIGATOR_FLAGS"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Walk", DetourNavigator::Flag_walk }, - { "Swim", DetourNavigator::Flag_swim }, - { "OpenDoor", DetourNavigator::Flag_openDoor }, - { "UsePathgrid", DetourNavigator::Flag_usePathgrid }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Walk", DetourNavigator::Flag_walk }, + { "Swim", DetourNavigator::Flag_swim }, + { "OpenDoor", DetourNavigator::Flag_openDoor }, + { "UsePathgrid", DetourNavigator::Flag_usePathgrid }, + })); api["COLLISION_SHAPE_TYPE"] = LuaUtil::makeStrictReadOnly( - context.mLua->tableFromPairs({ - { "Aabb", DetourNavigator::CollisionShapeType::Aabb }, - { "RotatingBox", DetourNavigator::CollisionShapeType::RotatingBox }, - { "Cylinder", DetourNavigator::CollisionShapeType::Cylinder }, - })); + LuaUtil::tableFromPairs(lua, + { + { "Aabb", DetourNavigator::CollisionShapeType::Aabb }, + { "RotatingBox", DetourNavigator::CollisionShapeType::RotatingBox }, + { "Cylinder", DetourNavigator::CollisionShapeType::Cylinder }, + })); api["FIND_PATH_STATUS"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Success", DetourNavigator::Status::Success }, - { "PartialPath", DetourNavigator::Status::PartialPath }, - { "NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound }, - { "StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound }, - { "EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound }, - { "MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed }, - { "FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed }, - { "InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed }, - { "FindStraightPathFailed", DetourNavigator::Status::FindStraightPathFailed }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Success", DetourNavigator::Status::Success }, + { "PartialPath", DetourNavigator::Status::PartialPath }, + { "NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound }, + { "StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound }, + { "EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound }, + { "MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed }, + { "FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed }, + { "InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed }, + { "FindStraightPathFailed", DetourNavigator::Status::FindStraightPathFailed }, + })); static const DetourNavigator::AgentBounds defaultAgentBounds{ Settings::game().mActorCollisionShapeType, diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 322098003f..3cd68363fb 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -164,7 +164,7 @@ namespace MWLua void registerObjectList(const std::string& prefix, const Context& context) { using ListT = ObjectList; - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::usertype listT = lua.new_usertype(prefix + "ObjectList"); listT[sol::meta_function::to_string] = [](const ListT& list) { return "{" + std::to_string(list.mIds->size()) + " objects}"; }; @@ -205,7 +205,7 @@ namespace MWLua void addOwnerbindings(sol::usertype& objectT, const std::string& prefix, const Context& context) { using OwnerT = Owner; - sol::usertype ownerT = context.mLua->sol().new_usertype(prefix + "Owner"); + sol::usertype ownerT = context.sol().new_usertype(prefix + "Owner"); ownerT[sol::meta_function::to_string] = [](const OwnerT& o) { return "Owner[" + o.mObj.toString() + "]"; }; @@ -329,9 +329,10 @@ namespace MWLua return LuaUtil::Box{ bb.center(), bb._max - bb.center() }; }; - objectT["type"] = sol::readonly_property( - [types = getTypeToPackageTable(context.mLua->sol())]( - const ObjectT& o) mutable { return types[getLiveCellRefType(o.ptr().mRef)]; }); + objectT["type"] + = sol::readonly_property([types = getTypeToPackageTable(context.sol())](const ObjectT& o) mutable { + return types[getLiveCellRefType(o.ptr().mRef)]; + }); objectT["count"] = sol::readonly_property([](const ObjectT& o) { return o.ptr().getCellRef().getCount(); }); objectT[sol::meta_function::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); }; @@ -553,12 +554,12 @@ namespace MWLua void addInventoryBindings(sol::usertype& objectT, const std::string& prefix, const Context& context) { using InventoryT = Inventory; - sol::usertype inventoryT = context.mLua->sol().new_usertype(prefix + "Inventory"); + sol::usertype inventoryT = context.sol().new_usertype(prefix + "Inventory"); inventoryT[sol::meta_function::to_string] = [](const InventoryT& inv) { return "Inventory[" + inv.mObj.toString() + "]"; }; - inventoryT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())]( + inventoryT["getAll"] = [ids = getPackageToTypeTable(context.mLua->unsafeState())]( const InventoryT& inventory, sol::optional type) { int mask = -1; sol::optional typeId = sol::nullopt; @@ -681,7 +682,7 @@ namespace MWLua void initObjectBindings(const std::string& prefix, const Context& context) { sol::usertype objectT - = context.mLua->sol().new_usertype(prefix + "Object", sol::base_classes, sol::bases()); + = context.sol().new_usertype(prefix + "Object", sol::base_classes, sol::bases()); addBasicBindings(objectT, context); addInventoryBindings(objectT, prefix, context); addOwnerbindings(objectT, prefix, context); diff --git a/apps/openmw/mwlua/postprocessingbindings.cpp b/apps/openmw/mwlua/postprocessingbindings.cpp index 0fea46039c..e64bf0fa9e 100644 --- a/apps/openmw/mwlua/postprocessingbindings.cpp +++ b/apps/openmw/mwlua/postprocessingbindings.cpp @@ -96,9 +96,10 @@ namespace MWLua sol::table initPostprocessingPackage(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table api(lua, sol::create); - sol::usertype shader = context.mLua->sol().new_usertype("Shader"); + sol::usertype shader = lua.new_usertype("Shader"); shader[sol::meta_function::to_string] = [](const Shader& shader) { return shader.toString(); }; shader["enable"] = [context](Shader& shader, sol::optional optPos) { diff --git a/apps/openmw/mwlua/racebindings.cpp b/apps/openmw/mwlua/racebindings.cpp index ea23e883e1..b5c4d6093f 100644 --- a/apps/openmw/mwlua/racebindings.cpp +++ b/apps/openmw/mwlua/racebindings.cpp @@ -43,8 +43,8 @@ namespace MWLua { sol::table initRaceRecordBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); - sol::table races(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table races(lua, sol::create); addRecordFunctionBinding(races, context); auto raceT = lua.new_usertype("ESM3_Race"); diff --git a/apps/openmw/mwlua/recordstore.hpp b/apps/openmw/mwlua/recordstore.hpp index 5756feb5b2..aed84a1271 100644 --- a/apps/openmw/mwlua/recordstore.hpp +++ b/apps/openmw/mwlua/recordstore.hpp @@ -39,7 +39,7 @@ namespace MWLua // Define a custom user type for the store. // Provide the interface of a read-only array. using StoreT = MWWorld::Store; - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::usertype storeT = lua.new_usertype(recordName + "WorldStore"); storeT[sol::meta_function::to_string] = [recordName](const StoreT& store) { return "{" + std::to_string(store.getSize()) + " " + recordName + " records}"; diff --git a/apps/openmw/mwlua/soundbindings.cpp b/apps/openmw/mwlua/soundbindings.cpp index 50b693fe32..09309803d3 100644 --- a/apps/openmw/mwlua/soundbindings.cpp +++ b/apps/openmw/mwlua/soundbindings.cpp @@ -100,7 +100,7 @@ namespace MWLua { sol::table initAmbientPackage(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); if (lua["openmw_ambient"] != sol::nil) return lua["openmw_ambient"]; @@ -171,7 +171,7 @@ namespace MWLua sol::table initCoreSoundBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table api(lua, sol::create); api["isEnabled"] = []() { return MWBase::Environment::get().getSoundManager()->isEnabled(); }; diff --git a/apps/openmw/mwlua/stats.cpp b/apps/openmw/mwlua/stats.cpp index 209a852697..317ffbd406 100644 --- a/apps/openmw/mwlua/stats.cpp +++ b/apps/openmw/mwlua/stats.cpp @@ -54,7 +54,7 @@ namespace if (it != self->mStatsCache.end()) return it->second; } - return sol::make_object(context.mLua->sol(), getter(obj.ptr())); + return sol::make_object(context.mLua->unsafeState(), getter(obj.ptr())); } } @@ -531,11 +531,12 @@ namespace MWLua { void addActorStatsBindings(sol::table& actor, const Context& context) { - sol::table stats(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table stats(lua, sol::create); actor["stats"] = LuaUtil::makeReadOnly(stats); auto skillIncreasesForAttributeStatsT - = context.mLua->sol().new_usertype("SkillIncreasesForAttributeStats"); + = lua.new_usertype("SkillIncreasesForAttributeStats"); for (const auto& attribute : MWBase::Environment::get().getESMStore()->get()) { skillIncreasesForAttributeStatsT[ESM::RefId(attribute.mId).serializeText()] = sol::property( @@ -546,8 +547,7 @@ namespace MWLua } // ESM::Class::specializationIndexToLuaId.at(rec.mData.mSpecialization) auto skillIncreasesForSpecializationStatsT - = context.mLua->sol().new_usertype( - "skillIncreasesForSpecializationStats"); + = lua.new_usertype("skillIncreasesForSpecializationStats"); for (int i = 0; i < 3; i++) { std::string_view index = ESM::Class::specializationIndexToLuaId.at(i); @@ -558,7 +558,7 @@ namespace MWLua }); } - auto levelStatT = context.mLua->sol().new_usertype("LevelStat"); + auto levelStatT = lua.new_usertype("LevelStat"); levelStatT["current"] = sol::property([context](const LevelStat& stat) { return stat.getCurrent(context); }, [context](const LevelStat& stat, const sol::object& value) { stat.setCurrent(context, value); }); levelStatT["progress"] = sol::property([context](const LevelStat& stat) { return stat.getProgress(context); }, @@ -569,32 +569,32 @@ namespace MWLua [](const LevelStat& stat) { return stat.getSkillIncreasesForSpecializationStats(); }); stats["level"] = addIndexedAccessor(0); - auto dynamicStatT = context.mLua->sol().new_usertype("DynamicStat"); + auto dynamicStatT = lua.new_usertype("DynamicStat"); addProp(context, dynamicStatT, "base", &MWMechanics::DynamicStat::getBase); addProp(context, dynamicStatT, "current", &MWMechanics::DynamicStat::getCurrent); addProp(context, dynamicStatT, "modifier", &MWMechanics::DynamicStat::getModifier); - sol::table dynamic(context.mLua->sol(), sol::create); + sol::table dynamic(lua, sol::create); stats["dynamic"] = LuaUtil::makeReadOnly(dynamic); dynamic["health"] = addIndexedAccessor(0); dynamic["magicka"] = addIndexedAccessor(1); dynamic["fatigue"] = addIndexedAccessor(2); - auto attributeStatT = context.mLua->sol().new_usertype("AttributeStat"); + auto attributeStatT = lua.new_usertype("AttributeStat"); addProp(context, attributeStatT, "base", &MWMechanics::AttributeValue::getBase); addProp(context, attributeStatT, "damage", &MWMechanics::AttributeValue::getDamage); attributeStatT["modified"] = sol::readonly_property([=](const AttributeStat& stat) { return stat.getModified(context); }); addProp(context, attributeStatT, "modifier", &MWMechanics::AttributeValue::getModifier); - sol::table attributes(context.mLua->sol(), sol::create); + sol::table attributes(lua, sol::create); stats["attributes"] = LuaUtil::makeReadOnly(attributes); for (const ESM::Attribute& attribute : MWBase::Environment::get().getESMStore()->get()) attributes[ESM::RefId(attribute.mId).serializeText()] = addIndexedAccessor(attribute.mId); - auto aiStatT = context.mLua->sol().new_usertype("AIStat"); + auto aiStatT = lua.new_usertype("AIStat"); addProp(context, aiStatT, "base", &MWMechanics::Stat::getBase); addProp(context, aiStatT, "modifier", &MWMechanics::Stat::getModifier); aiStatT["modified"] = sol::readonly_property([=](const AIStat& stat) { return stat.getModified(context); }); - sol::table ai(context.mLua->sol(), sol::create); + sol::table ai(lua, sol::create); stats["ai"] = LuaUtil::makeReadOnly(ai); ai["alarm"] = addIndexedAccessor(MWMechanics::AiSetting::Alarm); ai["fight"] = addIndexedAccessor(MWMechanics::AiSetting::Fight); @@ -604,13 +604,14 @@ namespace MWLua void addNpcStatsBindings(sol::table& npc, const Context& context) { - sol::table npcStats(context.mLua->sol(), sol::create); - sol::table baseMeta(context.mLua->sol(), sol::create); + sol::state_view lua = context.sol(); + sol::table npcStats(lua, sol::create); + sol::table baseMeta(lua, sol::create); baseMeta[sol::meta_function::index] = LuaUtil::getMutableFromReadOnly(npc["baseType"]["stats"]); npcStats[sol::metatable_key] = baseMeta; npc["stats"] = LuaUtil::makeReadOnly(npcStats); - auto skillStatT = context.mLua->sol().new_usertype("SkillStat"); + auto skillStatT = lua.new_usertype("SkillStat"); addProp(context, skillStatT, "base", &MWMechanics::SkillValue::getBase); addProp(context, skillStatT, "damage", &MWMechanics::SkillValue::getDamage); skillStatT["modified"] @@ -618,7 +619,7 @@ namespace MWLua addProp(context, skillStatT, "modifier", &MWMechanics::SkillValue::getModifier); skillStatT["progress"] = sol::property([context](const SkillStat& stat) { return stat.getProgress(context); }, [context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); }); - sol::table skills(context.mLua->sol(), sol::create); + sol::table skills(lua, sol::create); npcStats["skills"] = LuaUtil::makeReadOnly(skills); for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get()) skills[ESM::RefId(skill.mId).serializeText()] = addIndexedAccessor(skill.mId); @@ -626,7 +627,7 @@ namespace MWLua sol::table initCoreStatsBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table statsApi(lua, sol::create); auto* vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); @@ -635,7 +636,7 @@ namespace MWLua statsApi["Attribute"] = LuaUtil::makeReadOnly(attributes); statsApi["Attribute"][sol::metatable_key][sol::meta_function::to_string] = ESM::Attribute::getRecordType; - auto attributeT = context.mLua->sol().new_usertype("Attribute"); + auto attributeT = lua.new_usertype("Attribute"); attributeT[sol::meta_function::to_string] = [](const ESM::Attribute& rec) { return "ESM3_Attribute[" + rec.mId.toDebugString() + "]"; }; attributeT["id"] = sol::readonly_property( @@ -653,7 +654,7 @@ namespace MWLua statsApi["Skill"] = LuaUtil::makeReadOnly(skills); statsApi["Skill"][sol::metatable_key][sol::meta_function::to_string] = ESM::Skill::getRecordType; - auto skillT = context.mLua->sol().new_usertype("Skill"); + auto skillT = lua.new_usertype("Skill"); skillT[sol::meta_function::to_string] = [](const ESM::Skill& rec) { return "ESM3_Skill[" + rec.mId.toDebugString() + "]"; }; skillT["id"] = sol::readonly_property( @@ -683,7 +684,7 @@ namespace MWLua return res; }); - auto schoolT = context.mLua->sol().new_usertype("MagicSchool"); + auto schoolT = lua.new_usertype("MagicSchool"); schoolT[sol::meta_function::to_string] = [](const ESM::MagicSchool& rec) { return "ESM3_MagicSchool[" + rec.mName + "]"; }; schoolT["name"] diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index 3531a476ad..e1c923d31a 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -43,7 +43,7 @@ namespace MWLua activator["createRecordDraft"] = tableToActivator; addRecordFunctionBinding(activator, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Activator"); + sol::usertype record = context.sol().new_usertype("ESM3_Activator"); record[sol::meta_function::to_string] = [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 3b0142e441..02686684e8 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -172,13 +172,15 @@ namespace MWLua void addActorBindings(sol::table actor, const Context& context) { + sol::state_view lua = context.sol(); actor["STANCE"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Nothing", MWMechanics::DrawState::Nothing }, - { "Weapon", MWMechanics::DrawState::Weapon }, - { "Spell", MWMechanics::DrawState::Spell }, - })); - actor["EQUIPMENT_SLOT"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs( + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Nothing", MWMechanics::DrawState::Nothing }, + { "Weapon", MWMechanics::DrawState::Weapon }, + { "Spell", MWMechanics::DrawState::Spell }, + })); + actor["EQUIPMENT_SLOT"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, { { "Helmet", MWWorld::InventoryStore::Slot_Helmet }, { "Cuirass", MWWorld::InventoryStore::Slot_Cuirass }, { "Greaves", MWWorld::InventoryStore::Slot_Greaves }, { "LeftPauldron", MWWorld::InventoryStore::Slot_LeftPauldron }, diff --git a/apps/openmw/mwlua/types/actor.hpp b/apps/openmw/mwlua/types/actor.hpp index 9cc992134c..425e44451b 100644 --- a/apps/openmw/mwlua/types/actor.hpp +++ b/apps/openmw/mwlua/types/actor.hpp @@ -23,7 +23,7 @@ namespace MWLua void addActorServicesBindings(sol::usertype& record, const Context& context) { record["servicesOffered"] = sol::readonly_property([context](const T& rec) -> sol::table { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table providedServices(lua, sol::create); constexpr std::array, 19> serviceNames = { { { ESM::NPC::Spells, "Spells" }, @@ -51,7 +51,7 @@ namespace MWLua }); record["travelDestinations"] = sol::readonly_property([context](const T& rec) -> sol::table { - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::table travelDests(lua, sol::create); if (!rec.getTransport().empty()) { diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index 025cba6550..d26f146096 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -20,18 +20,20 @@ namespace MWLua { void addApparatusBindings(sol::table apparatus, const Context& context) { - apparatus["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "MortarPestle", ESM::Apparatus::MortarPestle }, - { "Alembic", ESM::Apparatus::Alembic }, - { "Calcinator", ESM::Apparatus::Calcinator }, - { "Retort", ESM::Apparatus::Retort }, - })); + sol::state_view lua = context.sol(); + apparatus["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "MortarPestle", ESM::Apparatus::MortarPestle }, + { "Alembic", ESM::Apparatus::Alembic }, + { "Calcinator", ESM::Apparatus::Calcinator }, + { "Retort", ESM::Apparatus::Retort }, + })); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); addRecordFunctionBinding(apparatus, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Apparatus"); + sol::usertype record = lua.new_usertype("ESM3_Apparatus"); record[sol::meta_function::to_string] = [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index 3d1250af13..f26949c358 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -69,26 +69,28 @@ namespace MWLua { void addArmorBindings(sol::table armor, const Context& context) { - armor["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Helmet", ESM::Armor::Helmet }, - { "Cuirass", ESM::Armor::Cuirass }, - { "LPauldron", ESM::Armor::LPauldron }, - { "RPauldron", ESM::Armor::RPauldron }, - { "Greaves", ESM::Armor::Greaves }, - { "Boots", ESM::Armor::Boots }, - { "LGauntlet", ESM::Armor::LGauntlet }, - { "RGauntlet", ESM::Armor::RGauntlet }, - { "Shield", ESM::Armor::Shield }, - { "LBracer", ESM::Armor::LBracer }, - { "RBracer", ESM::Armor::RBracer }, - })); + sol::state_view lua = context.sol(); + armor["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Helmet", ESM::Armor::Helmet }, + { "Cuirass", ESM::Armor::Cuirass }, + { "LPauldron", ESM::Armor::LPauldron }, + { "RPauldron", ESM::Armor::RPauldron }, + { "Greaves", ESM::Armor::Greaves }, + { "Boots", ESM::Armor::Boots }, + { "LGauntlet", ESM::Armor::LGauntlet }, + { "RGauntlet", ESM::Armor::RGauntlet }, + { "Shield", ESM::Armor::Shield }, + { "LBracer", ESM::Armor::LBracer }, + { "RBracer", ESM::Armor::RBracer }, + })); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); addRecordFunctionBinding(armor, context); armor["createRecordDraft"] = tableToArmor; - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Armor"); + sol::usertype record = lua.new_usertype("ESM3_Armor"); record[sol::meta_function::to_string] = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 0733d89914..f869971b9b 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -82,9 +82,10 @@ namespace MWLua { void addBookBindings(sol::table book, const Context& context) { + sol::state_view lua = context.sol(); // types.book.SKILL is deprecated (core.SKILL should be used instead) // TODO: Remove book.SKILL after branching 0.49 - sol::table skill(context.mLua->sol(), sol::create); + sol::table skill(lua, sol::create); book["SKILL"] = LuaUtil::makeStrictReadOnly(skill); book["createRecordDraft"] = tableToBook; for (int id = 0; id < ESM::Skill::Length; ++id) @@ -97,7 +98,7 @@ namespace MWLua addRecordFunctionBinding(book, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Book"); + sol::usertype record = lua.new_usertype("ESM3_Book"); record[sol::meta_function::to_string] = [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index 733cf5ba11..778beee97a 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -66,24 +66,26 @@ namespace MWLua { clothing["createRecordDraft"] = tableToClothing; - clothing["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Amulet", ESM::Clothing::Amulet }, - { "Belt", ESM::Clothing::Belt }, - { "LGlove", ESM::Clothing::LGlove }, - { "Pants", ESM::Clothing::Pants }, - { "RGlove", ESM::Clothing::RGlove }, - { "Ring", ESM::Clothing::Ring }, - { "Robe", ESM::Clothing::Robe }, - { "Shirt", ESM::Clothing::Shirt }, - { "Shoes", ESM::Clothing::Shoes }, - { "Skirt", ESM::Clothing::Skirt }, - })); + sol::state_view lua = context.sol(); + clothing["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Amulet", ESM::Clothing::Amulet }, + { "Belt", ESM::Clothing::Belt }, + { "LGlove", ESM::Clothing::LGlove }, + { "Pants", ESM::Clothing::Pants }, + { "RGlove", ESM::Clothing::RGlove }, + { "Ring", ESM::Clothing::Ring }, + { "Robe", ESM::Clothing::Robe }, + { "Shirt", ESM::Clothing::Shirt }, + { "Shoes", ESM::Clothing::Shoes }, + { "Skirt", ESM::Clothing::Skirt }, + })); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); addRecordFunctionBinding(clothing, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Clothing"); + sol::usertype record = lua.new_usertype("ESM3_Clothing"); record[sol::meta_function::to_string] = [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index b5d9c082bd..67c2c5c65c 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -42,7 +42,7 @@ namespace MWLua addRecordFunctionBinding(container, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Container"); + sol::usertype record = context.sol().new_usertype("ESM3_Container"); record[sol::meta_function::to_string] = [](const ESM::Container& rec) -> std::string { return "ESM3_Container[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index 2ee6aacf63..f9ef65a707 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -20,16 +20,18 @@ namespace MWLua { void addCreatureBindings(sol::table creature, const Context& context) { - creature["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Creatures", ESM::Creature::Creatures }, - { "Daedra", ESM::Creature::Daedra }, - { "Undead", ESM::Creature::Undead }, - { "Humanoid", ESM::Creature::Humanoid }, - })); + sol::state_view lua = context.sol(); + creature["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Creatures", ESM::Creature::Creatures }, + { "Daedra", ESM::Creature::Daedra }, + { "Undead", ESM::Creature::Undead }, + { "Humanoid", ESM::Creature::Humanoid }, + })); addRecordFunctionBinding(creature, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Creature"); + sol::usertype record = lua.new_usertype("ESM3_Creature"); record[sol::meta_function::to_string] = [](const ESM::Creature& rec) { return "ESM3_Creature[" + rec.mId.toDebugString() + "]"; }; record["id"] @@ -50,8 +52,7 @@ namespace MWLua record["magicSkill"] = sol::readonly_property([](const ESM::Creature& rec) -> int { return rec.mData.mMagic; }); record["stealthSkill"] = sol::readonly_property([](const ESM::Creature& rec) -> int { return rec.mData.mStealth; }); - record["attack"] = sol::readonly_property([context](const ESM::Creature& rec) -> sol::table { - sol::state_view& lua = context.mLua->sol(); + record["attack"] = sol::readonly_property([](sol::this_state lua, const ESM::Creature& rec) -> sol::table { sol::table res(lua, sol::create); int index = 1; for (auto attack : rec.mData.mAttack) diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index 6759a1b4d2..4844210c24 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -41,11 +41,13 @@ namespace MWLua void addDoorBindings(sol::table door, const Context& context) { - door["STATE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Idle", MWWorld::DoorState::Idle }, - { "Opening", MWWorld::DoorState::Opening }, - { "Closing", MWWorld::DoorState::Closing }, - })); + sol::state_view lua = context.sol(); + door["STATE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Idle", MWWorld::DoorState::Idle }, + { "Opening", MWWorld::DoorState::Opening }, + { "Closing", MWWorld::DoorState::Closing }, + })); door["getDoorState"] = [](const Object& o) -> MWWorld::DoorState { auto door = doorPtr(o); return door.getClass().getDoorState(door); @@ -99,7 +101,7 @@ namespace MWLua addRecordFunctionBinding(door, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Door"); + sol::usertype record = lua.new_usertype("ESM3_Door"); record[sol::meta_function::to_string] = [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.toDebugString() + "]"; }; record["id"] @@ -136,7 +138,7 @@ namespace MWLua addRecordFunctionBinding(door, context, "ESM4Door"); - sol::usertype record = context.mLua->sol().new_usertype("ESM4_Door"); + sol::usertype record = context.sol().new_usertype("ESM4_Door"); record[sol::meta_function::to_string] = [](const ESM4::Door& rec) -> std::string { return "ESM4_Door[" + ESM::RefId(rec.mId).toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index 0df31d1e85..9855b44265 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -25,7 +25,7 @@ namespace MWLua addRecordFunctionBinding(ingredient, context); - sol::usertype record = context.mLua->sol().new_usertype(("ESM3_Ingredient")); + sol::usertype record = context.sol().new_usertype(("ESM3_Ingredient")); record[sol::meta_function::to_string] = [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.toDebugString() + "]"; }; record["id"] @@ -43,8 +43,8 @@ namespace MWLua record["weight"] = sol::readonly_property([](const ESM::Ingredient& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Ingredient& rec) -> int { return rec.mData.mValue; }); - record["effects"] = sol::readonly_property([context](const ESM::Ingredient& rec) -> sol::table { - sol::table res(context.mLua->sol(), sol::create); + record["effects"] = sol::readonly_property([](sol::this_state lua, const ESM::Ingredient& rec) -> sol::table { + sol::table res(lua, sol::create); for (size_t i = 0; i < 4; ++i) { if (rec.mData.mEffectID[i] < 0) diff --git a/apps/openmw/mwlua/types/levelledlist.cpp b/apps/openmw/mwlua/types/levelledlist.cpp index 4d9231dae7..fd848d9121 100644 --- a/apps/openmw/mwlua/types/levelledlist.cpp +++ b/apps/openmw/mwlua/types/levelledlist.cpp @@ -23,7 +23,7 @@ namespace MWLua { void addLevelledCreatureBindings(sol::table list, const Context& context) { - auto& state = context.mLua->sol(); + auto state = context.sol(); auto item = state.new_usertype("ESM3_LevelledListItem"); item["id"] = sol::readonly_property( [](const ESM::LevelledListBase::LevelItem& rec) -> std::string { return rec.mId.serializeText(); }); diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index ab758c22ec..788f6d3e4e 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -84,7 +84,7 @@ namespace MWLua addRecordFunctionBinding(light, context); light["createRecordDraft"] = tableToLight; - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Light"); + sol::usertype record = context.sol().new_usertype("ESM3_Light"); record[sol::meta_function::to_string] = [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index 4186f44378..be25d855ec 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -24,7 +24,7 @@ namespace MWLua addRecordFunctionBinding(lockpick, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Lockpick"); + sol::usertype record = context.sol().new_usertype("ESM3_Lockpick"); record[sol::meta_function::to_string] = [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 85eb03524c..2695abff9b 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -75,8 +75,7 @@ namespace MWLua }; miscellaneous["soul"] = miscellaneous["getSoul"]; // for compatibility; should be removed later - sol::usertype record - = context.mLua->sol().new_usertype("ESM3_Miscellaneous"); + sol::usertype record = context.sol().new_usertype("ESM3_Miscellaneous"); record[sol::meta_function::to_string] = [](const ESM::Miscellaneous& rec) { return "ESM3_Miscellaneous[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property( diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 5c50cfe105..1a2876dc98 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -73,7 +73,7 @@ namespace MWLua addRecordFunctionBinding(npc, context); - sol::state_view& lua = context.mLua->sol(); + sol::state_view lua = context.sol(); sol::usertype record = lua.new_usertype("ESM3_NPC"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index b2befe89de..97619dc3be 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -71,7 +71,8 @@ namespace MWLua || dynamic_cast(&player) != nullptr; return Quests{ .mMutable = allowChanges }; }; - sol::usertype quests = context.mLua->sol().new_usertype("Quests"); + sol::state_view lua = context.sol(); + sol::usertype quests = lua.new_usertype("Quests"); quests[sol::meta_function::to_string] = [](const Quests& quests) { return "Quests"; }; quests[sol::meta_function::index] = [](const Quests& quests, std::string_view questId) -> sol::optional { ESM::RefId quest = ESM::RefId::deserializeText(questId); @@ -94,7 +95,7 @@ namespace MWLua }; }; - sol::usertype quest = context.mLua->sol().new_usertype("Quest"); + sol::usertype quest = lua.new_usertype("Quest"); quest[sol::meta_function::to_string] = [](const Quest& quest) { return "Quest[" + quest.mQuestId.serializeText() + "]"; }; @@ -146,15 +147,16 @@ namespace MWLua }; player["CONTROL_SWITCH"] - = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Controls", "playercontrols" }, - { "Fighting", "playerfighting" }, - { "Jumping", "playerjumping" }, - { "Looking", "playerlooking" }, - { "Magic", "playermagic" }, - { "ViewMode", "playerviewswitch" }, - { "VanityMode", "vanitymode" }, - })); + = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Controls", "playercontrols" }, + { "Fighting", "playerfighting" }, + { "Jumping", "playerjumping" }, + { "Looking", "playerlooking" }, + { "Magic", "playermagic" }, + { "ViewMode", "playerviewswitch" }, + { "VanityMode", "vanitymode" }, + })); MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); player["getControlSwitch"] = [input](const Object& player, std::string_view key) { diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index a3dab55224..34d41d4588 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -69,7 +69,7 @@ namespace MWLua potion["createRecordDraft"] = tableToPotion; auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Potion"); + sol::usertype record = context.sol().new_usertype("ESM3_Potion"); record[sol::meta_function::to_string] = [](const ESM::Potion& rec) { return "ESM3_Potion[" + rec.mId.toDebugString() + "]"; }; record["id"] @@ -84,8 +84,8 @@ namespace MWLua [](const ESM::Potion& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); record["weight"] = sol::readonly_property([](const ESM::Potion& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Potion& rec) -> int { return rec.mData.mValue; }); - record["effects"] = sol::readonly_property([context](const ESM::Potion& rec) -> sol::table { - sol::table res(context.mLua->sol(), sol::create); + record["effects"] = sol::readonly_property([](sol::this_state lua, const ESM::Potion& rec) -> sol::table { + sol::table res(lua, sol::create); for (size_t i = 0; i < rec.mEffects.mList.size(); ++i) res[LuaUtil::toLuaIndex(i)] = rec.mEffects.mList[i]; // ESM::IndexedENAMstruct (effect params) return res; diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index 5db8141a23..7ce269744f 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -24,7 +24,7 @@ namespace MWLua addRecordFunctionBinding(probe, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Probe"); + sol::usertype record = context.sol().new_usertype("ESM3_Probe"); record[sol::meta_function::to_string] = [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index 4d35a55fbe..e44bdddd04 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -24,7 +24,7 @@ namespace MWLua addRecordFunctionBinding(repair, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Repair"); + sol::usertype record = context.sol().new_usertype("ESM3_Repair"); record[sol::meta_function::to_string] = [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index 78f8cffd67..b624db0276 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -19,7 +19,7 @@ namespace MWLua { addRecordFunctionBinding(stat, context); - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Static"); + sol::usertype record = context.sol().new_usertype("ESM3_Static"); record[sol::meta_function::to_string] = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/types/terminal.cpp b/apps/openmw/mwlua/types/terminal.cpp index 02a9465b91..58a3170b0b 100644 --- a/apps/openmw/mwlua/types/terminal.cpp +++ b/apps/openmw/mwlua/types/terminal.cpp @@ -21,7 +21,7 @@ namespace MWLua { addRecordFunctionBinding(term, context, "ESM4Terminal"); - sol::usertype record = context.mLua->sol().new_usertype("ESM4_Terminal"); + sol::usertype record = context.sol().new_usertype("ESM4_Terminal"); record[sol::meta_function::to_string] = [](const ESM4::Terminal& rec) -> std::string { return "ESM4_Terminal[" + ESM::RefId(rec.mId).toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/types.cpp b/apps/openmw/mwlua/types/types.cpp index 47db953b04..c7b0b6e9c4 100644 --- a/apps/openmw/mwlua/types/types.cpp +++ b/apps/openmw/mwlua/types/types.cpp @@ -165,22 +165,22 @@ namespace MWLua sol::table initTypesPackage(const Context& context) { - auto* lua = context.mLua; + auto lua = context.sol(); - if (lua->sol()["openmw_types"] != sol::nil) - return lua->sol()["openmw_types"]; + if (lua["openmw_types"] != sol::nil) + return lua["openmw_types"]; - sol::table types(lua->sol(), sol::create); + sol::table types(lua, sol::create); auto addType = [&](std::string_view name, std::vector recTypes, std::optional base = std::nullopt) -> sol::table { - sol::table t(lua->sol(), sol::create); + sol::table t(lua, sol::create); sol::table ro = LuaUtil::makeReadOnly(t); sol::table meta = ro[sol::metatable_key]; meta[sol::meta_function::to_string] = [name]() { return name; }; if (base) { t["baseType"] = types[*base]; - sol::table baseMeta(lua->sol(), sol::create); + sol::table baseMeta(lua, sol::create); baseMeta[sol::meta_function::index] = LuaUtil::getMutableFromReadOnly(types[*base]); t[sol::metatable_key] = baseMeta; } @@ -251,8 +251,8 @@ namespace MWLua addType(ObjectTypeName::ESM4Tree, { ESM::REC_TREE4 }); addType(ObjectTypeName::ESM4Weapon, { ESM::REC_WEAP4 }); - sol::table typeToPackage = getTypeToPackageTable(context.mLua->sol()); - sol::table packageToType = getPackageToTypeTable(context.mLua->sol()); + sol::table typeToPackage = getTypeToPackageTable(lua); + sol::table packageToType = getPackageToTypeTable(lua); for (const auto& [type, name] : luaObjectTypeInfo) { sol::object t = types[name]; @@ -262,7 +262,7 @@ namespace MWLua packageToType[t] = type; } - lua->sol()["openmw_types"] = LuaUtil::makeReadOnly(types); - return lua->sol()["openmw_types"]; + lua["openmw_types"] = LuaUtil::makeReadOnly(types); + return lua["openmw_types"]; } } diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index 386b81c843..51795cffc1 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -99,29 +99,31 @@ namespace MWLua { void addWeaponBindings(sol::table weapon, const Context& context) { - weapon["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand }, - { "LongBladeOneHand", ESM::Weapon::LongBladeOneHand }, - { "LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand }, - { "BluntOneHand", ESM::Weapon::BluntOneHand }, - { "BluntTwoClose", ESM::Weapon::BluntTwoClose }, - { "BluntTwoWide", ESM::Weapon::BluntTwoWide }, - { "SpearTwoWide", ESM::Weapon::SpearTwoWide }, - { "AxeOneHand", ESM::Weapon::AxeOneHand }, - { "AxeTwoHand", ESM::Weapon::AxeTwoHand }, - { "MarksmanBow", ESM::Weapon::MarksmanBow }, - { "MarksmanCrossbow", ESM::Weapon::MarksmanCrossbow }, - { "MarksmanThrown", ESM::Weapon::MarksmanThrown }, - { "Arrow", ESM::Weapon::Arrow }, - { "Bolt", ESM::Weapon::Bolt }, - })); + sol::state_view lua = context.sol(); + weapon["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand }, + { "LongBladeOneHand", ESM::Weapon::LongBladeOneHand }, + { "LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand }, + { "BluntOneHand", ESM::Weapon::BluntOneHand }, + { "BluntTwoClose", ESM::Weapon::BluntTwoClose }, + { "BluntTwoWide", ESM::Weapon::BluntTwoWide }, + { "SpearTwoWide", ESM::Weapon::SpearTwoWide }, + { "AxeOneHand", ESM::Weapon::AxeOneHand }, + { "AxeTwoHand", ESM::Weapon::AxeTwoHand }, + { "MarksmanBow", ESM::Weapon::MarksmanBow }, + { "MarksmanCrossbow", ESM::Weapon::MarksmanCrossbow }, + { "MarksmanThrown", ESM::Weapon::MarksmanThrown }, + { "Arrow", ESM::Weapon::Arrow }, + { "Bolt", ESM::Weapon::Bolt }, + })); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); addRecordFunctionBinding(weapon, context); weapon["createRecordDraft"] = tableToWeapon; - sol::usertype record = context.mLua->sol().new_usertype("ESM3_Weapon"); + sol::usertype record = lua.new_usertype("ESM3_Weapon"); record[sol::meta_function::to_string] = [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.toDebugString() + "]"; }; record["id"] diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index d08ef0ca66..9652df1238 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -82,11 +82,12 @@ namespace MWLua sol::table registerUiApi(const Context& context) { + sol::state_view lua = context.sol(); bool menu = context.mType == Context::Menu; MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); - sol::table api = context.mLua->newTable(); + sol::table api(lua, sol::create); api["_setHudVisibility"] = [luaManager = context.mLuaManager](bool state) { luaManager->addAction([state] { MWBase::Environment::get().getWindowManager()->setHudVisibility(state); }); }; @@ -107,12 +108,13 @@ namespace MWLua } luaManager->addUIMessage(message, mode); }; - api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) }, - { "Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1)) }, - { "Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1)) }, - { "Info", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Info.substr(1)) }, - })); + api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { + { "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) }, + { "Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1)) }, + { "Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1)) }, + { "Info", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Info.substr(1)) }, + })); api["printToConsole"] = [luaManager = context.mLuaManager](const std::string& message, const Misc::Color& color) { luaManager->addInGameConsoleMessage(message + "\n", color); @@ -150,7 +152,7 @@ namespace MWLua }; api["_getMenuTransparency"] = []() -> float { return Settings::gui().mMenuTransparency; }; - sol::table layersTable = context.mLua->newTable(); + sol::table layersTable(lua, sol::create); layersTable["indexOf"] = [](std::string_view name) -> sol::optional { size_t index = LuaUi::Layer::indexOf(name); if (index == LuaUi::Layer::count()) @@ -202,14 +204,14 @@ namespace MWLua } api["layers"] = layers; - sol::table typeTable = context.mLua->newTable(); + sol::table typeTable(lua, sol::create); for (const auto& it : LuaUi::widgetTypeToName()) typeTable.set(it.second, it.first); api["TYPE"] = LuaUtil::makeStrictReadOnly(typeTable); - api["ALIGNMENT"] = LuaUtil::makeStrictReadOnly( - context.mLua->tableFromPairs({ { "Start", LuaUi::Alignment::Start }, - { "Center", LuaUi::Alignment::Center }, { "End", LuaUi::Alignment::End } })); + api["ALIGNMENT"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs(lua, + { { "Start", LuaUi::Alignment::Start }, { "Center", LuaUi::Alignment::Center }, + { "End", LuaUi::Alignment::End } })); api["registerSettingsPage"] = &LuaUi::registerSettingsPage; api["removeSettingsPage"] = &LuaUi::removeSettingsPage; @@ -297,7 +299,7 @@ namespace MWLua { if (context.initializeOnce("openmw_ui_usertypes")) { - auto element = context.mLua->sol().new_usertype("UiElement"); + auto element = context.sol().new_usertype("UiElement"); element[sol::meta_function::to_string] = [](const LuaUi::Element& element) { std::stringstream res; res << "UiElement"; @@ -321,7 +323,7 @@ namespace MWLua [element] { wrapAction(element, [&] { LuaUi::Element::erase(element.get()); }); }, "Destroy UI"); }; - auto uiLayer = context.mLua->sol().new_usertype("UiLayer"); + auto uiLayer = context.sol().new_usertype("UiLayer"); uiLayer["name"] = sol::readonly_property([](LuaUi::Layer& self) -> std::string_view { return self.name(); }); uiLayer["size"] = sol::readonly_property([](LuaUi::Layer& self) { return self.size(); }); diff --git a/apps/openmw/mwlua/vfsbindings.cpp b/apps/openmw/mwlua/vfsbindings.cpp index 0e13c07ef9..39b612acb8 100644 --- a/apps/openmw/mwlua/vfsbindings.cpp +++ b/apps/openmw/mwlua/vfsbindings.cpp @@ -68,7 +68,7 @@ namespace MWLua Log(Debug::Verbose) << "Read a large data chunk (" << size << " bytes) from '" << file.mFileName << "'."; } - sol::object readFile(LuaUtil::LuaState* lua, FileHandle& file) + sol::object readFile(sol::this_state lua, FileHandle& file) { std::ostringstream os; if (file.mFilePtr && file.mFilePtr->peek() != EOF) @@ -76,34 +76,34 @@ namespace MWLua auto result = os.str(); printLargeDataMessage(file, result.size()); - return sol::make_object(lua->sol(), std::move(result)); + return sol::make_object(lua, std::move(result)); } - sol::object readLineFromFile(LuaUtil::LuaState* lua, FileHandle& file) + sol::object readLineFromFile(sol::this_state lua, FileHandle& file) { std::string result; if (file.mFilePtr && std::getline(*file.mFilePtr, result)) { printLargeDataMessage(file, result.size()); - return sol::make_object(lua->sol(), result); + return sol::make_object(lua, result); } return sol::nil; } - sol::object readNumberFromFile(LuaUtil::LuaState* lua, Files::IStreamPtr& file) + sol::object readNumberFromFile(sol::this_state lua, Files::IStreamPtr& file) { double number = 0; if (file && *file >> number) - return sol::make_object(lua->sol(), number); + return sol::make_object(lua, number); return sol::nil; } - sol::object readCharactersFromFile(LuaUtil::LuaState* lua, FileHandle& file, size_t count) + sol::object readCharactersFromFile(sol::this_state lua, FileHandle& file, size_t count) { if (count <= 0 && file.mFilePtr->peek() != EOF) - return sol::make_object(lua->sol(), std::string()); + return sol::make_object(lua, std::string()); auto bytesLeft = getBytesLeftInStream(file.mFilePtr); if (bytesLeft <= 0) @@ -116,7 +116,7 @@ namespace MWLua if (file.mFilePtr->read(&result[0], count)) { printLargeDataMessage(file, result.size()); - return sol::make_object(lua->sol(), result); + return sol::make_object(lua, result); } return sol::nil; @@ -131,7 +131,7 @@ namespace MWLua } sol::variadic_results seek( - LuaUtil::LuaState* lua, FileHandle& self, std::ios_base::seekdir dir, std::streamoff off) + sol::this_state lua, FileHandle& self, std::ios_base::seekdir dir, std::streamoff off) { sol::variadic_results values; try @@ -141,16 +141,16 @@ namespace MWLua { auto msg = "Failed to seek in file '" + self.mFileName + "'"; values.push_back(sol::nil); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(lua, msg)); } else - values.push_back(sol::make_object(lua->sol(), self.mFilePtr->tellg())); + values.push_back(sol::make_object(lua, self.mFilePtr->tellg())); } catch (std::exception& e) { auto msg = "Failed to seek in file '" + self.mFileName + "': " + std::string(e.what()); values.push_back(sol::nil); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(lua, msg)); } return values; @@ -159,18 +159,18 @@ namespace MWLua sol::table initVFSPackage(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::table api(context.mLua->unsafeState(), sol::create); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - sol::usertype handle = context.mLua->sol().new_usertype("FileHandle"); + sol::usertype handle = context.sol().new_usertype("FileHandle"); handle["fileName"] = sol::readonly_property([](const FileHandle& self) -> std::string_view { return self.mFileName; }); handle[sol::meta_function::to_string] = [](const FileHandle& self) { return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}"; }; handle["seek"] = sol::overload( - [lua = context.mLua](FileHandle& self, std::string_view whence, sol::optional offset) { + [](sol::this_state lua, FileHandle& self, std::string_view whence, sol::optional offset) { validateFile(self); auto off = static_cast(offset.value_or(0)); @@ -178,21 +178,21 @@ namespace MWLua return seek(lua, self, dir, off); }, - [lua = context.mLua](FileHandle& self, sol::optional offset) { + [](sol::this_state lua, FileHandle& self, sol::optional offset) { validateFile(self); auto off = static_cast(offset.value_or(0)); return seek(lua, self, std::ios_base::cur, off); }); - handle["lines"] = [lua = context.mLua](FileHandle& self) { + handle["lines"] = [](sol::this_state lua, FileHandle& self) { return sol::as_function([&lua, &self]() mutable { validateFile(self); return readLineFromFile(lua, self); }); }; - api["lines"] = [lua = context.mLua, vfs](std::string_view fileName) { + api["lines"] = [vfs](sol::this_state lua, std::string_view fileName) { auto normalizedName = VFS::Path::normalizeFilename(fileName); return sol::as_function( [lua, file = FileHandle(vfs->getNormalized(normalizedName), normalizedName)]() mutable { @@ -205,7 +205,7 @@ namespace MWLua }); }; - handle["close"] = [lua = context.mLua](FileHandle& self) { + handle["close"] = [](lua_State* L, FileHandle& self) { sol::variadic_results values; try { @@ -214,22 +214,22 @@ namespace MWLua { auto msg = "Can not close file '" + self.mFileName + "': file handle is still opened."; values.push_back(sol::nil); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(L, msg)); } else - values.push_back(sol::make_object(lua->sol(), true)); + values.push_back(sol::make_object(L, true)); } catch (std::exception& e) { auto msg = "Can not close file '" + self.mFileName + "': " + std::string(e.what()); values.push_back(sol::nil); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(L, msg)); } return values; }; - handle["read"] = [lua = context.mLua](FileHandle& self, const sol::variadic_args args) { + handle["read"] = [](sol::this_state lua, FileHandle& self, const sol::variadic_args args) { validateFile(self); if (args.size() > sMaximumReadArguments) @@ -297,25 +297,25 @@ namespace MWLua { auto msg = "Error when handling '" + self.mFileName + "': can not read data for argument #" + std::to_string(i); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(lua, msg)); } return values; }; - api["open"] = [lua = context.mLua, vfs](std::string_view fileName) { + api["open"] = [vfs](sol::this_state lua, std::string_view fileName) { sol::variadic_results values; try { auto normalizedName = VFS::Path::normalizeFilename(fileName); auto handle = FileHandle(vfs->getNormalized(normalizedName), normalizedName); - values.push_back(sol::make_object(lua->sol(), std::move(handle))); + values.push_back(sol::make_object(lua, std::move(handle))); } catch (std::exception& e) { auto msg = "Can not open file: " + std::string(e.what()); values.push_back(sol::nil); - values.push_back(sol::make_object(lua->sol(), msg)); + values.push_back(sol::make_object(lua, msg)); } return values; diff --git a/apps/openmw/mwlua/worldbindings.cpp b/apps/openmw/mwlua/worldbindings.cpp index 018c33cfa4..ac7bd307cf 100644 --- a/apps/openmw/mwlua/worldbindings.cpp +++ b/apps/openmw/mwlua/worldbindings.cpp @@ -102,7 +102,8 @@ namespace MWLua const MWWorld::Store* cells3Store = &MWBase::Environment::get().getESMStore()->get(); const MWWorld::Store* cells4Store = &MWBase::Environment::get().getESMStore()->get(); - sol::usertype cells = context.mLua->sol().new_usertype("Cells"); + auto view = context.sol(); + sol::usertype cells = view.new_usertype("Cells"); cells[sol::meta_function::length] = [cells3Store, cells4Store](const CellsStore&) { return cells3Store->getSize() + cells4Store->getSize(); }; cells[sol::meta_function::index] @@ -124,14 +125,14 @@ namespace MWLua cellRecord->mId, /*forceLoad=*/false) }; } }; - cells[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get(); - cells[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get(); + cells[sol::meta_function::pairs] = view["ipairsForArray"].template get(); + cells[sol::meta_function::ipairs] = view["ipairsForArray"].template get(); api["cells"] = CellsStore{}; } sol::table initWorldPackage(const Context& context) { - sol::table api(context.mLua->sol(), sol::create); + sol::table api(context.mLua->unsafeState(), sol::create); addCoreTimeBindings(api, context); addWorldTimeBindings(api, context); diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index 26b832bdf9..a005625b62 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -176,121 +176,125 @@ namespace LuaUtil if (sProfilerEnabled) lua_sethook(mLuaHolder.get(), &countHook, LUA_MASKCOUNT, countHookStep); - mSol.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::bit32, sol::lib::string, - sol::lib::table, sol::lib::os, sol::lib::debug); + protectedCall([&](LuaView& view) { + auto& sol = view.sol(); + sol.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::bit32, sol::lib::string, + sol::lib::table, sol::lib::os, sol::lib::debug); #ifndef NO_LUAJIT - mSol.open_libraries(sol::lib::jit); + sol.open_libraries(sol::lib::jit); #endif // NO_LUAJIT - mSol["math"]["randomseed"](static_cast(std::time(nullptr))); - mSol["math"]["randomseed"] = [] {}; + sol["math"]["randomseed"](static_cast(std::time(nullptr))); + sol["math"]["randomseed"] = [] {}; - mSol["utf8"] = LuaUtf8::initUtf8Package(mSol); + sol["utf8"] = LuaUtf8::initUtf8Package(sol); - mSol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; }; + sol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; }; - mSol["setEnvironment"] - = [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); }; - mSol["loadFromVFS"] = [this](std::string_view packageName) { - return loadScriptAndCache(packageNameToVfsPath(packageName, mVFS)); - }; - mSol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); }; - - // Some fixes for compatibility between different Lua versions - if (mSol["unpack"] == sol::nil) - mSol["unpack"] = mSol["table"]["unpack"]; - else if (mSol["table"]["unpack"] == sol::nil) - mSol["table"]["unpack"] = mSol["unpack"]; - if (LUA_VERSION_NUM <= 501) - { - mSol.script(R"( - local _pairs = pairs - local _ipairs = ipairs - pairs = function(v) return (rawget(getmetatable(v) or {}, '__pairs') or _pairs)(v) end - ipairs = function(v) return (rawget(getmetatable(v) or {}, '__ipairs') or _ipairs)(v) end - )"); - } + sol["setEnvironment"] + = [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); }; + sol["loadFromVFS"] = [this](std::string_view packageName) { + return loadScriptAndCache(packageNameToVfsPath(packageName, mVFS)); + }; + sol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); }; + + // Some fixes for compatibility between different Lua versions + if (sol["unpack"] == sol::nil) + sol["unpack"] = sol["table"]["unpack"]; + else if (sol["table"]["unpack"] == sol::nil) + sol["table"]["unpack"] = sol["unpack"]; + if (LUA_VERSION_NUM <= 501) + { + sol.script(R"( + local _pairs = pairs + local _ipairs = ipairs + pairs = function(v) return (rawget(getmetatable(v) or {}, '__pairs') or _pairs)(v) end + ipairs = function(v) return (rawget(getmetatable(v) or {}, '__ipairs') or _ipairs)(v) end + )"); + } - mSol.script(R"( - local printToLog = function(...) - local strs = {} - for i = 1, select('#', ...) do - strs[i] = tostring(select(i, ...)) + sol.script(R"( + local printToLog = function(...) + local strs = {} + for i = 1, select('#', ...) do + strs[i] = tostring(select(i, ...)) + end + return writeToLog(table.concat(strs, '\t')) end - return writeToLog(table.concat(strs, '\t')) - end - printGen = function(name) return function(...) return printToLog(name, ...) end end - - function requireGen(env, loaded, loadFn) - return function(packageName) - local p = loaded[packageName] - if p == nil then - local loader = loadFn(packageName) - setEnvironment(env, loader) - p = loader(packageName) - loaded[packageName] = p + printGen = function(name) return function(...) return printToLog(name, ...) end end + + function requireGen(env, loaded, loadFn) + return function(packageName) + local p = loaded[packageName] + if p == nil then + local loader = loadFn(packageName) + setEnvironment(env, loader) + p = loader(packageName) + loaded[packageName] = p + end + return p end - return p end - end - - function createStrictIndexFn(tbl) - return function(_, key) - local res = tbl[key] - if res ~= nil then - return res - else - error('Key not found: '..tostring(key), 2) + + function createStrictIndexFn(tbl) + return function(_, key) + local res = tbl[key] + if res ~= nil then + return res + else + error('Key not found: '..tostring(key), 2) + end end end - end - function pairsForReadOnly(v) - local nextFn, t, firstKey = pairs(getmetatable(v).t) - return function(_, k) return nextFn(t, k) end, v, firstKey - end - function ipairsForReadOnly(v) - local nextFn, t, firstKey = ipairs(getmetatable(v).t) - return function(_, k) return nextFn(t, k) end, v, firstKey - end - function lenForReadOnly(v) - return #getmetatable(v).t - end - local function nextForArray(array, index) - index = (index or 0) + 1 - if index <= #array then - return index, array[index] + function pairsForReadOnly(v) + local nextFn, t, firstKey = pairs(getmetatable(v).t) + return function(_, k) return nextFn(t, k) end, v, firstKey end - end - function ipairsForArray(array) - return nextForArray, array, 0 - end - - getmetatable('').__metatable = false - getSafeMetatable = function(v) - if type(v) ~= 'table' then error('getmetatable is allowed only for tables', 2) end - return getmetatable(v) - end - )"); - - mSandboxEnv = sol::table(mSol, sol::create); - mSandboxEnv["_VERSION"] = mSol["_VERSION"]; - for (const std::string& s : safeFunctions) - { - if (mSol[s] == sol::nil) - throw std::logic_error("Lua function not found: " + s); - mSandboxEnv[s] = mSol[s]; - } - for (const std::string& s : safePackages) - { - if (mSol[s] == sol::nil) - throw std::logic_error("Lua package not found: " + s); - mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mSol[s]); - } - mSandboxEnv["getmetatable"] = mSol["getSafeMetatable"]; - mCommonPackages["os"] = mSandboxEnv["os"] - = makeReadOnly(tableFromPairs({ { "date", mSol["os"]["date"] }, - { "difftime", mSol["os"]["difftime"] }, { "time", mSol["os"]["time"] } })); + function ipairsForReadOnly(v) + local nextFn, t, firstKey = ipairs(getmetatable(v).t) + return function(_, k) return nextFn(t, k) end, v, firstKey + end + function lenForReadOnly(v) + return #getmetatable(v).t + end + local function nextForArray(array, index) + index = (index or 0) + 1 + if index <= #array then + return index, array[index] + end + end + function ipairsForArray(array) + return nextForArray, array, 0 + end + + getmetatable('').__metatable = false + getSafeMetatable = function(v) + if type(v) ~= 'table' then error('getmetatable is allowed only for tables', 2) end + return getmetatable(v) + end + )"); + + mSandboxEnv = sol::table(sol, sol::create); + mSandboxEnv["_VERSION"] = sol["_VERSION"]; + for (const std::string& s : safeFunctions) + { + if (sol[s] == sol::nil) + throw std::logic_error("Lua function not found: " + s); + mSandboxEnv[s] = sol[s]; + } + for (const std::string& s : safePackages) + { + if (sol[s] == sol::nil) + throw std::logic_error("Lua package not found: " + s); + mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(sol[s]); + } + mSandboxEnv["getmetatable"] = sol["getSafeMetatable"]; + mCommonPackages["os"] = mSandboxEnv["os"] + = makeReadOnly(tableFromPairs(sol, + { { "date", sol["os"]["date"] }, { "difftime", sol["os"]["difftime"] }, + { "time", sol["os"]["time"] } })); + }); } sol::table makeReadOnly(const sol::table& table, bool strictIndex) @@ -333,6 +337,7 @@ namespace LuaUtil sol::protected_function_result LuaState::runInNewSandbox(const std::string& path, const std::string& namePrefix, const std::map& packages, const sol::object& hiddenData) { + // TODO sol::protected_function script = loadScriptAndCache(path); sol::environment env(mSol, sol::create, mSandboxEnv); @@ -366,6 +371,7 @@ namespace LuaUtil sol::environment LuaState::newInternalLibEnvironment() { + // TODO sol::environment env(mSol, sol::create, mSandboxEnv); sol::table loaded(mSol, sol::create); for (const std::string& s : safePackages) diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index 5dfad7af32..36b3f11cb7 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -34,6 +34,36 @@ namespace LuaUtil bool mLogMemoryUsage = false; }; + class LuaState; + class LuaView + { + sol::state_view mSol; + + LuaView(const LuaView&) = delete; + + LuaView(lua_State* L) + : mSol(L) + { + } + + public: + friend class LuaState; + // Returns underlying sol::state. + sol::state_view& sol() { return mSol; } + + // A shortcut to create a new Lua table. + sol::table newTable() { return sol::table(mSol, sol::create); } + }; + + template + sol::table tableFromPairs(lua_State* L, std::initializer_list> list) + { + sol::table res(L, sol::create); + for (const auto& [k, v] : list) + res[k] = v; + return res; + } + // Holds Lua state. // Provides additional features: // - Load scripts from the virtual filesystem; @@ -54,26 +84,53 @@ namespace LuaUtil LuaState(const LuaState&) = delete; LuaState(LuaState&&) = delete; - // Returns underlying sol::state. - sol::state_view& sol() { return mSol; } + // Pushing to the stack from outside a Lua context crashes the engine if no memory can be allocated to grow the + // stack + template + [[nodiscard]] int invokeProtectedCall(Lambda&& f) const + { + if (!lua_checkstack(mSol.lua_state(), 2)) + return LUA_ERRMEM; + lua_pushcfunction(mSol.lua_state(), [](lua_State* L) { + void* f = lua_touserdata(L, 1); + LuaView view(L); + (*static_cast(f))(view); + return 0; + }); + lua_pushlightuserdata(mSol.lua_state(), &f); + return lua_pcall(mSol.lua_state(), 1, 0, 0); + } + + template + void protectedCall(Lambda&& f) const + { + int result = invokeProtectedCall(std::forward(f)); + switch (result) + { + case LUA_OK: + break; + case LUA_ERRMEM: + throw std::runtime_error("Lua error: out of memory"); + case LUA_ERRRUN: + { + sol::optional error = sol::stack::check_get(mSol.lua_state()); + if (error) + throw std::runtime_error(*error); + } + [[fallthrough]]; + default: + throw std::runtime_error("Lua error: " + std::to_string(result)); + } + } + + // Note that constructing a sol::state_view is only safe from a Lua context. Use protectedCall to get one + lua_State* unsafeState() const { return mSol.lua_state(); } // Can be used by a C++ function that is called from Lua to get the Lua traceback. // Makes no sense if called not from Lua code. // Note: It is a slow function, should be used for debug purposes only. std::string debugTraceback() { return mSol["debug"]["traceback"]().get(); } - // A shortcut to create a new Lua table. - sol::table newTable() { return sol::table(mSol, sol::create); } - - template - sol::table tableFromPairs(std::initializer_list> list) - { - sol::table res(mSol, sol::create); - for (const auto& [k, v] : list) - res[k] = v; - return res; - } - // Registers a package that will be available from every sandbox via `require(name)`. // The package can be either a sol::table with an API or a sol::function. If it is a function, // it will be evaluated (once per sandbox) the first time when requested. If the package diff --git a/components/lua/scriptscontainer.cpp b/components/lua/scriptscontainer.cpp index ff45b963ca..b9a2c1594f 100644 --- a/components/lua/scriptscontainer.cpp +++ b/components/lua/scriptscontainer.cpp @@ -24,8 +24,10 @@ namespace LuaUtil { sInstanceCount++; registerEngineHandlers({ &mUpdateHandlers }); - mPublicInterfaces = sol::table(lua->sol(), sol::create); - addPackage("openmw.interfaces", mPublicInterfaces); + lua->protectedCall([&](LuaView& view) { + mPublicInterfaces = sol::table(view.sol(), sol::create); + addPackage("openmw.interfaces", mPublicInterfaces); + }); } void ScriptsContainer::printError(int scriptId, std::string_view msg, const std::exception& e) @@ -41,26 +43,31 @@ namespace LuaUtil bool ScriptsContainer::addCustomScript(int scriptId, std::string_view initData) { assert(mLua.getConfiguration().isCustomScript(scriptId)); - std::optional onInit, onLoad; - bool ok = addScript(scriptId, onInit, onLoad); - if (ok && onInit) - callOnInit(scriptId, *onInit, initData); + bool ok = false; + mLua.protectedCall([&](LuaView& view) { + std::optional onInit, onLoad; + bool ok = addScript(view, scriptId, onInit, onLoad); + if (ok && onInit) + callOnInit(view, scriptId, *onInit, initData); + }); return ok; } void ScriptsContainer::addAutoStartedScripts() { - for (const auto& [scriptId, data] : mAutoStartScripts) - { - std::optional onInit, onLoad; - bool ok = addScript(scriptId, onInit, onLoad); - if (ok && onInit) - callOnInit(scriptId, *onInit, data); - } + mLua.protectedCall([&](LuaView& view) { + for (const auto& [scriptId, data] : mAutoStartScripts) + { + std::optional onInit, onLoad; + bool ok = addScript(view, scriptId, onInit, onLoad); + if (ok && onInit) + callOnInit(view, scriptId, *onInit, data); + } + }); } bool ScriptsContainer::addScript( - int scriptId, std::optional& onInit, std::optional& onLoad) + LuaView& view, int scriptId, std::optional& onInit, std::optional& onLoad) { assert(scriptId >= 0 && scriptId < static_cast(mLua.getConfiguration().size())); if (mScripts.count(scriptId) != 0) @@ -73,7 +80,7 @@ namespace LuaUtil debugName.push_back(']'); Script& script = mScripts[scriptId]; - script.mHiddenData = mLua.newTable(); + script.mHiddenData = view.newTable(); script.mHiddenData[sScriptIdKey] = ScriptId{ this, scriptId }; script.mHiddenData[sScriptDebugNameKey] = debugName; script.mPath = path; @@ -298,32 +305,34 @@ namespace LuaUtil auto it = mEventHandlers.find(eventName); if (it == mEventHandlers.end()) return; - sol::object data; - try - { - data = LuaUtil::deserialize(mLua.sol(), eventData, mSerializer); - } - catch (std::exception& e) - { - Log(Debug::Error) << mNamePrefix << " can not parse eventData for '" << eventName << "': " << e.what(); - return; - } - EventHandlerList& list = it->second; - for (int i = list.size() - 1; i >= 0; --i) - { - const Handler& h = list[i]; + mLua.protectedCall([&](LuaView& view) { + sol::object data; try { - sol::object res = LuaUtil::call({ this, h.mScriptId }, h.mFn, data); - if (res.is() && !res.as()) - break; // Skip other handlers if 'false' was returned. + data = LuaUtil::deserialize(view.sol(), eventData, mSerializer); } catch (std::exception& e) { - Log(Debug::Error) << mNamePrefix << "[" << scriptPath(h.mScriptId) << "] eventHandler[" << eventName - << "] failed. " << e.what(); + Log(Debug::Error) << mNamePrefix << " can not parse eventData for '" << eventName << "': " << e.what(); + return; } - } + EventHandlerList& list = it->second; + for (int i = list.size() - 1; i >= 0; --i) + { + const Handler& h = list[i]; + try + { + sol::object res = LuaUtil::call({ this, h.mScriptId }, h.mFn, data); + if (res.is() && !res.as()) + break; // Skip other handlers if 'false' was returned. + } + catch (std::exception& e) + { + Log(Debug::Error) << mNamePrefix << "[" << scriptPath(h.mScriptId) << "] eventHandler[" << eventName + << "] failed. " << e.what(); + } + } + }); } void ScriptsContainer::registerEngineHandlers(std::initializer_list handlers) @@ -332,11 +341,11 @@ namespace LuaUtil mEngineHandlers[h->mName] = h; } - void ScriptsContainer::callOnInit(int scriptId, const sol::function& onInit, std::string_view data) + void ScriptsContainer::callOnInit(LuaView& view, int scriptId, const sol::function& onInit, std::string_view data) { try { - LuaUtil::call({ this, scriptId }, onInit, deserialize(mLua.sol(), data, mSerializer)); + LuaUtil::call({ this, scriptId }, onInit, deserialize(view.sol(), data, mSerializer)); } catch (std::exception& e) { @@ -418,57 +427,61 @@ namespace LuaUtil << "]; this script is not allowed here"; } - for (const auto& [scriptId, scriptInfo] : scripts) - { - std::optional onInit, onLoad; - if (!addScript(scriptId, onInit, onLoad)) - continue; - if (scriptInfo.mSavedData == nullptr) + mLua.protectedCall([&](LuaView& view) { + for (const auto& [scriptId, scriptInfo] : scripts) { - if (onInit) - callOnInit(scriptId, *onInit, scriptInfo.mInitData); - continue; - } - if (onLoad) - { - try + std::optional onInit, onLoad; + if (!addScript(view, scriptId, onInit, onLoad)) + continue; + if (scriptInfo.mSavedData == nullptr) { - sol::object state = deserialize(mLua.sol(), scriptInfo.mSavedData->mData, mSavedDataDeserializer); - sol::object initializationData = deserialize(mLua.sol(), scriptInfo.mInitData, mSerializer); - LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData); + if (onInit) + callOnInit(view, scriptId, *onInit, scriptInfo.mInitData); + continue; } - catch (std::exception& e) - { - printError(scriptId, "onLoad failed", e); - } - } - for (const ESM::LuaTimer& savedTimer : scriptInfo.mSavedData->mTimers) - { - Timer timer; - timer.mCallback = savedTimer.mCallbackName; - timer.mSerializable = true; - timer.mScriptId = scriptId; - timer.mTime = savedTimer.mTime; - - try + if (onLoad) { - 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); - - if (savedTimer.mType == TimerType::GAME_TIME) - mGameTimersQueue.push_back(std::move(timer)); - else - mSimulationTimersQueue.push_back(std::move(timer)); + try + { + sol::object state + = deserialize(view.sol(), scriptInfo.mSavedData->mData, mSavedDataDeserializer); + sol::object initializationData = deserialize(view.sol(), scriptInfo.mInitData, mSerializer); + LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData); + } + catch (std::exception& e) + { + printError(scriptId, "onLoad failed", e); + } } - catch (std::exception& e) + for (const ESM::LuaTimer& savedTimer : scriptInfo.mSavedData->mTimers) { - printError(scriptId, "can not load timer", e); + Timer timer; + timer.mCallback = savedTimer.mCallbackName; + timer.mSerializable = true; + timer.mScriptId = scriptId; + timer.mTime = savedTimer.mTime; + + try + { + timer.mArg = sol::main_object( + deserialize(view.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); + + if (savedTimer.mType == TimerType::GAME_TIME) + mGameTimersQueue.push_back(std::move(timer)); + else + mSimulationTimersQueue.push_back(std::move(timer)); + } + catch (std::exception& e) + { + printError(scriptId, "can not load timer", e); + } } } - } + }); std::make_heap(mSimulationTimersQueue.begin(), mSimulationTimersQueue.end()); std::make_heap(mGameTimersQueue.begin(), mGameTimersQueue.end()); diff --git a/components/lua/scriptscontainer.hpp b/components/lua/scriptscontainer.hpp index 631b1e58a8..54880b52e1 100644 --- a/components/lua/scriptscontainer.hpp +++ b/components/lua/scriptscontainer.hpp @@ -232,14 +232,15 @@ namespace LuaUtil void addMemoryUsage(int scriptId, int64_t memoryDelta); // Add to container without calling onInit/onLoad. - bool addScript(int scriptId, std::optional& onInit, std::optional& onLoad); + bool addScript( + LuaView& view, int scriptId, std::optional& onInit, std::optional& onLoad); // Returns script by id (throws an exception if doesn't exist) Script& getScript(int scriptId); void printError(int scriptId, std::string_view msg, const std::exception& e); const std::string& scriptPath(int scriptId) const { return mLua.getConfiguration()[scriptId].mScriptPath; } - void callOnInit(int scriptId, const sol::function& onInit, std::string_view data); + void callOnInit(LuaView& view, int scriptId, const sol::function& onInit, std::string_view data); void callTimer(const Timer& t); void updateTimerQueue(std::vector& timerQueue, double time); static void insertTimer(std::vector& timerQueue, Timer&& t); diff --git a/components/lua/storage.cpp b/components/lua/storage.cpp index 063dbf0d10..9f3a159b3a 100644 --- a/components/lua/storage.cpp +++ b/components/lua/storage.cpp @@ -5,6 +5,8 @@ #include +#include "luastate.hpp" + namespace sol { template <> @@ -17,13 +19,14 @@ namespace LuaUtil { LuaStorage::Value LuaStorage::Section::sEmpty; - void LuaStorage::registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res) + void LuaStorage::registerLifeTime(LuaUtil::LuaView& view, sol::table& res) { - res["LIFE_TIME"] = LuaUtil::makeStrictReadOnly(luaState.tableFromPairs({ - { "Persistent", Section::LifeTime::Persistent }, - { "GameSession", Section::LifeTime::GameSession }, - { "Temporary", Section::LifeTime::Temporary }, - })); + res["LIFE_TIME"] = LuaUtil::makeStrictReadOnly(tableFromPairs(view.sol(), + { + { "Persistent", Section::LifeTime::Persistent }, + { "GameSession", Section::LifeTime::GameSession }, + { "Temporary", Section::LifeTime::Temporary }, + })); } sol::object LuaStorage::Value::getCopy(lua_State* L) const @@ -112,26 +115,26 @@ namespace LuaUtil runCallbacks(sol::nullopt); } - sol::table LuaStorage::Section::asTable() + sol::table LuaStorage::Section::asTable(lua_State* L) { checkIfActive(); - sol::table res(mStorage->mLua, sol::create); + sol::table res(L, sol::create); for (const auto& [k, v] : mValues) - res[k] = v.getCopy(mStorage->mLua); + res[k] = v.getCopy(L); return res; } - void LuaStorage::initLuaBindings(lua_State* L) + void LuaStorage::initLuaBindings(LuaUtil::LuaView& view) { - sol::state_view lua(L); - sol::usertype sview = lua.new_usertype("Section"); + sol::usertype sview = view.sol().new_usertype("Section"); sview["get"] = [](sol::this_state s, const SectionView& section, std::string_view key) { return section.mSection->get(key).getReadOnly(s); }; sview["getCopy"] = [](sol::this_state s, const SectionView& section, std::string_view key) { return section.mSection->get(key).getCopy(s); }; - sview["asTable"] = [](const SectionView& section) { return section.mSection->asTable(); }; + sview["asTable"] + = [](sol::this_state lua, const SectionView& section) { return section.mSection->asTable(lua); }; sview["subscribe"] = [](const SectionView& section, const sol::table& callback) { std::vector& callbacks = section.mForMenuScripts ? section.mSection->mMenuScriptsCallbacks : section.mSection->mCallbacks; @@ -165,53 +168,57 @@ namespace LuaUtil }; } - sol::table LuaStorage::initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage) + sol::table LuaStorage::initGlobalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage) { - sol::table res(luaState.sol(), sol::create); - registerLifeTime(luaState, res); + sol::table res(view.sol(), sol::create); + registerLifeTime(view, res); - res["globalSection"] - = [globalStorage](std::string_view section) { return globalStorage->getMutableSection(section); }; - res["allGlobalSections"] = [globalStorage]() { return globalStorage->getAllSections(); }; + res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) { + return globalStorage->getMutableSection(lua, section); + }; + res["allGlobalSections"] = [globalStorage](sol::this_state lua) { return globalStorage->getAllSections(lua); }; return LuaUtil::makeReadOnly(res); } - sol::table LuaStorage::initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage) + sol::table LuaStorage::initLocalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage) { - sol::table res(luaState.sol(), sol::create); - registerLifeTime(luaState, res); + sol::table res(view.sol(), sol::create); + registerLifeTime(view, res); - res["globalSection"] - = [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); }; + res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) { + return globalStorage->getReadOnlySection(lua, section); + }; return LuaUtil::makeReadOnly(res); } sol::table LuaStorage::initPlayerPackage( - LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage) + LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage) { - sol::table res(luaState.sol(), sol::create); - registerLifeTime(luaState, res); + sol::table res(view.sol(), sol::create); + registerLifeTime(view, res); - res["globalSection"] - = [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); }; - res["playerSection"] - = [playerStorage](std::string_view section) { return playerStorage->getMutableSection(section); }; - res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); }; + res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) { + return globalStorage->getReadOnlySection(lua, section); + }; + res["playerSection"] = [playerStorage](sol::this_state lua, std::string_view section) { + return playerStorage->getMutableSection(lua, section); + }; + res["allPlayerSections"] = [playerStorage](sol::this_state lua) { return playerStorage->getAllSections(lua); }; return LuaUtil::makeReadOnly(res); } - sol::table LuaStorage::initMenuPackage( - LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage) + sol::table LuaStorage::initMenuPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage) { - sol::table res(luaState.sol(), sol::create); - registerLifeTime(luaState, res); + sol::table res(view.sol(), sol::create); + registerLifeTime(view, res); - res["playerSection"] = [playerStorage](std::string_view section) { - return playerStorage->getMutableSection(section, /*forMenuScripts=*/true); + res["playerSection"] = [playerStorage](sol::this_state lua, std::string_view section) { + return playerStorage->getMutableSection(lua, section, /*forMenuScripts=*/true); + }; + res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) { + return globalStorage->getReadOnlySection(lua, section); }; - res["globalSection"] - = [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); }; - res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); }; + res["allPlayerSections"] = [playerStorage](sol::this_state lua) { return playerStorage->getAllSections(lua); }; return LuaUtil::makeReadOnly(res); } @@ -234,7 +241,7 @@ namespace LuaUtil } } - void LuaStorage::load(const std::filesystem::path& path) + void LuaStorage::load(lua_State* L, const std::filesystem::path& path) { assert(mData.empty()); // Shouldn't be used before loading try @@ -246,7 +253,7 @@ namespace LuaUtil std::ifstream fin(path, std::fstream::binary); std::string serializedData((std::istreambuf_iterator(fin)), std::istreambuf_iterator()); - sol::table data = deserialize(mLua, serializedData); + sol::table data = deserialize(L, serializedData); for (const auto& [sectionName, sectionTable] : data) { const std::shared_ptr
& section = getSection(cast(sectionName)); @@ -260,13 +267,13 @@ namespace LuaUtil } } - void LuaStorage::save(const std::filesystem::path& path) const + void LuaStorage::save(lua_State* L, const std::filesystem::path& path) const { - sol::table data(mLua, sol::create); + sol::table data(L, sol::create); for (const auto& [sectionName, section] : mData) { if (section->mLifeTime == Section::Persistent && !section->mValues.empty()) - data[sectionName] = section->asTable(); + data[sectionName] = section->asTable(L); } std::string serializedData = serialize(data); Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; @@ -287,19 +294,19 @@ namespace LuaUtil return newIt->second; } - sol::object LuaStorage::getSection(std::string_view sectionName, bool readOnly, bool forMenuScripts) + sol::object LuaStorage::getSection(lua_State* L, std::string_view sectionName, bool readOnly, bool forMenuScripts) { checkIfActive(); const std::shared_ptr
& section = getSection(sectionName); - return sol::make_object(mLua, SectionView{ section, readOnly, forMenuScripts }); + return sol::make_object(L, SectionView{ section, readOnly, forMenuScripts }); } - sol::table LuaStorage::getAllSections(bool readOnly) + sol::table LuaStorage::getAllSections(lua_State* L, bool readOnly) { checkIfActive(); - sol::table res(mLua, sol::create); + sol::table res(L, sol::create); for (const auto& [sectionName, _] : mData) - res[sectionName] = getSection(sectionName, readOnly); + res[sectionName] = getSection(L, sectionName, readOnly); return res; } diff --git a/components/lua/storage.hpp b/components/lua/storage.hpp index 061a5aace3..5ca151c30d 100644 --- a/components/lua/storage.hpp +++ b/components/lua/storage.hpp @@ -10,35 +10,34 @@ namespace LuaUtil { + class LuaView; class LuaStorage { public: - static void initLuaBindings(lua_State* L); - static sol::table initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage); - static sol::table initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage); + static void initLuaBindings(LuaUtil::LuaView& view); + static sol::table initGlobalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage); + static sol::table initLocalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage); static sol::table initPlayerPackage( - LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage); - static sol::table initMenuPackage( - LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage); + LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage); + static sol::table initMenuPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage); - explicit LuaStorage(lua_State* lua) - : mLua(lua) - , mActive(false) - { - } + explicit LuaStorage() {} void clearTemporaryAndRemoveCallbacks(); - void load(const std::filesystem::path& path); - void save(const std::filesystem::path& path) const; + void load(lua_State* L, const std::filesystem::path& path); + void save(lua_State* L, const std::filesystem::path& path) const; - sol::object getSection(std::string_view sectionName, bool readOnly, bool forMenuScripts = false); - sol::object getMutableSection(std::string_view sectionName, bool forMenuScripts = false) + sol::object getSection(lua_State* L, std::string_view sectionName, bool readOnly, bool forMenuScripts = false); + sol::object getMutableSection(lua_State* L, std::string_view sectionName, bool forMenuScripts = false) + { + return getSection(L, sectionName, false, forMenuScripts); + } + sol::object getReadOnlySection(lua_State* L, std::string_view sectionName) { - return getSection(sectionName, false, forMenuScripts); + return getSection(L, sectionName, true); } - sol::object getReadOnlySection(std::string_view sectionName) { return getSection(sectionName, true); } - sol::table getAllSections(bool readOnly = false); + sol::table getAllSections(lua_State* L, bool readOnly = false); void setSingleValue(std::string_view section, std::string_view key, const sol::object& value) { @@ -95,7 +94,7 @@ namespace LuaUtil const Value& get(std::string_view key) const; void set(std::string_view key, const sol::object& value); void setAll(const sol::optional& values); - sol::table asTable(); + sol::table asTable(lua_State* L); void runCallbacks(sol::optional changedKey); void throwIfCallbackRecursionIsTooDeep(); @@ -119,17 +118,16 @@ namespace LuaUtil const std::shared_ptr
& getSection(std::string_view sectionName); - lua_State* mLua; std::map> mData; const Listener* mListener = nullptr; std::set mRunningCallbacks; - bool mActive; + bool mActive = false; void checkIfActive() const { if (!mActive) throw std::logic_error("Trying to access inactive storage"); } - static void registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res); + static void registerLifeTime(LuaUtil::LuaView& view, sol::table& res); }; } From 4529af9b7fca26ab41323757ec993f3692ea63d7 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Fri, 23 Aug 2024 22:40:39 +0200 Subject: [PATCH 2/3] Fix the tests --- apps/components_tests/lua/test_async.cpp | 28 +-- apps/components_tests/lua/test_l10n.cpp | 161 +++++++-------- apps/components_tests/lua/test_lua.cpp | 45 ++--- .../lua/test_scriptscontainer.cpp | 40 ++-- apps/components_tests/lua/test_storage.cpp | 184 +++++++++--------- apps/components_tests/lua/test_ui_content.cpp | 9 +- apps/openmw/mwlua/mwscriptbindings.cpp | 2 +- 7 files changed, 248 insertions(+), 221 deletions(-) diff --git a/apps/components_tests/lua/test_async.cpp b/apps/components_tests/lua/test_async.cpp index e4010e319f..eb6ce7116a 100644 --- a/apps/components_tests/lua/test_async.cpp +++ b/apps/components_tests/lua/test_async.cpp @@ -13,12 +13,14 @@ namespace { void SetUp() override { - mLua.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback { - sol::table hiddenData(mLua.sol(), sol::create); - hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; - return LuaUtil::Callback{ std::move(fn), hiddenData }; - }; - mLua.sol()["pass"] = [this](LuaUtil::Callback callback) { mCb = callback; }; + mLua.protectedCall([&](LuaUtil::LuaView& view) { + view.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback { + sol::table hiddenData(view.sol(), sol::create); + hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; + return LuaUtil::Callback{ std::move(fn), hiddenData }; + }; + view.sol()["pass"] = [&](LuaUtil::Callback callback) { mCb = callback; }; + }); } LuaUtil::LuaState mLua{ nullptr, nullptr }; @@ -28,25 +30,29 @@ namespace TEST_F(LuaCoroutineCallbackTest, CoroutineCallbacks) { internal::CaptureStdout(); - mLua.sol().safe_script(R"X( + mLua.protectedCall([&](LuaUtil::LuaView& view) { + view.sol().safe_script(R"X( local s = 'test' coroutine.wrap(function() pass(callback(function(v) print(s) end)) end)() )X"); - mLua.sol().collect_garbage(); - mCb.call(); + view.sol().collect_garbage(); + mCb.call(); + }); EXPECT_THAT(internal::GetCapturedStdout(), "test\n"); } TEST_F(LuaCoroutineCallbackTest, ErrorInCoroutineCallbacks) { - mLua.sol().safe_script(R"X( + mLua.protectedCall([&](LuaUtil::LuaView& view) { + view.sol().safe_script(R"X( coroutine.wrap(function() pass(callback(function() error('COROUTINE CALLBACK') end)) end)() )X"); - mLua.sol().collect_garbage(); + view.sol().collect_garbage(); + }); EXPECT_ERROR(mCb.call(), "COROUTINE CALLBACK"); } } diff --git a/apps/components_tests/lua/test_l10n.cpp b/apps/components_tests/lua/test_l10n.cpp index a9194ffd7b..d58bd41a94 100644 --- a/apps/components_tests/lua/test_l10n.cpp +++ b/apps/components_tests/lua/test_l10n.cpp @@ -81,84 +81,87 @@ you_have_arrows: "Arrows count: {count}" TEST_F(LuaL10nTest, L10n) { LuaUtil::LuaState lua{ mVFS.get(), &mCfg }; - sol::state_view& l = lua.sol(); - internal::CaptureStdout(); - l10n::Manager l10nManager(mVFS.get()); - l10nManager.setPreferredLocales({ "de", "en" }); - EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n"); - - l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager); - - internal::CaptureStdout(); - l.safe_script("t1 = l10n('Test1')"); - EXPECT_THAT(internal::GetCapturedStdout(), - "Language file \"l10n/Test1/de.yaml\" is enabled\n" - "Language file \"l10n/Test1/en.yaml\" is enabled\n"); - - internal::CaptureStdout(); - l.safe_script("t2 = l10n('Test2')"); - { - std::string output = internal::GetCapturedStdout(); - EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled")); - } - - EXPECT_EQ(get(l, "t1('good_morning')"), "Guten Morgen."); - EXPECT_EQ(get(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil."); - EXPECT_EQ(get(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile."); - EXPECT_EQ(get(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!"); - EXPECT_EQ(get(l, "t2('good_morning')"), "Morning!"); - EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); - - internal::CaptureStdout(); - l10nManager.setPreferredLocales({ "en", "de" }); - EXPECT_THAT(internal::GetCapturedStdout(), - "Preferred locales: gmst en de\n" - "Language file \"l10n/Test1/en.yaml\" is enabled\n" - "Language file \"l10n/Test1/de.yaml\" is enabled\n" - "Language file \"l10n/Test2/en.yaml\" is enabled\n"); - - EXPECT_EQ(get(l, "t1('good_morning')"), "Good morning."); - EXPECT_EQ(get(l, "t1('you_have_arrows', {count=1})"), "You have one arrow."); - EXPECT_EQ(get(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows."); - EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us."); - EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us."); - EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us."); - EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us."); - EXPECT_EQ(get(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete."); - EXPECT_EQ(get(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete."); - EXPECT_EQ(get(l, "t1('ordinal', {num=1})"), "You came in 1st place."); - EXPECT_EQ(get(l, "t1('ordinal', {num=100})"), "You came in 100th place."); - EXPECT_EQ(get(l, "t1('spellout', {num=1})"), "There is one thing."); - EXPECT_EQ(get(l, "t1('spellout', {num=100})"), "There are one hundred things."); - EXPECT_EQ(get(l, "t1('duration', {num=100})"), "It took 1:40"); - EXPECT_EQ(get(l, "t1('numbers', {int=123, double=123.456})"), - "123 and 123 are integers, but 123.456 is a double"); - EXPECT_EQ(get(l, "t1('rounding', {value=123.456789})"), "123.46"); - // Check that failed messages display the key instead of an empty string - EXPECT_EQ(get(l, "t1('{mismatched_braces')"), "{mismatched_braces"); - EXPECT_EQ(get(l, "t1('{unknown_arg}')"), "{unknown_arg}"); - EXPECT_EQ(get(l, "t1('{num, integer}', {num=1})"), "{num, integer}"); - // Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency. - l10nManager.setPreferredLocales({ "en-US", "de" }); - EXPECT_EQ(get(l, "t1('currency', {money=10000.10})"), "You have $10,000.10"); - // Note: Not defined in English localisation file, so we fall back to the German before falling back to the key - EXPECT_EQ(get(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!"); - EXPECT_EQ(get(l, "t2('good_morning')"), "Morning!"); - EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); - - // Test that locales with variants and country codes fall back to more generic locales - internal::CaptureStdout(); - l10nManager.setPreferredLocales({ "en-GB-oed", "de" }); - EXPECT_THAT(internal::GetCapturedStdout(), - "Preferred locales: gmst en_GB_OED de\n" - "Language file \"l10n/Test1/en.yaml\" is enabled\n" - "Language file \"l10n/Test1/de.yaml\" is enabled\n" - "Language file \"l10n/Test2/en.yaml\" is enabled\n"); - EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); - - // Test setting fallback language - l.safe_script("t3 = l10n('Test3', 'de')"); - l10nManager.setPreferredLocales({ "en" }); - EXPECT_EQ(get(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!"); + lua.protectedCall([&](LuaUtil::LuaView& view) { + sol::state_view& l = view.sol(); + internal::CaptureStdout(); + l10n::Manager l10nManager(mVFS.get()); + l10nManager.setPreferredLocales({ "de", "en" }); + EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n"); + + l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager); + + internal::CaptureStdout(); + l.safe_script("t1 = l10n('Test1')"); + EXPECT_THAT(internal::GetCapturedStdout(), + "Language file \"l10n/Test1/de.yaml\" is enabled\n" + "Language file \"l10n/Test1/en.yaml\" is enabled\n"); + + internal::CaptureStdout(); + l.safe_script("t2 = l10n('Test2')"); + { + std::string output = internal::GetCapturedStdout(); + EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled")); + } + + EXPECT_EQ(get(l, "t1('good_morning')"), "Guten Morgen."); + EXPECT_EQ(get(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil."); + EXPECT_EQ(get(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile."); + EXPECT_EQ(get(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!"); + EXPECT_EQ(get(l, "t2('good_morning')"), "Morning!"); + EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); + + internal::CaptureStdout(); + l10nManager.setPreferredLocales({ "en", "de" }); + EXPECT_THAT(internal::GetCapturedStdout(), + "Preferred locales: gmst en de\n" + "Language file \"l10n/Test1/en.yaml\" is enabled\n" + "Language file \"l10n/Test1/de.yaml\" is enabled\n" + "Language file \"l10n/Test2/en.yaml\" is enabled\n"); + + EXPECT_EQ(get(l, "t1('good_morning')"), "Good morning."); + EXPECT_EQ(get(l, "t1('you_have_arrows', {count=1})"), "You have one arrow."); + EXPECT_EQ(get(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows."); + EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us."); + EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us."); + EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us."); + EXPECT_EQ(get(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us."); + EXPECT_EQ(get(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete."); + EXPECT_EQ(get(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete."); + EXPECT_EQ(get(l, "t1('ordinal', {num=1})"), "You came in 1st place."); + EXPECT_EQ(get(l, "t1('ordinal', {num=100})"), "You came in 100th place."); + EXPECT_EQ(get(l, "t1('spellout', {num=1})"), "There is one thing."); + EXPECT_EQ(get(l, "t1('spellout', {num=100})"), "There are one hundred things."); + EXPECT_EQ(get(l, "t1('duration', {num=100})"), "It took 1:40"); + EXPECT_EQ(get(l, "t1('numbers', {int=123, double=123.456})"), + "123 and 123 are integers, but 123.456 is a double"); + EXPECT_EQ(get(l, "t1('rounding', {value=123.456789})"), "123.46"); + // Check that failed messages display the key instead of an empty string + EXPECT_EQ(get(l, "t1('{mismatched_braces')"), "{mismatched_braces"); + EXPECT_EQ(get(l, "t1('{unknown_arg}')"), "{unknown_arg}"); + EXPECT_EQ(get(l, "t1('{num, integer}', {num=1})"), "{num, integer}"); + // Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency. + l10nManager.setPreferredLocales({ "en-US", "de" }); + EXPECT_EQ(get(l, "t1('currency', {money=10000.10})"), "You have $10,000.10"); + // Note: Not defined in English localisation file, so we fall back to the German before falling back to the + // key + EXPECT_EQ(get(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!"); + EXPECT_EQ(get(l, "t2('good_morning')"), "Morning!"); + EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); + + // Test that locales with variants and country codes fall back to more generic locales + internal::CaptureStdout(); + l10nManager.setPreferredLocales({ "en-GB-oed", "de" }); + EXPECT_THAT(internal::GetCapturedStdout(), + "Preferred locales: gmst en_GB_OED de\n" + "Language file \"l10n/Test1/en.yaml\" is enabled\n" + "Language file \"l10n/Test1/de.yaml\" is enabled\n" + "Language file \"l10n/Test2/en.yaml\" is enabled\n"); + EXPECT_EQ(get(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3"); + + // Test setting fallback language + l.safe_script("t3 = l10n('Test3', 'de')"); + l10nManager.setPreferredLocales({ "en" }); + EXPECT_EQ(get(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!"); + }); } } diff --git a/apps/components_tests/lua/test_lua.cpp b/apps/components_tests/lua/test_lua.cpp index 09f0151267..6596b509db 100644 --- a/apps/components_tests/lua/test_lua.cpp +++ b/apps/components_tests/lua/test_lua.cpp @@ -97,26 +97,26 @@ return { TEST_F(LuaStateTest, ToString) { - EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), 3.14)), "3.14"); - EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), true)), "true"); + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), 3.14)), "3.14"); + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), true)), "true"); EXPECT_EQ(LuaUtil::toString(sol::nil), "nil"); - EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), "something")), "\"something\""); + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), "something")), "\"something\""); } TEST_F(LuaStateTest, Cast) { - EXPECT_EQ(LuaUtil::cast(sol::make_object(mLua.sol(), 3.14)), 3); - EXPECT_ERROR( - LuaUtil::cast(sol::make_object(mLua.sol(), "3.14")), "Value \"\"3.14\"\" can not be casted to int"); - EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.sol(), sol::nil)), + EXPECT_EQ(LuaUtil::cast(sol::make_object(mLua.unsafeState(), 3.14)), 3); + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), "3.14")), + "Value \"\"3.14\"\" can not be casted to int"); + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), sol::nil)), "Value \"nil\" can not be casted to string"); - EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.sol(), sol::nil)), + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), sol::nil)), "Value \"nil\" can not be casted to string"); - EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.sol(), sol::nil)), + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), sol::nil)), "Value \"nil\" can not be casted to sol::table"); - EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.sol(), "3.14")), + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), "3.14")), "Value \"\"3.14\"\" can not be casted to sol::function"); - EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.sol(), "3.14")), + EXPECT_ERROR(LuaUtil::cast(sol::make_object(mLua.unsafeState(), "3.14")), "Value \"\"3.14\"\" can not be casted to sol::function"); } @@ -186,21 +186,22 @@ return { TEST_F(LuaStateTest, ProvideAPI) { LuaUtil::LuaState lua(mVFS.get(), &mCfg); + lua.protectedCall([&](LuaUtil::LuaView& view) { + sol::table api1 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api1")); + sol::table api2 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api2")); - sol::table api1 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api1")); - sol::table api2 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api2")); - - sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } }); + sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } }); - lua.addCommonPackage("sqrlib", lua.sol().create_table_with("sqr", [](int x) { return x * x; })); + lua.addCommonPackage("sqrlib", view.sol().create_table_with("sqr", [](int x) { return x * x; })); - sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } }); + sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } }); - EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib"); - EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get(), 9); + EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib"); + EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get(), 9); - EXPECT_EQ(LuaUtil::call(script1["apiName"]).get(), "api1"); - EXPECT_EQ(LuaUtil::call(script2["apiName"]).get(), "api2"); + EXPECT_EQ(LuaUtil::call(script1["apiName"]).get(), "api1"); + EXPECT_EQ(LuaUtil::call(script2["apiName"]).get(), "api2"); + }); } TEST_F(LuaStateTest, GetLuaVersion) @@ -212,7 +213,7 @@ return { { auto getMem = [&] { for (int i = 0; i < 5; ++i) - lua_gc(mLua.sol(), LUA_GCCOLLECT, 0); + lua_gc(mLua.unsafeState(), LUA_GCCOLLECT, 0); return mLua.getTotalMemoryUsage(); }; int64_t memWithScript; diff --git a/apps/components_tests/lua/test_scriptscontainer.cpp b/apps/components_tests/lua/test_scriptscontainer.cpp index c048e29f5e..7491675a01 100644 --- a/apps/components_tests/lua/test_scriptscontainer.cpp +++ b/apps/components_tests/lua/test_scriptscontainer.cpp @@ -198,8 +198,9 @@ CUSTOM, PLAYER: useInterface.lua EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua"))); EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua"))); - std::string X0 = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5)); - std::string X1 = LuaUtil::serialize(mLua.sol().create_table_with("x", 1.5)); + sol::state_view sol = mLua.unsafeState(); + std::string X0 = LuaUtil::serialize(sol.create_table_with("x", 0.5)); + std::string X1 = LuaUtil::serialize(sol.create_table_with("x", 1.5)); { testing::internal::CaptureStdout(); @@ -243,7 +244,8 @@ CUSTOM, PLAYER: useInterface.lua EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test1.lua"))); EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua"))); EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua"))); - std::string X = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5)); + sol::state_view sol = mLua.unsafeState(); + std::string X = LuaUtil::serialize(sol.create_table_with("x", 0.5)); { testing::internal::CaptureStdout(); @@ -334,8 +336,9 @@ CUSTOM, PLAYER: useInterface.lua scripts1.addAutoStartedScripts(); EXPECT_TRUE(scripts1.addCustomScript(*mCfg.findId("test1.lua"))); - scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 1, "x", 0.5, "y", 3.5))); - scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 2, "x", 2.5, "y", 1.5))); + sol::state_view sol = mLua.unsafeState(); + scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 1, "x", 0.5, "y", 3.5))); + scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 2, "x", 2.5, "y", 1.5))); ESM::LuaScripts data; scripts1.save(data); @@ -379,10 +382,10 @@ CUSTOM, PLAYER: useInterface.lua EXPECT_EQ(internal::GetCapturedStdout(), ""); int counter1 = 0, counter2 = 0, counter3 = 0, counter4 = 0; - sol::function fn1 = sol::make_object(mLua.sol(), [&]() { counter1++; }); - sol::function fn2 = sol::make_object(mLua.sol(), [&]() { counter2++; }); - sol::function fn3 = sol::make_object(mLua.sol(), [&](int d) { counter3 += d; }); - sol::function fn4 = sol::make_object(mLua.sol(), [&](int d) { counter4 += d; }); + sol::function fn1 = sol::make_object(mLua.unsafeState(), [&]() { counter1++; }); + sol::function fn2 = sol::make_object(mLua.unsafeState(), [&]() { counter2++; }); + sol::function fn3 = sol::make_object(mLua.unsafeState(), [&](int d) { counter3 += d; }); + sol::function fn4 = sol::make_object(mLua.unsafeState(), [&](int d) { counter4 += d; }); scripts.registerTimerCallback(test1Id, "A", fn3); scripts.registerTimerCallback(test1Id, "B", fn4); @@ -391,12 +394,16 @@ CUSTOM, PLAYER: useInterface.lua scripts.processTimers(1, 2); - scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.sol(), 3)); - scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.sol(), 4)); - scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.sol(), 1)); - scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.sol(), 2)); - scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.sol(), 10)); - scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.sol(), 20)); + scripts.setupSerializableTimer( + TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.unsafeState(), 3)); + scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.unsafeState(), 4)); + scripts.setupSerializableTimer( + TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.unsafeState(), 1)); + scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.unsafeState(), 2)); + scripts.setupSerializableTimer( + TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.unsafeState(), 10)); + scripts.setupSerializableTimer( + TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.unsafeState(), 20)); scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 10, test2Id, fn2); scripts.setupUnsavableTimer(TimerType::GAME_TIME, 10, test1Id, fn2); @@ -446,7 +453,8 @@ CUSTOM, PLAYER: useInterface.lua TEST_F(LuaScriptsContainerTest, CallbackWrapper) { - LuaUtil::Callback callback{ mLua.sol()["print"], mLua.newTable() }; + sol::state_view view = mLua.unsafeState(); + LuaUtil::Callback callback{ view["print"], sol::table(view, sol::create) }; callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptDebugNameKey] = "some_script.lua"; callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{ nullptr, 0 }; diff --git a/apps/components_tests/lua/test_storage.cpp b/apps/components_tests/lua/test_storage.cpp index 165737d1ed..cf6db0ca64 100644 --- a/apps/components_tests/lua/test_storage.cpp +++ b/apps/components_tests/lua/test_storage.cpp @@ -19,102 +19,110 @@ namespace { // Note: LuaUtil::Callback can be used only if Lua is initialized via LuaUtil::LuaState LuaUtil::LuaState luaState{ nullptr, nullptr }; - sol::state_view& mLua = luaState.sol(); - LuaUtil::LuaStorage::initLuaBindings(mLua); - LuaUtil::LuaStorage storage(mLua); - storage.setActive(true); - - sol::table callbackHiddenData(mLua, sol::create); - callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; - LuaUtil::getAsyncPackageInitializer( - mLua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData); - mLua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData }; - - mLua["mutable"] = storage.getMutableSection("test"); - mLua["ro"] = storage.getReadOnlySection("test"); - - mLua.safe_script(R"( - callbackCalls = {} - ro:subscribe(async:callback(function(section, key) - table.insert(callbackCalls, section .. '_' .. (key or '*')) - end)) - )"); - - mLua.safe_script("mutable:set('x', 5)"); - EXPECT_EQ(get(mLua, "mutable:get('x')"), 5); - EXPECT_EQ(get(mLua, "ro:get('x')"), 5); - - EXPECT_THROW(mLua.safe_script("ro:set('y', 3)"), std::exception); - - mLua.safe_script("t1 = mutable:asTable()"); - mLua.safe_script("t2 = ro:asTable()"); - EXPECT_EQ(get(mLua, "t1.x"), 5); - EXPECT_EQ(get(mLua, "t2.x"), 5); - - mLua.safe_script("mutable:reset()"); - EXPECT_TRUE(get(mLua, "ro:get('x') == nil")); - - mLua.safe_script("mutable:reset({x=4, y=7})"); - EXPECT_EQ(get(mLua, "ro:get('x')"), 4); - EXPECT_EQ(get(mLua, "ro:get('y')"), 7); - - EXPECT_THAT(get(mLua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*"); + luaState.protectedCall([](LuaUtil::LuaView& view) { + sol::state_view& lua = view.sol(); + LuaUtil::LuaStorage::initLuaBindings(view); + LuaUtil::LuaStorage storage; + storage.setActive(true); + + sol::table callbackHiddenData(lua, sol::create); + callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; + LuaUtil::getAsyncPackageInitializer( + lua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData); + lua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData }; + + lua["mutable"] = storage.getMutableSection(lua, "test"); + lua["ro"] = storage.getReadOnlySection(lua, "test"); + + lua.safe_script(R"( + callbackCalls = {} + ro:subscribe(async:callback(function(section, key) + table.insert(callbackCalls, section .. '_' .. (key or '*')) + end)) + )"); + + lua.safe_script("mutable:set('x', 5)"); + EXPECT_EQ(get(lua, "mutable:get('x')"), 5); + EXPECT_EQ(get(lua, "ro:get('x')"), 5); + + EXPECT_THROW(lua.safe_script("ro:set('y', 3)"), std::exception); + + lua.safe_script("t1 = mutable:asTable()"); + lua.safe_script("t2 = ro:asTable()"); + EXPECT_EQ(get(lua, "t1.x"), 5); + EXPECT_EQ(get(lua, "t2.x"), 5); + + lua.safe_script("mutable:reset()"); + EXPECT_TRUE(get(lua, "ro:get('x') == nil")); + + lua.safe_script("mutable:reset({x=4, y=7})"); + EXPECT_EQ(get(lua, "ro:get('x')"), 4); + EXPECT_EQ(get(lua, "ro:get('y')"), 7); + + EXPECT_THAT(get(lua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*"); + }); } TEST(LuaUtilStorageTest, Table) { - sol::state mLua; - LuaUtil::LuaStorage::initLuaBindings(mLua); - LuaUtil::LuaStorage storage(mLua); - storage.setActive(true); - mLua["mutable"] = storage.getMutableSection("test"); - mLua["ro"] = storage.getReadOnlySection("test"); - - mLua.safe_script("mutable:set('x', { y = 'abc', z = 7 })"); - EXPECT_EQ(get(mLua, "mutable:get('x').z"), 7); - EXPECT_THROW(mLua.safe_script("mutable:get('x').z = 3"), std::exception); - EXPECT_NO_THROW(mLua.safe_script("mutable:getCopy('x').z = 3")); - EXPECT_EQ(get(mLua, "mutable:get('x').z"), 7); - EXPECT_EQ(get(mLua, "ro:get('x').z"), 7); - EXPECT_EQ(get(mLua, "ro:get('x').y"), "abc"); + LuaUtil::LuaState luaState{ nullptr, nullptr }; + luaState.protectedCall([](LuaUtil::LuaView& view) { + LuaUtil::LuaStorage::initLuaBindings(view); + LuaUtil::LuaStorage storage; + auto& lua = view.sol(); + storage.setActive(true); + lua["mutable"] = storage.getMutableSection(lua, "test"); + lua["ro"] = storage.getReadOnlySection(lua, "test"); + + lua.safe_script("mutable:set('x', { y = 'abc', z = 7 })"); + EXPECT_EQ(get(lua, "mutable:get('x').z"), 7); + EXPECT_THROW(lua.safe_script("mutable:get('x').z = 3"), std::exception); + EXPECT_NO_THROW(lua.safe_script("mutable:getCopy('x').z = 3")); + EXPECT_EQ(get(lua, "mutable:get('x').z"), 7); + EXPECT_EQ(get(lua, "ro:get('x').z"), 7); + EXPECT_EQ(get(lua, "ro:get('x').y"), "abc"); + }); } TEST(LuaUtilStorageTest, Saving) { - sol::state mLua; - LuaUtil::LuaStorage::initLuaBindings(mLua); - LuaUtil::LuaStorage storage(mLua); - storage.setActive(true); - - mLua["permanent"] = storage.getMutableSection("permanent"); - mLua["temporary"] = storage.getMutableSection("temporary"); - mLua.safe_script("temporary:removeOnExit()"); - mLua.safe_script("permanent:set('x', 1)"); - mLua.safe_script("temporary:set('y', 2)"); - - const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin"; - storage.save(tmpFile); - EXPECT_EQ(get(mLua, "permanent:get('x')"), 1); - EXPECT_EQ(get(mLua, "temporary:get('y')"), 2); - - storage.clearTemporaryAndRemoveCallbacks(); - mLua["permanent"] = storage.getMutableSection("permanent"); - mLua["temporary"] = storage.getMutableSection("temporary"); - EXPECT_EQ(get(mLua, "permanent:get('x')"), 1); - EXPECT_TRUE(get(mLua, "temporary:get('y') == nil")); - - mLua.safe_script("permanent:set('x', 3)"); - mLua.safe_script("permanent:set('z', 4)"); - - LuaUtil::LuaStorage storage2(mLua); - storage2.setActive(true); - storage2.load(tmpFile); - mLua["permanent"] = storage2.getMutableSection("permanent"); - mLua["temporary"] = storage2.getMutableSection("temporary"); - - EXPECT_EQ(get(mLua, "permanent:get('x')"), 1); - EXPECT_TRUE(get(mLua, "permanent:get('z') == nil")); - EXPECT_TRUE(get(mLua, "temporary:get('y') == nil")); + LuaUtil::LuaState luaState{ nullptr, nullptr }; + luaState.protectedCall([](LuaUtil::LuaView& view) { + LuaUtil::LuaStorage::initLuaBindings(view); + LuaUtil::LuaStorage storage; + auto& lua = view.sol(); + storage.setActive(true); + + lua["permanent"] = storage.getMutableSection(lua, "permanent"); + lua["temporary"] = storage.getMutableSection(lua, "temporary"); + lua.safe_script("temporary:removeOnExit()"); + lua.safe_script("permanent:set('x', 1)"); + lua.safe_script("temporary:set('y', 2)"); + + const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin"; + storage.save(lua, tmpFile); + EXPECT_EQ(get(lua, "permanent:get('x')"), 1); + EXPECT_EQ(get(lua, "temporary:get('y')"), 2); + + storage.clearTemporaryAndRemoveCallbacks(); + lua["permanent"] = storage.getMutableSection(lua, "permanent"); + lua["temporary"] = storage.getMutableSection(lua, "temporary"); + EXPECT_EQ(get(lua, "permanent:get('x')"), 1); + EXPECT_TRUE(get(lua, "temporary:get('y') == nil")); + + lua.safe_script("permanent:set('x', 3)"); + lua.safe_script("permanent:set('z', 4)"); + + LuaUtil::LuaStorage storage2; + storage2.setActive(true); + storage2.load(lua, tmpFile); + lua["permanent"] = storage2.getMutableSection(lua, "permanent"); + lua["temporary"] = storage2.getMutableSection(lua, "temporary"); + + EXPECT_EQ(get(lua, "permanent:get('x')"), 1); + EXPECT_TRUE(get(lua, "permanent:get('z') == nil")); + EXPECT_TRUE(get(lua, "temporary:get('y') == nil")); + }); } } diff --git a/apps/components_tests/lua/test_ui_content.cpp b/apps/components_tests/lua/test_ui_content.cpp index c4f23634ce..fcdfd8a1b3 100644 --- a/apps/components_tests/lua/test_ui_content.cpp +++ b/apps/components_tests/lua/test_ui_content.cpp @@ -27,7 +27,7 @@ namespace return LuaUi::ContentView(result.get()); } - sol::table makeTable() { return sol::table(mLuaState.sol(), sol::create); } + sol::table makeTable() { return sol::table(mLuaState.unsafeState(), sol::create); } sol::table makeTable(std::string name) { @@ -39,13 +39,14 @@ namespace TEST_F(LuaUiContentTest, ProtectedMetatable) { - mLuaState.sol()["makeContent"] = mNew; - mLuaState.sol()["M"] = makeContent(makeTable()).getMetatable(); + sol::state_view sol = mLuaState.unsafeState(); + sol["makeContent"] = mNew; + sol["M"] = makeContent(makeTable()).getMetatable(); std::string testScript = R"( assert(not pcall(function() setmetatable(makeContent{}, {}) end), 'Metatable is not protected') assert(getmetatable(makeContent{}) == false, 'Metatable is not protected') )"; - EXPECT_NO_THROW(mLuaState.sol().safe_script(testScript)); + EXPECT_NO_THROW(sol.safe_script(testScript)); } TEST_F(LuaUiContentTest, Create) diff --git a/apps/openmw/mwlua/mwscriptbindings.cpp b/apps/openmw/mwlua/mwscriptbindings.cpp index 2a92a6c5af..90d24b39fe 100644 --- a/apps/openmw/mwlua/mwscriptbindings.cpp +++ b/apps/openmw/mwlua/mwscriptbindings.cpp @@ -95,7 +95,7 @@ namespace MWLua sol::table initMWScriptBindings(const Context& context) { - sol::state_view lua = lua; + sol::state_view lua = context.sol(); sol::table api(lua, sol::create); api["getGlobalScript"] From 032d506aa7e3741db567369e3a5cf85abb4baedf Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 24 Aug 2024 09:10:23 +0200 Subject: [PATCH 3/3] Fix components_tests --- apps/components_tests/lua/test_async.cpp | 22 +++++++++++----------- components/lua/scriptscontainer.cpp | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/components_tests/lua/test_async.cpp b/apps/components_tests/lua/test_async.cpp index eb6ce7116a..f1602b8cac 100644 --- a/apps/components_tests/lua/test_async.cpp +++ b/apps/components_tests/lua/test_async.cpp @@ -14,8 +14,8 @@ namespace void SetUp() override { mLua.protectedCall([&](LuaUtil::LuaView& view) { - view.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback { - sol::table hiddenData(view.sol(), sol::create); + view.sol()["callback"] = [](sol::this_state state, sol::protected_function fn) -> LuaUtil::Callback { + sol::table hiddenData(state, sol::create); hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; return LuaUtil::Callback{ std::move(fn), hiddenData }; }; @@ -32,11 +32,11 @@ namespace internal::CaptureStdout(); mLua.protectedCall([&](LuaUtil::LuaView& view) { view.sol().safe_script(R"X( - local s = 'test' - coroutine.wrap(function() - pass(callback(function(v) print(s) end)) - end)() - )X"); + local s = 'test' + coroutine.wrap(function() + pass(callback(function(v) print(s) end)) + end)() + )X"); view.sol().collect_garbage(); mCb.call(); }); @@ -47,10 +47,10 @@ namespace { mLua.protectedCall([&](LuaUtil::LuaView& view) { view.sol().safe_script(R"X( - coroutine.wrap(function() - pass(callback(function() error('COROUTINE CALLBACK') end)) - end)() - )X"); + coroutine.wrap(function() + pass(callback(function() error('COROUTINE CALLBACK') end)) + end)() + )X"); view.sol().collect_garbage(); }); EXPECT_ERROR(mCb.call(), "COROUTINE CALLBACK"); diff --git a/components/lua/scriptscontainer.cpp b/components/lua/scriptscontainer.cpp index b9a2c1594f..1294271676 100644 --- a/components/lua/scriptscontainer.cpp +++ b/components/lua/scriptscontainer.cpp @@ -46,7 +46,7 @@ namespace LuaUtil bool ok = false; mLua.protectedCall([&](LuaView& view) { std::optional onInit, onLoad; - bool ok = addScript(view, scriptId, onInit, onLoad); + ok = addScript(view, scriptId, onInit, onLoad); if (ok && onInit) callOnInit(view, scriptId, *onInit, initData); });