New commands implemented

Controller restructured
This commit is contained in:
Joachim Stolberg 2018-03-18 21:26:15 +01:00
parent f58bb6336a
commit d40b9a54c5
3 changed files with 275 additions and 193 deletions

@ -2,33 +2,7 @@
This tubelib extension provides small and smart sensors, actors and controllers. This tubelib extension provides small and smart sensors, actors and controllers.
The most important and smart node of SmartLine is the SmartLine Controller, a 'computer' to control and monitor Tubelib based machines. A Tutorial to this Mod is available as ![Wiki](https://github.com/joe7575/techpack/wiki)
You don't need any programming skills, it is more like a configuration according to the "IF this THEN that" concept:
IF <cond1> OR <cond2> THEN <action>
IF <cond1> AND <cond2> THEN <action>
Examples for conditions are:
- the Player Detector detects a player
- a button is pressed
- a node state is fault, blocked, standby,...
- a timer is expired
Examples for actions are:
- switch on/off tubelib nodes, like lamps, door blocks, machines
- send mail/chat messages to the owner
- output a text message to the display
- set timer variables
- set/reset flag variables
The mod comes with several new nodes, all in a smart and small housing:
- a Player Detector, sending on/off commands to connected nodes
- a Smart Button, sending on/off commands to connected nodes
- a Display for text outputs of the controller
- a Signal Tower, with green, amber, red lights to signal error/fault states
- a Timer (derived from Tubelib Addons2), for daytime based actions
- a Sequencer (derived from Tubelib Addons2), for time triggered actions (time in seconds)
API Reference: ![api.md](https://github.com/joe7575/techpack/blob/master/smartline/api.md) API Reference: ![api.md](https://github.com/joe7575/techpack/blob/master/smartline/api.md)

@ -17,22 +17,28 @@
smartline.register_condition("default", { smartline.register_condition("default", {
title = "", title = "",
formspec = {}, formspec = {},
on_execute = function(data, flags, timers, inputs, actions) end, on_execute = function(data, environ) end,
button_label = function(data) return "" end, button_label = function(data) return "" end,
}) })
smartline.register_action("default", { smartline.register_action("default", {
title = "", title = "",
formspec = {}, formspec = {},
on_execute = function(data, flags, timers, inputs) end, on_execute = function(data, environ, number) end,
button_label = function(data) return "" end, button_label = function(data) return "" end,
}) })
smartline.register_condition("true", { smartline.register_condition("true", {
title = "true", title = "true",
formspec = {}, formspec = {
on_execute = function(data, flags, timers, inputs, actions) {
type = "label",
name = "lbl",
label = "Hint: Condition is always true.",
},
},
on_execute = function(data, environ)
return true return true
end, end,
button_label = function(data) button_label = function(data)
@ -42,8 +48,14 @@ smartline.register_condition("true", {
smartline.register_condition("false", { smartline.register_condition("false", {
title = "false", title = "false",
formspec = {}, formspec = {
on_execute = function(data, flags, timers, inputs, actions) {
type = "label",
name = "lbl",
label = "Hint: Condition is always false.",
},
},
on_execute = function(data, environ)
return false return false
end, end,
button_label = function(data) button_label = function(data)
@ -51,8 +63,25 @@ smartline.register_condition("false", {
end, end,
}) })
smartline.register_condition("toggle", {
title = "toggle flag",
formspec = {
{
type = "label",
name = "lbl",
label = "Hint: This flag toggles (true/false) every second\nand can be used to trigger\nan action every two seconds.",
},
},
on_execute = function(data, environ)
return environ.toggle
end,
button_label = function(data)
return "toggle"
end,
})
smartline.register_condition("flag", { smartline.register_condition("flag", {
title = "flag test", title = "flag",
formspec = { formspec = {
{ {
type = "textlist", type = "textlist",
@ -71,17 +100,43 @@ smartline.register_condition("flag", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: Don't forget to reset the flag again.", label = "Hint: The flag will keep its state.",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
return flags[data.flag] == data.value_text return environ.flags[data.flag] == data.value_text
end, end,
button_label = function(data) button_label = function(data)
return data.flag_text.."=="..data.value_text return data.flag_text.."=="..data.value_text
end, end,
}) })
smartline.register_condition("flag_reset", {
title = "flag test and clear",
formspec = {
{
type = "textlist",
name = "flag",
label = "flag",
choices = "f1,f2,f3,f4,f5,f6,f7,f8",
default = 1,
},
{
type = "label",
name = "lbl",
label = "Hint: The result is true, if the flag was true.\nAfter evaluation the flag is set to false.",
},
},
on_execute = function(data, environ)
local res = environ.flags[data.flag] == "true"
environ.flags[data.flag] = "false"
return res
end,
button_label = function(data)
return "test_clear("..data.flag_text..")"
end,
})
smartline.register_action("flag", { smartline.register_action("flag", {
title = "flag set", title = "flag set",
formspec = { formspec = {
@ -102,11 +157,11 @@ smartline.register_action("flag", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: Flags are stored permanently and can be used by other rules.", label = "Hint: Flags are stored permanently and\ncan be used as condition by other rules.",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
flags[data.flag] = data.value_text environ.flags[data.flag] = data.value_text
end, end,
button_label = function(data) button_label = function(data)
return data.flag_text.."="..data.value_text return data.flag_text.."="..data.value_text
@ -114,7 +169,7 @@ smartline.register_action("flag", {
}) })
smartline.register_condition("input", { smartline.register_condition("input", {
title = "check input", title = "inputs",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -126,17 +181,17 @@ smartline.register_condition("input", {
type = "textlist", type = "textlist",
name = "value", name = "value",
label = "is", label = "is",
choices = "on,off", choices = "on,off,false",
default = 1, default = 1,
}, },
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: An input is only available,\nif the sending node is connected with the controller.", label = "Hint: An input is only available,\nif the sending node is connected\nwith the controller.",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
return inputs[data.number] == data.value_text return environ.inputs[data.number] == data.value_text
end, end,
button_label = function(data) button_label = function(data)
return "i("..data.number..")=="..data.value_text return "i("..data.number..")=="..data.value_text
@ -155,8 +210,8 @@ smartline.register_condition("timer", {
default = 1, default = 1,
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
return timers[data.timer] == 0 return environ.timers[data.timer] == 0
end, end,
button_label = function(data) button_label = function(data)
return data.timer_text.." expired" return data.timer_text.." expired"
@ -180,8 +235,8 @@ smartline.register_action("timer", {
default = "", default = "",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
timers[data.timer] = tonumber(data.value) or 0 environ.timers[data.timer] = tonumber(data.value) or 0
end, end,
button_label = function(data) button_label = function(data)
return data.timer_text.."="..data.value return data.timer_text.."="..data.value
@ -189,30 +244,31 @@ smartline.register_action("timer", {
}) })
smartline.register_condition("pusher", { smartline.register_condition("pusher", {
title = "Pusher state", title = "node state request",
formspec = { formspec = {
{ {
type = "field", type = "field",
name = "number", name = "number",
label = "state from Pusher with number", label = "state from node with number",
default = "", default = "",
}, },
{ {
type = "textlist", type = "textlist",
name = "value", name = "value",
label = "is", label = "is",
choices = "stopped,running,standby,blocked,fault", choices = "stopped,running,standby,blocked,fault,false",
default = 1, default = 1,
}, },
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint:\n - standby means 'nothing to do'\n - blocked means 'inventory is full'", label = "Hint: Read the state from another node.\nWorks for Pusher, Harvester, Quarry,\nFermenter, and Reformer",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
return tubelib.send_request(data.number, "state", "") == data.value_text environ.state = tubelib.send_request(data.number, "state", "")
return environ.state == data.value_text
end, end,
button_label = function(data) button_label = function(data)
return "st("..data.number..")=="..string.sub(data.value_text or "???", 1, 4).."." return "st("..data.number..")=="..string.sub(data.value_text or "???", 1, 4).."."
@ -220,7 +276,7 @@ smartline.register_condition("pusher", {
}) })
smartline.register_condition("fuel", { smartline.register_condition("fuel", {
title = "fuel state", title = "fuel state request",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -232,12 +288,17 @@ smartline.register_condition("fuel", {
type = "textlist", type = "textlist",
name = "value", name = "value",
label = "is", label = "is",
choices = "full,empty,not full,not empty", choices = "full,empty,not full,not empty,false",
default = 1, default = 1,
}, },
{
type = "label",
name = "lbl",
label = "Hint: Read the fuel state from another node.\nWorks for Harvester and Quarry",
},
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
if data.value > 2 then if data.value > 2 then
return tubelib.send_request(data.number, "fuel", nil) ~= string.sub(data.value_text or "???", 5) return tubelib.send_request(data.number, "fuel", nil) ~= string.sub(data.value_text or "???", 5)
else else
@ -254,7 +315,7 @@ smartline.register_condition("fuel", {
}) })
smartline.register_condition("signaltower", { smartline.register_condition("signaltower", {
title = "Signal Tower state", title = "Signal Tower state request",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -266,17 +327,17 @@ smartline.register_condition("signaltower", {
type = "textlist", type = "textlist",
name = "value", name = "value",
label = "is", label = "is",
choices = "off,green,amber,red,not off,not green,not amber,not red", choices = "off,green,amber,red,not off,not green,not amber,not red,false",
default = 1, default = 1,
}, },
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: Works also for Signal Towers in unloaded areas.", label = "Hint: Read the state from a Signal Tower.",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
if data.value > 4 then if data.value > 4 then
return tubelib.send_request(data.number, "state", nil) ~= string.sub(data.value_text or "???", 5) return tubelib.send_request(data.number, "state", nil) ~= string.sub(data.value_text or "???", 5)
else else
@ -308,8 +369,13 @@ smartline.register_action("signaltower", {
choices = "off,green,amber,red", choices = "off,green,amber,red",
default = 1, default = 1,
}, },
{
type = "label",
name = "lbl",
label = "Hint: Turn on a lamp from a Signal Tower.",
},
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
tubelib.send_message(data.number, data.owner, nil, data.value_text, number) tubelib.send_message(data.number, data.owner, nil, data.value_text, number)
end, end,
button_label = function(data) button_label = function(data)
@ -318,7 +384,7 @@ smartline.register_action("signaltower", {
}) })
smartline.register_action("switch", { smartline.register_action("switch", {
title = "switch nodes on/off", title = "node on/off command",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -339,7 +405,7 @@ smartline.register_action("switch", {
label = "Hint: Used for pushers, lamps, machines, gates,...", label = "Hint: Used for pushers, lamps, machines, gates,...",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
tubelib.send_message(data.number, data.owner, nil, data.value_text, number) tubelib.send_message(data.number, data.owner, nil, data.value_text, number)
end, end,
button_label = function(data) button_label = function(data)
@ -365,11 +431,12 @@ smartline.register_action("display1", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: Works also for Displays in unloaded areas.", label = "Hint: Use a '*' character as reference to any\ncondition state",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
tubelib.send_message(data.number, data.owner, nil, "text", data.text) local text = string.gsub(data.text, "*", environ.state or "<unknown>")
tubelib.send_message(data.number, data.owner, nil, "text", text)
end, end,
button_label = function(data) button_label = function(data)
return "display("..data.number..")" return "display("..data.number..")"
@ -401,11 +468,12 @@ smartline.register_action("display2", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: Works also for Displays in unloaded areas.", label = "Hint: Use a '*' character as reference to any\ncondition state",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
local payload = {row = data.row, str = data.text} local text = string.gsub(data.text, "*", environ.state or "<unknown>")
local payload = {row = data.row, str = text}
tubelib.send_message(data.number, data.owner, nil, "row", payload) tubelib.send_message(data.number, data.owner, nil, "row", payload)
end, end,
button_label = function(data) button_label = function(data)
@ -431,11 +499,11 @@ smartline.register_action("display3", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: use a '*' character as reference to the player name", label = "Hint: Use a '*' character as reference to the\nplayer name",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
local text = string.gsub(data.text, "*", flags.name or "<unknown>") local text = string.gsub(data.text, "*", environ.name or "<unknown>")
tubelib.send_message(data.number, data.owner, nil, "text", text) tubelib.send_message(data.number, data.owner, nil, "text", text)
end, end,
button_label = function(data) button_label = function(data)
@ -453,7 +521,7 @@ smartline.register_action("display4", {
default = "", default = "",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
tubelib.send_message(data.number, data.owner, nil, "clear", "") tubelib.send_message(data.number, data.owner, nil, "clear", "")
end, end,
button_label = function(data) button_label = function(data)
@ -463,7 +531,7 @@ smartline.register_action("display4", {
if minetest.get_modpath("mail") and mail ~= nil then if minetest.get_modpath("mail") and mail ~= nil then
smartline.register_action("mail", { smartline.register_action("mail", {
title = "mail", title = "mail send",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -471,8 +539,13 @@ if minetest.get_modpath("mail") and mail ~= nil then
label = "send the message", label = "send the message",
default = "", default = "",
}, },
{
type = "label",
name = "lbl",
label = "Hint: The mail is send to the Controller owner, only.",
},
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
mail.send("Server", data.owner, "[SmartLine Controller]", data.text) mail.send("Server", data.owner, "[SmartLine Controller]", data.text)
end, end,
button_label = function(data) button_label = function(data)
@ -482,7 +555,7 @@ if minetest.get_modpath("mail") and mail ~= nil then
end end
smartline.register_action("chat", { smartline.register_action("chat", {
title = "chat", title = "chat send",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -490,8 +563,13 @@ smartline.register_action("chat", {
label = "send the message", label = "send the message",
default = "", default = "",
}, },
{
type = "label",
name = "lbl",
label = "Hint: The chat message is send to the\nController owner, only.",
},
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
minetest.chat_send_player(data.owner, "[SmartLine Controller] "..data.text) minetest.chat_send_player(data.owner, "[SmartLine Controller] "..data.text)
end, end,
button_label = function(data) button_label = function(data)
@ -527,7 +605,7 @@ smartline.register_action("door", {
}, },
{ {
type = "textlist", type = "textlist",
name = "state", name = "door_state",
label = "set", label = "set",
choices = "open,close", choices = "open,close",
default = 1, default = 1,
@ -535,24 +613,24 @@ smartline.register_action("door", {
{ {
type = "label", type = "label",
name = "lbl1", name = "lbl1",
label = "For standard doors like the Steel Door", label = "For standard doors like the Steel Doors.",
}, },
{ {
type = "label", type = "label",
name = "lbl2", name = "lbl2",
label = "Hint: use a marker stick to determine the door position", label = "Hint: Use the Tubelib Programmer to\ndetermine the door position.",
}, },
}, },
on_execute = function(data, flags, timers, number) on_execute = function(data, environ, number)
door_toggle(data.pos, data.owner, data.state_text) door_toggle(data.pos, data.owner, data.door_state_text)
end, end,
button_label = function(data) button_label = function(data)
return "door("..data.state_text..")" return "door("..data.door_state_text..")"
end, end,
}) })
smartline.register_condition("playerdetector", { smartline.register_condition("playerdetector", {
title = "detected player name", title = "Player Detector: name request",
formspec = { formspec = {
{ {
type = "field", type = "field",
@ -569,13 +647,13 @@ smartline.register_condition("playerdetector", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: use a '*' character for all player names", label = "Hint: Read and check the name\nfrom a Player Detector.\n Use a '*' character for all player names.",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
flags.name = tubelib.send_request(data.number, "name", nil) environ.name = tubelib.send_request(data.number, "name", nil)
return (data.name == "*" and flags.name ~= "") or flags.name == data.name return (data.name == "*" and environ.name ~= "") or environ.name == data.name
end, end,
button_label = function(data) button_label = function(data)
if string.len(data.name) > 6 then if string.len(data.name) > 6 then
@ -586,7 +664,7 @@ smartline.register_condition("playerdetector", {
}) })
smartline.register_condition("action", { smartline.register_condition("action", {
title = "action", title = "actions",
formspec = { formspec = {
{ {
type = "textlist", type = "textlist",
@ -598,11 +676,11 @@ smartline.register_condition("action", {
{ {
type = "label", type = "label",
name = "lbl", name = "lbl",
label = "Hint: The corresponding flag is set for each\nexecute action. Useful to execute\nmore than one action with one condition.", label = "Hint: The corresponding flag is set for each\nexecuted action. Useful to execute\nmore than one action with one condition.",
}, },
}, },
on_execute = function(data, flags, timers, inputs, actions) on_execute = function(data, environ)
return actions[data.action] == true return environ.actions[data.action] == true
end, end,
button_label = function(data) button_label = function(data)
return "action"..data.action return "action"..data.action

@ -63,7 +63,7 @@ The colors show, if conditions are true or false and
if actions were already executed or not. if actions were already executed or not.
It has a 'update' button to update the view. It has a 'update' button to update the view.
For more information, see: goo.gl/wZ5GUR For more information, see: goo.gl/fF5ap6
]] ]]
local sOUTPUT = "Press 'help' for edit commands" local sOUTPUT = "Press 'help' for edit commands"
@ -109,12 +109,12 @@ local CondRunTimeHandlers = {}
local ActnRunTimeHandlers = {} local ActnRunTimeHandlers = {}
local function eval_cond(data, flags, timers, inputs, actions) local function eval_cond(data, environ)
return CondRunTimeHandlers[data.__idx__](data, flags, timers, inputs, actions) and 1 or 0 return CondRunTimeHandlers[data.__idx__](data, environ) and 1 or 0
end end
local function exec_action(data, flags, timers, number) local function exec_action(data, environ, number)
ActnRunTimeHandlers[data.__idx__](data, flags, timers, number) ActnRunTimeHandlers[data.__idx__](data, environ, number)
end end
smartline = {} smartline = {}
@ -255,20 +255,30 @@ local function runtime_data(postfix, type, fs_data)
end end
local function decrement_timers(timers) local function decrement_timers(timers)
for idx,_ in ipairs(timers) do if timers ~= nil then
timers[idx] = tonumber(timers[idx]) for idx,_ in pairs(timers) do
if timers[idx] >= 0 then timers[idx] = tonumber(timers[idx])
timers[idx] = timers[idx] - 1 if timers[idx] >= 0 then
timers[idx] = timers[idx] - 1
end
end end
end end
end end
local function toggle_flag(environ)
if environ.toggle == true then
environ.toggle = false
else
environ.toggle = true
end
end
-- --
-- Condition formspec -- Condition formspec
-- --
local function formspec_cond(_postfix_, fs_data) local function formspec_cond(_postfix_, fs_data)
local tbl = {"size[8.2,10]".. local tbl = {"size[8.2,9]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -280,8 +290,8 @@ local function formspec_cond(_postfix_, fs_data)
tbl[#tbl+1] = "label[0,0.1;Condition type:]" tbl[#tbl+1] = "label[0,0.1;Condition type:]"
tbl[#tbl+1] = "textlist[0,0.6;8,1.4;cond;"..sConditions..";"..cond_idx.."]" tbl[#tbl+1] = "textlist[0,0.6;8,1.4;cond;"..sConditions..";"..cond_idx.."]"
tbl = add_controls_to_table(tbl, _postfix_, fs_data, fs_definition) tbl = add_controls_to_table(tbl, _postfix_, fs_data, fs_definition)
tbl[#tbl+1] = "button[4,9.4;2,1;_cancel_;cancel]" tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]"
tbl[#tbl+1] = "button[6,9.4;2,1;_exit_;ok]" tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]"
return table.concat(tbl) return table.concat(tbl)
end end
@ -312,7 +322,7 @@ end
-- Action formspec -- Action formspec
-- --
local function formspec_actn(_postfix_, fs_data) local function formspec_actn(_postfix_, fs_data)
local tbl = {"size[8.2,10]".. local tbl = {"size[8.2,9]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -324,8 +334,8 @@ local function formspec_actn(_postfix_, fs_data)
tbl[#tbl+1] = "label[0,0.1;Action type:]" tbl[#tbl+1] = "label[0,0.1;Action type:]"
tbl[#tbl+1] = "textlist[0,0.6;8,1.4;actn;"..sActions..";"..actn_idx.."]" tbl[#tbl+1] = "textlist[0,0.6;8,1.4;actn;"..sActions..";"..actn_idx.."]"
tbl = add_controls_to_table(tbl, _postfix_, fs_data, fs_definition) tbl = add_controls_to_table(tbl, _postfix_, fs_data, fs_definition)
tbl[#tbl+1] = "button[4,9.4;2,1;_cancel_;cancel]" tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]"
tbl[#tbl+1] = "button[6,9.4;2,1;_exit_;ok]" tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]"
return table.concat(tbl) return table.concat(tbl)
end end
@ -416,7 +426,7 @@ local function eval_formspec_oprnd(meta, fs_data, fields, readonly)
end end
local function formspec_main(state, fs_data, output) local function formspec_main(state, fs_data, output)
local tbl = {"size[15,10;true]".. local tbl = {"size[15,9;true]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -424,7 +434,7 @@ local function formspec_main(state, fs_data, output)
"label[0.8,0;label:]label[3.8,0;IF cond 1:]label[7,0;and/or]label[8.3,0;cond 2:]label[11.7,0;THEN action:]"} "label[0.8,0;label:]label[3.8,0;IF cond 1:]label[7,0;and/or]label[8.3,0;cond 2:]label[11.7,0;THEN action:]"}
for idx = 1,NUM_RULES do for idx = 1,NUM_RULES do
local ypos = idx * 0.8 - 0.4 local ypos = idx * 0.75 - 0.4
tbl[#tbl+1] = "label[0,"..(0.2+ypos)..";"..idx.."]" tbl[#tbl+1] = "label[0,"..(0.2+ypos)..";"..idx.."]"
tbl[#tbl+1] = "button[0.4,"..ypos..";3,1;label"..idx..";"..(fs_data["label"..idx] or "...").."]" tbl[#tbl+1] = "button[0.4,"..ypos..";3,1;label"..idx..";"..(fs_data["label"..idx] or "...").."]"
tbl[#tbl+1] = "button[3.5,"..ypos..";3.4,1;cond1"..idx..";"..(fs_data["cond1"..idx] or "...").."]" tbl[#tbl+1] = "button[3.5,"..ypos..";3.4,1;cond1"..idx..";"..(fs_data["cond1"..idx] or "...").."]"
@ -432,12 +442,12 @@ local function formspec_main(state, fs_data, output)
tbl[#tbl+1] = "button[8,".. ypos..";3.4,1;cond2"..idx..";"..(fs_data["cond2"..idx] or "...").."]" tbl[#tbl+1] = "button[8,".. ypos..";3.4,1;cond2"..idx..";"..(fs_data["cond2"..idx] or "...").."]"
tbl[#tbl+1] = "button[11.5,".. ypos..";3.4,1;actna"..idx..";"..(fs_data["actna"..idx] or "...").."]" tbl[#tbl+1] = "button[11.5,".. ypos..";3.4,1;actna"..idx..";"..(fs_data["actna"..idx] or "...").."]"
end end
tbl[#tbl+1] = "image_button[14,9;1,1;".. tubelib.state_button(state) ..";button;]" tbl[#tbl+1] = "image_button[14,8.1;1,1;".. tubelib.state_button(state) ..";button;]"
tbl[#tbl+1] = "button[10.6,9;1.5,1;state;state]" tbl[#tbl+1] = "button[10.6,8.2;1.5,1;state;state]"
tbl[#tbl+1] = "button[12.2,9;1.5,1;help;help]" tbl[#tbl+1] = "button[12.2,8.2;1.5,1;help;help]"
tbl[#tbl+1] = "label[0.2,8.8;"..output.."]" tbl[#tbl+1] = "label[0.2,8.4;"..output.."]"
tbl[#tbl+1] = "field[0.4,9.6;4.8,1;cmnd;;<cmnd>]" tbl[#tbl+1] = "field[6.5,8.5;3,1;cmnd;;<cmnd>]"
tbl[#tbl+1] = "button[5,9.3;1,1;ok;OK]" tbl[#tbl+1] = "button[9.2,8.2;1,1;ok;OK]"
return table.concat(tbl) return table.concat(tbl)
end end
@ -466,7 +476,7 @@ local function eval_formspec_main(meta, fs_data, fields, readonly)
end end
local function formspec_help(offs) local function formspec_help(offs)
return "size[15,10]".. return "size[15,9]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -474,7 +484,7 @@ local function formspec_help(offs)
"label[0,"..(-offs/50)..";"..sHELP.."]".. "label[0,"..(-offs/50)..";"..sHELP.."]"..
--"label[0.2,0;test]".. --"label[0.2,0;test]"..
"scrollbar[13.5,1;0.5,7;vertical;sb_help;"..offs.."]".. "scrollbar[13.5,1;0.5,7;vertical;sb_help;"..offs.."]"..
"button[13.5,9;1.5,1;close;close]" "button[13.3,8.2;1.5,1;close;close]"
end end
local function background(xpos, ypos, val) local function background(xpos, ypos, val)
@ -490,7 +500,7 @@ end
local function formspec_state(meta, fs_data) local function formspec_state(meta, fs_data)
local number = meta:get_string("number") local number = meta:get_string("number")
local state = meta:get_int("state") local state = meta:get_int("state")
local tbl = {"size[15,10;true]".. local tbl = {"size[15,9;true]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -498,83 +508,79 @@ local function formspec_state(meta, fs_data)
"label[0.8,0;label:]label[3.8,0;IF cond 1:]label[7,0;and/or]label[8.3,0;cond 2:]label[11.7,0;THEN action:]"} "label[0.8,0;label:]label[3.8,0;IF cond 1:]label[7,0;and/or]label[8.3,0;cond 2:]label[11.7,0;THEN action:]"}
if state == tubelib.RUNNING and number then if state == tubelib.RUNNING and number then
local inputs = tubelib.get_data(number, "inputs") or {} local environ = tubelib.get_data(number, "environ")
local act_gate = tubelib.get_data(number, "act_gate") or {} local act_gate = tubelib.get_data(number, "act_gate")
local timers = tubelib.get_data(number, "timers") or {} local conds = tubelib.get_data(number, "conds")
local flags = tubelib.get_data(number, "flags") or {}
local conds = tubelib.get_data(number, "conds") or {}
for idx = 1,NUM_RULES do if environ and act_gate and conds then
local ypos = idx * 0.6 + 0.2 for idx = 1,NUM_RULES do
local s1 = fs_data["cond1"..idx] or " ... " local ypos = idx * 0.6 + 0.2
local s2 = fs_data["cond2"..idx] or " ... " local s1 = fs_data["cond1"..idx] or " ... "
local sa = fs_data["actna"..idx] or " ... " local s2 = fs_data["cond2"..idx] or " ... "
if conds[idx] == nil then local sa = fs_data["actna"..idx] or " ... "
tbl[#tbl+1] = background(3.7, ypos, nil) if conds[idx] == nil then
tbl[#tbl+1] = background(8, ypos, nil) tbl[#tbl+1] = background(3.7, ypos, nil)
else tbl[#tbl+1] = background(8, ypos, nil)
tbl[#tbl+1] = background(3.7, ypos, conds[idx] == 1 or conds[idx] == 3) else
tbl[#tbl+1] = background(8, ypos, conds[idx] == 2 or conds[idx] == 3) tbl[#tbl+1] = background(3.7, ypos, conds[idx] == 1 or conds[idx] == 3)
tbl[#tbl+1] = background(8, ypos, conds[idx] == 2 or conds[idx] == 3)
end
tbl[#tbl+1] = background(11.5, ypos, act_gate[idx])
tbl[#tbl+1] = "label[0,".. ypos..";"..idx.."]"
tbl[#tbl+1] = "label[0.5,"..ypos..";"..(fs_data["label"..idx] or " ... ").."]"
tbl[#tbl+1] = "label[3.7,".. ypos..";"..s1.."]"
tbl[#tbl+1] = "label[7.2,".. ypos..";"..(fs_data["oprnd"..idx] or "or").."]"
tbl[#tbl+1] = "label[8,".. ypos..";"..s2.."]"
tbl[#tbl+1] = "label[11.5,".. ypos..";"..sa.."]"
if act_gate[idx] == true then
act_gate[idx] = false
end
end end
tbl[#tbl+1] = background(11.5, ypos, act_gate[idx])
tbl[#tbl+1] = "label[0,".. ypos..";"..idx.."]" tbl[#tbl+1] = "label[10,7; Seconds: "..(meta:get_int("runtime") or 1).."]"
tbl[#tbl+1] = "label[0.5,"..ypos..";"..(fs_data["label"..idx] or " ... ").."]"
tbl[#tbl+1] = "label[3.7,".. ypos..";"..s1.."]" tbl[#tbl+1] = "label[0,7;"..output("Inputs", "i(", ")", environ.inputs).."]"
tbl[#tbl+1] = "label[7.2,".. ypos..";"..(fs_data["oprnd"..idx] or "or").."]" tbl[#tbl+1] = "label[0,7.6;"..output("Timers", "t", "", environ.timers).."]"
tbl[#tbl+1] = "label[8,".. ypos..";"..s2.."]" tbl[#tbl+1] = "label[0,8.2;"..output("Flags", "f", "", environ.flags).."]"
tbl[#tbl+1] = "label[11.5,".. ypos..";"..sa.."]"
tbl[#tbl+1] = "label[0,8.8;Hint:]"
tbl[#tbl+1] = "box[1.3,8.8;6,0.4;#008000]"
tbl[#tbl+1] = "label[1.4,8.8;condition true / action executed]"
tbl[#tbl+1] = "box[7.9,8.8;6,0.4;#800000]"
tbl[#tbl+1] = "label[8,8.8;condition false / action out-of-date]"
end end
tbl[#tbl+1] = "label[10,8.2; Seconds: "..(meta:get_int("runtime") or 1).."]"
tbl[#tbl+1] = "label[0,7;"..output("Inputs", "i(", ")", inputs).."]"
tbl[#tbl+1] = "label[0,7.6;"..output("Timers", "t", "", timers).."]"
tbl[#tbl+1] = "label[0,8.2;"..output("Flags", "f", "", flags).."]"
tbl[#tbl+1] = "label[0,9;Hint:]"
tbl[#tbl+1] = "box[1.3,9;7,0.4;#008000]"
tbl[#tbl+1] = "label[1.4,9;condition is true / action was executed]"
tbl[#tbl+1] = "box[8.9,9;4,0.4;#800000]"
tbl[#tbl+1] = "label[9,9;condition is false]"
tbl[#tbl+1] = "box[1.3,9.6;7,0.4;#202020]"
tbl[#tbl+1] = "label[1.4,9.6;action was not executed]"
end end
tbl[#tbl+1] = "button[13.3,8;1.7,1;update;update]" tbl[#tbl+1] = "button[13.3,6.9;1.7,1;update;update]"
tbl[#tbl+1] = "button[13.3,9;1.7,1;close;close]" tbl[#tbl+1] = "button[13.3,7.8;1.7,1;close;close]"
return table.concat(tbl) return table.concat(tbl)
end end
local function execute(meta, number, debug) local function execute(meta, number, debug)
local rt_rules = tubelib.get_data(number, "rt_rules") local rt_rules = tubelib.get_data(number, "rt_rules")
local inputs = tubelib.get_data(number, "inputs") or {} local environ = tubelib.get_data(number, "environ")
local act_gate = tubelib.get_data(number, "act_gate") or {} local act_gate = tubelib.get_data(number, "act_gate")
local timers = tubelib.get_data(number, "timers") or {} local conds = tubelib.get_data(number, "conds")
local flags = tubelib.get_data(number, "flags") or {} if rt_rules and environ and act_gate and conds then
local conds = tubelib.get_data(number, "conds") or {} environ.actions = {}
local actions = {} decrement_timers(environ.timers)
decrement_timers(timers) toggle_flag(environ)
for i,item in ipairs(rt_rules) do for i,item in ipairs(rt_rules) do
local c1 = eval_cond(item.cond1, flags, timers, inputs, actions) local c1 = eval_cond(item.cond1, environ)
local c2 = eval_cond(item.cond2, flags, timers, inputs, actions) local c2 = eval_cond(item.cond2, environ)
conds[i] = c1 + c2*2 conds[i] = c1 + c2*2
if c1 + c2 >= item.cond_cnt then if c1 + c2 >= item.cond_cnt then
if act_gate[i] == nil then if act_gate[i] == nil then
-- execute action -- execute action
exec_action(item.actn, flags, timers, number) exec_action(item.actn, environ, number)
actions[i] = true environ.actions[i] = true
act_gate[i] = true
end
else
act_gate[i] = nil
end end
act_gate[i] = true
else
act_gate[i] = nil
end end
end end
tubelib.set_data(number, "inputs", inputs)
tubelib.set_data(number, "act_gate", act_gate)
tubelib.set_data(number, "timers", timers)
tubelib.set_data(number, "flags", flags)
tubelib.set_data(number, "conds", conds)
end end
local function check_rules(pos, elapsed) local function check_rules(pos, elapsed)
@ -605,11 +611,14 @@ local function switch_state(pos, state, fs_data)
end end
local function start_controller(pos, number, fs_data) local function start_controller(pos, number, fs_data)
tubelib.set_data(number, "timers", {}) -- local timers -- delete old data
tubelib.set_data(number, "inputs", {}) -- for rx commands tubelib.set_data(number, "environ", {
tubelib.set_data(number, "flags", {}) -- to store flags timers = {},
tubelib.set_data(number, "conds", {}) -- to store conditions flags = {},
tubelib.set_data(number, "act_gate", {}) -- for action states inputs = {}
})
tubelib.set_data(number, "conds", {})
tubelib.set_data(number, "act_gate", {})
switch_state(pos, tubelib.RUNNING, fs_data) switch_state(pos, tubelib.RUNNING, fs_data)
end end
@ -854,10 +863,10 @@ minetest.register_craft({
local function set_input(meta, payload, val) local function set_input(meta, payload, val)
if payload then if payload then
local number = meta:get_string("number") local number = meta:get_string("number")
local inputs = tubelib.get_data(number, "inputs") local environ = tubelib.get_data(number, "environ") or {}
if inputs then if environ.inputs then
inputs[payload] = val environ.inputs[payload] = val
tubelib.set_data(number, "inputs", inputs) tubelib.set_data(number, "environ", environ)
end end
end end
end end
@ -908,6 +917,25 @@ local function update_node_database(meta)
return tOld2NewCond, tOld2NewActn return tOld2NewCond, tOld2NewActn
end end
local function maintain_dataset(number)
local flags = tubelib.get_data(number, "flags")
if flags ~= nil then
local timers = tubelib.get_data(number, "timers") or {}
local inputs = tubelib.get_data(number, "inputs") or {}
tubelib.set_data(number, "environ", {
flags = flags,
timers = timers,
inputs = inputs,
vars = {}
})
tubelib.set_data(number, "inputs", nil)
tubelib.set_data(number, "timers", nil)
tubelib.set_data(number, "flags", nil)
end
end
minetest.register_lbm({ minetest.register_lbm({
label = "[SmartLine] Controller update", label = "[SmartLine] Controller update",
name = "smartline:update", name = "smartline:update",
@ -932,6 +960,8 @@ minetest.register_lbm({
local number = meta:get_string("number") local number = meta:get_string("number")
local owner = meta:get_string("owner") local owner = meta:get_string("owner")
formspec2runtime_rule(number, owner, fs_data) formspec2runtime_rule(number, owner, fs_data)
maintain_dataset(number)
end end
}) })