From 2d004b19eaaac21b4a82fa4ba6736e5e7090041a Mon Sep 17 00:00:00 2001 From: Jeija Date: Fri, 10 Jan 2014 22:29:18 +0100 Subject: [PATCH 01/12] First draft of some kind of Action Queue (just like the globalstep queue in to_update), but more flexible and also including delay functionality (mesecon_delayer). The queue is also saved to a file, so that when restarting mesecons, delayers resume to the state they had when the game shut down. Needs testing. --- mesecons/actionqueue.lua | 90 ++++++++++++++++++++++ mesecons/init.lua | 66 +++++----------- mesecons/internal.lua | 153 ++++++++++++++------------------------ mesecons/services.lua | 2 +- mesecons/util.lua | 11 +++ mesecons_delayer/init.lua | 14 +--- 6 files changed, 177 insertions(+), 159 deletions(-) create mode 100644 mesecons/actionqueue.lua diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua new file mode 100644 index 0000000..8eae192 --- /dev/null +++ b/mesecons/actionqueue.lua @@ -0,0 +1,90 @@ +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 +function mesecon.queue:add_action(pos, func, params, time, overwritecheck) + -- Create Action Table: + time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution + action = { pos=pos, + func=func, + params=mesecon:tablecopy(params), + time=time, + owcheck=overwritecheck} + + --print(dump(action)) + -- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done + if not MESECONS_GLOBALSTEP then + mesecon.queue:execute(action) + return + end + + -- 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, action.pos) + and mesecon:cmpAny(overwritecheck, ac.owcheck)) then + table.remove(mesecon.queue.actions, i) + break + end + end + 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 m_time = 0 +minetest.register_globalstep(function (dtime) + m_time = m_time + dtime + if (m_time < 5) then return end -- don't even try if server has not been running for 2 seconds + local actions = mesecon:tablecopy(mesecon.queue.actions) + mesecon.queue.actions = {} + + for i, action in ipairs(actions) do + 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 +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..8facf73 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,31 +76,33 @@ 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 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 + mesecon.queue:add_action(pos, "receptor_on", {rules}) + end local rulenames = mesecon:rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do 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}) end -function mesecon:receptor_off_i(pos, rules) +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 + mesecon.queue:add_action(pos, "receptor_off", {rules}) + end local rulenames = mesecon:rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do if not mesecon:connected_to_receptor(np, mesecon:invertRule(rule)) then @@ -135,15 +112,10 @@ function mesecon:receptor_off_i(pos, rules) 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}) end diff --git a/mesecons/internal.lua b/mesecons/internal.lua index cb77f5d..f575c83 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -177,121 +177,76 @@ function mesecon:effector_get_rules(node) return mesecon.rules.default end ---Signals +-- ####################### +-- # Signals (effectors) # +-- ####################### + +-- Activation: +mesecon.queue:add_function("activate", function (pos, rulename) + node = minetest.get_node(pos) + effector = mesecon:get_effector(node.name) + + if effector and effector.action_on then + effector.action_on(pos, node, rulename) + end +end) 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) + if rulename == nil then + for _,rule in ipairs(mesecon:effector_get_rules(node)) do + mesecon:activate(pos, node, rule) end + return end + mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename) 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 +end) + 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) + if rulename == nil then + for _,rule in ipairs(mesecon:effector_get_rules(node)) do + mesecon:deactivate(pos, node, rule) end + return end + mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename) end + +-- 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) - - 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 + 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) - end end + + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename) 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 - 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 - end -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 - end - end - mesecon.to_update[#mesecon.to_update+1] = {pos = pos, action = action, rname = rname} -end - ---Rules +-- ######### +-- # Rules # "Database" for rulenames +-- ######### function mesecon:add_rules(name, rules) mesecon.rules[name] = rules diff --git a/mesecons/services.lua b/mesecons/services.lua index 9d192ae..29b5183 100644 --- a/mesecons/services.lua +++ b/mesecons/services.lua @@ -18,7 +18,7 @@ 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/util.lua b/mesecons/util.lua index b3ca7a0..ad2a4ae 100644 --- a/mesecons/util.lua +++ b/mesecons/util.lua @@ -181,3 +181,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 From f1ae54ed12413ee90675a6fc92da25f3a78e97d2 Mon Sep 17 00:00:00 2001 From: Novatux Date: Fri, 10 Jan 2014 16:38:02 +0100 Subject: [PATCH 02/12] Try to fix gateswith serverstep code. --- mesecons/legacy.lua | 29 ++++++++++++++- mesecons_gates/init.lua | 3 +- mesecons_luacontroller/init.lua | 51 ++++++++++++++++++++------ mesecons_microcontroller/init.lua | 61 +++++++++++++++++++++---------- 4 files changed, 111 insertions(+), 33 deletions(-) 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_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 From 93fb489bdb8c13989c398b37be3135004f7b0bbc Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 08:57:21 +0100 Subject: [PATCH 03/12] Fix the bugs spotted by Novatux - thanks for spotting them --- mesecons/actionqueue.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 8eae192..9d31426 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -9,11 +9,12 @@ end function mesecon.queue:add_action(pos, func, params, time, overwritecheck) -- Create Action Table: time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution - action = { pos=pos, + overwritecheck = overwritecheck or {} + action = { pos=mesecon:tablecopy(pos), func=func, params=mesecon:tablecopy(params), time=time, - owcheck=overwritecheck} + owcheck=mesecon:tablecopy(overwritecheck)} --print(dump(action)) -- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done @@ -25,7 +26,7 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck) -- 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, action.pos) + if(mesecon:cmpPos(pos, ac.pos) and mesecon:cmpAny(overwritecheck, ac.owcheck)) then table.remove(mesecon.queue.actions, i) break From f1211f7dae58ff4298b6bf4fcaa572e7995ab5e2 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 10:04:32 +0100 Subject: [PATCH 04/12] Add ActionQueue priority system This makes effectors nearer to the source of the action (the receptor) update first. This defines behaviour for this piston circuit: http://i.imgur.com/9Pp2Mzb.png And defines, that this memory circuit does not work from this direction: http://i.imgur.com/jJn0aFh.png But it will work when using the switch from the other side: http://i.imgur.com/nvw0oZB.png Only if two effectors have the same distance, there is nothing we can do about it, behaviour is not defined. "Distance" is determined by the stack size of recursions in turnon / turnoff. Priorities are between 0 (lowest) and 1 (highest). --- mesecons/actionqueue.lua | 28 ++++++++++++++++--- mesecons/init.lua | 14 +++++++--- mesecons/internal.lua | 58 +++++++++++++++++----------------------- mesecons/services.lua | 6 ++--- mesecons/util.lua | 1 + 5 files changed, 63 insertions(+), 44 deletions(-) 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 From ff5e3153257ae8789d43297d1c3739e6a22cd105 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 15:36:30 +0100 Subject: [PATCH 05/12] Fix ActionQueue delays --- mesecons/actionqueue.lua | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index a00054a..1c02b46 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -63,19 +63,24 @@ minetest.register_globalstep(function (dtime) m_time = m_time + dtime if (m_time < 5) then return end -- don't even try if server has not been running for 2 seconds local actions = mesecon:tablecopy(mesecon.queue.actions) + local actions_now={} + mesecon.queue.actions = {} - for i, action in ipairs(actions) do - if action.time > 0 then - action.time = action.time - dtime - table.insert(mesecon.queue.actions, action) -- will be handled another time + -- 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 > 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) + 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) From 6afded8284e42c8b976d8685f537d8d54264277a Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 16:18:35 +0100 Subject: [PATCH 06/12] Fix unloaded area in receptor_off, yet it was only fixed in receptor_on --- mesecons/init.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mesecons/init.lua b/mesecons/init.lua index 4d4819c..523263d 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -79,7 +79,7 @@ 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 + -- if area (any of the rule targets) 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 minetest.get_node_or_nil(np) == nil then @@ -104,11 +104,17 @@ end 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 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}) 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) for _, rulename in ipairs(rulenames) do if not mesecon:connected_to_receptor(np, mesecon:invertRule(rule)) then From 1083539e9b82c729687f012e741614d1fc216757 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 16:46:27 +0100 Subject: [PATCH 07/12] Resume turnon/off calls as soon as area is loaded in case turnon/off calls end in unloaded territory --- mesecons/actionqueue.lua | 8 ++++++-- mesecons/internal.lua | 44 ++++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 1c02b46..66e9fd7 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -20,24 +20,28 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior 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 if not MESECONS_GLOBALSTEP 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 - table.remove(mesecon.queue.actions, i) + toremove = i break end end end + if (toremove ~= nil) then + table.remove(mesecon.queue.actions, i) + end + table.insert(mesecon.queue.actions, action) end diff --git a/mesecons/internal.lua b/mesecons/internal.lua index f713a7c..8e58d73 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -368,6 +368,12 @@ end 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, rulename) + end if mesecon:is_conductor_off(node, rulename) then local rules = mesecon:conductor_get_rules(node) @@ -385,10 +391,16 @@ function mesecon:turnon(pos, rulename, recdepth) 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, rulename) + else + local rulenames = mesecon:rules_link_rule_all(pos, rule) - for _, rulename in ipairs(rulenames) do - mesecon:turnon(np, rulename, recdepth + 1) + for _, rulename in ipairs(rulenames) do + mesecon:turnon(np, rulename, recdepth + 1) + end end end elseif mesecon:is_effector(node.name) then @@ -399,20 +411,36 @@ function mesecon:turnon(pos, rulename, recdepth) end end +mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) + mesecon:turnon(pos, rulename, recdepth) +end) + function mesecon:turnoff(pos, rulename, recdepth) recdepth = recdepth or 0 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, rulename) + end + if mesecon:is_conductor_on(node, rulename) then local rules = mesecon:conductor_get_rules(node) 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, rulename) + else + local rulenames = mesecon:rules_link_rule_all(pos, rule) - for _, rulename in ipairs(rulenames) do - mesecon:turnoff(np, rulename, recdepth + 1) + for _, rulename in ipairs(rulenames) do + mesecon:turnoff(np, rulename, recdepth + 1) + end end end elseif mesecon:is_effector(node.name) then @@ -424,6 +452,10 @@ function mesecon:turnoff(pos, rulename, recdepth) end end +mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) + mesecon:turnoff(pos, rulename, recdepth) +end) + function mesecon:connected_to_receptor(pos, rulename) local node = minetest.get_node(pos) From d066b91632ac34df15c731bd86671ef78f52d3df Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 16:48:25 +0100 Subject: [PATCH 08/12] Fix infinite priority bug in mesecon:turnoff, thanks to Novatux --- mesecons/internal.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesecons/internal.lua b/mesecons/internal.lua index 8e58d73..0d998d3 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -416,7 +416,7 @@ mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) end) function mesecon:turnoff(pos, rulename, recdepth) - recdepth = recdepth or 0 + recdepth = recdepth or 2 local node = minetest.get_node(pos) if(node.name == "ignore") then From 1a492feb7a137a7acfe8cc4d5849970556478e40 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 18:31:30 +0100 Subject: [PATCH 09/12] Turnon/turnoff overwritable --- mesecons/internal.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mesecons/internal.lua b/mesecons/internal.lua index 0d998d3..32a28b2 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -372,7 +372,7 @@ function mesecon:turnon(pos, rulename, recdepth) if(node.name == "ignore") then -- try turning on later again mesecon.queue:add_action( - pos, "turnon", {rulename, recdepth + 1}, nil, rulename) + pos, "turnon", {rulename, recdepth + 1}, nil, true) end if mesecon:is_conductor_off(node, rulename) then @@ -394,7 +394,7 @@ function mesecon:turnon(pos, rulename, recdepth) if(minetest.get_node(np).name == "ignore") then -- try turning on later again mesecon.queue:add_action( - np, "turnon", {rulename, recdepth + 1}, nil, rulename) + np, "turnon", {rulename, recdepth + 1}, nil, true) else local rulenames = mesecon:rules_link_rule_all(pos, rule) @@ -422,7 +422,7 @@ function mesecon:turnoff(pos, rulename, recdepth) if(node.name == "ignore") then -- try turning on later again mesecon.queue:add_action( - pos, "turnoff", {rulename, recdepth + 1}, nil, rulename) + pos, "turnoff", {rulename, recdepth + 1}, nil, true) end if mesecon:is_conductor_on(node, rulename) then @@ -434,7 +434,7 @@ function mesecon:turnoff(pos, rulename, recdepth) if(minetest.get_node(np).name == "ignore") then -- try turning on later again mesecon.queue:add_action( - np, "turnoff", {rulename, recdepth + 1}, nil, rulename) + np, "turnoff", {rulename, recdepth + 1}, nil, true) else local rulenames = mesecon:rules_link_rule_all(pos, rule) From c8ef37f5226778e549924c49e6f1d7d19b285a29 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 11 Jan 2014 10:04:32 +0100 Subject: [PATCH 10/12] Actionqueue tweaks --- mesecons/actionqueue.lua | 1 - mesecons/init.lua | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 66e9fd7..03dedd2 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -12,7 +12,6 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior -- 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), diff --git a/mesecons/init.lua b/mesecons/init.lua index 523263d..fe3bbfd 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -82,6 +82,7 @@ mesecon.queue:add_function("receptor_on", function (pos, rules) -- if area (any of the rule targets) 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.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_on", {rules}) return @@ -110,6 +111,7 @@ mesecon.queue:add_function("receptor_off", function (pos, rules) local np = mesecon:addPosRule(pos, rule) if minetest.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_off", {rules}) + return end end From fe50e87da17acafb6e869ca94bd4716cc97eb165 Mon Sep 17 00:00:00 2001 From: Novatux Date: Sat, 11 Jan 2014 20:03:37 +0100 Subject: [PATCH 11/12] Make receptor_on/off overwritable, fix a serious bug. --- mesecons/actionqueue.lua | 2 +- mesecons/init.lua | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 03dedd2..41a587c 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -38,7 +38,7 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior end if (toremove ~= nil) then - table.remove(mesecon.queue.actions, i) + table.remove(mesecon.queue.actions, toremove) end table.insert(mesecon.queue.actions, action) diff --git a/mesecons/init.lua b/mesecons/init.lua index fe3bbfd..f528dfd 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -84,7 +84,7 @@ mesecon.queue:add_function("receptor_on", function (pos, rules) 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}) + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) return end end @@ -100,7 +100,7 @@ mesecon.queue:add_function("receptor_on", function (pos, rules) end) function mesecon:receptor_on(pos, rules) - mesecon.queue:add_action(pos, "receptor_on", {rules}) + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) end mesecon.queue:add_function("receptor_off", function (pos, rules) @@ -110,7 +110,7 @@ mesecon.queue:add_function("receptor_off", function (pos, rules) 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}) + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) return end end @@ -122,14 +122,14 @@ 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, 1) + mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) end end end end) function mesecon:receptor_off(pos, rules) - mesecon.queue:add_action(pos, "receptor_off", {rules}) + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) end From a632a8abc80155118708108d846f52bbc230f257 Mon Sep 17 00:00:00 2001 From: Jeija Date: Sun, 19 Jan 2014 13:57:11 +0100 Subject: [PATCH 12/12] Fix delayers and disable resuming if not using MESECONS_GLOBALSTEP --- mesecons/actionqueue.lua | 4 ++-- mesecons/init.lua | 26 +++++++++++++++----------- mesecons/internal.lua | 8 ++++++-- mesecons/settings.lua | 2 ++ 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua index 41a587c..cf74d47 100644 --- a/mesecons/actionqueue.lua +++ b/mesecons/actionqueue.lua @@ -20,7 +20,7 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior priority=priority} -- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done - if not MESECONS_GLOBALSTEP then + if not MESECONS_GLOBALSTEP and action.time == 0 then mesecon.queue:execute(action) return end @@ -64,7 +64,7 @@ end local m_time = 0 minetest.register_globalstep(function (dtime) m_time = m_time + dtime - if (m_time < 5) then return end -- don't even try if server has not been running for 2 seconds + 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={} diff --git a/mesecons/init.lua b/mesecons/init.lua index f528dfd..b5cf68b 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -80,12 +80,14 @@ 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 - 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 + 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 @@ -107,11 +109,13 @@ 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 - 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 + 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 diff --git a/mesecons/internal.lua b/mesecons/internal.lua index 32a28b2..3975b6a 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -412,7 +412,9 @@ function mesecon:turnon(pos, rulename, recdepth) end mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) - mesecon:turnon(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) @@ -453,7 +455,9 @@ function mesecon:turnoff(pos, rulename, recdepth) end mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) - mesecon:turnoff(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) 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