LuaAutomation: Add interrupt to the ingame API and implement initialization code handling and env management

master
orwell96 2017-02-02 21:14:20 +01:00
parent b19033b224
commit 948482a99e
6 changed files with 125 additions and 6 deletions

View File

@ -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

View File

@ -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 = {

View File

@ -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 = "<environment name>",
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 = "<environment name>",
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)

View File

@ -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

View File

@ -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")

View File

@ -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