Calculate light update conductors at the beginning

This was suggested by sfan5. This saves on memory, and I think it's a
bit faster too. I didn't use register_on_mods_loaded. This is because
other mods might register their own callbacks which run after mesecons'.
These callbacks could override node properties. The code does not check
the same conductor twice. This makes the code a bit more complicated,
but some conductors have many states. If a conductor has 16 states, it
requires 256 checks in the initial light update calculation. I think
this is worth avoiding, especially since I don't know the maximum number
of states a conductor can have.
This commit is contained in:
Jude Melton-Houghton
2021-11-17 18:32:08 -05:00
parent 8277799f29
commit bbc6391e0a

View File

@ -368,46 +368,59 @@ function mesecon.is_power_off(pos, rulename)
return false return false
end end
-- This is the callback for swap_node_force in turnon and turnoff. It determines -- The set of conductor states which require light updates when they change.
-- whether a conductor node necessitates a lighting update. local light_update_conductors
local cached_update_light = {}
local function get_update_light_conductor(pos, name)
local update_light = cached_update_light[name]
if update_light == nil then -- Calculate the contents of the above set if they have not been calculated.
-- Calculate and cache whether the conductor needs light updates. -- This must be called before get_update_light_conductor.
local function find_light_update_conductors()
-- The expensive calculation is only done the first time.
if light_update_conductors then return end
local def = minetest.registered_nodes[name] light_update_conductors = {}
-- Find conductors whose lighting characteristics change depending on their state.
local checked = {}
for name, def in pairs(minetest.registered_nodes) do
local conductor = mesecon.get_conductor(name) local conductor = mesecon.get_conductor(name)
local other_states if conductor then
if conductor.onstate then if not checked[name] then
other_states = {conductor.onstate} -- Find the other states of the conductor besides the current one.
elseif conductor.offstate then local other_states
other_states = {conductor.offstate} if conductor.onstate then
else other_states = {conductor.onstate}
other_states = conductor.states elseif conductor.offstate then
end other_states = {conductor.offstate}
else
other_states = conductor.states
end
update_light = false -- Check the conductor. Other states are marked as checked.
for _, other_state in ipairs(other_states) do for _, other_state in ipairs(other_states) do
local other_def = minetest.registered_nodes[other_state] local other_def = minetest.registered_nodes[other_state]
if (def.paramtype == "light") ~= (other_def.paramtype == "light") if (def.paramtype == "light") ~= (other_def.paramtype == "light")
or def.sunlight_propagates ~= other_def.sunlight_propagates or def.sunlight_propagates ~= other_def.sunlight_propagates
or def.light_source ~= other_def.light_source then or def.light_source ~= other_def.light_source then
-- The light characteristics change depending on the state. -- The light characteristics change depending on the state.
update_light = true -- The states are added to the set.
break light_update_conductors[name] = true
for _, other_state in ipairs(other_states) do
light_update_conductors[other_state] = true
checked[other_state] = true
end
break
end
checked[other_state] = true
end
end end
end end
cached_update_light[name] = update_light
for _, other_state in ipairs(other_states) do
cached_update_light[other_state] = update_light
end
end end
end
return update_light -- This is the callback for swap_node_force in turnon and turnoff. It determines
-- whether a conductor node necessitates a lighting update.
local function get_update_light_conductor(pos, name)
return light_update_conductors[name] ~= nil
end end
-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`. -- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`.
@ -415,6 +428,8 @@ end
-- Follow all all conductor paths replacing conductors that were already -- Follow all all conductor paths replacing conductors that were already
-- looked at, activating / changing all effectors along the way. -- looked at, activating / changing all effectors along the way.
function mesecon.turnon(pos, link) function mesecon.turnon(pos, link)
find_light_update_conductors()
local frontiers = fifo_queue.new() local frontiers = fifo_queue.new()
frontiers:add({pos = pos, link = link}) frontiers:add({pos = pos, link = link})
local pos_can_be_skipped = {} local pos_can_be_skipped = {}
@ -476,6 +491,8 @@ end
-- depth = indicates order in which signals wire fired, higher is later -- depth = indicates order in which signals wire fired, higher is later
-- } -- }
function mesecon.turnoff(pos, link) function mesecon.turnoff(pos, link)
find_light_update_conductors()
local frontiers = fifo_queue.new() local frontiers = fifo_queue.new()
frontiers:add({pos = pos, link = link}) frontiers:add({pos = pos, link = link})
local signals = {} local signals = {}