From b268e3d5262f602e868ccf24489f11fe97cc44c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B3th=20Korn=C3=A9l?= Date: Fri, 29 Nov 2024 18:58:51 +0100 Subject: [PATCH] Fix machines connected to multiple networks (#655) Machines sometimes were be a part of multiple networks and generated power for each. This is fixed by checking if the machine is already part of an other network before assigning it to the current network. --- technic/machines/register/cables.lua | 154 ++++++++++++++----------- technic/machines/switching_station.lua | 34 ++++-- 2 files changed, 111 insertions(+), 77 deletions(-) diff --git a/technic/machines/register/cables.lua b/technic/machines/register/cables.lua index 70da6d6..a87a3a8 100644 --- a/technic/machines/register/cables.lua +++ b/technic/machines/register/cables.lua @@ -43,84 +43,106 @@ local function check_connections(pos) return connections end -local function clear_networks(pos) +local clear_networks + +local function clear_network(network_id) + if not network_id then + return + end + + for _,v in pairs(technic.networks[network_id].all_nodes) do + local pos1 = minetest.hash_node_position(v) + technic.cables[pos1] = nil + end + local network_bckup = technic.networks[network_id] + technic.networks[network_id] = nil + + for _,n_pos in pairs(network_bckup.PR_nodes) do + clear_networks(n_pos) + end + for _,n_pos in pairs(network_bckup.RE_nodes) do + clear_networks(n_pos) + end + for _,n_pos in pairs(network_bckup.BA_nodes) do + clear_networks(n_pos) + end +end + +clear_networks = function(pos) local node = minetest.get_node(pos) local meta = minetest.get_meta(pos) local placed = node.name ~= "air" local positions = check_connections(pos) + if #positions < 1 then return end - local dead_end = #positions == 1 - for _,connected_pos in pairs(positions) do - local net = technic.cables[minetest.hash_node_position(connected_pos)] - if net and technic.networks[net] then - if dead_end and placed then - -- Dead end placed, add it to the network - -- Get the network - local network_id = technic.cables[minetest.hash_node_position(positions[1])] - if not network_id then - -- We're evidently not on a network, nothing to add ourselves to - return - end - local sw_pos = minetest.get_position_from_hash(network_id) - sw_pos.y = sw_pos.y + 1 - local network = technic.networks[network_id] - local tier = network.tier - -- Actually add it to the (cached) network - -- !! IMPORTANT: ../switching_station.lua -> check_node_subp() must be kept in sync + if #positions == 1 then + if placed then + -- Dead end placed, add it to the network + -- Get the network + local network_id = technic.cables[minetest.hash_node_position(positions[1])] + if not network_id then + -- We're evidently not on a network, nothing to add ourselves to + return + end + local network = technic.networks[network_id] + local tier = network.tier + + -- Actually add it to the (cached) network + -- !! IMPORTANT: ../switching_station.lua -> check_node_subp() must be kept in sync + if technic.is_tier_cable(node.name, tier) then technic.cables[minetest.hash_node_position(pos)] = network_id - pos.visited = 1 - if technic.is_tier_cable(node.name, tier) then - -- Found a cable - table.insert(network.all_nodes,pos) - elseif technic.machines[tier][node.name] then - -- Found a machine - local eu_type = technic.machines[tier][node.name] - meta:set_string(tier.."_network", string.format("%.20g", network_id)) - if eu_type == technic.producer then - table.insert(network.PR_nodes, pos) - elseif eu_type == technic.receiver then - table.insert(network.RE_nodes, pos) - elseif eu_type == technic.producer_receiver then - table.insert(network.PR_nodes, pos) - table.insert(network.RE_nodes, pos) - elseif eu_type == technic.battery then - table.insert(network.BA_nodes, pos) - end - -- Note: SPECIAL (i.e. switching station) is not traversed! + table.insert(network.all_nodes,pos) + elseif technic.machines[tier][node.name] then + -- Found a machine + local eu_type = technic.machines[tier][node.name] + meta:set_string(tier.."_network", string.format("%.20g", network_id)) + meta:set_int(tier.."_EU_timeout", 2) + if eu_type == technic.producer then + table.insert(network.PR_nodes, pos) + elseif eu_type == technic.receiver then + table.insert(network.RE_nodes, pos) + elseif eu_type == technic.producer_receiver then + table.insert(network.PR_nodes, pos) + table.insert(network.RE_nodes, pos) + elseif eu_type == technic.battery then + table.insert(network.BA_nodes, pos) end - elseif dead_end and not placed then - -- Dead end removed, remove it from the network - -- Get the network - local network_id = technic.cables[minetest.hash_node_position(positions[1])] - if not network_id then - -- We're evidently not on a network, nothing to add ourselves to - return - end - local network = technic.networks[network_id] + -- Note: SPECIAL (i.e. switching station) is not traversed! + end + else + -- Dead end removed, remove it from the network + -- Get the network + local network_id = technic.cables[minetest.hash_node_position(positions[1])] + if not network_id then + -- We're evidently not on a network, nothing to add ourselves to + return + end + local network = technic.networks[network_id] - -- Search for and remove machine - technic.cables[minetest.hash_node_position(pos)] = nil - for tblname,table in pairs(network) do - if tblname ~= "tier" then - for machinenum,machine in pairs(table) do - if machine.x == pos.x - and machine.y == pos.y - and machine.z == pos.z then - table[machinenum] = nil - end + -- Search for and remove machine + technic.cables[minetest.hash_node_position(pos)] = nil + for tblname,table in pairs(network) do + if tblname ~= "tier" then + for machinenum,machine in pairs(table) do + if machine.x == pos.x + and machine.y == pos.y + and machine.z == pos.z then + table[machinenum] = nil end end end - else - -- Not a dead end, so the whole network needs to be recalculated - for _,v in pairs(technic.networks[net].all_nodes) do - local pos1 = minetest.hash_node_position(v) - technic.cables[pos1] = nil - end - technic.networks[net] = nil end end + return + end + + clear_network(technic.cables[minetest.hash_node_position(pos)]) + + for _,connected_pos in pairs(positions) do + local network_id = technic.cables[minetest.hash_node_position(connected_pos)] + -- Not a dead end, so the whole network needs to be recalculated + clear_network(network_id) end end @@ -170,7 +192,7 @@ function technic.register_cable(tier, size) connects_to = {"group:technic_"..ltier.."_cable", "group:technic_"..ltier, "group:technic_all_tiers"}, on_construct = clear_networks, - on_destruct = clear_networks, + after_destruct = clear_networks, }) local xyz = { @@ -210,7 +232,7 @@ function technic.register_cable(tier, size) connects_to = {"group:technic_"..ltier.."_cable", "group:technic_"..ltier, "group:technic_all_tiers"}, on_construct = clear_networks, - on_destruct = clear_networks, + after_destruct = clear_networks, } def.node_box.fixed = { {-size, -size, -size, size, size, size}, diff --git a/technic/machines/switching_station.lua b/technic/machines/switching_station.lua index d1cabf0..b671585 100644 --- a/technic/machines/switching_station.lua +++ b/technic/machines/switching_station.lua @@ -97,12 +97,14 @@ local function flatten(map) return list end --- Add a wire node to the LV/MV/HV network --- Returns: indicator whether the cable is new in the network +-- Add a node to the LV/MV/HV network +-- Returns: indicator whether the node is new in the network local hash_node_position = minetest.hash_node_position local function add_network_node(nodes, pos, network_id) local node_id = hash_node_position(pos) - technic.cables[node_id] = network_id + if network_id then + technic.cables[node_id] = network_id + end if nodes[node_id] then return false end @@ -136,21 +138,31 @@ local check_node_subp = function(network, pos, machines, sw_pos, from_below, net local meta = minetest.get_meta(pos) -- Normal tostring() does not have enough precision, neither does meta:set_int() -- Lua 5.1 bug: Cannot use hexadecimal notation for compression (see LuaJIT #911) - meta:set_string(network.tier.."_network", string.format("%.20g", network_id)) + local network_str = string.format("%.20g", network_id) + local network_key = network.tier.."_network" + local m_network_str = meta:get_string(network_key) + + if m_network_str == "" then + meta:set_string(network_key, network_str) + else + if m_network_str ~= network_str then + return + end + end if eu_type == technic.producer then - add_network_node(network.PR_nodes, pos, network_id) + add_network_node(network.PR_nodes, pos) elseif eu_type == technic.receiver then - add_network_node(network.RE_nodes, pos, network_id) + add_network_node(network.RE_nodes, pos) elseif eu_type == technic.producer_receiver then - add_network_node(network.PR_nodes, pos, network_id) - add_network_node(network.RE_nodes, pos, network_id) + add_network_node(network.PR_nodes, pos) + add_network_node(network.RE_nodes, pos) elseif eu_type == technic.battery then - add_network_node(network.BA_nodes, pos, network_id) + add_network_node(network.BA_nodes, pos) elseif eu_type == "SPECIAL" and from_below and not vector.equals(pos, sw_pos) then -- Another switching station -> disable it - add_network_node(network.SP_nodes, pos, network_id) + add_network_node(network.SP_nodes, pos) meta:set_int("active", 0) end @@ -193,7 +205,6 @@ local get_network = function(sw_pos, cable_pos, tier) end return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes end - local machines = technic.machines[tier] local network = { tier = tier, @@ -455,6 +466,7 @@ local function switching_station_timeout_count(pos, tier) local meta = minetest.get_meta(pos) local timeout = meta:get_int(tier.."_EU_timeout") if timeout <= 0 then + meta:set_string(tier.."_network", "") meta:set_int(tier.."_EU_input", 0) -- Not needed anymore <-- actually, it is for supply converter return true else