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.
This commit is contained in:
Tóth Kornél 2024-11-29 18:58:51 +01:00 committed by GitHub
parent 87e512ff24
commit b268e3d526
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 111 additions and 77 deletions

View File

@ -43,84 +43,106 @@ local function check_connections(pos)
return connections return connections
end 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 node = minetest.get_node(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local placed = node.name ~= "air" local placed = node.name ~= "air"
local positions = check_connections(pos) local positions = check_connections(pos)
if #positions < 1 then return end 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 if #positions == 1 then
-- !! IMPORTANT: ../switching_station.lua -> check_node_subp() must be kept in sync 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 technic.cables[minetest.hash_node_position(pos)] = network_id
pos.visited = 1 table.insert(network.all_nodes,pos)
if technic.is_tier_cable(node.name, tier) then elseif technic.machines[tier][node.name] then
-- Found a cable -- Found a machine
table.insert(network.all_nodes,pos) local eu_type = technic.machines[tier][node.name]
elseif technic.machines[tier][node.name] then meta:set_string(tier.."_network", string.format("%.20g", network_id))
-- Found a machine meta:set_int(tier.."_EU_timeout", 2)
local eu_type = technic.machines[tier][node.name] if eu_type == technic.producer then
meta:set_string(tier.."_network", string.format("%.20g", network_id)) table.insert(network.PR_nodes, pos)
if eu_type == technic.producer then elseif eu_type == technic.receiver then
table.insert(network.PR_nodes, pos) table.insert(network.RE_nodes, pos)
elseif eu_type == technic.receiver then elseif eu_type == technic.producer_receiver then
table.insert(network.RE_nodes, pos) table.insert(network.PR_nodes, pos)
elseif eu_type == technic.producer_receiver then table.insert(network.RE_nodes, pos)
table.insert(network.PR_nodes, pos) elseif eu_type == technic.battery then
table.insert(network.RE_nodes, pos) table.insert(network.BA_nodes, pos)
elseif eu_type == technic.battery then
table.insert(network.BA_nodes, pos)
end
-- Note: SPECIAL (i.e. switching station) is not traversed!
end end
elseif dead_end and not placed then -- Note: SPECIAL (i.e. switching station) is not traversed!
-- Dead end removed, remove it from the network end
-- Get the network else
local network_id = technic.cables[minetest.hash_node_position(positions[1])] -- Dead end removed, remove it from the network
if not network_id then -- Get the network
-- We're evidently not on a network, nothing to add ourselves to local network_id = technic.cables[minetest.hash_node_position(positions[1])]
return if not network_id then
end -- We're evidently not on a network, nothing to add ourselves to
local network = technic.networks[network_id] return
end
local network = technic.networks[network_id]
-- Search for and remove machine -- Search for and remove machine
technic.cables[minetest.hash_node_position(pos)] = nil technic.cables[minetest.hash_node_position(pos)] = nil
for tblname,table in pairs(network) do for tblname,table in pairs(network) do
if tblname ~= "tier" then if tblname ~= "tier" then
for machinenum,machine in pairs(table) do for machinenum,machine in pairs(table) do
if machine.x == pos.x if machine.x == pos.x
and machine.y == pos.y and machine.y == pos.y
and machine.z == pos.z then and machine.z == pos.z then
table[machinenum] = nil table[machinenum] = nil
end
end end
end 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
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
end end
@ -170,7 +192,7 @@ function technic.register_cable(tier, size)
connects_to = {"group:technic_"..ltier.."_cable", connects_to = {"group:technic_"..ltier.."_cable",
"group:technic_"..ltier, "group:technic_all_tiers"}, "group:technic_"..ltier, "group:technic_all_tiers"},
on_construct = clear_networks, on_construct = clear_networks,
on_destruct = clear_networks, after_destruct = clear_networks,
}) })
local xyz = { local xyz = {
@ -210,7 +232,7 @@ function technic.register_cable(tier, size)
connects_to = {"group:technic_"..ltier.."_cable", connects_to = {"group:technic_"..ltier.."_cable",
"group:technic_"..ltier, "group:technic_all_tiers"}, "group:technic_"..ltier, "group:technic_all_tiers"},
on_construct = clear_networks, on_construct = clear_networks,
on_destruct = clear_networks, after_destruct = clear_networks,
} }
def.node_box.fixed = { def.node_box.fixed = {
{-size, -size, -size, size, size, size}, {-size, -size, -size, size, size, size},

View File

@ -97,12 +97,14 @@ local function flatten(map)
return list return list
end end
-- Add a wire node to the LV/MV/HV network -- Add a node to the LV/MV/HV network
-- Returns: indicator whether the cable is new in the network -- Returns: indicator whether the node is new in the network
local hash_node_position = minetest.hash_node_position local hash_node_position = minetest.hash_node_position
local function add_network_node(nodes, pos, network_id) local function add_network_node(nodes, pos, network_id)
local node_id = hash_node_position(pos) 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 if nodes[node_id] then
return false return false
end end
@ -136,21 +138,31 @@ local check_node_subp = function(network, pos, machines, sw_pos, from_below, net
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
-- Normal tostring() does not have enough precision, neither does meta:set_int() -- 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) -- 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 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 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 elseif eu_type == technic.producer_receiver then
add_network_node(network.PR_nodes, pos, network_id) add_network_node(network.PR_nodes, pos)
add_network_node(network.RE_nodes, pos, network_id) add_network_node(network.RE_nodes, pos)
elseif eu_type == technic.battery then 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 elseif eu_type == "SPECIAL" and from_below and
not vector.equals(pos, sw_pos) then not vector.equals(pos, sw_pos) then
-- Another switching station -> disable it -- 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) meta:set_int("active", 0)
end end
@ -193,7 +205,6 @@ local get_network = function(sw_pos, cable_pos, tier)
end end
return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes
end end
local machines = technic.machines[tier] local machines = technic.machines[tier]
local network = { local network = {
tier = tier, tier = tier,
@ -455,6 +466,7 @@ local function switching_station_timeout_count(pos, tier)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local timeout = meta:get_int(tier.."_EU_timeout") local timeout = meta:get_int(tier.."_EU_timeout")
if timeout <= 0 then 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 meta:set_int(tier.."_EU_input", 0) -- Not needed anymore <-- actually, it is for supply converter
return true return true
else else