diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 9d31426..a00054a 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -6,15 +6,19 @@ 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 -function mesecon.queue:add_action(pos, func, params, time, overwritecheck) +-- 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 overwritecheck = overwritecheck or {} action = { pos=mesecon:tablecopy(pos), func=func, params=mesecon:tablecopy(params), time=time, - owcheck=mesecon:tablecopy(overwritecheck)} + owcheck=(overwritecheck and mesecon:tablecopy(overwritecheck)) or nil, + priority=priority} --print(dump(action)) -- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done @@ -42,6 +46,18 @@ end -- 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 @@ -53,10 +69,14 @@ minetest.register_globalstep(function (dtime) if action.time > 0 then action.time = action.time - dtime table.insert(mesecon.queue.actions, action) -- will be handled another time - else -- execute and remove - mesecon.queue:execute(action) end end + + while(#actions > 0) do -- execute highest priorities first, until all are executed + local hp = get_highest_priority(actions) + mesecon.queue:execute(actions[hp]) + table.remove(actions, hp) + end end) function mesecon.queue:execute(action) diff --git a/mesecons/init.lua b/mesecons/init.lua index 8facf73..4d4819c 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -79,12 +79,18 @@ dofile(minetest.get_modpath("mesecons").."/legacy.lua"); mesecon.queue:add_function("receptor_on", function (pos, rules) rules = rules or mesecon.rules.default + -- if area (any of the neighbors) is not loaded, keep trying and call this again later for _, rule in ipairs(mesecon:flattenrules(rules)) do local np = mesecon:addPosRule(pos, rule) - -- if area is not loaded, keep trying - if minetest.env:get_node_or_nil(np) == nil then + if minetest.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_on", {rules}) + return 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) for _, rulename in ipairs(rulenames) do mesecon:turnon(np, rulename) @@ -100,7 +106,7 @@ mesecon.queue:add_function("receptor_off", function (pos, rules) rules = rules or mesecon.rules.default for _, rule in ipairs(mesecon:flattenrules(rules)) do local np = mesecon:addPosRule(pos, rule) - if minetest.env:get_node_or_nil(np) == nil then + if minetest.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_off", {rules}) end local rulenames = mesecon:rules_link_rule_all(pos, rule) @@ -108,7 +114,7 @@ mesecon.queue:add_function("receptor_off", function (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, 1) end end end diff --git a/mesecons/internal.lua b/mesecons/internal.lua index f575c83..f713a7c 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 @@ -191,14 +191,14 @@ mesecon.queue:add_function("activate", function (pos, rulename) end end) -function mesecon:activate(pos, node, rulename) +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) + mesecon:activate(pos, node, rule, recdepth + 1) end return end - mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename) + mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / recdepth) end @@ -212,14 +212,14 @@ mesecon.queue:add_function("deactivate", function (pos, rulename) end end) -function mesecon:deactivate(pos, node, rulename) +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) + mesecon:deactivate(pos, node, rule, recdepth + 1) end return end - mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename) + mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / recdepth) end @@ -233,15 +233,15 @@ mesecon.queue:add_function("change", function (pos, rulename, changetype) end end) -function mesecon:changesignal(pos, node, rulename, newstate) +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) + mesecon:changesignal(pos, node, rule, newstate, recdepth + 1) end return end - mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename) + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / recdepth) end -- ######### @@ -365,7 +365,8 @@ 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 mesecon:is_conductor_off(node, rulename) then @@ -374,7 +375,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 @@ -387,32 +388,23 @@ function mesecon:turnon(pos, rulename) local rulenames = mesecon:rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do - mesecon:turnon(np, rulename) + mesecon:turnon(np, rulename, recdepth + 1) 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) +function mesecon:turnoff(pos, rulename, recdepth) + recdepth = recdepth or 0 local node = minetest.get_node(pos) 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 @@ -420,14 +412,14 @@ function mesecon:turnoff(pos, rulename) local rulenames = mesecon:rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do - mesecon:turnoff(np, rulename) + mesecon:turnoff(np, rulename, recdepth + 1) 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 diff --git a/mesecons/services.lua b/mesecons/services.lua index 29b5183..de0c8b6 100644 --- a/mesecons/services.lua +++ b/mesecons/services.lua @@ -6,13 +6,13 @@ 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 diff --git a/mesecons/util.lua b/mesecons/util.lua index ad2a4ae..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