diff --git a/smartline/README.md b/smartline/README.md index 851b662..83371d5 100644 --- a/smartline/README.md +++ b/smartline/README.md @@ -2,33 +2,7 @@ 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. -You don't need any programming skills, it is more like a configuration according to the "IF this THEN that" concept: - - IF OR THEN - IF AND THEN - -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) - +A Tutorial to this Mod is available as ![Wiki](https://github.com/joe7575/techpack/wiki) API Reference: ![api.md](https://github.com/joe7575/techpack/blob/master/smartline/api.md) diff --git a/smartline/commands.lua b/smartline/commands.lua index b7592c6..e3dc884 100644 --- a/smartline/commands.lua +++ b/smartline/commands.lua @@ -17,22 +17,28 @@ smartline.register_condition("default", { title = "", formspec = {}, - on_execute = function(data, flags, timers, inputs, actions) end, + on_execute = function(data, environ) end, button_label = function(data) return "" end, }) smartline.register_action("default", { title = "", formspec = {}, - on_execute = function(data, flags, timers, inputs) end, + on_execute = function(data, environ, number) end, button_label = function(data) return "" end, }) smartline.register_condition("true", { title = "true", - formspec = {}, - on_execute = function(data, flags, timers, inputs, actions) + formspec = { + { + type = "label", + name = "lbl", + label = "Hint: Condition is always true.", + }, + }, + on_execute = function(data, environ) return true end, button_label = function(data) @@ -42,8 +48,14 @@ smartline.register_condition("true", { smartline.register_condition("false", { title = "false", - formspec = {}, - on_execute = function(data, flags, timers, inputs, actions) + formspec = { + { + type = "label", + name = "lbl", + label = "Hint: Condition is always false.", + }, + }, + on_execute = function(data, environ) return false end, button_label = function(data) @@ -51,8 +63,25 @@ smartline.register_condition("false", { 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", { - title = "flag test", + title = "flag", formspec = { { type = "textlist", @@ -71,17 +100,43 @@ smartline.register_condition("flag", { { type = "label", 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) - return flags[data.flag] == data.value_text + on_execute = function(data, environ) + return environ.flags[data.flag] == data.value_text end, button_label = function(data) return data.flag_text.."=="..data.value_text 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", { title = "flag set", formspec = { @@ -102,11 +157,11 @@ smartline.register_action("flag", { { type = "label", 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) - flags[data.flag] = data.value_text + on_execute = function(data, environ, number) + environ.flags[data.flag] = data.value_text end, button_label = function(data) return data.flag_text.."="..data.value_text @@ -114,7 +169,7 @@ smartline.register_action("flag", { }) smartline.register_condition("input", { - title = "check input", + title = "inputs", formspec = { { type = "field", @@ -126,17 +181,17 @@ smartline.register_condition("input", { type = "textlist", name = "value", label = "is", - choices = "on,off", + choices = "on,off,false", default = 1, }, { type = "label", 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) - return inputs[data.number] == data.value_text + on_execute = function(data, environ) + return environ.inputs[data.number] == data.value_text end, button_label = function(data) return "i("..data.number..")=="..data.value_text @@ -155,8 +210,8 @@ smartline.register_condition("timer", { default = 1, }, }, - on_execute = function(data, flags, timers, inputs, actions) - return timers[data.timer] == 0 + on_execute = function(data, environ) + return environ.timers[data.timer] == 0 end, button_label = function(data) return data.timer_text.." expired" @@ -180,8 +235,8 @@ smartline.register_action("timer", { default = "", }, }, - on_execute = function(data, flags, timers, number) - timers[data.timer] = tonumber(data.value) or 0 + on_execute = function(data, environ, number) + environ.timers[data.timer] = tonumber(data.value) or 0 end, button_label = function(data) return data.timer_text.."="..data.value @@ -189,30 +244,31 @@ smartline.register_action("timer", { }) smartline.register_condition("pusher", { - title = "Pusher state", + title = "node state request", formspec = { { type = "field", name = "number", - label = "state from Pusher with number", + label = "state from node with number", default = "", }, { type = "textlist", name = "value", label = "is", - choices = "stopped,running,standby,blocked,fault", + choices = "stopped,running,standby,blocked,fault,false", default = 1, }, { type = "label", 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) - return tubelib.send_request(data.number, "state", "") == data.value_text + on_execute = function(data, environ) + environ.state = tubelib.send_request(data.number, "state", "") + return environ.state == data.value_text end, button_label = function(data) return "st("..data.number..")=="..string.sub(data.value_text or "???", 1, 4).."." @@ -220,7 +276,7 @@ smartline.register_condition("pusher", { }) smartline.register_condition("fuel", { - title = "fuel state", + title = "fuel state request", formspec = { { type = "field", @@ -232,12 +288,17 @@ smartline.register_condition("fuel", { type = "textlist", name = "value", label = "is", - choices = "full,empty,not full,not empty", + choices = "full,empty,not full,not empty,false", 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 return tubelib.send_request(data.number, "fuel", nil) ~= string.sub(data.value_text or "???", 5) else @@ -254,7 +315,7 @@ smartline.register_condition("fuel", { }) smartline.register_condition("signaltower", { - title = "Signal Tower state", + title = "Signal Tower state request", formspec = { { type = "field", @@ -266,17 +327,17 @@ smartline.register_condition("signaltower", { type = "textlist", name = "value", 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, }, { type = "label", 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 return tubelib.send_request(data.number, "state", nil) ~= string.sub(data.value_text or "???", 5) else @@ -308,8 +369,13 @@ smartline.register_action("signaltower", { choices = "off,green,amber,red", 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) end, button_label = function(data) @@ -318,7 +384,7 @@ smartline.register_action("signaltower", { }) smartline.register_action("switch", { - title = "switch nodes on/off", + title = "node on/off command", formspec = { { type = "field", @@ -339,7 +405,7 @@ smartline.register_action("switch", { 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) end, button_label = function(data) @@ -365,11 +431,12 @@ smartline.register_action("display1", { { type = "label", 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) - tubelib.send_message(data.number, data.owner, nil, "text", data.text) + on_execute = function(data, environ, number) + local text = string.gsub(data.text, "*", environ.state or "") + tubelib.send_message(data.number, data.owner, nil, "text", text) end, button_label = function(data) return "display("..data.number..")" @@ -401,11 +468,12 @@ smartline.register_action("display2", { { type = "label", 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) - local payload = {row = data.row, str = data.text} + on_execute = function(data, environ, number) + local text = string.gsub(data.text, "*", environ.state or "") + local payload = {row = data.row, str = text} tubelib.send_message(data.number, data.owner, nil, "row", payload) end, button_label = function(data) @@ -431,11 +499,11 @@ smartline.register_action("display3", { { type = "label", 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) - local text = string.gsub(data.text, "*", flags.name or "") + on_execute = function(data, environ, number) + local text = string.gsub(data.text, "*", environ.name or "") tubelib.send_message(data.number, data.owner, nil, "text", text) end, button_label = function(data) @@ -453,7 +521,7 @@ smartline.register_action("display4", { default = "", }, }, - on_execute = function(data, flags, timers, number) + on_execute = function(data, environ, number) tubelib.send_message(data.number, data.owner, nil, "clear", "") end, button_label = function(data) @@ -463,7 +531,7 @@ smartline.register_action("display4", { if minetest.get_modpath("mail") and mail ~= nil then smartline.register_action("mail", { - title = "mail", + title = "mail send", formspec = { { type = "field", @@ -471,8 +539,13 @@ if minetest.get_modpath("mail") and mail ~= nil then label = "send the message", 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) end, button_label = function(data) @@ -482,7 +555,7 @@ if minetest.get_modpath("mail") and mail ~= nil then end smartline.register_action("chat", { - title = "chat", + title = "chat send", formspec = { { type = "field", @@ -490,8 +563,13 @@ smartline.register_action("chat", { label = "send the message", 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) end, button_label = function(data) @@ -527,7 +605,7 @@ smartline.register_action("door", { }, { type = "textlist", - name = "state", + name = "door_state", label = "set", choices = "open,close", default = 1, @@ -535,24 +613,24 @@ smartline.register_action("door", { { type = "label", name = "lbl1", - label = "For standard doors like the Steel Door", + label = "For standard doors like the Steel Doors.", }, { type = "label", 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) - door_toggle(data.pos, data.owner, data.state_text) + on_execute = function(data, environ, number) + door_toggle(data.pos, data.owner, data.door_state_text) end, button_label = function(data) - return "door("..data.state_text..")" + return "door("..data.door_state_text..")" end, }) smartline.register_condition("playerdetector", { - title = "detected player name", + title = "Player Detector: name request", formspec = { { type = "field", @@ -569,13 +647,13 @@ smartline.register_condition("playerdetector", { { type = "label", 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) - flags.name = tubelib.send_request(data.number, "name", nil) - return (data.name == "*" and flags.name ~= "") or flags.name == data.name + on_execute = function(data, environ) + environ.name = tubelib.send_request(data.number, "name", nil) + return (data.name == "*" and environ.name ~= "") or environ.name == data.name end, button_label = function(data) if string.len(data.name) > 6 then @@ -586,7 +664,7 @@ smartline.register_condition("playerdetector", { }) smartline.register_condition("action", { - title = "action", + title = "actions", formspec = { { type = "textlist", @@ -598,11 +676,11 @@ smartline.register_condition("action", { { type = "label", 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) - return actions[data.action] == true + on_execute = function(data, environ) + return environ.actions[data.action] == true end, button_label = function(data) return "action"..data.action diff --git a/smartline/controller.lua b/smartline/controller.lua index 085a476..f2cab0e 100644 --- a/smartline/controller.lua +++ b/smartline/controller.lua @@ -63,7 +63,7 @@ The colors show, if conditions are true or false and if actions were already executed or not. 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" @@ -109,12 +109,12 @@ local CondRunTimeHandlers = {} local ActnRunTimeHandlers = {} -local function eval_cond(data, flags, timers, inputs, actions) - return CondRunTimeHandlers[data.__idx__](data, flags, timers, inputs, actions) and 1 or 0 +local function eval_cond(data, environ) + return CondRunTimeHandlers[data.__idx__](data, environ) and 1 or 0 end -local function exec_action(data, flags, timers, number) - ActnRunTimeHandlers[data.__idx__](data, flags, timers, number) +local function exec_action(data, environ, number) + ActnRunTimeHandlers[data.__idx__](data, environ, number) end smartline = {} @@ -255,20 +255,30 @@ local function runtime_data(postfix, type, fs_data) end local function decrement_timers(timers) - for idx,_ in ipairs(timers) do - timers[idx] = tonumber(timers[idx]) - if timers[idx] >= 0 then - timers[idx] = timers[idx] - 1 + if timers ~= nil then + for idx,_ in pairs(timers) do + timers[idx] = tonumber(timers[idx]) + if timers[idx] >= 0 then + timers[idx] = timers[idx] - 1 + 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 -- 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_img.. 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] = "textlist[0,0.6;8,1.4;cond;"..sConditions..";"..cond_idx.."]" 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[6,9.4;2,1;_exit_;ok]" + tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]" + tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]" return table.concat(tbl) end @@ -312,7 +322,7 @@ end -- Action formspec -- 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_img.. 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] = "textlist[0,0.6;8,1.4;actn;"..sActions..";"..actn_idx.."]" 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[6,9.4;2,1;_exit_;ok]" + tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]" + tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]" return table.concat(tbl) end @@ -416,7 +426,7 @@ local function eval_formspec_oprnd(meta, fs_data, fields, readonly) end 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_img.. 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:]"} 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] = "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 "...").."]" @@ -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[11.5,".. ypos..";3.4,1;actna"..idx..";"..(fs_data["actna"..idx] or "...").."]" end - tbl[#tbl+1] = "image_button[14,9;1,1;".. tubelib.state_button(state) ..";button;]" - tbl[#tbl+1] = "button[10.6,9;1.5,1;state;state]" - tbl[#tbl+1] = "button[12.2,9;1.5,1;help;help]" - tbl[#tbl+1] = "label[0.2,8.8;"..output.."]" - tbl[#tbl+1] = "field[0.4,9.6;4.8,1;cmnd;;]" - tbl[#tbl+1] = "button[5,9.3;1,1;ok;OK]" + tbl[#tbl+1] = "image_button[14,8.1;1,1;".. tubelib.state_button(state) ..";button;]" + tbl[#tbl+1] = "button[10.6,8.2;1.5,1;state;state]" + tbl[#tbl+1] = "button[12.2,8.2;1.5,1;help;help]" + tbl[#tbl+1] = "label[0.2,8.4;"..output.."]" + tbl[#tbl+1] = "field[6.5,8.5;3,1;cmnd;;]" + tbl[#tbl+1] = "button[9.2,8.2;1,1;ok;OK]" return table.concat(tbl) end @@ -466,7 +476,7 @@ local function eval_formspec_main(meta, fs_data, fields, readonly) end local function formspec_help(offs) - return "size[15,10]".. + return "size[15,9]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. @@ -474,7 +484,7 @@ local function formspec_help(offs) "label[0,"..(-offs/50)..";"..sHELP.."]".. --"label[0.2,0;test]".. "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 local function background(xpos, ypos, val) @@ -490,7 +500,7 @@ end local function formspec_state(meta, fs_data) local number = meta:get_string("number") local state = meta:get_int("state") - local tbl = {"size[15,10;true]".. + local tbl = {"size[15,9;true]".. default.gui_bg.. default.gui_bg_img.. 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:]"} if state == tubelib.RUNNING and number then - local inputs = tubelib.get_data(number, "inputs") or {} - local act_gate = tubelib.get_data(number, "act_gate") or {} - local timers = tubelib.get_data(number, "timers") or {} - local flags = tubelib.get_data(number, "flags") or {} - local conds = tubelib.get_data(number, "conds") or {} + local environ = tubelib.get_data(number, "environ") + local act_gate = tubelib.get_data(number, "act_gate") + local conds = tubelib.get_data(number, "conds") - for idx = 1,NUM_RULES do - local ypos = idx * 0.6 + 0.2 - local s1 = fs_data["cond1"..idx] or " ... " - local s2 = fs_data["cond2"..idx] or " ... " - local sa = fs_data["actna"..idx] or " ... " - if conds[idx] == nil then - tbl[#tbl+1] = background(3.7, ypos, nil) - tbl[#tbl+1] = background(8, ypos, nil) - else - 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) + if environ and act_gate and conds then + for idx = 1,NUM_RULES do + local ypos = idx * 0.6 + 0.2 + local s1 = fs_data["cond1"..idx] or " ... " + local s2 = fs_data["cond2"..idx] or " ... " + local sa = fs_data["actna"..idx] or " ... " + if conds[idx] == nil then + tbl[#tbl+1] = background(3.7, ypos, nil) + tbl[#tbl+1] = background(8, ypos, nil) + else + 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 - 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.."]" + + tbl[#tbl+1] = "label[10,7; Seconds: "..(meta:get_int("runtime") or 1).."]" + + tbl[#tbl+1] = "label[0,7;"..output("Inputs", "i(", ")", environ.inputs).."]" + tbl[#tbl+1] = "label[0,7.6;"..output("Timers", "t", "", environ.timers).."]" + tbl[#tbl+1] = "label[0,8.2;"..output("Flags", "f", "", environ.flags).."]" + + 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 - - 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 - tbl[#tbl+1] = "button[13.3,8;1.7,1;update;update]" - tbl[#tbl+1] = "button[13.3,9;1.7,1;close;close]" + tbl[#tbl+1] = "button[13.3,6.9;1.7,1;update;update]" + tbl[#tbl+1] = "button[13.3,7.8;1.7,1;close;close]" return table.concat(tbl) end local function execute(meta, number, debug) local rt_rules = tubelib.get_data(number, "rt_rules") - local inputs = tubelib.get_data(number, "inputs") or {} - local act_gate = tubelib.get_data(number, "act_gate") or {} - local timers = tubelib.get_data(number, "timers") or {} - local flags = tubelib.get_data(number, "flags") or {} - local conds = tubelib.get_data(number, "conds") or {} - local actions = {} - decrement_timers(timers) - for i,item in ipairs(rt_rules) do - local c1 = eval_cond(item.cond1, flags, timers, inputs, actions) - local c2 = eval_cond(item.cond2, flags, timers, inputs, actions) - conds[i] = c1 + c2*2 - if c1 + c2 >= item.cond_cnt then - if act_gate[i] == nil then - -- execute action - exec_action(item.actn, flags, timers, number) - actions[i] = true + local environ = tubelib.get_data(number, "environ") + local act_gate = tubelib.get_data(number, "act_gate") + local conds = tubelib.get_data(number, "conds") + if rt_rules and environ and act_gate and conds then + environ.actions = {} + decrement_timers(environ.timers) + toggle_flag(environ) + for i,item in ipairs(rt_rules) do + local c1 = eval_cond(item.cond1, environ) + local c2 = eval_cond(item.cond2, environ) + conds[i] = c1 + c2*2 + if c1 + c2 >= item.cond_cnt then + if act_gate[i] == nil then + -- execute action + exec_action(item.actn, environ, number) + environ.actions[i] = true + act_gate[i] = true + end + else + act_gate[i] = nil end - act_gate[i] = true - else - act_gate[i] = nil 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 local function check_rules(pos, elapsed) @@ -605,11 +611,14 @@ local function switch_state(pos, state, fs_data) end local function start_controller(pos, number, fs_data) - tubelib.set_data(number, "timers", {}) -- local timers - tubelib.set_data(number, "inputs", {}) -- for rx commands - tubelib.set_data(number, "flags", {}) -- to store flags - tubelib.set_data(number, "conds", {}) -- to store conditions - tubelib.set_data(number, "act_gate", {}) -- for action states + -- delete old data + tubelib.set_data(number, "environ", { + timers = {}, + flags = {}, + inputs = {} + }) + tubelib.set_data(number, "conds", {}) + tubelib.set_data(number, "act_gate", {}) switch_state(pos, tubelib.RUNNING, fs_data) end @@ -854,10 +863,10 @@ minetest.register_craft({ local function set_input(meta, payload, val) if payload then local number = meta:get_string("number") - local inputs = tubelib.get_data(number, "inputs") - if inputs then - inputs[payload] = val - tubelib.set_data(number, "inputs", inputs) + local environ = tubelib.get_data(number, "environ") or {} + if environ.inputs then + environ.inputs[payload] = val + tubelib.set_data(number, "environ", environ) end end end @@ -908,6 +917,25 @@ local function update_node_database(meta) return tOld2NewCond, tOld2NewActn 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({ label = "[SmartLine] Controller update", name = "smartline:update", @@ -932,6 +960,8 @@ minetest.register_lbm({ local number = meta:get_string("number") local owner = meta:get_string("owner") formspec2runtime_rule(number, owner, fs_data) + + maintain_dataset(number) end })