Merge branch 'lua_refactoring' into 'master'

MWLua refactoring

See merge request OpenMW/openmw!2956
simplify_debugging
psi29a 2 years ago
commit cdc753df70

@ -1,5 +1,6 @@
#include "luabindings.hpp" #include "luabindings.hpp"
#include <components/lua/luastate.hpp>
#include <components/lua/utilpackage.hpp> #include <components/lua/utilpackage.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -13,15 +14,15 @@ namespace MWLua
using CameraMode = MWRender::Camera::Mode; using CameraMode = MWRender::Camera::Mode;
sol::table initCameraPackage(const Context& context) sol::table initCameraPackage(sol::state_view& lua)
{ {
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera(); MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager(); MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
sol::table api(context.mLua->sol(), sol::create); sol::table api(lua, sol::create);
api["MODE"] = LuaUtil::makeStrictReadOnly( api["MODE"] = LuaUtil::makeStrictReadOnly(
context.mLua->sol().create_table_with("Static", CameraMode::Static, "FirstPerson", CameraMode::FirstPerson, lua.create_table_with("Static", CameraMode::Static, "FirstPerson", CameraMode::FirstPerson, "ThirdPerson",
"ThirdPerson", CameraMode::ThirdPerson, "Vanity", CameraMode::Vanity, "Preview", CameraMode::Preview)); CameraMode::ThirdPerson, "Vanity", CameraMode::Vanity, "Preview", CameraMode::Preview));
api["getMode"] = [camera]() -> int { return static_cast<int>(camera->getMode()); }; api["getMode"] = [camera]() -> int { return static_cast<int>(camera->getMode()); };
api["getQueuedMode"] = [camera]() -> sol::optional<int> { api["getQueuedMode"] = [camera]() -> sol::optional<int> {

@ -0,0 +1,11 @@
#ifndef MWLUA_CAMERABINDINGS_H
#define MWLUA_CAMERABINDINGS_H
#include <sol/forward.hpp>
namespace MWLua
{
sol::table initCameraPackage(sol::state_view& lua);
}
#endif // MWLUA_CAMERABINDINGS_H

@ -1,4 +1,4 @@
#include "luabindings.hpp" #include "cellbindings.hpp"
#include <components/esm/esmbridge.hpp> #include <components/esm/esmbridge.hpp>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>

@ -0,0 +1,12 @@
#ifndef MWLUA_CELLBINDINGS_H
#define MWLUA_CELLBINDINGS_H
#include "context.hpp"
namespace MWLua
{
void initCellBindingsForLocalScripts(const Context&);
void initCellBindingsForGlobalScripts(const Context&);
}
#endif // MWLUA_CELLBINDINGS_H

@ -1,7 +1,7 @@
#include "engineevents.hpp" #include "engineevents.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/settings/settings.hpp> #include <components/settings/values.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -75,7 +75,7 @@ namespace MWLua
MWWorld::Ptr getPtr(const ESM::RefNum& id) const MWWorld::Ptr getPtr(const ESM::RefNum& id) const
{ {
MWWorld::Ptr res = mWorldModel->getPtr(id); MWWorld::Ptr res = mWorldModel->getPtr(id);
if (res.isEmpty() && mLuaDebug) if (res.isEmpty() && Settings::lua().mLuaDebug)
Log(Debug::Verbose) << "Can not find object" << id.toString() << " when calling engine hanglers"; Log(Debug::Verbose) << "Can not find object" << id.toString() << " when calling engine hanglers";
return res; return res;
} }
@ -91,7 +91,6 @@ namespace MWLua
LocalScripts* getLocalScripts(const ESM::RefNum& id) const { return getLocalScripts(getPtr(id)); } LocalScripts* getLocalScripts(const ESM::RefNum& id) const { return getLocalScripts(getPtr(id)); }
GlobalScripts& mGlobalScripts; GlobalScripts& mGlobalScripts;
bool mLuaDebug = Settings::Manager::getBool("lua debug", "Lua");
MWWorld::WorldModel* mWorldModel = MWBase::Environment::get().getWorldModel(); MWWorld::WorldModel* mWorldModel = MWBase::Environment::get().getWorldModel();
}; };

@ -1,9 +1,10 @@
#include "luabindings.hpp" #include "inputbindings.hpp"
#include <SDL_events.h> #include <SDL_events.h>
#include <SDL_gamecontroller.h> #include <SDL_gamecontroller.h>
#include <SDL_mouse.h> #include <SDL_mouse.h>
#include <components/lua/luastate.hpp>
#include <components/sdlutil/events.hpp> #include <components/sdlutil/events.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"

@ -0,0 +1,13 @@
#ifndef MWLUA_INPUTBINDINGS_H
#define MWLUA_INPUTBINDINGS_H
#include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua
{
sol::table initInputPackage(const Context&);
}
#endif // MWLUA_INPUTBINDINGS_H

@ -3,11 +3,12 @@
#include <chrono> #include <chrono>
#include <components/esm/attr.hpp> #include <components/esm/attr.hpp>
#include <components/esm3/activespells.hpp>
#include <components/esm3/loadalch.hpp> #include <components/esm3/loadalch.hpp>
#include <components/esm3/loadskil.hpp> #include <components/esm3/loadskil.hpp>
#include <components/lua/l10n.hpp> #include <components/lua/l10n.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/utilpackage.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
@ -22,7 +23,16 @@
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "worldview.hpp" #include "worldview.hpp"
#include "camerabindings.hpp"
#include "cellbindings.hpp"
#include "debugbindings.hpp"
#include "inputbindings.hpp"
#include "magicbindings.hpp" #include "magicbindings.hpp"
#include "nearbybindings.hpp"
#include "objectbindings.hpp"
#include "postprocessingbindings.hpp"
#include "types/types.hpp"
#include "uibindings.hpp"
namespace MWLua namespace MWLua
{ {
@ -54,7 +64,7 @@ namespace MWLua
// api["resume"] = []() {}; // api["resume"] = []() {};
} }
sol::table initCorePackage(const Context& context) static sol::table initCorePackage(const Context& context)
{ {
auto* lua = context.mLua; auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create); sol::table api(lua->sol(), sol::create);
@ -96,7 +106,7 @@ namespace MWLua
return LuaUtil::makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
sol::table initWorldPackage(const Context& context) static sol::table initWorldPackage(const Context& context)
{ {
sol::table api(context.mLua->sol(), sol::create); sol::table api(context.mLua->sol(), sol::create);
WorldView* worldView = context.mWorldView; WorldView* worldView = context.mWorldView;
@ -137,33 +147,48 @@ namespace MWLua
return LuaUtil::makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
sol::table initGlobalStoragePackage(const Context& context, LuaUtil::LuaStorage* globalStorage) std::map<std::string, sol::object> initCommonPackages(const Context& context)
{
sol::state_view lua = context.mLua->sol();
WorldView* w = context.mWorldView;
return {
{ "openmw.async",
LuaUtil::getAsyncPackageInitializer(
lua, [w] { return w->getSimulationTime(); }, [w] { return w->getGameTime(); }) },
{ "openmw.core", initCorePackage(context) },
{ "openmw.types", initTypesPackage(context) },
{ "openmw.util", LuaUtil::initUtilPackage(lua) },
};
}
std::map<std::string, sol::object> initGlobalPackages(const Context& context)
{ {
sol::table res(context.mLua->sol(), sol::create); initObjectBindingsForGlobalScripts(context);
res["globalSection"] initCellBindingsForGlobalScripts(context);
= [globalStorage](std::string_view section) { return globalStorage->getMutableSection(section); }; return {
res["allGlobalSections"] = [globalStorage]() { return globalStorage->getAllSections(); }; { "openmw.world", initWorldPackage(context) },
return LuaUtil::makeReadOnly(res); };
} }
sol::table initLocalStoragePackage(const Context& context, LuaUtil::LuaStorage* globalStorage) std::map<std::string, sol::object> initLocalPackages(const Context& context)
{ {
sol::table res(context.mLua->sol(), sol::create); initObjectBindingsForLocalScripts(context);
res["globalSection"] initCellBindingsForLocalScripts(context);
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); }; LocalScripts::initializeSelfPackage(context);
return LuaUtil::makeReadOnly(res); return {
{ "openmw.nearby", initNearbyPackage(context) },
};
} }
sol::table initPlayerStoragePackage( std::map<std::string, sol::object> initPlayerPackages(const Context& context)
const Context& context, LuaUtil::LuaStorage* globalStorage, LuaUtil::LuaStorage* playerStorage)
{ {
sol::table res(context.mLua->sol(), sol::create); return {
res["globalSection"] { "openmw.camera", initCameraPackage(context.mLua->sol()) },
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); }; { "openmw.debug", initDebugPackage(context) },
res["playerSection"] { "openmw.input", initInputPackage(context) },
= [playerStorage](std::string_view section) { return playerStorage->getMutableSection(section); }; { "openmw.postprocessing", initPostprocessingPackage(context) },
res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); }; { "openmw.ui", initUserInterfacePackage(context) },
return LuaUtil::makeReadOnly(res); };
} }
} }

@ -1,49 +1,25 @@
#ifndef MWLUA_LUABINDINGS_H #ifndef MWLUA_LUABINDINGS_H
#define MWLUA_LUABINDINGS_H #define MWLUA_LUABINDINGS_H
#include <components/lua/scriptscontainer.hpp> #include <map>
#include <components/lua/storage.hpp> #include <sol/forward.hpp>
#include <string>
#include "context.hpp" #include "context.hpp"
namespace MWWorld
{
class CellStore;
}
namespace MWLua namespace MWLua
{ {
// Initialize Lua packages that are available for all scripts.
std::map<std::string, sol::object> initCommonPackages(const Context&);
sol::table initCorePackage(const Context&); // Initialize Lua packages that are available only for global scripts.
sol::table initWorldPackage(const Context&); std::map<std::string, sol::object> initGlobalPackages(const Context&);
sol::table initPostprocessingPackage(const Context&);
sol::table initGlobalStoragePackage(const Context&, LuaUtil::LuaStorage* globalStorage);
sol::table initLocalStoragePackage(const Context&, LuaUtil::LuaStorage* globalStorage);
sol::table initPlayerStoragePackage(
const Context&, LuaUtil::LuaStorage* globalStorage, LuaUtil::LuaStorage* playerStorage);
// Implemented in nearbybindings.cpp
sol::table initNearbyPackage(const Context&);
// Implemented in objectbindings.cpp
void initObjectBindingsForLocalScripts(const Context&);
void initObjectBindingsForGlobalScripts(const Context&);
// Implemented in cellbindings.cpp
void initCellBindingsForLocalScripts(const Context&);
void initCellBindingsForGlobalScripts(const Context&);
// Implemented in camerabindings.cpp
sol::table initCameraPackage(const Context&);
// Implemented in uibindings.cpp
sol::table initUserInterfacePackage(const Context&);
// Implemented in inputbindings.cpp // Initialize Lua packages that are available only for local scripts (including player scripts).
sol::table initInputPackage(const Context&); std::map<std::string, sol::object> initLocalPackages(const Context&);
// openmw.self package is implemented in localscripts.cpp // Initialize Lua packages that are available only for local scripts on the player.
std::map<std::string, sol::object> initPlayerPackages(const Context&);
} }
#endif // MWLUA_LUABINDINGS_H #endif // MWLUA_LUABINDINGS_H

@ -12,13 +12,10 @@
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp> #include <components/esm3/esmwriter.hpp>
#include <components/settings/settings.hpp> #include <components/settings/values.hpp>
#include <components/l10n/manager.hpp> #include <components/l10n/manager.hpp>
#include <components/lua/asyncpackage.hpp>
#include <components/lua/utilpackage.hpp>
#include <components/lua_ui/content.hpp> #include <components/lua_ui/content.hpp>
#include <components/lua_ui/util.hpp> #include <components/lua_ui/util.hpp>
@ -31,7 +28,6 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/scene.hpp" #include "../mwworld/scene.hpp"
#include "debugbindings.hpp"
#include "luabindings.hpp" #include "luabindings.hpp"
#include "playerscripts.hpp" #include "playerscripts.hpp"
#include "types/types.hpp" #include "types/types.hpp"
@ -42,12 +38,12 @@ namespace MWLua
static LuaUtil::LuaStateSettings createLuaStateSettings() static LuaUtil::LuaStateSettings createLuaStateSettings()
{ {
if (!Settings::Manager::getBool("lua profiler", "Lua")) if (!Settings::lua().mLuaProfiler)
LuaUtil::LuaState::disableProfiler(); LuaUtil::LuaState::disableProfiler();
return { .mInstructionLimit = Settings::Manager::getUInt64("instruction limit per call", "Lua"), return { .mInstructionLimit = Settings::lua().mInstructionLimitPerCall,
.mMemoryLimit = Settings::Manager::getUInt64("memory limit", "Lua"), .mMemoryLimit = Settings::lua().mMemoryLimit,
.mSmallAllocMaxSize = Settings::Manager::getUInt64("small alloc max size", "Lua"), .mSmallAllocMaxSize = Settings::lua().mSmallAllocMaxSize,
.mLogMemoryUsage = Settings::Manager::getBool("log memory usage", "Lua") }; .mLogMemoryUsage = Settings::lua().mLogMemoryUsage };
} }
LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir) LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir)
@ -88,31 +84,21 @@ namespace MWLua
localContext.mIsGlobal = false; localContext.mIsGlobal = false;
localContext.mSerializer = mLocalSerializer.get(); localContext.mSerializer = mLocalSerializer.get();
initObjectBindingsForGlobalScripts(context); for (const auto& [name, package] : initCommonPackages(context))
initCellBindingsForGlobalScripts(context); mLua.addCommonPackage(name, package);
initObjectBindingsForLocalScripts(localContext); for (const auto& [name, package] : initGlobalPackages(context))
initCellBindingsForLocalScripts(localContext); mGlobalScripts.addPackage(name, package);
LocalScripts::initializeSelfPackage(localContext);
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
mLua.addCommonPackage("openmw.async", mLocalPackages = initLocalPackages(localContext);
LuaUtil::getAsyncPackageInitializer( mPlayerPackages = initPlayerPackages(localContext);
mLua.sol(), [this] { return mWorldView.getSimulationTime(); }, mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
[this] { return mWorldView.getGameTime(); }));
mLua.addCommonPackage("openmw.util", LuaUtil::initUtilPackage(mLua.sol())); LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
mLua.addCommonPackage("openmw.core", initCorePackage(context)); mGlobalScripts.addPackage(
mLua.addCommonPackage("openmw.types", initTypesPackage(context)); "openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua.sol(), &mGlobalStorage));
mGlobalScripts.addPackage("openmw.world", initWorldPackage(context)); mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua.sol(), &mGlobalStorage);
mGlobalScripts.addPackage("openmw.storage", initGlobalStoragePackage(context, &mGlobalStorage)); mPlayerPackages["openmw.storage"]
= LuaUtil::LuaStorage::initPlayerPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage);
mCameraPackage = initCameraPackage(localContext);
mUserInterfacePackage = initUserInterfacePackage(localContext);
mInputPackage = initInputPackage(localContext);
mNearbyPackage = initNearbyPackage(localContext);
mLocalStoragePackage = initLocalStoragePackage(localContext, &mGlobalStorage);
mPlayerStoragePackage = initPlayerStoragePackage(localContext, &mGlobalStorage, &mPlayerStorage);
mPostprocessingPackage = initPostprocessingPackage(localContext);
mDebugPackage = initDebugPackage(localContext);
initConfiguration(); initConfiguration();
mInitialized = true; mInitialized = true;
@ -136,9 +122,8 @@ namespace MWLua
void LuaManager::update() void LuaManager::update()
{ {
static const int gcStepCount = Settings::Manager::getInt("gc steps per frame", "Lua"); if (Settings::lua().mGcStepsPerFrame > 0)
if (gcStepCount > 0) lua_gc(mLua.sol(), LUA_GCSTEP, Settings::lua().mGcStepsPerFrame);
lua_gc(mLua.sol(), LUA_GCSTEP, gcStepCount);
if (mPlayer.isEmpty()) if (mPlayer.isEmpty())
return; // The game is not started yet. return; // The game is not started yet.
@ -147,7 +132,7 @@ namespace MWLua
MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (!(getId(mPlayer) == getId(newPlayerPtr))) if (!(getId(mPlayer) == getId(newPlayerPtr)))
throw std::logic_error("Player Refnum was changed unexpectedly"); throw std::logic_error("Player RefNum was changed unexpectedly");
if (!mPlayer.isInCell() || !newPlayerPtr.isInCell() || mPlayer.getCell() != newPlayerPtr.getCell()) if (!mPlayer.isInCell() || !newPlayerPtr.isInCell() || mPlayer.getCell() != newPlayerPtr.getCell())
{ {
mPlayer = newPlayerPtr; // player was moved to another cell, update ptr in registry mPlayer = newPlayerPtr; // player was moved to another cell, update ptr in registry
@ -220,12 +205,12 @@ namespace MWLua
windowManager->printToConsole(msg, "#" + color.toHex()); windowManager->printToConsole(msg, "#" + color.toHex());
mInGameConsoleMessages.clear(); mInGameConsoleMessages.clear();
for (std::unique_ptr<Action>& action : mActionQueue) for (DelayedAction& action : mActionQueue)
action->safeApply(); action.apply();
mActionQueue.clear(); mActionQueue.clear();
if (mTeleportPlayerAction) if (mTeleportPlayerAction)
mTeleportPlayerAction->safeApply(); mTeleportPlayerAction->apply();
mTeleportPlayerAction.reset(); mTeleportPlayerAction.reset();
} }
@ -352,12 +337,8 @@ namespace MWLua
{ {
scripts = std::make_shared<PlayerScripts>(&mLua, LObject(getId(ptr))); scripts = std::make_shared<PlayerScripts>(&mLua, LObject(getId(ptr)));
scripts->setAutoStartConf(mConfiguration.getPlayerConf()); scripts->setAutoStartConf(mConfiguration.getPlayerConf());
scripts->addPackage("openmw.ui", mUserInterfacePackage); for (const auto& [name, package] : mPlayerPackages)
scripts->addPackage("openmw.camera", mCameraPackage); scripts->addPackage(name, package);
scripts->addPackage("openmw.input", mInputPackage);
scripts->addPackage("openmw.storage", mPlayerStoragePackage);
scripts->addPackage("openmw.postprocessing", mPostprocessingPackage);
scripts->addPackage("openmw.debug", mDebugPackage);
} }
else else
{ {
@ -365,9 +346,9 @@ namespace MWLua
if (!autoStartConf.has_value()) if (!autoStartConf.has_value())
autoStartConf = mConfiguration.getLocalConf(type, ptr.getCellRef().getRefId(), getId(ptr)); autoStartConf = mConfiguration.getLocalConf(type, ptr.getCellRef().getRefId(), getId(ptr));
scripts->setAutoStartConf(std::move(*autoStartConf)); scripts->setAutoStartConf(std::move(*autoStartConf));
scripts->addPackage("openmw.storage", mLocalStoragePackage); for (const auto& [name, package] : mLocalPackages)
scripts->addPackage(name, package);
} }
scripts->addPackage("openmw.nearby", mNearbyPackage);
scripts->setSerializer(mLocalSerializer.get()); scripts->setSerializer(mLocalSerializer.get());
MWWorld::RefData& refData = ptr.getRefData(); MWWorld::RefData& refData = ptr.getRefData();
@ -483,22 +464,23 @@ namespace MWLua
"No Lua handlers for console\n", MWBase::WindowManager::sConsoleColor_Error); "No Lua handlers for console\n", MWBase::WindowManager::sConsoleColor_Error);
} }
LuaManager::Action::Action(LuaUtil::LuaState* state) LuaManager::DelayedAction::DelayedAction(LuaUtil::LuaState* state, std::function<void()> fn, std::string_view name)
: mFn(std::move(fn))
, mName(name)
{ {
static const bool luaDebug = Settings::Manager::getBool("lua debug", "Lua"); if (Settings::lua().mLuaDebug)
if (luaDebug)
mCallerTraceback = state->debugTraceback(); mCallerTraceback = state->debugTraceback();
} }
void LuaManager::Action::safeApply() const void LuaManager::DelayedAction::apply() const
{ {
try try
{ {
apply(); mFn();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
Log(Debug::Error) << "Error in " << this->toString() << ": " << e.what(); Log(Debug::Error) << "Error in DelayedAction " << mName << ": " << e.what();
if (mCallerTraceback.empty()) if (mCallerTraceback.empty())
Log(Debug::Error) << "Set 'lua_debug=true' in settings.cfg to enable action tracebacks"; Log(Debug::Error) << "Set 'lua_debug=true' in settings.cfg to enable action tracebacks";
@ -507,35 +489,14 @@ namespace MWLua
} }
} }
namespace
{
class FunctionAction final : public LuaManager::Action
{
public:
FunctionAction(LuaUtil::LuaState* state, std::function<void()> fn, std::string_view name)
: Action(state)
, mFn(std::move(fn))
, mName(name)
{
}
void apply() const override { mFn(); }
std::string toString() const override { return "FunctionAction " + mName; }
private:
std::function<void()> mFn;
std::string mName;
};
}
void LuaManager::addAction(std::function<void()> action, std::string_view name) void LuaManager::addAction(std::function<void()> action, std::string_view name)
{ {
mActionQueue.push_back(std::make_unique<FunctionAction>(&mLua, std::move(action), name)); mActionQueue.emplace_back(&mLua, std::move(action), name);
} }
void LuaManager::addTeleportPlayerAction(std::function<void()> action) void LuaManager::addTeleportPlayerAction(std::function<void()> action)
{ {
mTeleportPlayerAction = std::make_unique<FunctionAction>(&mLua, std::move(action), "TeleportPlayer"); mTeleportPlayerAction = DelayedAction(&mLua, std::move(action), "TeleportPlayer");
} }
void LuaManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const void LuaManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const
@ -566,7 +527,7 @@ namespace MWLua
out << (bytes / (1024 * 1024 * 1024)) << " GB"; out << (bytes / (1024 * 1024 * 1024)) << " GB";
}; };
static const uint64_t smallAllocSize = Settings::Manager::getUInt64("small alloc max size", "Lua"); const uint64_t smallAllocSize = Settings::lua().mSmallAllocMaxSize;
out << "Total memory usage:"; out << "Total memory usage:";
outMemSize(mLua.getTotalMemoryUsage()); outMemSize(mLua.getTotalMemoryUsage());
out << "\n"; out << "\n";

@ -1,16 +1,14 @@
#ifndef MWLUA_LUAMANAGERIMP_H #ifndef MWLUA_LUAMANAGERIMP_H
#define MWLUA_LUAMANAGERIMP_H #define MWLUA_LUAMANAGERIMP_H
#include <filesystem>
#include <map> #include <map>
#include <set> #include <set>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/storage.hpp> #include <components/lua/storage.hpp>
#include <components/lua_ui/resources.hpp> #include <components/lua_ui/resources.hpp>
#include <components/misc/color.hpp> #include <components/misc/color.hpp>
#include <filesystem>
#include "../mwbase/luamanager.hpp" #include "../mwbase/luamanager.hpp"
@ -88,24 +86,8 @@ namespace MWLua
} }
// Some changes to the game world can not be done from the scripting thread (because it runs in parallel with // Some changes to the game world can not be done from the scripting thread (because it runs in parallel with
// OSG Cull), so we need to queue it and apply from the main thread. All such changes should be implemented as // OSG Cull), so we need to queue it and apply from the main thread.
// classes inherited from MWLua::Action.
class Action
{
public:
Action(LuaUtil::LuaState* state);
virtual ~Action() {}
void safeApply() const;
virtual void apply() const = 0;
virtual std::string toString() const = 0;
private:
std::string mCallerTraceback;
};
void addAction(std::function<void()> action, std::string_view name = ""); void addAction(std::function<void()> action, std::string_view name = "");
void addAction(std::unique_ptr<Action>&& action) { mActionQueue.push_back(std::move(action)); }
void addTeleportPlayerAction(std::function<void()> action); void addTeleportPlayerAction(std::function<void()> action);
// Saving // Saving
@ -157,14 +139,8 @@ namespace MWLua
LuaUtil::ScriptsConfiguration mConfiguration; LuaUtil::ScriptsConfiguration mConfiguration;
LuaUtil::LuaState mLua; LuaUtil::LuaState mLua;
LuaUi::ResourceManager mUiResourceManager; LuaUi::ResourceManager mUiResourceManager;
sol::table mNearbyPackage; std::map<std::string, sol::object> mLocalPackages;
sol::table mUserInterfacePackage; std::map<std::string, sol::object> mPlayerPackages;
sol::table mCameraPackage;
sol::table mInputPackage;
sol::table mLocalStoragePackage;
sol::table mPlayerStoragePackage;
sol::table mPostprocessingPackage;
sol::table mDebugPackage;
GlobalScripts mGlobalScripts{ &mLua }; GlobalScripts mGlobalScripts{ &mLua };
std::set<LocalScripts*> mActiveLocalScripts; std::set<LocalScripts*> mActiveLocalScripts;
@ -191,8 +167,19 @@ namespace MWLua
std::vector<CallbackWithData> mQueuedCallbacks; std::vector<CallbackWithData> mQueuedCallbacks;
// Queued actions that should be done in main thread. Processed by applyQueuedChanges(). // Queued actions that should be done in main thread. Processed by applyQueuedChanges().
std::vector<std::unique_ptr<Action>> mActionQueue; class DelayedAction
std::unique_ptr<Action> mTeleportPlayerAction; {
public:
DelayedAction(LuaUtil::LuaState* state, std::function<void()> fn, std::string_view name);
void apply() const;
private:
std::string mCallerTraceback;
std::function<void()> mFn;
std::string mName;
};
std::vector<DelayedAction> mActionQueue;
std::optional<DelayedAction> mTeleportPlayerAction;
std::vector<std::string> mUIMessages; std::vector<std::string> mUIMessages;
std::vector<std::pair<std::string, Misc::Color>> mInGameConsoleMessages; std::vector<std::pair<std::string, Misc::Color>> mInGameConsoleMessages;

@ -1,4 +1,4 @@
#include "luabindings.hpp" #include "nearbybindings.hpp"
#include <components/detournavigator/navigator.hpp> #include <components/detournavigator/navigator.hpp>
#include <components/detournavigator/navigatorutils.hpp> #include <components/detournavigator/navigatorutils.hpp>

@ -0,0 +1,13 @@
#ifndef MWLUA_NEARBYBINDINGS_H
#define MWLUA_NEARBYBINDINGS_H
#include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua
{
sol::table initNearbyPackage(const Context&);
}
#endif // MWLUA_NEARBYBINDINGS_H

@ -1,4 +1,4 @@
#include "luabindings.hpp" #include "objectbindings.hpp"
#include <components/esm3/loadfact.hpp> #include <components/esm3/loadfact.hpp>
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>

@ -0,0 +1,12 @@
#ifndef MWLUA_OBJECTBINDINGS_H
#define MWLUA_OBJECTBINDINGS_H
#include "context.hpp"
namespace MWLua
{
void initObjectBindingsForLocalScripts(const Context&);
void initObjectBindingsForGlobalScripts(const Context&);
}
#endif // MWLUA_OBJECTBINDINGS_H

@ -1,43 +1,10 @@
#include "luabindings.hpp" #include "postprocessingbindings.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwrender/postprocessor.hpp" #include "../mwrender/postprocessor.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
namespace
{
template <class T>
class SetUniformShaderAction final : public MWLua::LuaManager::Action
{
public:
SetUniformShaderAction(
LuaUtil::LuaState* state, std::shared_ptr<fx::Technique> shader, const std::string& name, const T& value)
: MWLua::LuaManager::Action(state)
, mShader(std::move(shader))
, mName(name)
, mValue(value)
{
}
void apply() const override
{
MWBase::Environment::get().getWorld()->getPostProcessor()->setUniform(mShader, mName, mValue);
}
std::string toString() const override
{
return std::string("SetUniformShaderAction shader=") + (mShader ? mShader->getName() : "nil")
+ std::string("uniform=") + (mShader ? mName : "nil");
}
private:
std::shared_ptr<fx::Technique> mShader;
std::string mName;
T mValue;
};
}
namespace MWLua namespace MWLua
{ {
struct Shader; struct Shader;
@ -84,7 +51,10 @@ namespace MWLua
{ {
return [context](const Shader& shader, const std::string& name, const T& value) { return [context](const Shader& shader, const std::string& name, const T& value) {
context.mLuaManager->addAction( context.mLuaManager->addAction(
std::make_unique<SetUniformShaderAction<T>>(context.mLua, shader.mShader, name, value)); [&] {
MWBase::Environment::get().getWorld()->getPostProcessor()->setUniform(shader.mShader, name, value);
},
"SetUniformShaderAction");
}; };
} }
@ -114,7 +84,10 @@ namespace MWLua
} }
context.mLuaManager->addAction( context.mLuaManager->addAction(
std::make_unique<SetUniformShaderAction<std::vector<T>>>(context.mLua, shader.mShader, name, values)); [&] {
MWBase::Environment::get().getWorld()->getPostProcessor()->setUniform(shader.mShader, name, values);
},
"SetUniformShaderAction");
}; };
} }

@ -0,0 +1,13 @@
#ifndef MWLUA_POSTPROCESSINGBINDINGS_H
#define MWLUA_POSTPROCESSINGBINDINGS_H
#include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua
{
sol::table initPostprocessingPackage(const Context&);
}
#endif // MWLUA_POSTPROCESSINGBINDINGS_H

@ -55,29 +55,17 @@ namespace
namespace MWLua namespace MWLua
{ {
namespace static void addStatUpdateAction(MWLua::LuaManager* manager, const SelfObject& obj)
{ {
class StatUpdateAction final : public LuaManager::Action if (!obj.mStatsCache.empty())
{ return; // was already added before
ObjectId mId; manager->addAction(
[obj = Object(obj)] {
public:
StatUpdateAction(LuaUtil::LuaState* state, ObjectId id)
: Action(state)
, mId(id)
{
}
void apply() const override
{
LObject obj(mId);
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts(); LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
if (scripts) if (scripts)
scripts->applyStatsCache(); scripts->applyStatsCache();
} },
"StatUpdateAction");
std::string toString() const override { return "StatUpdateAction"; }
};
} }
class LevelStat class LevelStat
@ -99,8 +87,7 @@ namespace MWLua
void setCurrent(const Context& context, const sol::object& value) const void setCurrent(const Context& context, const sol::object& value) const
{ {
SelfObject* obj = mObject.asSelfObject(); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) addStatUpdateAction(context.mLuaManager, *obj);
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, 0, "current" }] = value; obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, 0, "current" }] = value;
} }
@ -158,8 +145,7 @@ namespace MWLua
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = mObject.asSelfObject(); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) addStatUpdateAction(context.mLuaManager, *obj);
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value;
} }
@ -217,8 +203,7 @@ namespace MWLua
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = mObject.asSelfObject(); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) addStatUpdateAction(context.mLuaManager, *obj);
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value;
} }
@ -302,8 +287,7 @@ namespace MWLua
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = mObject.asSelfObject(); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) addStatUpdateAction(context.mLuaManager, *obj);
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value;
} }

@ -18,107 +18,84 @@
namespace MWLua namespace MWLua
{ {
namespace using EquipmentItem = std::variant<std::string, ObjectId>;
using Equipment = std::map<int, EquipmentItem>;
static void setEquipment(const MWWorld::Ptr& actor, const Equipment& equipment)
{ {
class SetEquipmentAction final : public LuaManager::Action MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor);
{ std::array<bool, MWWorld::InventoryStore::Slots> usedSlots;
public: std::fill(usedSlots.begin(), usedSlots.end(), false);
using Item = std::variant<std::string, ObjectId>; // recordId or ObjectId
using Equipment = std::map<int, Item>; // slot to item
SetEquipmentAction(LuaUtil::LuaState* state, ObjectId actor, Equipment equipment) static constexpr int anySlot = -1;
: Action(state) auto tryEquipToSlot = [&store, &usedSlots](int slot, const EquipmentItem& item) -> bool {
, mActor(actor) auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
, mEquipment(std::move(equipment)) MWWorld::Ptr itemPtr;
if (std::holds_alternative<ObjectId>(item))
{ {
itemPtr = MWBase::Environment::get().getWorldModel()->getPtr(std::get<ObjectId>(item));
if (old_it != store.end() && *old_it == itemPtr)
return true; // already equipped
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0
|| itemPtr.getContainerStore() != static_cast<const MWWorld::ContainerStore*>(&store))
{
Log(Debug::Warning) << "Object" << std::get<ObjectId>(item).toString() << " is not in inventory";
return false;
}
} }
else
void apply() const override
{ {
MWWorld::Ptr actor = MWBase::Environment::get().getWorldModel()->getPtr(mActor); const ESM::RefId& recordId = ESM::RefId::stringRefId(std::get<std::string>(item));
MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); if (old_it != store.end() && old_it->getCellRef().getRefId() == recordId)
std::array<bool, MWWorld::InventoryStore::Slots> usedSlots; return true; // already equipped
std::fill(usedSlots.begin(), usedSlots.end(), false); itemPtr = store.search(recordId);
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0)
static constexpr int anySlot = -1; {
auto tryEquipToSlot = [&store, &usedSlots](int slot, const Item& item) -> bool { Log(Debug::Warning) << "There is no object with recordId='" << recordId << "' in inventory";
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end(); return false;
MWWorld::Ptr itemPtr; }
if (std::holds_alternative<ObjectId>(item)) }
{
itemPtr = MWBase::Environment::get().getWorldModel()->getPtr(std::get<ObjectId>(item));
if (old_it != store.end() && *old_it == itemPtr)
return true; // already equipped
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0
|| itemPtr.getContainerStore() != static_cast<const MWWorld::ContainerStore*>(&store))
{
Log(Debug::Warning)
<< "Object" << std::get<ObjectId>(item).toString() << " is not in inventory";
return false;
}
}
else
{
const ESM::RefId& recordId = ESM::RefId::stringRefId(std::get<std::string>(item));
if (old_it != store.end() && old_it->getCellRef().getRefId() == recordId)
return true; // already equipped
itemPtr = store.search(recordId);
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0)
{
Log(Debug::Warning) << "There is no object with recordId='" << recordId << "' in inventory";
return false;
}
}
auto [allowedSlots, _] = itemPtr.getClass().getEquipmentSlots(itemPtr);
bool requestedSlotIsAllowed
= std::find(allowedSlots.begin(), allowedSlots.end(), slot) != allowedSlots.end();
if (!requestedSlotIsAllowed)
{
auto firstAllowed = std::find_if(
allowedSlots.begin(), allowedSlots.end(), [&](int s) { return !usedSlots[s]; });
if (firstAllowed == allowedSlots.end())
{
Log(Debug::Warning) << "No suitable slot for " << itemPtr.toString();
return false;
}
slot = *firstAllowed;
}
// TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
MWWorld::ContainerStoreIterator it = std::find(store.begin(), store.end(), itemPtr);
if (it == store.end()) // should never happen
throw std::logic_error("Item not found in container");
store.equip(slot, it);
return requestedSlotIsAllowed; // return true if equipped to requested slot and false if slot was
// changed
};
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) auto [allowedSlots, _] = itemPtr.getClass().getEquipmentSlots(itemPtr);
bool requestedSlotIsAllowed
= std::find(allowedSlots.begin(), allowedSlots.end(), slot) != allowedSlots.end();
if (!requestedSlotIsAllowed)
{
auto firstAllowed
= std::find_if(allowedSlots.begin(), allowedSlots.end(), [&](int s) { return !usedSlots[s]; });
if (firstAllowed == allowedSlots.end())
{ {
auto old_it = store.getSlot(slot); Log(Debug::Warning) << "No suitable slot for " << itemPtr.toString();
auto new_it = mEquipment.find(slot); return false;
if (new_it == mEquipment.end())
{
if (old_it != store.end())
store.unequipSlot(slot);
continue;
}
if (tryEquipToSlot(slot, new_it->second))
usedSlots[slot] = true;
} }
for (const auto& [slot, item] : mEquipment) slot = *firstAllowed;
if (slot >= MWWorld::InventoryStore::Slots)
tryEquipToSlot(anySlot, item);
} }
std::string toString() const override { return "SetEquipmentAction"; } // TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
MWWorld::ContainerStoreIterator it = std::find(store.begin(), store.end(), itemPtr);
if (it == store.end()) // should never happen
throw std::logic_error("Item not found in container");
private: store.equip(slot, it);
ObjectId mActor; return requestedSlotIsAllowed; // return true if equipped to requested slot and false if slot was changed
Equipment mEquipment;
}; };
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
auto old_it = store.getSlot(slot);
auto new_it = equipment.find(slot);
if (new_it == equipment.end())
{
if (old_it != store.end())
store.unequipSlot(slot);
continue;
}
if (tryEquipToSlot(slot, new_it->second))
usedSlots[slot] = true;
}
for (const auto& [slot, item] : equipment)
if (slot >= MWWorld::InventoryStore::Slots)
tryEquipToSlot(anySlot, item);
} }
void addActorBindings(sol::table actor, const Context& context) void addActorBindings(sol::table actor, const Context& context)
@ -263,13 +240,14 @@ namespace MWLua
return store.isEquipped(item.ptr()); return store.isEquipped(item.ptr());
}; };
actor["setEquipment"] = [context](const SelfObject& obj, const sol::table& equipment) { actor["setEquipment"] = [context](const SelfObject& obj, const sol::table& equipment) {
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr())) const MWWorld::Ptr& ptr = obj.ptr();
if (!ptr.getClass().hasInventoryStore(ptr))
{ {
if (!equipment.empty()) if (!equipment.empty())
throw std::runtime_error(obj.toString() + " has no equipment slots"); throw std::runtime_error(obj.toString() + " has no equipment slots");
return; return;
} }
SetEquipmentAction::Equipment eqp; Equipment eqp;
for (auto& [key, value] : equipment) for (auto& [key, value] : equipment)
{ {
int slot = LuaUtil::cast<int>(key); int slot = LuaUtil::cast<int>(key);
@ -279,7 +257,7 @@ namespace MWLua
eqp[slot] = LuaUtil::cast<std::string>(value); eqp[slot] = LuaUtil::cast<std::string>(value);
} }
context.mLuaManager->addAction( context.mLuaManager->addAction(
std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp))); [obj = Object(ptr), eqp = std::move(eqp)] { setEquipment(obj.ptr(), eqp); }, "SetEquipmentAction");
}; };
actor["getPathfindingAgentBounds"] = [](sol::this_state lua, const LObject& o) { actor["getPathfindingAgentBounds"] = [](sol::this_state lua, const LObject& o) {
const DetourNavigator::AgentBounds agentBounds const DetourNavigator::AgentBounds agentBounds

@ -1,3 +1,5 @@
#include "uibindings.hpp"
#include <components/lua_ui/alignment.hpp> #include <components/lua_ui/alignment.hpp>
#include <components/lua_ui/content.hpp> #include <components/lua_ui/content.hpp>
#include <components/lua_ui/element.hpp> #include <components/lua_ui/element.hpp>
@ -18,71 +20,20 @@ namespace MWLua
{ {
namespace namespace
{ {
class UiAction final : public LuaManager::Action template <typename Fn>
void wrapAction(const std::shared_ptr<LuaUi::Element>& element, Fn&& fn)
{ {
public: try
enum Type
{
CREATE = 0,
UPDATE,
DESTROY,
};
UiAction(Type type, std::shared_ptr<LuaUi::Element> element, LuaUtil::LuaState* state)
: Action(state)
, mType{ type }
, mElement{ std::move(element) }
{ {
fn();
} }
catch (...)
void apply() const override
{ {
try // prevent any actions on a potentially corrupted widget
{ element->mRoot = nullptr;
switch (mType) throw;
{
case CREATE:
mElement->create();
break;
case UPDATE:
mElement->update();
break;
case DESTROY:
mElement->destroy();
break;
}
}
catch (std::exception&)
{
// prevent any actions on a potentially corrupted widget
mElement->mRoot = nullptr;
throw;
}
} }
}
std::string toString() const override
{
std::string result;
switch (mType)
{
case CREATE:
result += "Create";
break;
case UPDATE:
result += "Update";
break;
case DESTROY:
result += "Destroy";
break;
}
result += " UI";
return result;
}
private:
Type mType;
std::shared_ptr<LuaUi::Element> mElement;
};
// Lua arrays index from 1 // Lua arrays index from 1
inline size_t fromLuaIndex(size_t i) inline size_t fromLuaIndex(size_t i)
@ -100,17 +51,17 @@ namespace MWLua
auto element = context.mLua->sol().new_usertype<LuaUi::Element>("Element"); auto element = context.mLua->sol().new_usertype<LuaUi::Element>("Element");
element["layout"] = sol::property([](LuaUi::Element& element) { return element.mLayout; }, element["layout"] = sol::property([](LuaUi::Element& element) { return element.mLayout; },
[](LuaUi::Element& element, const sol::table& layout) { element.mLayout = layout; }); [](LuaUi::Element& element, const sol::table& layout) { element.mLayout = layout; });
element["update"] = [context](const std::shared_ptr<LuaUi::Element>& element) { element["update"] = [luaManager = context.mLuaManager](const std::shared_ptr<LuaUi::Element>& element) {
if (element->mDestroy || element->mUpdate) if (element->mDestroy || element->mUpdate)
return; return;
element->mUpdate = true; element->mUpdate = true;
context.mLuaManager->addAction(std::make_unique<UiAction>(UiAction::UPDATE, element, context.mLua)); luaManager->addAction([element] { wrapAction(element, [&] { element->update(); }); }, "Update UI");
}; };
element["destroy"] = [context](const std::shared_ptr<LuaUi::Element>& element) { element["destroy"] = [luaManager = context.mLuaManager](const std::shared_ptr<LuaUi::Element>& element) {
if (element->mDestroy) if (element->mDestroy)
return; return;
element->mDestroy = true; element->mDestroy = true;
context.mLuaManager->addAction(std::make_unique<UiAction>(UiAction::DESTROY, element, context.mLua)); luaManager->addAction([element] { wrapAction(element, [&] { element->destroy(); }); }, "Destroy UI");
}; };
sol::table api = context.mLua->newTable(); sol::table api = context.mLua->newTable();
@ -142,9 +93,9 @@ namespace MWLua
} }
}; };
api["content"] = LuaUi::loadContentConstructor(context.mLua); api["content"] = LuaUi::loadContentConstructor(context.mLua);
api["create"] = [context](const sol::table& layout) { api["create"] = [luaManager = context.mLuaManager](const sol::table& layout) {
auto element = LuaUi::Element::make(layout); auto element = LuaUi::Element::make(layout);
context.mLuaManager->addAction(std::make_unique<UiAction>(UiAction::CREATE, element, context.mLua)); luaManager->addAction([element] { wrapAction(element, [&] { element->create(); }); }, "Create UI");
return element; return element;
}; };
api["updateAll"] = [context]() { api["updateAll"] = [context]() {

@ -0,0 +1,13 @@
#ifndef MWLUA_UIBINDINGS_H
#define MWLUA_UIBINDINGS_H
#include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua
{
sol::table initUserInterfacePackage(const Context&);
}
#endif // MWLUA_UIBINDINGS_H

@ -4,7 +4,7 @@
#include <apps/openmw/profile.hpp> #include <apps/openmw/profile.hpp>
#include <components/settings/settings.hpp> #include <components/settings/values.hpp>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
@ -14,7 +14,7 @@ namespace MWLua
: mManager(manager) : mManager(manager)
, mViewer(viewer) , mViewer(viewer)
{ {
if (Settings::Manager::getInt("lua num threads", "Lua") > 0) if (Settings::lua().mLuaNumThreads > 0)
mThread = std::thread([this] { run(); }); mThread = std::thread([this] { run(); });
} }

@ -316,7 +316,7 @@ namespace LuaUtil
{ {
if (!package.is<sol::function>()) if (!package.is<sol::function>())
package = makeReadOnly(std::move(package)); package = makeReadOnly(std::move(package));
mCommonPackages.emplace(std::move(packageName), std::move(package)); mCommonPackages.insert_or_assign(std::move(packageName), std::move(package));
} }
sol::protected_function_result LuaState::runInNewSandbox(const std::string& path, const std::string& namePrefix, sol::protected_function_result LuaState::runInNewSandbox(const std::string& path, const std::string& namePrefix,

@ -35,7 +35,7 @@ namespace LuaUtil
void ScriptsContainer::addPackage(std::string packageName, sol::object package) void ScriptsContainer::addPackage(std::string packageName, sol::object package)
{ {
mAPI.emplace(std::move(packageName), makeReadOnly(std::move(package))); mAPI.insert_or_assign(std::move(packageName), makeReadOnly(std::move(package)));
} }
bool ScriptsContainer::addCustomScript(int scriptId, std::string_view initData) bool ScriptsContainer::addCustomScript(int scriptId, std::string_view initData)

@ -138,6 +138,34 @@ namespace LuaUtil
}; };
} }
sol::table LuaStorage::initGlobalPackage(lua_State* lua, LuaStorage* globalStorage)
{
sol::table res(lua, sol::create);
res["globalSection"]
= [globalStorage](std::string_view section) { return globalStorage->getMutableSection(section); };
res["allGlobalSections"] = [globalStorage]() { return globalStorage->getAllSections(); };
return LuaUtil::makeReadOnly(res);
}
sol::table LuaStorage::initLocalPackage(lua_State* lua, LuaStorage* globalStorage)
{
sol::table res(lua, sol::create);
res["globalSection"]
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
return LuaUtil::makeReadOnly(res);
}
sol::table LuaStorage::initPlayerPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage)
{
sol::table res(lua, sol::create);
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(); };
return LuaUtil::makeReadOnly(res);
}
void LuaStorage::clearTemporaryAndRemoveCallbacks() void LuaStorage::clearTemporaryAndRemoveCallbacks()
{ {
auto it = mData.begin(); auto it = mData.begin();

@ -14,6 +14,9 @@ namespace LuaUtil
{ {
public: public:
static void initLuaBindings(lua_State*); static void initLuaBindings(lua_State*);
static sol::table initGlobalPackage(lua_State* lua, LuaStorage* globalStorage);
static sol::table initLocalPackage(lua_State* lua, LuaStorage* globalStorage);
static sol::table initPlayerPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage);
explicit LuaStorage(lua_State* lua) explicit LuaStorage(lua_State* lua)
: mLua(lua) : mLua(lua)

Loading…
Cancel
Save