Add library support to Luacontrollers

This allows mods to provide their own libraries that can be accessed from within a Luacontroller, for example to make working with advanced digilines peripherals somewhat easier.
Libraries can be added to the mesecon.luacontroller_libraries table, and then the code running in the Luacontroller can use require() to request one. require() will return nil if the library is not present.
This commit is contained in:
cheapie 2021-03-21 00:56:38 -05:00
parent 93aa24dc42
commit 9904be9160
2 changed files with 31 additions and 0 deletions

View File

@ -193,6 +193,25 @@ function mesecon.tablecopy(obj) -- deep copy
return obj
end
-- Performs a deep copy of a table, changing the environment of any functions.
-- Adapted from the builtin table.copy() function.
function mesecon.tablecopy_change_env(t, env, seen)
local n = {}
seen = seen or {}
seen[t] = n
for k, v in pairs(t) do
if type(v) == "function" then
local newfunc = v
setfenv(newfunc, env)
n[(type(k) == "table" and (seen[k] or mesecon.tablecopy_change_env(k, env, seen))) or k] = newfunc
else
n[(type(k) == "table" and (seen[k] or mesecon.tablecopy_change_env(k, env, seen))) or k] =
(type(v) == "table" and (seen[v] or mesecon.tablecopy_change_env(v, env, seen))) or v
end
end
return n
end
-- Returns whether two values are equal.
-- In tables, keys are compared for identity but values are compared recursively.
-- There is no protection from infinite recursion.

View File

@ -459,6 +459,16 @@ local function get_digiline_send(pos, itbl, send_warning)
end
end
mesecon.luacontroller_libraries = {}
local function get_require(env)
return function(name)
if mesecon.luacontroller_libraries[name] then
return mesecon.tablecopy_change_env(mesecon.luacontroller_libraries[name],env)
end
end
end
local safe_globals = {
-- Don't add pcall/xpcall unless willing to deal with the consequences (unless very careful, incredibly likely to allow killing server indirectly)
"assert", "error", "ipairs", "next", "pairs", "select",
@ -546,6 +556,8 @@ local function create_environment(pos, mem, event, itbl, send_warning)
for _, name in pairs(safe_globals) do
env[name] = _G[name]
end
env.require = get_require(env)
return env
end