Skip to content

Commit ffacbfd

Browse files
author
Jeija
committedNov 22, 2014
Use an iterative algorithm for turnon() and turnoff(), fixes #160
This may also bring some performance benefit.
1 parent b5cc933 commit ffacbfd

File tree

2 files changed

+84
-82
lines changed

2 files changed

+84
-82
lines changed
 

Diff for: ‎mesecons/internal.lua

+82-79
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
-- mesecon:effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified)
2323

2424
-- SIGNALS
25-
-- mesecon:activate(pos, node, recdepth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher recdepths are executed later
26-
-- mesecon:deactivate(pos, node, recdepth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), "
27-
-- mesecon:changesignal(pos, node, rulename, newstate) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), "
25+
-- mesecon:activate(pos, node, depth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher depths are executed later
26+
-- mesecon:deactivate(pos, node, depth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), higher depths are executed later
27+
-- mesecon:changesignal(pos, node, rulename, newstate, depth) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), higher depths are executed later
2828

2929
-- CONDUCTORS
3030
-- mesecon:is_conductor(nodename) --> Returns true if nodename is a conductor
@@ -187,14 +187,14 @@ mesecon.queue:add_function("activate", function (pos, rulename)
187187
end
188188
end)
189189

190-
function mesecon:activate(pos, node, rulename, recdepth)
190+
function mesecon:activate(pos, node, rulename, depth)
191191
if rulename == nil then
192192
for _,rule in ipairs(mesecon:effector_get_rules(node)) do
193-
mesecon:activate(pos, node, rule, recdepth + 1)
193+
mesecon:activate(pos, node, rule, depth + 1)
194194
end
195195
return
196196
end
197-
mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / recdepth)
197+
mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth)
198198
end
199199

200200

@@ -208,36 +208,36 @@ mesecon.queue:add_function("deactivate", function (pos, rulename)
208208
end
209209
end)
210210

211-
function mesecon:deactivate(pos, node, rulename, recdepth)
211+
function mesecon:deactivate(pos, node, rulename, depth)
212212
if rulename == nil then
213213
for _,rule in ipairs(mesecon:effector_get_rules(node)) do
214-
mesecon:deactivate(pos, node, rule, recdepth + 1)
214+
mesecon:deactivate(pos, node, rule, depth + 1)
215215
end
216216
return
217217
end
218-
mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / recdepth)
218+
mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth)
219219
end
220220

221221

222222
-- Change
223223
mesecon.queue:add_function("change", function (pos, rulename, changetype)
224-
node = minetest.get_node(pos)
225-
effector = mesecon:get_effector(node.name)
224+
local node = minetest.get_node(pos)
225+
local effector = mesecon:get_effector(node.name)
226226

227227
if effector and effector.action_change then
228228
effector.action_change(pos, node, rulename, changetype)
229229
end
230230
end)
231231

232-
function mesecon:changesignal(pos, node, rulename, newstate, recdepth)
232+
function mesecon:changesignal(pos, node, rulename, newstate, depth)
233233
if rulename == nil then
234234
for _,rule in ipairs(mesecon:effector_get_rules(node)) do
235-
mesecon:changesignal(pos, node, rule, newstate, recdepth + 1)
235+
mesecon:changesignal(pos, node, rule, newstate, depth + 1)
236236
end
237237
return
238238
end
239239

240-
mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / recdepth)
240+
mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / depth)
241241
end
242242

243243
-- Conductors
@@ -349,92 +349,95 @@ function mesecon:is_power_off(pos, rulename)
349349
return false
350350
end
351351

352-
function mesecon:turnon(pos, rulename, recdepth)
353-
recdepth = recdepth or 2
354-
if (recdepth > STACK_SIZE) then return end
355-
local node = minetest.get_node(pos)
352+
function mesecon:turnon(pos, link)
353+
local frontiers = {{pos = pos, link = link}}
356354

357-
if(node.name == "ignore") then
358-
-- try turning on later again
359-
mesecon.queue:add_action(
360-
pos, "turnon", {rulename, recdepth + 1}, nil, true)
361-
end
362-
363-
if mesecon:is_conductor_off(node, rulename) then
364-
local rules = mesecon:conductor_get_rules(node)
355+
local depth = 1
356+
while frontiers[depth] do
357+
local f = frontiers[depth]
358+
local node = minetest.get_node_or_nil(f.pos)
365359

366-
if not rulename then
367-
for _, rule in ipairs(mesecon:flattenrules(rules)) do
368-
if mesecon:connected_to_receptor(pos, rule) then
369-
mesecon:turnon(pos, rule, recdepth + 1)
370-
end
371-
end
372-
return
360+
-- area not loaded, postpone action
361+
if not node then
362+
mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
373363
end
374364

375-
minetest.swap_node(pos, {name = mesecon:get_conductor_on(node, rulename), param2 = node.param2})
365+
if mesecon:is_conductor_off(node, f.link) then
366+
local rules = mesecon:conductor_get_rules(node)
376367

377-
for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do
378-
local np = mesecon:addPosRule(pos, rule)
379-
if(minetest.get_node(np).name == "ignore") then
380-
-- try turning on later again
381-
mesecon.queue:add_action(
382-
np, "turnon", {rulename, recdepth + 1}, nil, true)
383-
else
384-
local rulenames = mesecon:rules_link_rule_all(pos, rule)
385-
386-
for _, rulename in ipairs(rulenames) do
387-
mesecon:turnon(np, rulename, recdepth + 1)
368+
minetest.swap_node(f.pos, {name = mesecon:get_conductor_on(node, f.link),
369+
param2 = node.param2})
370+
371+
-- call turnon on neighbors: normal rules
372+
for _, r in ipairs(mesecon:rule2meta(f.link, rules)) do
373+
local np = mesecon:addPosRule(f.pos, r)
374+
375+
-- area not loaded, postpone action
376+
if not minetest.get_node_or_nil(np) then
377+
mesecon.queue:add_action(np, "turnon", {rulename},
378+
nil, true)
379+
else
380+
local links = mesecon:rules_link_rule_all(f.pos, r)
381+
for _, l in ipairs(links) do
382+
table.insert(frontiers, {pos = np, link = l})
383+
end
388384
end
389385
end
386+
elseif mesecon:is_effector(node.name) then
387+
mesecon:changesignal(f.pos, node, f.link, mesecon.state.on, depth)
388+
if mesecon:is_effector_off(node.name) then
389+
mesecon:activate(f.pos, node, f.link, depth)
390+
end
390391
end
391-
elseif mesecon:is_effector(node.name) then
392-
mesecon:changesignal(pos, node, rulename, mesecon.state.on, recdepth)
393-
if mesecon:is_effector_off(node.name) then
394-
mesecon:activate(pos, node, rulename, recdepth)
395-
end
392+
depth = depth + 1
396393
end
397394
end
398395

399396
mesecon.queue:add_function("turnon", function (pos, rulename, recdepth)
400397
mesecon:turnon(pos, rulename, recdepth)
401398
end)
402399

403-
function mesecon:turnoff(pos, rulename, recdepth)
404-
recdepth = recdepth or 2
405-
if (recdepth > STACK_SIZE) then return end
406-
local node = minetest.get_node(pos)
400+
function mesecon:turnoff(pos, link)
401+
local frontiers = {{pos = pos, link = link}}
407402

408-
if(node.name == "ignore") then
409-
-- try turning on later again
410-
mesecon.queue:add_action(
411-
pos, "turnoff", {rulename, recdepth + 1}, nil, true)
412-
end
403+
local depth = 1
404+
while frontiers[depth] do
405+
local f = frontiers[depth]
406+
local node = minetest.get_node_or_nil(f.pos)
413407

414-
if mesecon:is_conductor_on(node, rulename) then
415-
local rules = mesecon:conductor_get_rules(node)
416-
minetest.swap_node(pos, {name = mesecon:get_conductor_off(node, rulename), param2 = node.param2})
408+
-- area not loaded, postpone action
409+
if not node then
410+
mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true)
411+
end
417412

418-
for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do
419-
local np = mesecon:addPosRule(pos, rule)
420-
if(minetest.get_node(np).name == "ignore") then
421-
-- try turning on later again
422-
mesecon.queue:add_action(
423-
np, "turnoff", {rulename, recdepth + 1}, nil, true)
424-
else
425-
local rulenames = mesecon:rules_link_rule_all(pos, rule)
426-
427-
for _, rulename in ipairs(rulenames) do
428-
mesecon:turnoff(np, rulename, recdepth + 1)
413+
if mesecon:is_conductor_on(node, f.link) then
414+
local rules = mesecon:conductor_get_rules(node)
415+
416+
minetest.swap_node(f.pos, {name = mesecon:get_conductor_off(node, f.link),
417+
param2 = node.param2})
418+
419+
-- call turnoff on neighbors: normal rules
420+
for _, r in ipairs(mesecon:rule2meta(f.link, rules)) do
421+
local np = mesecon:addPosRule(f.pos, r)
422+
423+
-- area not loaded, postpone action
424+
if not minetest.get_node_or_nil(np) then
425+
mesecon.queue:add_action(np, "turnoff", {rulename},
426+
nil, true)
427+
else
428+
local links = mesecon:rules_link_rule_all(f.pos, r)
429+
for _, l in ipairs(links) do
430+
table.insert(frontiers, {pos = np, link = l})
431+
end
429432
end
430433
end
434+
elseif mesecon:is_effector(node.name) then
435+
mesecon:changesignal(f.pos, node, f.link, mesecon.state.off, depth)
436+
if mesecon:is_effector_on(node.name) and not mesecon:is_powered(f.pos) then
437+
mesecon:deactivate(f.pos, node, f.link, depth)
438+
end
431439
end
432-
elseif mesecon:is_effector(node.name) then
433-
mesecon:changesignal(pos, node, rulename, mesecon.state.off, recdepth)
434-
if mesecon:is_effector_on(node.name)
435-
and not mesecon:is_powered(pos) then
436-
mesecon:deactivate(pos, node, rulename, recdepth + 1)
437-
end
440+
depth = depth + 1
438441
end
439442
end
440443

Diff for: ‎mesecons_luacontroller/init.lua

+2-3
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ local merge_portstates = function (ports, vports)
8383
end
8484

8585
local generate_name = function (ports)
86-
local overwrite = overwrite or {}
8786
local d = ports.d and 1 or 0
8887
local c = ports.c and 1 or 0
8988
local b = ports.b and 1 or 0
@@ -271,7 +270,7 @@ local create_sandbox = function (code, env)
271270
if code:byte(1) == 27 then
272271
return _, "You Hacker You! Don't use binary code!"
273272
end
274-
f, msg = loadstring(code)
273+
local f, msg = loadstring(code)
275274
if not f then return _, msg end
276275
setfenv(f, env)
277276
return f
@@ -321,7 +320,7 @@ lc_update = function (pos, event)
321320
-- create the sandbox and execute code
322321
local chunk, msg = create_sandbox (code, env)
323322
if not chunk then return msg end
324-
local success, msg = pcall(f)
323+
local success, msg = pcall(chunk)
325324
if not success then return msg end
326325
if ports_invalid(env.port) then return ports_invalid(env.port) end
327326

0 commit comments

Comments
 (0)
Please sign in to comment.