summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJude Melton-Houghton <jwmhjwmh@gmail.com>2021-11-27 10:28:13 -0500
committerGitHub <noreply@github.com>2021-11-27 16:28:13 +0100
commitecea0a2896d488f82f34505eb608ab5f527f50ec (patch)
tree315a2366f0c28140993789bd3a2ba45fbbd3eb29
parent9323445182e47aacba0fc0a2f004f08194283a5a (diff)
downloadmesecons-ecea0a2896d488f82f34505eb608ab5f527f50ec.tar
mesecons-ecea0a2896d488f82f34505eb608ab5f527f50ec.tar.gz
mesecons-ecea0a2896d488f82f34505eb608ab5f527f50ec.tar.bz2
mesecons-ecea0a2896d488f82f34505eb608ab5f527f50ec.tar.xz
mesecons-ecea0a2896d488f82f34505eb608ab5f527f50ec.zip
Optimize light updates when turning conductors on and off (#578)
-rw-r--r--mesecons/internal.lua61
-rw-r--r--mesecons/util.lua17
2 files changed, 70 insertions, 8 deletions
diff --git a/mesecons/internal.lua b/mesecons/internal.lua
index 8b82fa1..165c001 100644
--- a/mesecons/internal.lua
+++ b/mesecons/internal.lua
@@ -368,11 +368,66 @@ function mesecon.is_power_off(pos, rulename)
return false
end
+-- The set of conductor states which require light updates when they change.
+local light_update_conductors
+
+-- 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
+
+ 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)
+ if conductor and 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
+
+ -- 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
+end
+
+-- 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`.
-- 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)
+ find_light_update_conductors()
+
local frontiers = fifo_queue.new()
frontiers:add({pos = pos, link = link})
local pos_can_be_skipped = {}
@@ -398,7 +453,7 @@ function mesecon.turnon(pos, link)
end
end
- mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link))
+ mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link), get_update_light_conductor)
end
-- Only conductors with flat rules can be reliably skipped later
@@ -434,6 +489,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 = {}
@@ -470,7 +527,7 @@ function mesecon.turnoff(pos, link)
end
end
- mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link))
+ mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link), get_update_light_conductor)
end
-- Only conductors with flat rules can be reliably skipped later
diff --git a/mesecons/util.lua b/mesecons/util.lua
index 234775b..7fb95cc 100644
--- a/mesecons/util.lua
+++ b/mesecons/util.lua
@@ -343,7 +343,7 @@ function mesecon.vm_commit()
if tbl.dirty then
local vm = tbl.vm
vm:set_data(tbl.data)
- vm:write_to_map()
+ vm:write_to_map(tbl.update_light)
vm:update_map()
end
end
@@ -364,7 +364,7 @@ local function vm_get_or_create_entry(pos)
local vm = minetest.get_voxel_manip(pos, pos)
local min_pos, max_pos = vm:get_emerged_area()
local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
- tbl = {vm = vm, va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data(), dirty = false}
+ tbl = {vm = vm, va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data(), dirty = false, update_light = false}
vm_cache[hash] = tbl
end
return tbl
@@ -388,8 +388,11 @@ end
-- Sets a node’s name during a VoxelManipulator-based transaction.
--
-- Existing param1, param2, and metadata are left alone.
-function mesecon.vm_swap_node(pos, name)
+--
+-- See mesecon.swap_node_force for documentation about get_update_light.
+function mesecon.vm_swap_node(pos, name, get_update_light)
local tbl = vm_get_or_create_entry(pos)
+ tbl.update_light = tbl.update_light or (get_update_light == nil or get_update_light(pos, name))
local index = tbl.va:indexp(pos)
tbl.data[index] = minetest.get_content_id(name)
tbl.dirty = true
@@ -423,13 +426,15 @@ end
-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into
-- the server’s main map data cache and then accessed from there.
--
--- Inside a VM transaction, the transaction’s VM cache is used.
+-- Inside a VM transaction, the transaction’s VM cache is used. If a third
+-- argument is supplied, it may be called. If it returns false, the swap does
+-- not necessitate a lighting update.
--
-- This function can only be used to change the node’s name, not its parameters
-- or metadata.
-function mesecon.swap_node_force(pos, name)
+function mesecon.swap_node_force(pos, name, get_update_light)
if vm_cache then
- return mesecon.vm_swap_node(pos, name)
+ return mesecon.vm_swap_node(pos, name, get_update_light)
else
-- This serves to both ensure the mapblock is loaded and also hand us
-- the old node table so we can preserve param2.