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
1 changed files with 48 additions and 31 deletions

View File

@ -368,46 +368,59 @@ function mesecon.is_power_off(pos, rulename)
return false
end
-- This is the callback for swap_node_force in turnon and turnoff. It determines
-- whether a conductor node necessitates a lighting update.
local cached_update_light = {}
local function get_update_light_conductor(pos, name)
local update_light = cached_update_light[name]
-- The set of conductor states which require light updates when they change.
local light_update_conductors
if update_light == nil then
-- Calculate and cache whether the conductor needs light updates.
-- Calculate the contents of the above set if they have not been calculated.
-- 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 other_states
if conductor.onstate then
other_states = {conductor.onstate}
elseif conductor.offstate then
other_states = {conductor.offstate}
else
other_states = conductor.states
end
if conductor then
if not checked[name] then
-- Find the other states of the conductor besides the current one.
local other_states
if conductor.onstate then
other_states = {conductor.onstate}
elseif conductor.offstate then
other_states = {conductor.offstate}
else
other_states = conductor.states
end
update_light = false
for _, other_state in ipairs(other_states) do
local other_def = minetest.registered_nodes[other_state]
if (def.paramtype == "light") ~= (other_def.paramtype == "light")
or def.sunlight_propagates ~= other_def.sunlight_propagates
or def.light_source ~= other_def.light_source then
-- The light characteristics change depending on the state.
update_light = true
break
-- Check the conductor. Other states are marked as checked.
for _, other_state in ipairs(other_states) do
local other_def = minetest.registered_nodes[other_state]
if (def.paramtype == "light") ~= (other_def.paramtype == "light")
or def.sunlight_propagates ~= other_def.sunlight_propagates
or def.light_source ~= other_def.light_source then
-- The light characteristics change depending on the state.
-- The states are added to the set.
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
cached_update_light[name] = update_light
for _, other_state in ipairs(other_states) do
cached_update_light[other_state] = update_light
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
-- 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
-- looked at, activating / changing all effectors along the way.
function mesecon.turnon(pos, link)
find_light_update_conductors()
local frontiers = fifo_queue.new()
frontiers:add({pos = pos, link = link})
local pos_can_be_skipped = {}
@ -476,6 +491,8 @@ end
-- depth = indicates order in which signals wire fired, higher is later
-- }
function mesecon.turnoff(pos, link)
find_light_update_conductors()
local frontiers = fifo_queue.new()
frontiers:add({pos = pos, link = link})
local signals = {}