diff --git a/mesecons/internal.lua b/mesecons/internal.lua index 1bc0666..0d65d27 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -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 = {}