summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesecons/actionqueue.lua119
-rw-r--r--mesecons/init.lua86
-rw-r--r--mesecons/internal.lua233
-rw-r--r--mesecons/legacy.lua29
-rw-r--r--mesecons/services.lua8
-rw-r--r--mesecons/settings.lua2
-rw-r--r--mesecons/util.lua12
-rw-r--r--mesecons_delayer/init.lua14
-rw-r--r--mesecons_gates/init.lua3
-rw-r--r--mesecons_luacontroller/init.lua51
-rw-r--r--mesecons_microcontroller/init.lua61
11 files changed, 396 insertions, 222 deletions
diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua
new file mode 100644
index 0000000..cf74d47
--- /dev/null
+++ b/mesecons/actionqueue.lua
@@ -0,0 +1,119 @@
+mesecon.queue.actions={} -- contains all ActionQueue actions
+
+function mesecon.queue:add_function(name, func)
+ mesecon.queue.funcs[name] = func
+end
+
+-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
+-- use overwritecheck nil to never overwrite, but just add the event to the queue
+-- priority specifies the order actions are executed within one globalstep, highest by default
+-- should be between 0 and 1
+function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
+ -- Create Action Table:
+ time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
+ priority = priority or 1
+ action = { pos=mesecon:tablecopy(pos),
+ func=func,
+ params=mesecon:tablecopy(params),
+ time=time,
+ owcheck=(overwritecheck and mesecon:tablecopy(overwritecheck)) or nil,
+ priority=priority}
+
+ -- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done
+ if not MESECONS_GLOBALSTEP and action.time == 0 then
+ mesecon.queue:execute(action)
+ return
+ end
+
+ local toremove = nil
+ -- Otherwise, add the action to the queue
+ if overwritecheck then -- check if old action has to be overwritten / removed:
+ for i, ac in ipairs(mesecon.queue.actions) do
+ if(mesecon:cmpPos(pos, ac.pos)
+ and mesecon:cmpAny(overwritecheck, ac.owcheck)) then
+ toremove = i
+ break
+ end
+ end
+ end
+
+ if (toremove ~= nil) then
+ table.remove(mesecon.queue.actions, toremove)
+ end
+
+ table.insert(mesecon.queue.actions, action)
+end
+
+-- execute the stored functions on a globalstep
+-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
+-- this makes sure that resuming mesecons circuits when restarting minetest works fine
+-- However, even that does not work in some cases, that's why we delay the time the globalsteps
+-- start to be execute by 5 seconds
+local get_highest_priority = function (actions)
+ local highestp = 0, highesti
+ for i, ac in ipairs(actions) do
+ if ac.priority > highestp then
+ highestp = ac.priority
+ highesti = i
+ end
+ end
+
+ return highesti
+end
+
+local m_time = 0
+minetest.register_globalstep(function (dtime)
+ m_time = m_time + dtime
+ if (m_time < MESECONS_RESUMETIME) then return end -- don't even try if server has not been running for XY seconds
+ local actions = mesecon:tablecopy(mesecon.queue.actions)
+ local actions_now={}
+
+ mesecon.queue.actions = {}
+
+ -- sort actions in execute now (actions_now) and for later (mesecon.queue.actions)
+ for i, ac in ipairs(actions) do
+ if ac.time > 0 then
+ ac.time = ac.time - dtime -- executed later
+ table.insert(mesecon.queue.actions, ac)
+ else
+ table.insert(actions_now, ac)
+ end
+ end
+
+ while(#actions_now > 0) do -- execute highest priorities first, until all are executed
+ local hp = get_highest_priority(actions_now)
+ mesecon.queue:execute(actions_now[hp])
+ table.remove(actions_now, hp)
+ end
+end)
+
+function mesecon.queue:execute(action)
+ mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
+end
+
+
+-- Store and read the ActionQueue to / from a file
+-- so that upcoming actions are remembered when the game
+-- is restarted
+
+local wpath = minetest.get_worldpath()
+local function file2table(filename)
+ local f = io.open(filename, "r")
+ if f==nil then return {} end
+ local t = f:read("*all")
+ f:close()
+ if t=="" or t==nil then return {} end
+ return minetest.deserialize(t)
+end
+
+local function table2file(filename, table)
+ local f = io.open(filename, "w")
+ f:write(minetest.serialize(table))
+ f:close()
+end
+
+mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue")
+
+minetest.register_on_shutdown(function()
+ mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
+end)
diff --git a/mesecons/init.lua b/mesecons/init.lua
index 640af4d..b5cf68b 100644
--- a/mesecons/init.lua
+++ b/mesecons/init.lua
@@ -42,37 +42,8 @@
-- PUBLIC VARIABLES
mesecon={} -- contains all functions and all global variables
-mesecon.actions_on={} -- Saves registered function callbacks for mesecon on | DEPRECATED
-mesecon.actions_off={} -- Saves registered function callbacks for mesecon off | DEPRECATED
-mesecon.actions_change={} -- Saves registered function callbacks for mesecon change | DEPRECATED
-mesecon.receptors={} -- saves all information about receptors | DEPRECATED
-mesecon.effectors={} -- saves all information about effectors | DEPRECATED
-mesecon.conductors={} -- saves all information about conductors | DEPRECATED
-
-
-local wpath = minetest.get_worldpath()
-local function read_file(fn)
- local f = io.open(fn, "r")
- if f==nil then return {} end
- local t = f:read("*all")
- f:close()
- if t=="" or t==nil then return {} end
- return minetest.deserialize(t)
-end
-
-local function write_file(fn, tbl)
- local f = io.open(fn, "w")
- f:write(minetest.serialize(tbl))
- f:close()
-end
-
-mesecon.to_update = read_file(wpath.."/mesecon_to_update")
-mesecon.r_to_update = read_file(wpath.."/mesecon_r_to_update")
-
-minetest.register_on_shutdown(function()
- write_file(wpath.."/mesecon_to_update",mesecon.to_update)
- write_file(wpath.."/mesecon_r_to_update",mesecon.r_to_update)
-end)
+mesecon.queue={} -- contains the ActionQueue
+mesecon.queue.funcs={} -- contains all ActionQueue functions
-- Settings
dofile(minetest.get_modpath("mesecons").."/settings.lua")
@@ -86,6 +57,10 @@ dofile(minetest.get_modpath("mesecons").."/presets.lua");
-- mostly things that make the source look cleaner
dofile(minetest.get_modpath("mesecons").."/util.lua");
+-- The ActionQueue
+-- Saves all the actions that have to be execute in the future
+dofile(minetest.get_modpath("mesecons").."/actionqueue.lua");
+
-- Internal stuff
-- This is the most important file
-- it handles signal transmission and basically everything else
@@ -101,9 +76,22 @@ dofile(minetest.get_modpath("mesecons").."/legacy.lua");
-- API
-- these are the only functions you need to remember
-function mesecon:receptor_on_i(pos, rules)
+mesecon.queue:add_function("receptor_on", function (pos, rules)
rules = rules or mesecon.rules.default
+ -- if area (any of the rule targets) is not loaded, keep trying and call this again later
+ if MESECONS_GLOBALSTEP then -- trying to enable resuming with globalstep disabled would cause an endless loop
+ for _, rule in ipairs(mesecon:flattenrules(rules)) do
+ local np = mesecon:addPosRule(pos, rule)
+ -- if area is not loaded, keep trying
+ if minetest.get_node_or_nil(np) == nil then
+ mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
+ return
+ end
+ end
+ end
+
+ -- execute action
for _, rule in ipairs(mesecon:flattenrules(rules)) do
local np = mesecon:addPosRule(pos, rule)
local rulenames = mesecon:rules_link_rule_all(pos, rule)
@@ -111,19 +99,26 @@ function mesecon:receptor_on_i(pos, rules)
mesecon:turnon(np, rulename)
end
end
-end
+end)
function mesecon:receptor_on(pos, rules)
- if MESECONS_GLOBALSTEP then
- rules = rules or mesecon.rules.default
- mesecon.r_to_update[#mesecon.r_to_update+1]={pos=pos, rules=rules, action="on"}
- else
- mesecon:receptor_on_i(pos, rules)
- end
+ mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
end
-function mesecon:receptor_off_i(pos, rules)
+mesecon.queue:add_function("receptor_off", function (pos, rules)
rules = rules or mesecon.rules.default
+
+ -- if area (any of the rule targets) is not loaded, keep trying and call this again later
+ if MESECONS_GLOBALSTEP then
+ for _, rule in ipairs(mesecon:flattenrules(rules)) do
+ local np = mesecon:addPosRule(pos, rule)
+ if minetest.get_node_or_nil(np) == nil then
+ mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
+ return
+ end
+ end
+ end
+
for _, rule in ipairs(mesecon:flattenrules(rules)) do
local np = mesecon:addPosRule(pos, rule)
local rulenames = mesecon:rules_link_rule_all(pos, rule)
@@ -131,19 +126,14 @@ function mesecon:receptor_off_i(pos, rules)
if not mesecon:connected_to_receptor(np, mesecon:invertRule(rule)) then
mesecon:turnoff(np, rulename)
else
- mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off)
+ mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
end
end
end
-end
+end)
function mesecon:receptor_off(pos, rules)
- if MESECONS_GLOBALSTEP then
- rules = rules or mesecon.rules.default
- mesecon.r_to_update[#mesecon.r_to_update+1]={pos=pos, rules=rules, action="off"}
- else
- mesecon:receptor_off_i(pos, rules)
- end
+ mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
end
diff --git a/mesecons/internal.lua b/mesecons/internal.lua
index cb77f5d..3975b6a 100644
--- a/mesecons/internal.lua
+++ b/mesecons/internal.lua
@@ -22,9 +22,9 @@
-- mesecon:effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified)
-- SIGNALS
--- mesecon:activate(pos, node) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on)
--- mesecon:deactivate(pos, node) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off)
--- mesecon:changesignal(pos, node, rulename, newstate) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change)
+-- mesecon:activate(pos, node, recdepth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher recdepths are executed later
+-- mesecon:deactivate(pos, node, recdepth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), "
+-- mesecon:changesignal(pos, node, rulename, newstate) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), "
-- RULES
-- mesecon:add_rules(name, rules) | deprecated? --> Saves rules table by name
@@ -41,8 +41,8 @@
-- HIGH-LEVEL Internals
-- mesecon:is_power_on(pos) --> Returns true if pos emits power in any way
-- mesecon:is_power_off(pos) --> Returns true if pos does not emit power in any way
--- mesecon:turnon(pos, rulename) --> Returns true whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon
--- mesecon:turnoff(pos, rulename) --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff
+-- mesecon:turnon(pos, rulename) --> Returns true whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion
+-- mesecon:turnoff(pos, rulename) --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion
-- mesecon:connected_to_receptor(pos) --> Returns true if pos is connected to a receptor directly or via conductors; calls itself if pos is a conductor --> recursive
-- mesecon:rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
-- mesecon:rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon:rules_link but also returns true if output and input are swapped
@@ -177,121 +177,76 @@ function mesecon:effector_get_rules(node)
return mesecon.rules.default
end
---Signals
+-- #######################
+-- # Signals (effectors) #
+-- #######################
-function mesecon:activate(pos, node, rulename)
- if MESECONS_GLOBALSTEP then
- if rulename == nil then
- for _,rule in ipairs(mesecon:effector_get_rules(node)) do
- mesecon:activate(pos, node, rule)
- end
- return
- end
- add_action(pos, "on", rulename)
- else
- local effector = mesecon:get_effector(node.name)
- if effector and effector.action_on then
- effector.action_on (pos, node, rulename)
- end
- end
-end
+-- Activation:
+mesecon.queue:add_function("activate", function (pos, rulename)
+ node = minetest.get_node(pos)
+ effector = mesecon:get_effector(node.name)
-function mesecon:deactivate(pos, node, rulename)
- if MESECONS_GLOBALSTEP then
- if rulename == nil then
- for _,rule in ipairs(mesecon:effector_get_rules(node)) do
- mesecon:deactivate(pos, node, rule)
- end
- return
- end
- add_action(pos, "off", rulename)
- else
- local effector = mesecon:get_effector(node.name)
- if effector and effector.action_off then
- effector.action_off (pos, node, rulename)
- end
+ if effector and effector.action_on then
+ effector.action_on(pos, node, rulename)
end
-end
+end)
-function mesecon:changesignal(pos, node, rulename, newstate)
-
- newstate = newstate or "on"
- --rulename = rulename or mesecon.rules.default
- if MESECONS_GLOBALSTEP then
- if rulename == nil then
- for _,rule in ipairs(mesecon:effector_get_rules(node)) do
- mesecon:changesignal(pos, node, rule, newstate)
- end
- return
- end
- add_action(pos, "c"..newstate, rulename)
- else
- local effector = mesecon:get_effector(node.name)
- if effector and effector.action_change then
- effector.action_change (pos, node, rulename, newstate)
+function mesecon:activate(pos, node, rulename, recdepth)
+ if rulename == nil then
+ for _,rule in ipairs(mesecon:effector_get_rules(node)) do
+ mesecon:activate(pos, node, rule, recdepth + 1)
end
+ return
end
+ mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / recdepth)
end
-function execute_actions(dtime)
- local nactions = mesecon.to_update
- mesecon.to_update = {}
- for _,i in ipairs(nactions) do
- node = minetest.get_node(i.pos)
- if node.name=="ignore" then
- add_action(i.pos, i.action, i.rname)
- else
- effector = mesecon:get_effector(node.name)
- if i.action == "on" then
- if effector and effector.action_on then
- effector.action_on(i.pos, node, i.rname)
- end
- elseif i.action == "off" then
- if effector and effector.action_off then
- effector.action_off(i.pos, node, i.rname)
- end
- elseif i.action == "con" then
- if effector and effector.action_change then
- effector.action_change(i.pos, node, i.rname, "on")
- end
- elseif i.action == "coff" then
- if effector and effector.action_change then
- effector.action_change(i.pos, node, i.rname, "off")
- end
- end
- end
+
+-- Deactivation
+mesecon.queue:add_function("deactivate", function (pos, rulename)
+ node = minetest.get_node(pos)
+ effector = mesecon:get_effector(node.name)
+
+ if effector and effector.action_off then
+ effector.action_off(pos, node, rulename)
end
- local nactions = mesecon.r_to_update
- mesecon.r_to_update = {}
- for _,i in ipairs(nactions) do
- if i.action == "on" then
- mesecon:receptor_on_i(i.pos, i.rules)
- else
- mesecon:receptor_off_i(i.pos,i.rules)
+end)
+
+function mesecon:deactivate(pos, node, rulename, recdepth)
+ if rulename == nil then
+ for _,rule in ipairs(mesecon:effector_get_rules(node)) do
+ mesecon:deactivate(pos, node, rule, recdepth + 1)
end
+ return
end
+ mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / recdepth)
end
-minetest.register_globalstep(execute_actions)
-function add_action(pos, action, rname)
- for _,i in ipairs(mesecon.to_update) do
- if i.pos.x == pos.x and i.pos.y == pos.y and i.pos.z == pos.z and i.rname.x == rname.x and i.rname.y == rname.y and i.rname.z == rname.z then
- if (i.action == "on" and action == "on") or (i.action == "off" and action == "off") then
- --nothing
- elseif i.action == "coff" and action == "on" then i.action = "on"
- elseif i.action == "con" and action == "off" then i.action = "off"
- else
- if action == "on" or action == "con" then i.action = "con" end
- if action == "off" or action == "coff" then i.action = "coff" end
- end
- break
+-- Change
+mesecon.queue:add_function("change", function (pos, rulename, changetype)
+ node = minetest.get_node(pos)
+ effector = mesecon:get_effector(node.name)
+
+ if effector and effector.action_change then
+ effector.action_change(pos, node, rulename, changetype)
+ end
+end)
+
+function mesecon:changesignal(pos, node, rulename, newstate, recdepth)
+ if rulename == nil then
+ for _,rule in ipairs(mesecon:effector_get_rules(node)) do
+ mesecon:changesignal(pos, node, rule, newstate, recdepth + 1)
end
+ return
end
- mesecon.to_update[#mesecon.to_update+1] = {pos = pos, action = action, rname = rname}
+
+ mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / recdepth)
end
---Rules
+-- #########
+-- # Rules # "Database" for rulenames
+-- #########
function mesecon:add_rules(name, rules)
mesecon.rules[name] = rules
@@ -410,8 +365,15 @@ function mesecon:is_power_off(pos, rulename)
return false
end
-function mesecon:turnon(pos, rulename)
+function mesecon:turnon(pos, rulename, recdepth)
+ recdepth = recdepth or 2
local node = minetest.get_node(pos)
+
+ if(node.name == "ignore") then
+ -- try turning on later again
+ mesecon.queue:add_action(
+ pos, "turnon", {rulename, recdepth + 1}, nil, true)
+ end
if mesecon:is_conductor_off(node, rulename) then
local rules = mesecon:conductor_get_rules(node)
@@ -419,7 +381,7 @@ function mesecon:turnon(pos, rulename)
if not rulename then
for _, rule in ipairs(mesecon:flattenrules(rules)) do
if mesecon:connected_to_receptor(pos, rule) then
- mesecon:turnon(pos, rule)
+ mesecon:turnon(pos, rule, recdepth + 1)
end
end
return
@@ -429,54 +391,75 @@ function mesecon:turnon(pos, rulename)
for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do
local np = mesecon:addPosRule(pos, rule)
- local rulenames = mesecon:rules_link_rule_all(pos, rule)
+ if(minetest.get_node(np).name == "ignore") then
+ -- try turning on later again
+ mesecon.queue:add_action(
+ np, "turnon", {rulename, recdepth + 1}, nil, true)
+ else
+ local rulenames = mesecon:rules_link_rule_all(pos, rule)
- for _, rulename in ipairs(rulenames) do
- mesecon:turnon(np, rulename)
+ for _, rulename in ipairs(rulenames) do
+ mesecon:turnon(np, rulename, recdepth + 1)
+ end
end
end
elseif mesecon:is_effector(node.name) then
- mesecon:changesignal(pos, node, rulename, mesecon.state.on)
+ mesecon:changesignal(pos, node, rulename, mesecon.state.on, recdepth)
if mesecon:is_effector_off(node.name) then
- mesecon:activate(pos, node, rulename)
+ mesecon:activate(pos, node, rulename, recdepth)
end
end
end
-function mesecon:turnoff(pos, rulename)
+mesecon.queue:add_function("turnon", function (pos, rulename, recdepth)
+ if (MESECONS_GLOBALSTEP) then -- do not resume if we don't use globalstep - that would cause an endless loop
+ mesecon:turnon(pos, rulename, recdepth)
+ end
+end)
+
+function mesecon:turnoff(pos, rulename, recdepth)
+ recdepth = recdepth or 2
local node = minetest.get_node(pos)
+ if(node.name == "ignore") then
+ -- try turning on later again
+ mesecon.queue:add_action(
+ pos, "turnoff", {rulename, recdepth + 1}, nil, true)
+ end
+
if mesecon:is_conductor_on(node, rulename) then
local rules = mesecon:conductor_get_rules(node)
- --[[
- if not rulename then
- for _, rule in ipairs(mesecon:flattenrules(rules)) do
- if mesecon:is_powered(pos, rule) then
- mesecon:turnoff(pos, rule)
- end
- end
- return
- end
- --]]
minetest.swap_node(pos, {name = mesecon:get_conductor_off(node, rulename), param2 = node.param2})
for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do
local np = mesecon:addPosRule(pos, rule)
- local rulenames = mesecon:rules_link_rule_all(pos, rule)
+ if(minetest.get_node(np).name == "ignore") then
+ -- try turning on later again
+ mesecon.queue:add_action(
+ np, "turnoff", {rulename, recdepth + 1}, nil, true)
+ else
+ local rulenames = mesecon:rules_link_rule_all(pos, rule)
- for _, rulename in ipairs(rulenames) do
- mesecon:turnoff(np, rulename)
+ for _, rulename in ipairs(rulenames) do
+ mesecon:turnoff(np, rulename, recdepth + 1)
+ end
end
end
elseif mesecon:is_effector(node.name) then
- mesecon:changesignal(pos, node, rulename, mesecon.state.off)
+ mesecon:changesignal(pos, node, rulename, mesecon.state.off, recdepth)
if mesecon:is_effector_on(node.name)
and not mesecon:is_powered(pos) then
- mesecon:deactivate(pos, node, rulename)
+ mesecon:deactivate(pos, node, rulename, recdepth + 1)
end
end
end
+mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth)
+ if (MESECONS_GLOBALSTEP) then -- do not resume if we don't use globalstep - that would cause an endless loop
+ mesecon:turnoff(pos, rulename, recdepth)
+ end
+end)
+
function mesecon:connected_to_receptor(pos, rulename)
local node = minetest.get_node(pos)
diff --git a/mesecons/legacy.lua b/mesecons/legacy.lua
index a68bab4..c4334cf 100644
--- a/mesecons/legacy.lua
+++ b/mesecons/legacy.lua
@@ -2,4 +2,31 @@ minetest.swap_node = minetest.swap_node or function(pos, node)
local data = minetest.get_meta(pos):to_table()
minetest.add_node(pos, node)
minetest.get_meta(pos):from_table(data)
-end \ No newline at end of file
+end
+
+local rules = {}
+rules.a = {x = -1, y = 0, z = 0, name="A"}
+rules.b = {x = 0, y = 0, z = 1, name="B"}
+rules.c = {x = 1, y = 0, z = 0, name="C"}
+rules.d = {x = 0, y = 0, z = -1, name="D"}
+
+function legacy_update_ports(pos)
+ local meta = minetest.get_meta(pos)
+ L = {
+ a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a),
+ mesecon:invertRule(rules.a)) and
+ mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos),
+ b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b),
+ mesecon:invertRule(rules.b)) and
+ mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos),
+ c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c),
+ mesecon:invertRule(rules.c)) and
+ mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos),
+ d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d),
+ mesecon:invertRule(rules.d)) and
+ mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos),
+ }
+ local n = (L.a and 1 or 0) + (L.b and 2 or 0) + (L.c and 4 or 0) + (L.d and 8 or 0) + 1
+ meta:set_int("real_portstates", n)
+ return L
+end
diff --git a/mesecons/services.lua b/mesecons/services.lua
index 9d192ae..de0c8b6 100644
--- a/mesecons/services.lua
+++ b/mesecons/services.lua
@@ -6,19 +6,19 @@ mesecon.on_placenode = function (pos, node)
mesecon:turnon (pos)
--mesecon:receptor_on (pos, mesecon:conductor_get_rules(node))
else
- mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "on")
- mesecon:activate(pos, node)
+ mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "on", 1)
+ mesecon:activate(pos, node, nil, 1)
end
elseif mesecon:is_conductor_on(node) then
minetest.swap_node(pos, {name = mesecon:get_conductor_off(node)})
elseif mesecon:is_effector_on (node.name) then
- mesecon:deactivate(pos, node)
+ mesecon:deactivate(pos, node, nil, 1)
end
end
mesecon.on_dignode = function (pos, node)
if mesecon:is_conductor_on(node) then
- mesecon:receptor_off_i(pos, mesecon:conductor_get_rules(node))
+ mesecon:receptor_off(pos, mesecon:conductor_get_rules(node))
elseif mesecon:is_receptor_on(node.name) then
mesecon:receptor_off(pos, mesecon:receptor_get_rules(node))
end
diff --git a/mesecons/settings.lua b/mesecons/settings.lua
index e35bb1e..593a79b 100644
--- a/mesecons/settings.lua
+++ b/mesecons/settings.lua
@@ -7,3 +7,5 @@ PISTON_MAXIMUM_PUSH = 15
MOVESTONE_MAXIMUM_PUSH = 100
MESECONS_GLOBALSTEP = true -- true = receptors/effectors won't be updated
-- until next globalstep, decreases server load
+MESECONS_RESUMETIME = 4 -- time to wait when starting the server before
+ -- processing the ActionQueue, don't set this too low
diff --git a/mesecons/util.lua b/mesecons/util.lua
index b3ca7a0..91d435a 100644
--- a/mesecons/util.lua
+++ b/mesecons/util.lua
@@ -169,6 +169,7 @@ function mesecon:cmpSpecial(r1, r2)
end
function mesecon:tablecopy(table) -- deep table copy
+ if type(table) ~= "table" then return table end -- no need to copy
local newtable = {}
for idx, item in pairs(table) do
@@ -181,3 +182,14 @@ function mesecon:tablecopy(table) -- deep table copy
return newtable
end
+
+function mesecon:cmpAny(t1, t2)
+ if type(t1) ~= type(t2) then return false end
+ if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end
+
+ for i, e in pairs(t1) do
+ if not mesecon:cmpAny(e, t2[i]) then return false end
+ end
+
+ return true
+end
diff --git a/mesecons_delayer/init.lua b/mesecons_delayer/init.lua
index a03737c..4ec0ebc 100644
--- a/mesecons_delayer/init.lua
+++ b/mesecons_delayer/init.lua
@@ -17,28 +17,18 @@ end
-- Functions that are called after the delay time
-local delayer_turnon = function(params)
- local rules = delayer_get_output_rules(params.node)
- mesecon:receptor_on(params.pos, rules)
-end
-
-local delayer_turnoff = function(params)
- local rules = delayer_get_output_rules(params.node)
- mesecon:receptor_off(params.pos, rules)
-end
-
local delayer_activate = function(pos, node)
local def = minetest.registered_nodes[node.name]
local time = def.delayer_time
minetest.swap_node(pos, {name = def.delayer_onstate, param2=node.param2})
- minetest.after(time, delayer_turnon , {pos = pos, node = node})
+ mesecon.queue:add_action(pos, "receptor_on", {rules=delayer_get_output_rules(node)}, time, nil)
end
local delayer_deactivate = function(pos, node)
local def = minetest.registered_nodes[node.name]
local time = def.delayer_time
minetest.swap_node(pos, {name = def.delayer_offstate, param2=node.param2})
- minetest.after(time, delayer_turnoff, {pos = pos, node = node})
+ mesecon.queue:add_action(pos, "receptor_off", {rules=delayer_get_output_rules(node)}, time, nil)
end
-- Register the 2 (states) x 4 (delay times) delayers
diff --git a/mesecons_gates/init.lua b/mesecons_gates/init.lua
index 1a9ee83..51ed4af 100644
--- a/mesecons_gates/init.lua
+++ b/mesecons_gates/init.lua
@@ -23,7 +23,8 @@ function gate_get_input_rules_twoinputs(node)
return gate_rotate_rules(node)
end
-function update_gate(pos)
+function update_gate(pos, node, rulename, newstate)
+ yc_update_real_portstates(pos, node, rulename, newstate)
gate = get_gate(pos)
L = rotate_ports(
yc_get_real_portstates(pos),
diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua
index acbf023..c9a765e 100644
--- a/mesecons_luacontroller/init.lua
+++ b/mesecons_luacontroller/init.lua
@@ -31,18 +31,46 @@ rules.d = {x = 0, y = 0, z = -1, name="D"}
------------------
-- These helpers are required to set the portstates of the luacontroller
+function lc_update_real_portstates(pos, rulename, newstate)
+ local meta = minetest.get_meta(pos)
+ if rulename == nil then
+ meta:set_int("real_portstates", 1)
+ return
+ end
+ local n = meta:get_int("real_portstates") - 1
+ if n < 0 then
+ legacy_update_ports(pos)
+ n = meta:get_int("real_portstates") - 1
+ end
+ local L = {}
+ for i = 1, 4 do
+ L[i] = n%2
+ n = math.floor(n/2)
+ end
+ if rulename.x == nil then
+ for _, rname in ipairs(rulename) do
+ local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3]
+ L[port] = (newstate == "on") and 1 or 0
+ end
+ else
+ local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3]
+ L[port] = (newstate == "on") and 1 or 0
+ end
+ meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
+end
+
local get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
- ports = {
- a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a), mesecon:invertRule(rules.a))
- and mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos),
- b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b), mesecon:invertRule(rules.b))
- and mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos),
- c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c), mesecon:invertRule(rules.c))
- and mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos),
- d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d), mesecon:invertRule(rules.d))
- and mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos),
- }
- return ports
+ local meta = minetest.get_meta(pos)
+ local L = {}
+ local n = meta:get_int("real_portstates") - 1
+ if n < 0 then
+ return legacy_update_ports(pos)
+ end
+ for _, index in ipairs({"a", "b", "c", "d"}) do
+ L[index] = ((n%2) == 1)
+ n = math.floor(n/2)
+ end
+ return L
end
local merge_portstates = function (ports, vports)
@@ -457,6 +485,7 @@ local mesecons = {
{
rules = input_rules[cid],
action_change = function (pos, _, rulename, newstate)
+ lc_update_real_portstates(pos, rulename, newstate)
lc_update(pos, {type=newstate, pin=rulename})
end,
},
diff --git a/mesecons_microcontroller/init.lua b/mesecons_microcontroller/init.lua
index 55faa5c..b6134da 100644
--- a/mesecons_microcontroller/init.lua
+++ b/mesecons_microcontroller/init.lua
@@ -39,7 +39,8 @@ mesecon:add_rules(nodename, rules)
local mesecons = {effector =
{
rules = input_rules,
- action_change = function (pos, node, rulename)
+ action_change = function (pos, node, rulename, newstate)
+ yc_update_real_portstates(pos, node, rulename, newstate)
update_yc(pos)
end
}}
@@ -633,25 +634,45 @@ function yc_set_portstate(port, state, L)
return L
end
-function yc_get_real_portstates(pos) -- port powered or not (by itself or from outside)?
- rulesA = mesecon:get_rules("mesecons_microcontroller:microcontroller0001")
- rulesB = mesecon:get_rules("mesecons_microcontroller:microcontroller0010")
- rulesC = mesecon:get_rules("mesecons_microcontroller:microcontroller0100")
- rulesD = mesecon:get_rules("mesecons_microcontroller:microcontroller1000")
- L = {
- a = mesecon:is_power_on(mesecon:addPosRule(pos, rulesA[1]),
- mesecon:invertRule(rulesA[1])) and
- mesecon:rules_link(mesecon:addPosRule(pos, rulesA[1]), pos),
- b = mesecon:is_power_on(mesecon:addPosRule(pos, rulesB[1]),
- mesecon:invertRule(rulesB[1])) and
- mesecon:rules_link(mesecon:addPosRule(pos, rulesB[1]), pos),
- c = mesecon:is_power_on(mesecon:addPosRule(pos, rulesC[1]),
- mesecon:invertRule(rulesC[1])) and
- mesecon:rules_link(mesecon:addPosRule(pos, rulesC[1]), pos),
- d = mesecon:is_power_on(mesecon:addPosRule(pos, rulesD[1]),
- mesecon:invertRule(rulesD[1])) and
- mesecon:rules_link(mesecon:addPosRule(pos, rulesD[1]), pos),
- }
+function yc_update_real_portstates(pos, node, rulename, newstate)
+ local meta = minetest.get_meta(pos)
+ if rulename == nil then
+ meta:set_int("real_portstates", 1)
+ return
+ end
+ local n = meta:get_int("real_portstates") - 1
+ if n < 0 then
+ legacy_update_ports(pos)
+ n = meta:get_int("real_portstates") - 1
+ end
+ local L = {}
+ for i = 1, 4 do
+ L[i] = n%2
+ n = math.floor(n/2)
+ end
+ if rulename.x == nil then
+ for _, rname in ipairs(rulename) do
+ local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3]
+ L[port] = (newstate == "on") and 1 or 0
+ end
+ else
+ local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3]
+ L[port] = (newstate == "on") and 1 or 0
+ end
+ meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
+end
+
+function yc_get_real_portstates(pos) -- determine if ports are powered (by itself or from outside)
+ local meta = minetest.get_meta(pos)
+ local L = {}
+ local n = meta:get_int("real_portstates") - 1
+ if n < 0 then
+ return legacy_update_ports(pos)
+ end
+ for _, index in ipairs({"a", "b", "c", "d"}) do
+ L[index] = ((n%2) == 1)
+ n = math.floor(n/2)
+ end
return L
end