1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-31 21:45:35 +00:00

Merge branch 'fix_6694' into 'master'

Fix #6694 and add a couple of utility functions

Closes #6694

See merge request OpenMW/openmw!1775
This commit is contained in:
uramer 2022-04-14 14:51:33 +00:00
commit 934c637c30
3 changed files with 45 additions and 17 deletions

View file

@ -46,7 +46,7 @@ namespace LuaUtil
static const std::string safeFunctions[] = { static const std::string safeFunctions[] = {
"assert", "error", "ipairs", "next", "pairs", "pcall", "select", "tonumber", "tostring", "assert", "error", "ipairs", "next", "pairs", "pcall", "select", "tonumber", "tostring",
"type", "unpack", "xpcall", "rawequal", "rawget", "rawset", "getmetatable", "setmetatable"}; "type", "unpack", "xpcall", "rawequal", "rawget", "rawset", "setmetatable"};
static const std::string safePackages[] = {"coroutine", "math", "string", "table"}; static const std::string safePackages[] = {"coroutine", "math", "string", "table"};
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs) LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs)
@ -58,7 +58,6 @@ namespace LuaUtil
mLua["math"]["randomseed"] = []{}; mLua["math"]["randomseed"] = []{};
mLua["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; }; mLua["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
mLua["cmetatable"] = [](const sol::table& v) -> sol::object { return v[sol::metatable_key]; };
// Some fixes for compatibility between different Lua versions // Some fixes for compatibility between different Lua versions
if (mLua["unpack"] == sol::nil) if (mLua["unpack"] == sol::nil)
@ -70,29 +69,35 @@ namespace LuaUtil
mLua.script(R"( mLua.script(R"(
local _pairs = pairs local _pairs = pairs
local _ipairs = ipairs local _ipairs = ipairs
local _cmeta = cmetatable pairs = function(v) return (rawget(getmetatable(v) or {}, '__pairs') or _pairs)(v) end
pairs = function(v) return ((_cmeta(v) or v).__pairs or _pairs)(v) end ipairs = function(v) return (rawget(getmetatable(v) or {}, '__ipairs') or _ipairs)(v) end
ipairs = function(v) return ((_cmeta(v) or v).__ipairs or _ipairs)(v) end
)"); )");
} }
mLua.script(R"( mLua.script(R"(
local _pairs = pairs local printToLog = function(...)
local _ipairs = ipairs local strs = {}
local _tostring = tostring for i = 1, select('#', ...) do
local _write = writeToLog strs[i] = tostring(select(i, ...))
local printToLog = function(name, ...)
local msg = name
for _, v in _ipairs({...}) do
msg = msg .. '\t' .. _tostring(v)
end end
return _write(msg) return writeToLog(table.concat(strs, '\t'))
end end
printGen = function(name) return function(...) return printToLog(name, ...) end end printGen = function(name) return function(...) return printToLog(name, ...) end end
local _cmeta = cmetatable function pairsForReadOnly(v)
function pairsForReadOnly(v) return _pairs(_cmeta(v).__index) end local nextFn, t, firstKey = pairs(getmetatable(v).__index)
function ipairsForReadOnly(v) return _ipairs(_cmeta(v).__index) end return function(_, k) return nextFn(t, k) end, v, firstKey
end
function ipairsForReadOnly(v)
local nextFn, t, firstKey = ipairs(getmetatable(v).__index)
return function(_, k) return nextFn(t, k) end, v, firstKey
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(mLua, sol::create); mSandboxEnv = sol::table(mLua, sol::create);
@ -107,6 +112,7 @@ namespace LuaUtil
if (mLua[s] == sol::nil) throw std::logic_error("Lua package not found: " + s); if (mLua[s] == sol::nil) throw std::logic_error("Lua package not found: " + s);
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mLua[s]); mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mLua[s]);
} }
mSandboxEnv["getmetatable"] = mLua["getSafeMetatable"];
mCommonPackages["os"] = mSandboxEnv["os"] = makeReadOnly(tableFromPairs<std::string_view, sol::function>({ mCommonPackages["os"] = mSandboxEnv["os"] = makeReadOnly(tableFromPairs<std::string_view, sol::function>({
{"date", mLua["os"]["date"]}, {"date", mLua["os"]["date"]},
{"difftime", mLua["os"]["difftime"]}, {"difftime", mLua["os"]["difftime"]},
@ -162,6 +168,8 @@ namespace LuaUtil
sol::environment env(mLua, sol::create, mSandboxEnv); sol::environment env(mLua, sol::create, mSandboxEnv);
std::string envName = namePrefix + "[" + path + "]:"; std::string envName = namePrefix + "[" + path + "]:";
env["print"] = mLua["printGen"](envName); env["print"] = mLua["printGen"](envName);
env["_G"] = env;
env[sol::metatable_key]["__metatable"] = false;
auto maybeRunLoader = [&hiddenData](const sol::object& package) -> sol::object auto maybeRunLoader = [&hiddenData](const sol::object& package) -> sol::object
{ {

View file

@ -247,6 +247,19 @@ namespace LuaUtil
util["bitNot"] = [](unsigned a) { return ~a; }; util["bitNot"] = [](unsigned a) { return ~a; };
} }
util["loadCode"] = [](const std::string& code, const sol::table& env, sol::this_state s)
{
sol::state_view lua(s);
sol::load_result res = lua.load(code, "", sol::load_mode::text);
if (!res.valid())
throw std::runtime_error("Lua error: " + res.get<std::string>());
sol::function fn = res;
sol::environment newEnv(lua, sol::create, env);
newEnv[sol::metatable_key][sol::meta_function::new_index] = env;
sol::set_environment(newEnv, fn);
return fn;
};
return util; return util;
} }

View file

@ -25,6 +25,13 @@
-- @param #table table Any table. -- @param #table table Any table.
-- @return #table The same table wrapped with read only userdata. -- @return #table The same table wrapped with read only userdata.
---
-- Parses Lua code from string and returns as a function.
-- @function [parent=#util] loadCode
-- @param #string code Lua code.
-- @param #table table Environment to run the code in.
-- @return #function The loaded code.
--- ---
-- Bitwise And (supports any number of arguments). -- Bitwise And (supports any number of arguments).
-- @function [parent=#util] bitAnd -- @function [parent=#util] bitAnd