From 1e4156d0a4e42b519ca2f64f4146c7a7faec49a3 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 17 Feb 2021 19:10:40 +0100 Subject: [PATCH] LuaATC: Improve error/print logging, log only to subscribed players --- advtrains_luaautomation/active_common.lua | 9 +-- advtrains_luaautomation/chatcmds.lua | 68 ++++++++++++++++++++++- advtrains_luaautomation/environment.lua | 55 +++++++++--------- 3 files changed, 99 insertions(+), 33 deletions(-) diff --git a/advtrains_luaautomation/active_common.lua b/advtrains_luaautomation/active_common.lua index d3985dc..f06eb51 100644 --- a/advtrains_luaautomation/active_common.lua +++ b/advtrains_luaautomation/active_common.lua @@ -109,8 +109,9 @@ function ac.run_in_env(pos, evtdata, customfct_p) atwarn("LuaAutomation component at",ph,": Not an existing environment: "..(nodetbl.env or "")) return false end + local env = atlatc.envs[nodetbl.env] if not nodetbl.code or nodetbl.code=="" then - atwarn("LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)") + env:log("warning", "LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)") return false end @@ -141,14 +142,14 @@ function ac.run_in_env(pos, evtdata, customfct_p) end local datain=nodetbl.data or {} - local succ, dataout = atlatc.envs[nodetbl.env]:execute_code(datain, nodetbl.code, evtdata, customfct) + local succ, dataout = env:execute_code(datain, nodetbl.code, evtdata, customfct) if succ then atlatc.active.nodes[ph].data=atlatc.remove_invalid_data(dataout) else atlatc.active.nodes[ph].err=dataout - atwarn("LuaAutomation ATC interface rail at",ph,": LUA Error:",dataout) + env:log("error", "LuaATC component at",ph,": LUA Error:",dataout) if meta then - meta:set_string("infotext", "LuaAutomation ATC interface rail, ERROR:"..dataout) + meta:set_string("infotext", "LuaATC component, ERROR:"..dataout) end --TODO temporary --if customfct.atc_id then diff --git a/advtrains_luaautomation/chatcmds.lua b/advtrains_luaautomation/chatcmds.lua index 2d0c69d..468698b 100644 --- a/advtrains_luaautomation/chatcmds.lua +++ b/advtrains_luaautomation/chatcmds.lua @@ -43,12 +43,78 @@ core.register_chatcommand("env_create", { privs = {atlatc=true}, func = function(name, param) if not param or param=="" then return false, "Name required!" end + if string.find(param, "[^a-zA-Z0-9-_]") then return false, "Invalid name (only common characters)" end if atlatc.envs[param] then return false, "Environment already exists!" end atlatc.envs[param] = atlatc.env_new(param) + atlatc.envs[param].subscribers = {name} return true, "Created environment '"..param.."'. Use '/env_setup "..param.."' to define global initialization code, or start building LuaATC components!" end, }) - +core.register_chatcommand("env_subscribe", { + params = "", + description = "Subscribe to the log of an Advtrains LuaATC environment", + privs = {atlatc=true}, + func = function(name, param) + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + for _,pname in ipairs(env.subscribers) do + if pname==name then + return false, "Already subscribed!" + end + end + table.insert(env.subscribers, name) + return true, "Subscribed to environment '"..param.."'." + end, +}) +core.register_chatcommand("env_unsubscribe", { + params = "", + description = "Unubscribe to the log of an Advtrains LuaATC environment", + privs = {atlatc=true}, + func = function(name, param) + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + for index,pname in ipairs(env.subscribers) do + if pname==name then + table.remove(env.subscribers, index) + return true, "Successfully unsubscribed!" + end + end + return false, "Not subscribed to environment '"..param.."'." + end, +}) +core.register_chatcommand("env_subscriptions", { + params = "[environment name]", + description = "List Advtrains LuaATC environments you are subscribed to (no parameters) or subscribers of an environment (giving an env name).", + privs = {atlatc=true}, + func = function(name, param) + if not param or param=="" then + local none=true + for envname, env in pairs(atlatc.envs) do + for _,pname in ipairs(env.subscribers) do + if pname==name then + none=false + minetest.chat_send_player(name, envname) + end + end + end + if none then + return false, "Not subscribed to any!" + end + return true + end + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + local none=true + for index,pname in ipairs(env.subscribers) do + none=false + minetest.chat_send_player(name, pname) + end + if none then + return false, "No subscribers!" + end + return true + end, +}) minetest.register_on_player_receive_fields(function(player, formname, fields) diff --git a/advtrains_luaautomation/environment.lua b/advtrains_luaautomation/environment.lua index 3e7787b..9ef320c 100644 --- a/advtrains_luaautomation/environment.lua +++ b/advtrains_luaautomation/environment.lua @@ -33,12 +33,12 @@ local env_proto={ self.sdata=data.sdata and atlatc.remove_invalid_data(data.sdata) or {} self.fdata={} self.init_code=data.init_code or "" - self.step_code=data.step_code or "" + self.subscribers=data.subscribers or {} end, save = function(self) -- throw any function values out of the sdata table self.sdata = atlatc.remove_invalid_data(self.sdata) - return {sdata = self.sdata, init_code=self.init_code, step_code=self.step_code} + return {sdata = self.sdata, init_code=self.init_code, subscribers=self.subscribers} end, } @@ -50,14 +50,6 @@ local safe_globals = { "tonumber", "tostring", "type", "unpack", "_VERSION" } ---print is actually minetest.chat_send_all() ---using advtrains.print_concat_table because it's cool -local function safe_print(t, ...) - local str=advtrains.print_concat_table({t, ...}) - minetest.log("action", "[atlatc] "..str) - minetest.chat_send_all(str) -end - local function safe_date(f, t) if not f then -- fall back to old behavior @@ -95,7 +87,6 @@ local mp=minetest.get_modpath("advtrains_luaautomation") local static_env = { --core LUA functions - print = safe_print, string = { byte = string.byte, char = string.char, @@ -252,7 +243,6 @@ for _, name in pairs(safe_globals) do static_env[name] = _G[name] end - --The environment all code calls get is a table that has set static_env as metatable. --In general, every variable is local to a single code chunk, but kept persistent over code re-runs. Data is also saved, but functions and userdata and circular references are removed --Init code and step code's environments are not saved @@ -265,6 +255,14 @@ local proxy_env={} -- returns: true, fenv if successful; nil, error if error function env_proto:execute_code(localenv, code, evtdata, customfct) + -- create us a print function specific for this environment + if not self.safe_print_func then + local myenv = self + self.safe_print_func = function(...) + myenv:log("info", ...) + end + end + local metatbl ={ __index = function(t, i) if i=="S" then @@ -277,6 +275,8 @@ function env_proto:execute_code(localenv, code, evtdata, customfct) return customfct[i] elseif localenv and localenv[i] then return localenv[i] + elseif i=="print" then + return self.safe_print_func end return static_env[i] end, @@ -306,35 +306,39 @@ function env_proto:run_initcode() if self.init_code and self.init_code~="" then local old_fdata=self.fdata self.fdata = {} - atprint("[atlatc]Running initialization code for environment '"..self.name.."'") + --atprint("[atlatc]Running initialization code for environment '"..self.name.."'") local succ, err = self:execute_code({}, self.init_code, {type="init", init=true}) if not succ then - atwarn("[atlatc]Executing InitCode for '"..self.name.."' failed:"..err) + self:log("error", "Executing InitCode for '"..self.name.."' failed:"..err) self.init_err=err if old_fdata then self.fdata=old_fdata - atwarn("[atlatc]The 'F' table has been restored to the previous state.") + self:log("warning", "The 'F' table has been restored to the previous state.") end end end end -function env_proto:run_stepcode() - if self.step_code and self.step_code~="" then - local succ, err = self:execute_code({}, self.step_code, nil, {}) - if not succ then - --TODO - end + +-- log to environment subscribers. severity can be "error", "warning" or "info" (used by internal print) +function env_proto:log(severity, ...) + local text=advtrains.print_concat_table({"[atlatc "..self.name.." "..severity.."]", ...}) + minetest.log("action", text) + for _, pname in ipairs(self.subscribers) do + minetest.chat_send_player(pname, text) end end +-- env.subscribers table may be directly altered by callers. + + --- class interface function atlatc.env_new(name) local newenv={ name=name, init_code="", - step_code="", - sdata={} + sdata={}, + subscribers={}, } setmetatable(newenv, {__index=env_proto}) return newenv @@ -351,11 +355,6 @@ function atlatc.run_initcode() env:run_initcode() end end -function atlatc.run_stepcode() - for envname, env in pairs(atlatc.envs) do - env:run_stepcode() - end -end