summaryrefslogtreecommitdiff
path: root/mesecons
diff options
context:
space:
mode:
authorJeija <norrepli@gmail.com>2016-08-30 19:12:09 +0200
committerJeija <norrepli@gmail.com>2016-08-30 19:12:09 +0200
commite561be7fa36b6de90a759c13d745f8e54359ce3d (patch)
treec19e3b21a913c954c8c149ddb2d91de62c8e2833 /mesecons
parent89153f6909558d1ba619b30a8c792c5f8493f7bc (diff)
downloadmesecons-e561be7fa36b6de90a759c13d745f8e54359ce3d.tar
mesecons-e561be7fa36b6de90a759c13d745f8e54359ce3d.tar.gz
mesecons-e561be7fa36b6de90a759c13d745f8e54359ce3d.tar.bz2
mesecons-e561be7fa36b6de90a759c13d745f8e54359ce3d.tar.xz
mesecons-e561be7fa36b6de90a759c13d745f8e54359ce3d.zip
Greatly improve performance by making use of VoxelManips in turnoff
Instead of seperately looking for onstate receptors along equipotential sections of the circuit before turning off, do that while already modifying the VoxelManip. In case an onstate receptor is found, discard the VoxelManip cache, otherwise commit it after turnoff is completed.
Diffstat (limited to 'mesecons')
-rw-r--r--mesecons/init.lua16
-rw-r--r--mesecons/internal.lua132
2 files changed, 53 insertions, 95 deletions
diff --git a/mesecons/init.lua b/mesecons/init.lua
index 944a86a..7da3583 100644
--- a/mesecons/init.lua
+++ b/mesecons/init.lua
@@ -101,8 +101,6 @@ function mesecon.receptor_on(pos, rules)
end
mesecon.queue:add_function("receptor_off", function (pos, rules)
- mesecon.vm_begin()
-
rules = rules or mesecon.rules.default
-- if area (any of the rule targets) is not loaded, keep trying and call this again later
@@ -118,15 +116,19 @@ mesecon.queue:add_function("receptor_off", function (pos, rules)
local np = vector.add(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
- mesecon.turnoff(np, rulename)
+ mesecon.vm_begin()
+ mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
+
+ -- Turnoff returns true if turnoff process was successful, no onstate receptor
+ -- was found along the way. Commit changes that were made in voxelmanip. If turnoff
+ -- returns true, an onstate receptor was found, abort voxelmanip transaction.
+ if (mesecon.turnoff(np, rulename)) then
+ mesecon.vm_commit()
else
- mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
+ mesecon.vm_abort()
end
end
end
-
- mesecon.vm_commit()
end)
function mesecon.receptor_off(pos, rules)
diff --git a/mesecons/internal.lua b/mesecons/internal.lua
index c125d3f..2a352f3 100644
--- a/mesecons/internal.lua
+++ b/mesecons/internal.lua
@@ -41,7 +41,6 @@
-- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative
-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative
-- 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
-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
-- RULES ROTATION helpers
@@ -371,6 +370,10 @@ function mesecon.is_power_off(pos, rulename)
return false
end
+-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`.
+-- Breadth-first search. Map is abstracted away in a voxelmanip.
+-- Follow all all conductor paths replacing conductors that were already
+-- looked at, activating / changing all effectors along the way.
function mesecon.turnon(pos, link)
local frontiers = {{pos = pos, link = link}}
@@ -384,7 +387,7 @@ function mesecon.turnon(pos, link)
elseif mesecon.is_conductor_off(node, f.link) then
local rules = mesecon.conductor_get_rules(node)
- -- call turnon on neighbors
+ -- Call turnon on neighbors
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = vector.add(f.pos, r)
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
@@ -403,8 +406,25 @@ function mesecon.turnon(pos, link)
end
end
+-- Turn on an equipotential section starting at `pos`, which outputs in the direction of `link`.
+-- Breadth-first search. Map is abstracted away in a voxelmanip.
+-- Follow all all conductor paths replacing conductors that were already
+-- looked at, deactivating / changing all effectors along the way.
+-- In case an onstate receptor is discovered, abort the process by returning false, which will
+-- cause `receptor_off` to discard all changes made in the voxelmanip.
+-- Contrary to turnon, turnoff has to cache all change and deactivate signals so that they will only
+-- be called in the very end when we can be sure that no conductor was found along the path.
+--
+-- Signal table entry structure:
+-- {
+-- pos = position of effector,
+-- node = node descriptor (name, param1 and param2),
+-- link = link the effector is connected to,
+-- depth = indicates order in which signals wire fired, higher is later
+-- }
function mesecon.turnoff(pos, link)
local frontiers = {{pos = pos, link = link}}
+ local signals = {}
local depth = 1
while frontiers[1] do
@@ -415,10 +435,19 @@ function mesecon.turnoff(pos, link)
-- Area does not exist; do nothing
elseif mesecon.is_conductor_on(node, f.link) then
local rules = mesecon.conductor_get_rules(node)
-
- -- call turnoff on neighbors
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = vector.add(f.pos, r)
+
+ -- Check if an onstate receptor is connected. If that is the case,
+ -- abort this turnoff process by returning false. `receptor_off` will
+ -- discard all the changes that we made in the voxelmanip:
+ for _, l in ipairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do
+ if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then
+ return false
+ end
+ end
+
+ -- Call turnoff on neighbors
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
table.insert(frontiers, {pos = np, link = l})
end
@@ -426,93 +455,24 @@ function mesecon.turnoff(pos, link)
mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link))
elseif mesecon.is_effector(node.name) then
- mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth)
- if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then
- mesecon.deactivate(f.pos, node, f.link, depth)
- end
+ table.insert(signals, {
+ pos = f.pos,
+ node = node,
+ link = f.link,
+ depth = depth
+ })
end
depth = depth + 1
end
-end
-
-function mesecon.connected_to_receptor(pos, link)
- local node = mesecon.get_node_force(pos)
- if not node then return false end
-
- -- Check if conductors around are connected
- local rules = mesecon.get_any_inputrules(node)
- if not rules then return false end
- for _, rule in ipairs(mesecon.rule2meta(link, rules)) do
- local links = mesecon.rules_link_rule_all_inverted(pos, rule)
- for _, l in ipairs(links) do
- local np = vector.add(pos, l)
- if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
- return true
- end
+ for _, sig in ipairs(signals) do
+ mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth)
+ if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then
+ mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth)
end
end
- return false
-end
-
-function mesecon.find_receptor_on(pos, link)
- local frontiers = {{pos = pos, link = link}}
- local checked = {}
-
- -- List of positions that have been searched for onstate receptors
- local depth = 1
- while frontiers[depth] do
- local f = frontiers[depth]
- local node = mesecon.get_node_force(f.pos)
-
- if not node then return false end
- if mesecon.is_receptor_on(node.name) then return true end
- if mesecon.is_conductor_on(node, f.link) then
- local rules = mesecon.conductor_get_rules(node)
-
- -- call turnoff on neighbors: normal rules
- for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
- local np = vector.add(f.pos, r)
-
- local links = mesecon.rules_link_rule_all_inverted(f.pos, r)
- for _, l in ipairs(links) do
- local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z
- if not checked[checkedstring] then
- table.insert(frontiers, {pos = np, link = l})
- checked[checkedstring] = true
- end
- end
- end
-
- end
- depth = depth + 1
- end
-end
-
-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
- local outputnode = mesecon.get_node_force(output)
- local inputnode = mesecon.get_node_force(input)
-
- local outputrules = dug_outputrules or mesecon.get_any_outputrules(outputnode)
- local inputrules = mesecon.get_any_inputrules(inputnode)
- if not outputrules or not inputrules then
- return
- end
-
- for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
- -- Check if output sends to input
- if vector.equals(vector.add(output, outputrule), input) then
- for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
- -- Check if input accepts from output
- if vector.equals(vector.add(input, inputrule), output) then
- return true, inputrule
- end
- end
- end
- end
-
- return false
+ return true
end
function mesecon.rules_link_rule_all(output, rule)
@@ -552,10 +512,6 @@ function mesecon.rules_link_rule_all_inverted(input, rule)
return rules
end
-function mesecon.rules_link_anydir(pos1, pos2)
- return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1)
-end
-
function mesecon.is_powered(pos, rule)
local node = mesecon.get_node_force(pos)
local rules = mesecon.get_any_inputrules(node)