From 948482a99e4aae4d51ff97879432140645959f46 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Thu, 2 Feb 2017 21:14:20 +0100 Subject: LuaAutomation: Add interrupt to the ingame API and implement initialization code handling and env management --- .../advtrains_luaautomation/active_common.lua | 7 ++- advtrains/advtrains_luaautomation/atc_rail.lua | 2 +- advtrains/advtrains_luaautomation/chatcmds.lua | 70 ++++++++++++++++++++++ advtrains/advtrains_luaautomation/environment.lua | 42 +++++++++++-- advtrains/advtrains_luaautomation/init.lua | 2 + advtrains/advtrains_luaautomation/passive.lua | 8 +++ 6 files changed, 125 insertions(+), 6 deletions(-) diff --git a/advtrains/advtrains_luaautomation/active_common.lua b/advtrains/advtrains_luaautomation/active_common.lua index b94a260..474838e 100644 --- a/advtrains/advtrains_luaautomation/active_common.lua +++ b/advtrains/advtrains_luaautomation/active_common.lua @@ -84,7 +84,7 @@ function ac.on_receive_fields(pos, formname, fields, player) end end -function ac.run_in_env(pos, evtdata, customfct) +function ac.run_in_env(pos, evtdata, customfct_p) local ph=minetest.hash_node_position(pos) local nodetbl = ac.nodes[ph] or {} @@ -100,6 +100,11 @@ function ac.run_in_env(pos, evtdata, customfct) return false, "No code to run!" end + local customfct=customfct_p or {} + customfct.interrupt=function(t, imesg) + atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg}) + end + local datain=nodetbl.data or {} local succ, dataout = atlatc.envs[nodetbl.env]:execute_code(datain, nodetbl.code, evtdata, customfct) if succ then diff --git a/advtrains/advtrains_luaautomation/atc_rail.lua b/advtrains/advtrains_luaautomation/atc_rail.lua index 2af03cf..b2a8aad 100644 --- a/advtrains/advtrains_luaautomation/atc_rail.lua +++ b/advtrains/advtrains_luaautomation/atc_rail.lua @@ -78,7 +78,7 @@ advtrains.register_tracks("default", { advtrains = { on_train_enter = function(pos, train_id) --do async. Event is fired in train steps - atlatc.interrupt.add(0, pos, {type="train", id=train_id}) + atlatc.interrupt.add(0, pos, {type="train", train=true, id=train_id}) end, }, luaautomation = { diff --git a/advtrains/advtrains_luaautomation/chatcmds.lua b/advtrains/advtrains_luaautomation/chatcmds.lua index e69de29..1a3f167 100644 --- a/advtrains/advtrains_luaautomation/chatcmds.lua +++ b/advtrains/advtrains_luaautomation/chatcmds.lua @@ -0,0 +1,70 @@ +--chatcmds.lua +--Registers commands to modify the init and step code for LuaAutomation + +local function get_init_form(env) + local err = env.init_err or "" + local code = env.init_code or "" + atprint(err) + local form = "size[10,10]button[0,0;2,1;run;Run InitCode]button[2,0;2,1;cls;Clear S]" + .."button[4,0;2,1;save;Save] button[6,0;2,1;del;Delete Env.] textarea[0.2,1;10,10;code;Environment initialization code;"..minetest.formspec_escape(code).."]" + .."label[0,9.8;"..err.."]" + return form +end + +core.register_chatcommand("env_setup", { + params = "", + description = "Set up and modify AdvTrains LuaAutomation environment", + privs = {atlatc=true}, + func = function(name, param) + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + minetest.show_formspec(name, "atlatc_envsetup_"..param, get_init_form(env)) + return true + end, +}) + +core.register_chatcommand("env_create", { + params = "", + description = "Create an AdvTrains LuaAutomation environment", + privs = {atlatc=true}, + func = function(name, param) + if not param or param=="" then return false, "Name required!" end + if atlatc.envs[param] then return false, "Environment already exists!" end + atlatc.envs[param] = atlatc.env_new(param) + return true, "Created environment '"..param.."'. Use '/env_setup "..param.."' to define global initialization code, or start building LuaATC components!" + end, +}) + + +minetest.register_on_player_receive_fields(function(player, formname, fields) + + local pname=player:get_player_name() + if not minetest.check_player_privs(pname, {atlatc=true}) then return end + + local envname=string.match(formname, "^atlatc_delconfirm_(.+)$") + if envname and fields.sure=="YES" then + atlatc.envs[envname]=nil + minetest.chat_send_player(pname, "Environment deleted!") + return + end + + envname=string.match(formname, "^atlatc_envsetup_(.+)$") + if not envname then return end + + local env=atlatc.envs[envname] + if not env then return end + + if fields.del then + minetest.show_formspec(pname, "atlatc_delconfirm_"..envname, "field[sure;"..minetest.formspec_escape("SURE TO DELETE ENVIRONMENT "..envname.."? Type YES (all uppercase) to continue or just quit form to cancel.")..";]") + return + end + + env.init_err=nil + if fields.code then + env.init_code=fields.code + end + if fields.run then + env:run_initcode() + minetest.show_formspec(pname, formname, get_init_form(env)) + end +end) diff --git a/advtrains/advtrains_luaautomation/environment.lua b/advtrains/advtrains_luaautomation/environment.lua index d04563a..c7b801c 100644 --- a/advtrains/advtrains_luaautomation/environment.lua +++ b/advtrains/advtrains_luaautomation/environment.lua @@ -25,6 +25,28 @@ function atlatc.remove_invalid_data(o, nested) nested[o] = nil return o end +function atlatc.replace_function_envs(o, fenv, nested) + if o==nil then return nil end + local valid_dt={["nil"]=true, boolean=true, number=true, string=true} + if type(o) ~= "table" then + --check valid data type + if type(o)=="function" then + setfenv(o, fenv) + end + return o + end + -- Contains table -> true/nil of currently nested tables + nested = nested or {} + if nested[o] then + return nil + end + nested[o] = true + for k, v in pairs(o) do + v = atlatc.replace_function_envs(v, fenv, nested) + end + nested[o] = nil + return o +end local env_proto={ @@ -149,7 +171,15 @@ local static_env = { POS = function(x,y,z) return {x=x, y=y, z=z} end, getstate = p_api_getstate, setstate = p_api_setstate, - + --interrupts are handled per node, position unknown. + --however external interrupts can be set here. + interrupt_pos = function(pos, imesg) + if not type(pos)=="table" or not pos.x or not pos.y or not pos.z then + debug.sethook() + error("Invalid position supplied to interrupt_pos") + end + atlatc.interrupt.add(0, pos, {type="ext_int", ext_int=true, message=imesg}) + end, } for _, name in pairs(safe_globals) do @@ -168,7 +198,6 @@ end function env_proto:execute_code(fenv, code, evtdata, customfct) local metatbl ={ __index = function(t, i) - print("index metamethod:",i) if i=="S" then return self.sdata elseif i=="F" then @@ -193,6 +222,9 @@ function env_proto:execute_code(fenv, code, evtdata, customfct) if not fun then return false, err end + --set function environment for all functions residing in F, so they get the right variables. Else it's a huge mess... + atlatc.replace_function_envs(self.fdata, fenv) + setfenv(fun, fenv) local succ, data = pcall(fun) if succ then @@ -203,9 +235,11 @@ end function env_proto:run_initcode() if self.init_code and self.init_code~="" then - local succ, err = self:execute_code(self.init_code, nil, {}, "Global init code") + self.fdata = {} + 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 - --TODO + self.init_err=err end end end diff --git a/advtrains/advtrains_luaautomation/init.lua b/advtrains/advtrains_luaautomation/init.lua index 12e1b1d..37e5714 100644 --- a/advtrains/advtrains_luaautomation/init.lua +++ b/advtrains/advtrains_luaautomation/init.lua @@ -26,6 +26,8 @@ dofile(mp.."/active_common.lua") dofile(mp.."/atc_rail.lua") dofile(mp.."/operation_panel.lua") dofile(mp.."/p_mesecon_iface.lua") +dofile(mp.."/chatcmds.lua") + local filename=minetest.get_worldpath().."/advtrains_luaautomation" local file, err = io.open(filename, "r") diff --git a/advtrains/advtrains_luaautomation/passive.lua b/advtrains/advtrains_luaautomation/passive.lua index 78b8c2d..e32bee9 100644 --- a/advtrains/advtrains_luaautomation/passive.lua +++ b/advtrains/advtrains_luaautomation/passive.lua @@ -2,6 +2,10 @@ -- API to passive components, as described in passive_api.txt local function getstate(pos) + if not type(pos)=="table" or not pos.x or not pos.y or not pos.z then + debug.sethook() + error("Invalid position supplied to getstate") + end local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.luaautomation and ndef.luaautomation.getstate then @@ -16,6 +20,10 @@ local function getstate(pos) end local function setstate(pos, newstate) + if not type(pos)=="table" or not pos.x or not pos.y or not pos.z then + debug.sethook() + error("Invalid position supplied to setstate") + end local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.luaautomation and ndef.luaautomation.setstate then -- cgit v1.2.3