From 9904be916012ffdbb031dd5dcbab706d50bbcdfc Mon Sep 17 00:00:00 2001 From: cheapie Date: Sun, 21 Mar 2021 00:56:38 -0500 Subject: [PATCH 1/2] 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. --- mesecons/util.lua | 19 +++++++++++++++++++ mesecons_luacontroller/init.lua | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/mesecons/util.lua b/mesecons/util.lua index 3cdeb64..d5d42ef 100644 --- a/mesecons/util.lua +++ b/mesecons/util.lua @@ -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. diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua index 1c411dd..44880c9 100644 --- a/mesecons_luacontroller/init.lua +++ b/mesecons_luacontroller/init.lua @@ -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 From 91e3b13d5acf40af5531994eb7eb847de5f6afcc Mon Sep 17 00:00:00 2001 From: cheapie Date: Fri, 26 Mar 2021 14:43:08 -0500 Subject: [PATCH 2/2] Luacontroller library enhancements Libraries can now be registered as a function which will be called when the library is requested. This allows functionality such as libraries that behave differently depending on where the Luacontroller is (for example, a sensor of some sort that only works if the LuaC is next to it) as well as various initialization that the library may need to perform. Supplying a table is still supported and works as before. --- mesecons/util.lua | 5 ++--- mesecons_luacontroller/init.lua | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/mesecons/util.lua b/mesecons/util.lua index d5d42ef..5f957b8 100644 --- a/mesecons/util.lua +++ b/mesecons/util.lua @@ -201,9 +201,8 @@ function mesecon.tablecopy_change_env(t, env, seen) 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 + setfenv(v, env) + n[(type(k) == "table" and (seen[k] or mesecon.tablecopy_change_env(k, env, seen))) or k] = v 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 diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua index 44880c9..d9bafb5 100644 --- a/mesecons_luacontroller/init.lua +++ b/mesecons_luacontroller/init.lua @@ -459,12 +459,20 @@ local function get_digiline_send(pos, itbl, send_warning) end end +-- Mods can place their own "libraries" in here to be loaded via require() from in a Luacontroller. +-- These can take two different forms: +-- Function (recommended for libraries adding new functionality): A function that, when called, returns something that will be passed to the LuaC code. +-- Function signature is getlibrary(env, pos) where 'env' is the environment that the Luacontroller code is running in, and 'pos' is the position of the controller. +-- Table (recommended for libraries containing mostly lookup tables): A table that will be copied, and the copy returned to the LuaC code. +-- When using the table format, any functions in the table will have their environment changed to that of the Luacontroller. mesecon.luacontroller_libraries = {} -local function get_require(env) +local function get_require(pos, env) return function(name) - if mesecon.luacontroller_libraries[name] then - return mesecon.tablecopy_change_env(mesecon.luacontroller_libraries[name],env) + if type(mesecon.luacontroller_libraries[name]) == "function" then + return mesecon.luacontroller_libraries[name](env, pos) + elseif type(mesecon.luacontroller_libraries[name]) == "table" then + return mesecon.tablecopy_change_env(mesecon.luacontroller_libraries[name], env) end end end @@ -557,7 +565,7 @@ local function create_environment(pos, mem, event, itbl, send_warning) env[name] = _G[name] end - env.require = get_require(env) + env.require = get_require(pos, env) return env end