From 1da30698d7e8fa6725f8e577209682e9b6dbd492 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Sun, 21 Apr 2024 22:50:40 +0000 Subject: [PATCH] Fix crash in comparitor code, add input rule processing --- mods/ITEMS/REDSTONE/mcl_comparators/init.lua | 2 + mods/ITEMS/REDSTONE/vl_redstone/init.lua | 163 ++++++++++++++++--- 2 files changed, 138 insertions(+), 27 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua index e887b1628..37bf65a62 100644 --- a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua @@ -100,6 +100,8 @@ end function mod.read_inventory(inv, inv_name) local stacks = inv:get_list(inv_name) + if not stacks then return 0 end + local count = 0 for i=1,#stacks do count = count + ( stacks[i]:get_count() / stacks[i]:get_stack_max() ) diff --git a/mods/ITEMS/REDSTONE/vl_redstone/init.lua b/mods/ITEMS/REDSTONE/vl_redstone/init.lua index 1c1048b4e..30ae4342a 100644 --- a/mods/ITEMS/REDSTONE/vl_redstone/init.lua +++ b/mods/ITEMS/REDSTONE/vl_redstone/init.lua @@ -16,6 +16,7 @@ local minetest_swap_node = minetest.swap_node local vector_add = vector.add local vector_to_string = vector.to_string local vector_from_string = vector.from_string +local math_floor = math.floor -- Constants local REDSTONE_POWER_META = modname .. ".power" @@ -23,46 +24,145 @@ local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."." local multipower_cache = {} +local function hash_from_direction(dir) + return 9 * (dir.x + 1) + 3 * (dir.y + 1) + dir.z + 1 +end +local function direction_from_hash(dir_hash) + local x = math_floor(dir_hash / 9) - 1 + local y = math_floor((dir_hash % 9) / 3 ) - 1 + local z = dir_hash % 3 - 1 + return vector.new(x,y,z) +end +local DIR_HASH_ZERO = hash_from_direction(vector.zero()) +print("DIR_HASH_ZERO="..tostring(DIR_HASH_ZERO)) + +local function get_input_rules_hash(mesecons, input_rules) + -- Skip build if already built + local redstone = mesecons._vl_redtone or {} + mesecons._vl_redstone = redstone + if redstone.input_rules_hash then return redstone.input_rules_hash end + + -- Build the rules + local input_rules_hash = {} + redstone.input_rules_hash = input_rules_hash + for i=1,#input_rules do + input_rules_hash[hash_from_direction(input_rules[i])] = true + end + + return input_rules_hash +end + local function get_node_multipower_data(pos, no_create) local hash = minetest_hash_node_pos(pos) local node_multipower = multipower_cache[hash] if not node_multipower and not no_create then local meta = minetest_get_meta(pos) - node_multipower = minetest_deserialize(meta:get_string("vl_redstone.multipower")) or {sources={}} + node_multipower = minetest_deserialize(meta:get_string("vl_redstone.multipower")) + if not node_multipower or node_multipower.version ~= 1 then + node_multipower = { + version = 1, + sources={} + } + end multipower_cache[hash] = node_multipower end return node_multipower end +local function calculate_driven_strength(pos, input_rules_hash) + local dir_hash = dir and hash_from_direction(dir) + local node_multipower = get_node_multipower_data(pos) + local strength = 0 + local strongest_direction_hash = nil + local sources = node_multipower.sources + input_rules_hash = input_rules_hash or {} + + print("in update_node(pos="..vector_to_string(pos)..") node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) + for pos_hash,data in pairs(sources) do + local source_strength = data[1] + local dirs = data[2] + --print("data="..dump(data)) + --print("\t"..vector_to_string(pos)..".source["..vector_to_string(minetest_get_position_from_hash(pos_hash)).."] = "..tostring(strength)) + + -- Filter by specified direction + local match = false + if not dir_hash then + match = true + else + for i=1,#dirs do + match = match or input_rules_hash[dirs[i]] + end + end + + print("match="..tostring(match)..",source_strength="..tostring(source_strength)) + + -- Update strength and track which direction the strongest power is coming from + if match and source_strength >= strength then + strength = source_strength + if #dirs ~= 0 then + strongest_direction_hash = dirs[1] + end + end + end + + return strength,strongest_direction_hash +end + local function update_node(pos) local node = mcl_util_force_get_node(pos) local nodedef = minetest.registered_nodes[node.name] - -- Only do this processing of signal sinks - if not nodedef.mesecons then return end + -- Only do this processing of signal sinks and conductors + local nodedef_mesecons = nodedef.mesecons + if not nodedef_mesecons then return end - -- Calculate the maximum power feeding into this node - local node_multipower = get_node_multipower_data(pos) - local strength = 0 - local sources = node_multipower.sources - --print("in update_node(pos="..vector_to_string(pos)..") node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) - for pos_hash,source_strength in pairs(sources) do - --print("\t"..vector_to_string(pos)..".source["..vector_to_string(minetest_get_position_from_hash(pos_hash)).."] = "..tostring(strength)) - if source_strength > strength then strength = source_strength end + print("Running update_node(pos="..vector_to_string(pos)..")") + + -- Get input rules + local input_rules = nil + if nodedef_mesecons.conductor then + input_rules = nodedef_mesecons.conductor.rules + elseif nodedef_mesecons.effector then + input_rules = nodedef_mesecons.effector.rules + else + -- No input rules, can't act + print("Unable to find input rules for "..node.name..": mesecons="..dump(nodedef_mesecons)) + return end + -- Calculate the maximum power feeding into this node + local input_rules_hash = get_input_rules_hash(nodedef_mesecons, input_rules) + print("input_rules_hash="..dump(input_rules_hash)..", input_rules="..dump(input_rules)) + local strength,dir_hash = calculate_driven_strength(pos, input_rules_hash) + print("strength="..tostring(strength)..",dir_hash="..tostring(dir_hash)) + -- Don't do any processing inf the actual strength at this node has changed + local node_multipower = get_node_multipower_data(pos) local last_strength = node_multipower.strength or 0 - --print("At "..vector_to_string(pos).." strength="..tostring(strength)..",last_strength="..tostring(last_strength)) + print("At "..vector_to_string(pos).." strength="..tostring(strength)..",last_strength="..tostring(last_strength)) if last_strength == strength then return end + -- Determine the input rule that the strength is coming from (for mesecons compatibility; there are mods that depend on it) + local rule = nil + for i = 1,#input_rules do + local input_rule = input_rules[i] + local input_rule_hash = hash_from_direction(input_rule) + if dir_hash == input_rule_hash then + rule = input_rule + break + end + end + if not rule then + print("No rule found") + return + else + print("rule="..dump(rule)) + end + -- Update the state node_multipower.strength = strength - -- TODO: determine the input rule that the strength is coming from (for mesecons compatibility; there are mods that depend on it) - local rule = nil - - local sink = nodedef.mesecons.effector + local sink = nodedef_mesecons.effector if sink then local new_node_name = nil --print("Updating "..node.name.." at "..vector_to_string(pos).."("..tostring(last_strength).."->"..tostring(strength)..")") @@ -87,7 +187,7 @@ local function update_node(pos) end end - -- TODO: handle signal level change notification + -- handle signal level change notification local hook = sink.action_change if hook then mcl_util_call_safe(nil, hook, {pos, node, rule, strength}) @@ -104,7 +204,7 @@ local function update_node(pos) return end - local conductor = nodedef.mesecons.conductor + local conductor = nodedef_mesecons.conductor if conductor then -- Figure out if the node name changes based on the new state local new_node_name = nil @@ -118,7 +218,7 @@ local function update_node(pos) -- Update the node if new_node_name and new_node_name ~= node.name then - --[[ + ---[[ print("Changing "..vector_to_string(pos).." from "..node.name.." to "..new_node_name.. ", strength="..tostring(strength)..",last_strength="..tostring(last_strength)) print("node.name="..node.name.. @@ -169,10 +269,13 @@ local function get_positions_from_node_rules(pos, rules_type, list, powered) -- Convert to absolute positions for i=1,#rules do - local next_pos = vector_add(pos, rules[i]) + local rule = rules[i] + local next_pos = vector_add(pos, rule) local next_pos_hash = minetest_hash_node_pos(next_pos) --print("\tnext: "..next_pos_str..", prev="..tostring(list[next_pos_str])) - list[next_pos_hash] = true + local dirs = list[next_pos_hash] or {} + list[next_pos_hash] = dirs + dirs[hash_from_direction(rule)] = true -- Power solid blocks if rules[i].spread then @@ -206,7 +309,7 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po local strength = source_strength - (i - 1) if strength < 0 then strength = 0 end - for pos_hash,dir in pairs(list) do + for pos_hash,dir_list in pairs(list) do --print("Processing "..pos_str) if not processed[pos_hash] then @@ -216,11 +319,17 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po -- Update node power directly local node_multipower = get_node_multipower_data(pos) - --local old_strength = node_multipower.sources[source_pos_hash] or 0 - --print("Changing "..vector.to_string(pos)..".source["..vector_to_string(source_pos).."] from "..tostring(old_strength).." to "..tostring(strength)) - --print("\tBefore node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) - node_multipower.sources[source_pos_hash] = strength - --print("\tAfter node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) + local old_data = node_multipower.sources[source_pos_hash] + local old_strength = old_data and old_data[1] or 0 + print("Changing "..vector.to_string(pos)..".source["..vector_to_string(source_pos).."] from "..tostring(old_strength).." to "..tostring(strength)) + print("\tBefore node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) + print("\tdir_list="..dump(dir_list)) + local dirs = {} + for k,_ in pairs(dir_list) do + dirs[#dirs+1] = k + end + node_multipower.sources[source_pos_hash] = {strength,dirs} + print("\tAfter node_multipower("..tostring(node_multipower)..")="..dump(node_multipower)) -- handle spread get_positions_from_node_rules(pos, "conductor", next_list, powered)