mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-31 18:45:36 +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:
commit
934c637c30
3 changed files with 45 additions and 17 deletions
|
@ -46,7 +46,7 @@ namespace LuaUtil
|
|||
|
||||
static const std::string safeFunctions[] = {
|
||||
"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"};
|
||||
|
||||
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs)
|
||||
|
@ -58,7 +58,6 @@ namespace LuaUtil
|
|||
mLua["math"]["randomseed"] = []{};
|
||||
|
||||
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
|
||||
if (mLua["unpack"] == sol::nil)
|
||||
|
@ -70,29 +69,35 @@ namespace LuaUtil
|
|||
mLua.script(R"(
|
||||
local _pairs = pairs
|
||||
local _ipairs = ipairs
|
||||
local _cmeta = cmetatable
|
||||
pairs = function(v) return ((_cmeta(v) or v).__pairs or _pairs)(v) end
|
||||
ipairs = function(v) return ((_cmeta(v) or v).__ipairs or _ipairs)(v) end
|
||||
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
|
||||
)");
|
||||
}
|
||||
|
||||
mLua.script(R"(
|
||||
local _pairs = pairs
|
||||
local _ipairs = ipairs
|
||||
local _tostring = tostring
|
||||
local _write = writeToLog
|
||||
local printToLog = function(name, ...)
|
||||
local msg = name
|
||||
for _, v in _ipairs({...}) do
|
||||
msg = msg .. '\t' .. _tostring(v)
|
||||
local printToLog = function(...)
|
||||
local strs = {}
|
||||
for i = 1, select('#', ...) do
|
||||
strs[i] = tostring(select(i, ...))
|
||||
end
|
||||
return _write(msg)
|
||||
return writeToLog(table.concat(strs, '\t'))
|
||||
end
|
||||
printGen = function(name) return function(...) return printToLog(name, ...) end end
|
||||
|
||||
local _cmeta = cmetatable
|
||||
function pairsForReadOnly(v) return _pairs(_cmeta(v).__index) end
|
||||
function ipairsForReadOnly(v) return _ipairs(_cmeta(v).__index) end
|
||||
function pairsForReadOnly(v)
|
||||
local nextFn, t, firstKey = pairs(getmetatable(v).__index)
|
||||
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);
|
||||
|
@ -107,6 +112,7 @@ namespace LuaUtil
|
|||
if (mLua[s] == sol::nil) throw std::logic_error("Lua package not found: " + s);
|
||||
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mLua[s]);
|
||||
}
|
||||
mSandboxEnv["getmetatable"] = mLua["getSafeMetatable"];
|
||||
mCommonPackages["os"] = mSandboxEnv["os"] = makeReadOnly(tableFromPairs<std::string_view, sol::function>({
|
||||
{"date", mLua["os"]["date"]},
|
||||
{"difftime", mLua["os"]["difftime"]},
|
||||
|
@ -162,6 +168,8 @@ namespace LuaUtil
|
|||
sol::environment env(mLua, sol::create, mSandboxEnv);
|
||||
std::string envName = namePrefix + "[" + path + "]:";
|
||||
env["print"] = mLua["printGen"](envName);
|
||||
env["_G"] = env;
|
||||
env[sol::metatable_key]["__metatable"] = false;
|
||||
|
||||
auto maybeRunLoader = [&hiddenData](const sol::object& package) -> sol::object
|
||||
{
|
||||
|
|
|
@ -247,6 +247,19 @@ namespace LuaUtil
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
-- @param #table table Any table.
|
||||
-- @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).
|
||||
-- @function [parent=#util] bitAnd
|
||||
|
|
Loading…
Reference in a new issue