Skip to content

Commit d19e975

Browse files
author
Jeija
committedNov 22, 2014
Use iterative algorithm for mesecon.find_receptor_on, major performance improvement for large
circuits. This also fixes a crash introduced with the previous commit that occured when placing a wire crossing.
1 parent 29dc500 commit d19e975

File tree

4 files changed

+46
-57
lines changed

4 files changed

+46
-57
lines changed
 

Diff for: ‎mesecons/internal.lua

+35-48
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
-- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way
4040
-- 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
4141
-- 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
42-
-- 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
42+
-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors; calls itself if pos is a conductor --> recursive
4343
-- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
4444
-- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped
4545
-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
@@ -179,8 +179,8 @@ end
179179

180180
-- Activation:
181181
mesecon.queue:add_function("activate", function (pos, rulename)
182-
node = minetest.get_node(pos)
183-
effector = mesecon.get_effector(node.name)
182+
local node = minetest.get_node(pos)
183+
local effector = mesecon.get_effector(node.name)
184184

185185
if effector and effector.action_on then
186186
effector.action_on(pos, node, rulename)
@@ -446,18 +446,18 @@ mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth)
446446
end)
447447

448448

449-
function mesecon.connected_to_receptor(pos, rulename)
449+
function mesecon.connected_to_receptor(pos, link)
450450
local node = minetest.get_node(pos)
451451

452452
-- Check if conductors around are connected
453453
local rules = mesecon.get_any_inputrules(node)
454454
if not rules then return false end
455455

456-
for _, rule in ipairs(mesecon.rule2meta(rulename, rules)) do
457-
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
458-
for _, rname in ipairs(rulenames) do
459-
local np = mesecon.addPosRule(pos, rname)
460-
if mesecon.find_receptor_on(np, {}, mesecon.invertRule(rname)) then
456+
for _, rule in ipairs(mesecon.rule2meta(link, rules)) do
457+
local links = mesecon.rules_link_rule_all_inverted(pos, rule)
458+
for _, l in ipairs(links) do
459+
local np = mesecon.addPosRule(pos, l)
460+
if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
461461
return true
462462
end
463463
end
@@ -466,49 +466,36 @@ function mesecon.connected_to_receptor(pos, rulename)
466466
return false
467467
end
468468

469-
function mesecon.find_receptor_on(pos, checked, rulename, recdepth)
470-
recdepth = recdepth or 2
471-
if (recdepth > STACK_SIZE) then return true end -- ignore request
472-
local node = minetest.get_node(pos)
469+
function mesecon.find_receptor_on(pos, link)
470+
local frontiers = {{pos = pos, link = link}}
471+
local checked = {}
473472

474-
if mesecon.is_receptor_on(node.name) then
475-
-- add current position to checked
476-
table.insert(checked, {x=pos.x, y=pos.y, z=pos.z})
477-
return true
478-
end
473+
-- List of positions that have been searched for onstate receptors
474+
local depth = 1
475+
while frontiers[depth] do
476+
local f = frontiers[depth]
477+
local node = minetest.get_node_or_nil(f.pos)
479478

480-
if mesecon.is_conductor(node.name) then
481-
local rules = mesecon.conductor_get_rules(node)
482-
local metaindex = mesecon.rule2metaindex(rulename, rules)
483-
-- find out if node has already been checked (to prevent from endless loop)
484-
for _, cp in ipairs(checked) do
485-
if mesecon.cmpPos(cp, pos) and cp.metaindex == metaindex then
486-
return false, checked
487-
end
488-
end
489-
-- add current position to checked
490-
table.insert(checked, {x=pos.x, y=pos.y, z=pos.z, metaindex = metaindex})
491-
for _, rule in ipairs(mesecon.rule2meta(rulename, rules)) do
492-
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
493-
for _, rname in ipairs(rulenames) do
494-
local np = mesecon.addPosRule(pos, rname)
495-
if mesecon.find_receptor_on(np, checked, mesecon.invertRule(rname),
496-
recdepth + 1) then
497-
return true
479+
if mesecon.is_receptor_on(node.name) then return true end
480+
if mesecon.is_conductor_on(node, f.link) then
481+
local rules = mesecon.conductor_get_rules(node)
482+
483+
-- call turnoff on neighbors: normal rules
484+
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
485+
local np = mesecon.addPosRule(f.pos, r)
486+
487+
local links = mesecon.rules_link_rule_all_inverted(f.pos, r)
488+
for _, l in ipairs(links) do
489+
if not checked[f.pos.x .. f.pos.y .. f.pos.z] then
490+
table.insert(frontiers, {pos = np, link = l})
491+
checked[f.pos.x .. f.pos.y .. f.pos.z] = true
492+
end
498493
end
499494
end
495+
500496
end
501-
else
502-
-- find out if node has already been checked (to prevent from endless loop)
503-
for _, cp in ipairs(checked) do
504-
if mesecon.cmpPos(cp, pos) then
505-
return false, checked
506-
end
507-
end
508-
table.insert(checked, {x=pos.x, y=pos.y, z=pos.z})
497+
depth = depth + 1
509498
end
510-
511-
return false
512499
end
513500

514501
function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule
@@ -551,7 +538,7 @@ function mesecon.rules_link_rule_all(output, rule)
551538
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
552539
if inputrule.sx == nil or rule.sx == nil
553540
or mesecon.cmpSpecial(inputrule, rule) then
554-
rules[#rules+1] = inputrule
541+
table.insert(rules, inputrule)
555542
end
556543
end
557544
end
@@ -572,7 +559,7 @@ function mesecon.rules_link_rule_all_inverted(input, rule)
572559
if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
573560
if outputrule.sx == nil or rule.sx == nil
574561
or mesecon.cmpSpecial(outputrule, rule) then
575-
rules[#rules+1] = mesecon.invertRule(outputrule)
562+
table.insert(rules, mesecon.invertRule(outputrule))
576563
end
577564
end
578565
end

Diff for: ‎mesecons/presets.lua

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ mesecon.rules.default =
1515
{x=0, y=1, z=-1},
1616
{x=0, y=-1, z=-1}}
1717

18-
mesecon.rules.pplate = {{x=0, y=-2, z=0}}
19-
mesecon.mergetable(mesecon.rules.default, mesecon.rules.pplate)
18+
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}})
2019

2120
mesecon.rules.buttonlike =
2221
{{x = 1, y = 0, z = 0},

Diff for: ‎mesecons/util.lua

+8-5
Original file line numberDiff line numberDiff line change
@@ -196,20 +196,23 @@ end
196196

197197
-- does not overwrite values; number keys (ipairs) are appended, not overwritten
198198
mesecon.mergetable = function(source, dest)
199+
local rval = mesecon.tablecopy(dest)
200+
199201
for k, v in pairs(source) do
200-
dest[k] = dest[k] or v
202+
rval[k] = dest[k] or mesecon.tablecopy(v)
201203
end
202-
203204
for i, v in ipairs(source) do
204-
table.insert(dest, v)
205+
table.insert(rval, mesecon.tablecopy(v))
205206
end
207+
208+
return rval
206209
end
207210

208211
mesecon.register_node = function(name, spec_common, spec_off, spec_on)
209212
spec_common.drop = spec_common.drop or name .. "_off"
210213

211-
mesecon.mergetable(spec_common, spec_on);
212-
mesecon.mergetable(spec_common, spec_off);
214+
spec_on = mesecon.mergetable(spec_common, spec_on);
215+
spec_off = mesecon.mergetable(spec_common, spec_off);
213216

214217
minetest.register_node(name .. "_on", spec_on)
215218
minetest.register_node(name .. "_off", spec_off)

Diff for: ‎mesecons/wires.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ local wire_getconnect = function (from_pos, self_pos)
1919
rules = mesecon.rules.default
2020
else
2121
rules = mesecon.get_any_inputrules(node) or {}
22-
mesecon.mergetable(mesecon.get_any_outputrules(node) or {}, rules)
22+
rules = mesecon.mergetable(mesecon.get_any_outputrules(node) or {}, rules)
2323
end
2424

2525
for _, r in ipairs(mesecon.flattenrules(rules)) do
@@ -80,7 +80,7 @@ local update_on_place_dig = function (pos, node)
8080
rules = mesecon.rules.default
8181
else
8282
rules = mesecon.get_any_inputrules(node) or {}
83-
mesecon.mergetable(mesecon.get_any_outputrules(node) or {}, rules)
83+
rules = mesecon.mergetable(mesecon.get_any_outputrules(node) or {}, rules)
8484
end
8585
if (not rules) then return end
8686

0 commit comments

Comments
 (0)
Please sign in to comment.