Convert from storing power information directly in node metadata to storing in memory in a multipower table that gets loaded and saved to node metadata as needed, change all locally cached functions to have the source prefix in the name for better core readability, fix global access in mcl_util.assign_uuid

This commit is contained in:
teknomunk 2024-04-15 08:21:14 +00:00
parent 6396b6f56c
commit 781ccc04f6

View file

@ -4,10 +4,15 @@ vl_redstone = {}
local mod = vl_redstone local mod = vl_redstone
-- Imports -- Imports
local force_get_node = mcl_util.force_get_node local mcl_util_force_get_node = mcl_util.force_get_node
local call_safe = mcl_util.call_safe local mcl_util_call_safe = mcl_util.call_safe
local get_item_group = minetest.get_item_group local minetest_get_item_group = minetest.get_item_group
local get_meta = minetest.get_meta local minetest_get_meta = minetest.get_meta
local minetest_hash_node_pos = minetest.hash_node_position
local minetest_get_position_from_hash = minetest.get_position_from_hash
local minetest_serialize = minetest.serialize
local minetest_deserialize = minetest.deserialize
local minetest_swap_node = minetest.swap_node
local vector_add = vector.add local vector_add = vector.add
local vector_to_string = vector.to_string local vector_to_string = vector.to_string
local vector_from_string = vector.from_string local vector_from_string = vector.from_string
@ -16,33 +21,42 @@ local vector_from_string = vector.from_string
local REDSTONE_POWER_META = modname .. ".power" local REDSTONE_POWER_META = modname .. ".power"
local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."." local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."."
local multipower_cache = {}
local function get_node_multipower_data(pos)
local hash = minetest_hash_node_pos(pos)
local node_multipower = multipower_cache[hash]
if not node_multipower then
local meta = minetest_get_meta(pos)
node_multipower = minetest_deserialize(meta:get_string("vl_redstone.multipower")) or {sources={}}
multipower_cache[hash] = node_multipower
end
return node_multipower
end
local function update_node(pos) local function update_node(pos)
local node = force_get_node(pos) local node = mcl_util_force_get_node(pos)
local nodedef = minetest.registered_nodes[node.name] local nodedef = minetest.registered_nodes[node.name]
-- Only do this processing of signal sinks -- Only do this processing of signal sinks
if not nodedef.mesecons then return end if not nodedef.mesecons then return end
-- Calculate the maximum power feeding into this node -- Calculate the maximum power feeding into this node
-- TODO: check how much time this is taking local node_multipower = get_node_multipower_data(pos)
local meta = minetest.get_meta(pos)
local strength = 0 local strength = 0
local meta_tbl = meta:to_table() local sources = node_multipower.sources
for k,v in pairs(meta_tbl.fields) do for pos_hash,source_strength in pairs(sources) do
if string.sub(k,1,#REDSTONE_POWER_META_SOURCE) == REDSTONE_POWER_META_SOURCE then --print("\t"..vector_to_string(minetest_get_position_from_hash(pos_hash)).." -> "..tostring(strength))
local source_strength = tonumber(v) if source_strength > strength then strength = source_strength end
if source_strength > strength then
strength = source_strength
end
end
end end
-- Don't do any processing inf the actual strength at this node has changed -- Don't do any processing inf the actual strength at this node has changed
local last_strength = meta:get_int(REDSTONE_POWER_META) local last_strength = node_multipower.strength
--print("At "..vector_to_string(pos).." strength="..tostring(strength)..",last_strength="..tostring(last_strength))
if last_strength == strength then return end if last_strength == strength then return end
-- Update the state -- Update the state
meta:set_int(REDSTONE_POWER_META, strength) node_multipower.strength = strength
-- TODO: determine the input rule that the strength is coming from -- TODO: determine the input rule that the strength is coming from
local rule = nil local rule = nil
@ -56,7 +70,7 @@ local function update_node(pos)
-- Handle activation -- Handle activation
local hook = sink.action_on local hook = sink.action_on
if hook then if hook then
call_safe(nil, hook, {pos, node, rule, strength}) mcl_util_call_safe(nil, hook, {pos, node, rule, strength})
end end
if sink.onstate then if sink.onstate then
new_node_name = sink.onstate new_node_name = sink.onstate
@ -65,7 +79,7 @@ local function update_node(pos)
-- Handle deactivation -- Handle deactivation
local hook = sink.action_off local hook = sink.action_off
if hook then if hook then
call_safe(nil, hook, {pos, node, rule, strength}) mcl_util_call_safe(nil, hook, {pos, node, rule, strength})
end end
if sink.offstate then if sink.offstate then
new_node_name = sink.offstate new_node_name = sink.offstate
@ -75,7 +89,7 @@ local function update_node(pos)
-- TODO: handle signal level change notification -- TODO: handle signal level change notification
local hook = sink.action_change local hook = sink.action_change
if hook then if hook then
call_safe(nil, hook, {pos, node, rule, strength}) mcl_util_call_safe(nil, hook, {pos, node, rule, strength})
end end
if sink.strength_state then if sink.strength_state then
new_node_name = sink.strength_state[strength] new_node_name = sink.strength_state[strength]
@ -84,7 +98,7 @@ local function update_node(pos)
-- Update the node -- Update the node
if new_node_name and new_node_name ~= node.name then if new_node_name and new_node_name ~= node.name then
node.name = new_node_name node.name = new_node_name
minetest.swap_node(pos, node) minetest_swap_node(pos, node)
end end
return return
end end
@ -110,9 +124,9 @@ local function update_node(pos)
",conductor.onstate="..tostring(conductor.onstate).. ",conductor.onstate="..tostring(conductor.onstate)..
",conductor.offstate="..tostring(conductor.offstate) ",conductor.offstate="..tostring(conductor.offstate)
) )
]] --]]
node.name = new_node_name node.name = new_node_name
minetest.swap_node(pos, node) minetest_swap_node(pos, node)
end end
end end
end end
@ -129,7 +143,7 @@ local POWERED_BLOCK_RULES = {
local function get_positions_from_node_rules(pos, rules_type, list, powered) local function get_positions_from_node_rules(pos, rules_type, list, powered)
list = list or {} list = list or {}
local node = force_get_node(pos) local node = mcl_util_force_get_node(pos)
local nodedef = minetest.registered_nodes[node.name] local nodedef = minetest.registered_nodes[node.name]
local rules local rules
if nodedef.mesecons then if nodedef.mesecons then
@ -143,8 +157,8 @@ local function get_positions_from_node_rules(pos, rules_type, list, powered)
else else
-- The only blocks that don't support mesecon that propagate power are solid blocks that -- The only blocks that don't support mesecon that propagate power are solid blocks that
-- are powered by another device. Mesecons calls this 'spread' -- are powered by another device. Mesecons calls this 'spread'
if not powered[vector_to_string(pos)] then return list end if not powered[minetest_hash_node_pos(pos)] then return list end
if get_item_group(node.name,"solid") == 0 then return list end if minetest_get_item_group(node.name,"solid") == 0 then return list end
rules = POWERED_BLOCK_RULES rules = POWERED_BLOCK_RULES
end end
@ -154,14 +168,14 @@ local function get_positions_from_node_rules(pos, rules_type, list, powered)
-- Convert to absolute positions -- Convert to absolute positions
for i=1,#rules do for i=1,#rules do
local next_pos = vector_add(pos, rules[i]) local next_pos = vector_add(pos, rules[i])
local next_pos_str = vector_to_string(next_pos) local next_pos_hash = minetest_hash_node_pos(next_pos)
--print("\tnext: "..next_pos_str..", prev="..tostring(list[next_pos_str])) --print("\tnext: "..next_pos_str..", prev="..tostring(list[next_pos_str]))
list[next_pos_str] = true list[next_pos_hash] = true
-- Power solid blocks -- Power solid blocks
if rules[i].spread then if rules[i].spread then
powered[next_pos_str] = true powered[next_pos_hash] = true
--print("powering "..next_pos_str) --print("powering "..vector_to_string(next_pos)
end end
end end
@ -172,12 +186,12 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po
print("Flowing lv"..tostring(source_strength).." power from "..vector_to_string(source_pos).." for "..tostring(distance).." blocks") print("Flowing lv"..tostring(source_strength).." power from "..vector_to_string(source_pos).." for "..tostring(distance).." blocks")
local processed = {} local processed = {}
local powered = {} local powered = {}
local source_pos_str = vector_to_string(source_pos) local source_pos_hash = minetest_hash_node_pos(source_pos)
processed[source_pos_str] = true processed[source_pos_hash] = true
-- Update the source node's redstone power -- Update the source node's redstone power
local meta = get_meta(source_pos) local node_multipower = get_node_multipower_data(source_pos)
meta:set_int(REDSTONE_POWER_META, source_strength) node_multipower.strength = source_strength
-- Get rules -- Get rules
local list = {} local list = {}
@ -189,17 +203,17 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po
local strength = source_strength - (i - 1) local strength = source_strength - (i - 1)
if strength < 0 then strength = 0 end if strength < 0 then strength = 0 end
for pos_str,dir in pairs(list) do for pos_hash,dir in pairs(list) do
--print("Processing "..pos_str) --print("Processing "..pos_str)
if not processed[pos_str] then if not processed[pos_hash] then
processed[pos_str] = true processed[pos_hash] = true
local pos = vector_from_string(pos_str) local pos = minetest_get_position_from_hash(pos_hash)
local meta = get_meta(pos)
-- Update node power directly -- Update node power directly
meta:set_int(REDSTONE_POWER_META.."."..source_pos_str, strength) local node_multipower = get_node_multipower_data(pos)
node_multipower.sources[source_pos_hash] = strength
--print("pos="..vector.to_string(pos)..", strength="..tostring(strength)) --print("pos="..vector.to_string(pos)..", strength="..tostring(strength))
-- handle spread -- handle spread
@ -216,13 +230,13 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po
end) end)
function vl_redstone.set_power(pos, strength) function vl_redstone.set_power(pos, strength)
local meta = get_meta(pos) local node_multipower = get_node_multipower_data(pos)
local distance = meta:get_int(REDSTONE_POWER_META) local distance = node_multipower.strength or 0
-- Don't perform an update if the power level is the same as before -- Don't perform an update if the power level is the same as before
if distance == strength then return end if distance == strength then return end
print("previous="..tostring(distance)..", new="..tostring(strength)) --print("previous="..tostring(distance)..", new="..tostring(strength))
-- Make the update distance the maximum of the new strength and the old strength -- Make the update distance the maximum of the new strength and the old strength
if distance < strength then if distance < strength then
@ -234,7 +248,15 @@ function vl_redstone.set_power(pos, strength)
end end
function vl_redstone.get_power_level(pos) function vl_redstone.get_power_level(pos)
local meta = get_meta(pos) local node_multipower = get_node_multipower_data(pos)
return meta:get_int(REDSTONE_POWER_META) return node_multipower.strength or 0
end end
-- Persist multipower data
minetest.register_on_shutdown(function()
for pos_hash,node_multipower in pairs(multipower_cache) do
local pos = minetest_get_position_from_hash(pos_hash)
local meta = minetest_get_meta(pos)
meta:set_string("vl_redstone.multipower", minetest_serialize(node_multipower))
end
end)