From f66c644fceb08d1e40e8b684b3a95b0e30fd9c94 Mon Sep 17 00:00:00 2001 From: SX <50966843+S-S-X@users.noreply.github.com> Date: Sat, 26 Sep 2020 04:37:20 +0300 Subject: [PATCH] Remove metadata for supply,demand,battery_count,battery_charge,battery_charge_max Remove switching station from networks Disable few debug prints, add removed machines to LBM clear_networks refatoring #95 Functions remove_network_node and add_network_branch #95 Fix undef network_id, remove flatten #95 --- technic/machines/network.lua | 149 ++++++++----- technic/machines/power_monitor.lua | 40 ++-- technic/machines/register/cables.lua | 209 ++++++++++-------- technic/machines/switching_station.lua | 34 ++- .../machines/switching_station_globalstep.lua | 9 +- technic/spec/fixtures/minetest.lua | 21 ++ technic/spec/fixtures/network.lua | 32 +++ technic/spec/network_spec.lua | 11 + 8 files changed, 299 insertions(+), 206 deletions(-) diff --git a/technic/machines/network.lua b/technic/machines/network.lua index 71ff05d..08182b3 100644 --- a/technic/machines/network.lua +++ b/technic/machines/network.lua @@ -35,6 +35,7 @@ function technic.sw_pos2tier(pos, use_vm) return technic.get_cable_tier(minetest.get_node(cable_pos).name) end +-- Destroy network data function technic.remove_network(network_id) local cables = technic.cables for pos_hash,cable_net_id in pairs(cables) do @@ -43,7 +44,23 @@ function technic.remove_network(network_id) end end technic.networks[network_id] = nil - print(string.format("NET DESTRUCT %s (%.17g)", minetest.pos_to_string(technic.network2pos(network_id)), network_id)) + --print(string.format("NET DESTRUCT %s (%.17g)", minetest.pos_to_string(technic.network2pos(network_id)), network_id)) +end + +-- Remove machine or cable from network +local network_node_tables = {"PR_nodes","BA_nodes","RE_nodes","SP_nodes","all_nodes"} +function technic.remove_network_node(network_id, pos) + local network = technic.networks[network_id] + if not network then return end + technic.cables[poshash(pos)] = nil + for _,tblname in ipairs(network_node_tables) do + local table = network[tblname] + for id,mpos in pairs(table) do + if mpos.x == pos.x and mpos.y == pos.y and mpos.z == pos.z then + table[id] = nil + end + end + end end function technic.sw_pos2network(pos) @@ -104,6 +121,11 @@ local overload_reset_time = tonumber(minetest.settings:get("technic.overload_res local overloaded_networks = {} function technic.overload_network(network_id) + local network = technic.networks[network_id] + if network then + network.supply = 0 + network.battery_charge = 0 + end overloaded_networks[network_id] = minetest.get_us_time() + (overload_reset_time * 1000 * 1000) end @@ -125,13 +147,6 @@ end -- -- Functions to traverse the electrical network -- -local function flatten(map) - local list = {} - for key, value in pairs(map) do - list[#list + 1] = value - end - return list -end local function attach_network_machine(network_id, pos) local pos_hash = poshash(pos) @@ -148,31 +163,26 @@ local function attach_network_machine(network_id, pos) end end --- Add a wire node to the LV/MV/HV network +-- Add a machine node to the LV/MV/HV network local function add_network_node(nodes, pos, network_id) + technic.cables[poshash(pos)] = network_id + table.insert(nodes, pos) +end + +-- Add a wire node to the LV/MV/HV network +local function add_cable_node(nodes, pos, network_id, queue) local node_id = poshash(pos) technic.cables[node_id] = network_id if nodes[node_id] then return false end nodes[node_id] = pos - return true -end - -local function add_cable_node(nodes, pos, network_id, queue) - if add_network_node(nodes, pos, network_id) then - queue[#queue + 1] = pos - end + -- Also add cables to queue + queue[#queue + 1] = pos end -- Generic function to add found connected nodes to the right classification array -local function check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, from_below, network_id, queue) - - local distance_to_switch = vector.distance(pos, sw_pos) - if distance_to_switch > switch_max_range then - -- max range exceeded - return - end +local function check_node_subp(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, machines, tier, sw_pos, from_below, network_id, queue) technic.get_or_load_node(pos) local name = minetest.get_node(pos).name @@ -192,10 +202,6 @@ local function check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes --attach_network_machine(network_id, pos) add_network_node(PR_nodes, pos, network_id) add_network_node(RE_nodes, pos, network_id) - elseif machines[name] == "SPECIAL" and from_below then - -- Another switching station -> disable it - attach_network_machine(network_id, pos) - add_network_node(SP_nodes, pos, network_id) elseif machines[name] == technic.battery then attach_network_machine(network_id, pos) add_network_node(BA_nodes, pos, network_id) @@ -206,7 +212,7 @@ local function check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes end -- Traverse a network given a list of machines and a cable type name -local function traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, network_id, queue) +local function traverse_network(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, machines, tier, sw_pos, network_id, queue) local positions = { {x=pos.x+1, y=pos.y, z=pos.z}, {x=pos.x-1, y=pos.y, z=pos.z}, @@ -215,7 +221,7 @@ local function traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_node {x=pos.x, y=pos.y, z=pos.z+1}, {x=pos.x, y=pos.y, z=pos.z-1}} for i, cur_pos in pairs(positions) do - check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos, i == 3, network_id, queue) + check_node_subp(PR_nodes, RE_nodes, BA_nodes, all_nodes, cur_pos, machines, tier, sw_pos, i == 3, network_id, queue) end end @@ -237,6 +243,28 @@ local function get_network(network_id, tier) return technic.build_network(network_id) end +function technic.add_network_branch(queue, sw_pos, network) + -- Adds whole branch to network, queue positions can be used to bypass sub branches + local PR_nodes = network.PR_nodes -- Indexed array + local BA_nodes = network.BA_nodes -- Indexed array + local RE_nodes = network.RE_nodes -- Indexed array + local all_nodes = network.all_nodes -- Hash table + local network_id = network.id + local tier = network.tier + while next(queue) do + local to_visit = {} + for _, pos in ipairs(queue) do + if vector.distance(pos, sw_pos) > switch_max_range then + -- max range exceeded + return + end + traverse_network(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, + technic.machines[tier], tier, sw_pos, network_id, to_visit) + end + queue = to_visit + end +end + function technic.build_network(network_id) print(string.format("NET CONSTRUCT %s (%.17g)", minetest.pos_to_string(technic.network2pos(network_id)), network_id)) technic.remove_network(network_id) @@ -246,29 +274,24 @@ function technic.build_network(network_id) print(string.format("Cannot build network, cannot get tier for switching station at %s", minetest.pos_to_string(sw_pos))) return end - local PR_nodes = {} - local BA_nodes = {} - local RE_nodes = {} - local SP_nodes = {} - local all_nodes = {} + local network = { + id = network_id, tier = tier, all_nodes = {}, + SP_nodes = {}, PR_nodes = {}, RE_nodes = {}, BA_nodes = {}, + supply = 0, demand = 0, timeout = 4, battery_charge = 0, battery_charge_max = 0, + } + -- Add first cable (one that is holding network id) and build network local queue = {} - -- Add first cable (one that is holding network id) - add_cable_node(all_nodes, technic.network2pos(network_id), network_id, queue) - while next(queue) do - local to_visit = {} - for _, pos in ipairs(queue) do - traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, - pos, technic.machines[tier], tier, sw_pos, network_id, to_visit) - end - queue = to_visit - end - PR_nodes = flatten(PR_nodes) - BA_nodes = flatten(BA_nodes) - RE_nodes = flatten(RE_nodes) - --SP_nodes = flatten(SP_nodes) -- can this be removed from network data? - technic.networks[network_id] = {tier = tier, all_nodes = all_nodes, SP_nodes = SP_nodes, - PR_nodes = PR_nodes, RE_nodes = RE_nodes, BA_nodes = BA_nodes, timeout = 4} - return PR_nodes, BA_nodes, RE_nodes + add_cable_node(network.all_nodes, technic.network2pos(network_id), network_id, queue) + technic.add_network_branch(queue, sw_pos, network) + -- Flatten hashes to optimize iterations + --network.PR_nodes = flatten(network.PR_nodes) -- Already processed as indexed array + --network.BA_nodes = flatten(network.BA_nodes) -- Already processed as indexed array + --network.RE_nodes = flatten(network.RE_nodes) -- Already processed as indexed array + network.battery_count = #network.BA_nodes + -- Add newly built network to cache array + technic.networks[network_id] = network + -- And return producers, batteries and receivers (should this simply return network?) + return network.PR_nodes, network.BA_nodes, network.RE_nodes end -- @@ -315,9 +338,11 @@ function technic.network_run(network_id) local RE_nodes local tier = technic.sw_pos2tier(pos) + local network if tier then PR_nodes, BA_nodes, RE_nodes = get_network(network_id, tier) if technic.is_overloaded(network_id) then return end + network = technic.networks[network_id] else --dprint("Not connected to a network") technic.network_infotext(network_id, S("%s Has No Network"):format(S("Switching Station"))) @@ -400,13 +425,12 @@ function technic.network_run(network_id) S("Switching Station"), technic.EU_string(PR_eu_supply), technic.EU_string(RE_eu_demand))) - local meta = minetest.get_meta(pos) - -- If mesecon signal and power supply or demand changed then -- send them via digilines. if mesecons_path and digilines_path and mesecon.is_powered(pos) then - if PR_eu_supply ~= meta:get_int("supply") or - RE_eu_demand ~= meta:get_int("demand") then + if PR_eu_supply ~= network.supply or + RE_eu_demand ~= network.demand then + local meta = minetest.get_meta(pos) local channel = meta:get_string("channel") digilines.receptor_send(pos, technic.digilines.rules, channel, { supply = PR_eu_supply, @@ -416,11 +440,11 @@ function technic.network_run(network_id) end -- Data that will be used by the power monitor - meta:set_int("supply",PR_eu_supply) - meta:set_int("demand",RE_eu_demand) - meta:set_int("battery_count",#BA_nodes) - meta:set_int("battery_charge",BA_charge) - meta:set_int("battery_charge_max",BA_charge_max) + network.supply = PR_eu_supply + network.demand = RE_eu_demand + network.battery_count = #BA_nodes + network.battery_charge = BA_charge + network.battery_charge_max = BA_charge_max -- If the PR supply is enough for the RE demand supply them all if PR_eu_supply >= RE_eu_demand then @@ -533,13 +557,16 @@ if false then nodenames = { "group:technic_machine", "group:technic_all_tiers", + "technic:switching_station", + "technic:power_monitor", }, action = function(pos, node) -- Delete all listed metadata key/value pairs from technic machines local keys = { "LV_EU_timeout", "MV_EU_timeout", "HV_EU_timeout", "LV_network", "MV_network", "HV_network", - "active_pos", + "active_pos", "supply", "demand", + "battery_count", "battery_charge", "battery_charge_max", } local meta = minetest.get_meta(pos) for _,key in ipairs(keys) do diff --git a/technic/machines/power_monitor.lua b/technic/machines/power_monitor.lua index e17a790..3618cf8 100644 --- a/technic/machines/power_monitor.lua +++ b/technic/machines/power_monitor.lua @@ -13,6 +13,7 @@ local function get_cable(pos) end -- return the position of connected cable or nil +-- TODO: Make it support every possible orientation local function get_connected_cable_network(pos) local param2 = minetest.get_node(pos).param2 -- should probably also work sideways or upside down but for now it wont @@ -26,18 +27,16 @@ local function get_connected_cable_network(pos) -- Behind? checkpos = vector.add(minetest.facedir_to_dir(param2),pos) network_id = get_cable(checkpos) and technic.pos2network(checkpos) - if network_id then - return network_id - end + return network_id end -- return the position of the associated switching station or nil -local function get_swpos(pos) +local function get_network(pos) local network_id = get_connected_cable_network(pos) local network = network_id and technic.networks[network_id] local swpos = network and technic.network2sw_pos(network_id) local is_powermonitor = swpos and minetest.get_node(swpos).name == "technic:switching_station" - return (is_powermonitor and network.all_nodes[network_id]) and swpos + return (is_powermonitor and network.all_nodes[network_id]) and network end minetest.register_craft({ @@ -97,19 +96,16 @@ minetest.register_node("technic:power_monitor",{ return end - local sw_pos = get_swpos(pos) - if not sw_pos then - return - end + local network = get_network(pos) + if not network then return end - local sw_meta = minetest.get_meta(sw_pos) digilines.receptor_send(pos, technic.digilines.rules, channel, { - supply = sw_meta:get_int("supply"), - demand = sw_meta:get_int("demand"), - lag = sw_meta:get_int("lag"), - battery_count = sw_meta:get_int("battery_count"), - battery_charge = sw_meta:get_int("battery_charge"), - battery_charge_max = sw_meta:get_int("battery_charge_max"), + supply = network.supply, + demand = network.demand, + lag = network.lag, + battery_count = network.battery_count, + battery_charge = network.battery_charge, + battery_charge_max = network.battery_charge_max, }) end }, @@ -123,14 +119,10 @@ minetest.register_abm({ chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) local meta = minetest.get_meta(pos) - local sw_pos = get_swpos(pos) - if sw_pos then - local sw_meta = minetest.get_meta(sw_pos) - local supply = sw_meta:get_int("supply") - local demand = sw_meta:get_int("demand") - meta:set_string("infotext", - S("Power Monitor. Supply: @1 Demand: @2", - technic.EU_string(supply), technic.EU_string(demand))) + local network = get_network(pos) + if network then + meta:set_string("infotext", S("Power Monitor. Supply: @1 Demand: @2", + technic.EU_string(network.supply), technic.EU_string(network.demand))) else meta:set_string("infotext",S("Power Monitor Has No Network")) end diff --git a/technic/machines/register/cables.lua b/technic/machines/register/cables.lua index 768c54f..e625422 100644 --- a/technic/machines/register/cables.lua +++ b/technic/machines/register/cables.lua @@ -13,6 +13,9 @@ end local function check_connections(pos) -- Build a table of all machines + -- TODO: Move this to network.lua + -- TODO: Build table for current tier only, we do not want to test other tiers. + -- Make sure that multi tier machines work (currently supply converter). local machines = {} for tier,list in pairs(technic.machines) do for k,v in pairs(list) do @@ -36,81 +39,94 @@ local function check_connections(pos) return connections end -local function clear_networks(pos) - local node = minetest.get_node(pos) - local placed = node.name ~= "air" +local function connect_networks(pos, positions) + -- TODO: Allow connecting networks: + -- If neighbor branch does not belong to any network attach it to this network + -- If neighbor branch belongs to another network check which one has least #all_nodes and rebuild that + for _,connected_pos in pairs(positions) do + local net = technic.pos2network(connected_pos) + if net and technic.networks[net] then + -- Not a dead end, so the whole network needs to be recalculated + technic.remove_network(net) + end + end +end + +local function place_network_node(pos, node) 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 - -- This is similar to check_node_subp - local pos_hash = minetest.hash_node_position(pos) - technic.cables[pos_hash] = network_id - pos.visited = 1 - if technic.is_tier_cable(name, tier) then - network.all_nodes[pos_hash] = pos - elseif technic.machines[tier][node.name] then - if technic.machines[tier][node.name] == technic.producer then - table.insert(network.PR_nodes,pos) - elseif technic.machines[tier][node.name] == technic.receiver then - table.insert(network.RE_nodes,pos) - elseif technic.machines[tier][node.name] == technic.producer_receiver then - table.insert(network.PR_nodes,pos) - table.insert(network.RE_nodes,pos) - elseif technic.machines[tier][node.name] == "SPECIAL" and - (pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and - from_below then - network.SP_nodes[pos_hash] = pos - elseif technic.machines[tier][node.name] == technic.battery then - table.insert(network.BA_nodes,pos) - end - 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] + -- Dead end placed, add it to the network + -- Get the network + local network_id = technic.pos2network(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 - -- 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 + if not dead_end then + return connect_networks(pos, positions) + end + + -- Actually add it to the (cached) network + -- This is similar to check_node_subp + local pos_hash = minetest.hash_node_position(pos) + technic.cables[pos_hash] = network_id + pos.visited = 1 + if technic.is_tier_cable(name, tier) then + network.all_nodes[pos_hash] = pos + elseif technic.machines[tier][node.name] then + if technic.machines[tier][node.name] == technic.producer then + table.insert(network.PR_nodes,pos) + elseif technic.machines[tier][node.name] == technic.receiver then + table.insert(network.RE_nodes,pos) + elseif technic.machines[tier][node.name] == technic.producer_receiver then + table.insert(network.PR_nodes,pos) + table.insert(network.RE_nodes,pos) + elseif technic.machines[tier][node.name] == technic.battery then + table.insert(network.BA_nodes,pos) + end + end +end + +local function remove_network_node(pos) + -- Get the network + local network_id = technic.pos2network(pos) + if not network_id then + -- We're evidently not on a network, nothing to add ourselves to + return + end + + local positions = check_connections(pos) + if #positions < 1 then return end + local dead_end = #positions == 1 + + if not dead_end then + -- TODO: Check branches around and switching stations for branches: + -- remove branches that do not have switching station. + -- remove branches not connected to another branch. + -- do not rebuild networks here, leave that for ABM to reduce unnecessary cache building. + -- For now remove network like how it was done before: + technic.remove_network(network_id) + return + end + + -- Dead end removed, remove it from the network + local network = technic.networks[network_id] + technic.cables[minetest.hash_node_position(pos)] = nil + -- TODO: Looping over all keys in network is not right way to do this, should fix to use known machine types. + -- Better to add network function that knows what to remove, something like technic.remove_node(network_id, pos) + for tblname,table in pairs(network) do + if type(table) == "table" 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 - 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 @@ -142,7 +158,8 @@ function technic.register_cable(tier, size, description, prefix, override_cable, prefix = prefix or "" override_cable_plate = override_cable_plate or override_cable local ltier = string.lower(tier) - cable_tier["technic:"..ltier..prefix.."_cable"] = tier + local node_name = "technic:"..ltier..prefix.."_cable" + cable_tier[node_name] = tier local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, ["technic_"..ltier.."_cable"] = 1} @@ -158,22 +175,22 @@ function technic.register_cable(tier, size, description, prefix, override_cable, connect_right = {-size, -size, -size, 0.5, size, size}, -- x+ } - minetest.register_node("technic:"..ltier..prefix.."_cable", override_table({ + minetest.register_node(node_name, override_table({ description = S("%s Cable"):format(tier), tiles = {"technic_"..ltier..prefix.."_cable.png"}, inventory_image = "technic_"..ltier..prefix.."_cable_wield.png", wield_image = "technic_"..ltier..prefix.."_cable_wield.png", groups = groups, sounds = default.node_sound_wood_defaults(), - drop = "technic:"..ltier..prefix.."_cable", + drop = node_name, paramtype = "light", sunlight_propagates = true, drawtype = "nodebox", node_box = node_box, connects_to = {"group:technic_"..ltier.."_cable", "group:technic_"..ltier, "group:technic_all_tiers"}, - on_construct = clear_networks, - on_destruct = clear_networks, + on_construct = function(pos) place_network_node(pos, node_name) end, + on_destruct = remove_network_node, }, override_cable)) local xyz = { @@ -205,15 +222,15 @@ function technic.register_cable(tier, size, description, prefix, override_cable, tiles = {"technic_"..ltier..prefix.."_cable.png"}, groups = table.copy(groups), sounds = default.node_sound_wood_defaults(), - drop = "technic:"..ltier..prefix.."_cable_plate_1", + drop = node_name .. "_plate_1", paramtype = "light", sunlight_propagates = true, drawtype = "nodebox", node_box = table.copy(node_box), connects_to = {"group:technic_"..ltier.."_cable", "group:technic_"..ltier, "group:technic_all_tiers"}, - on_construct = clear_networks, - on_destruct = clear_networks, + on_construct = function(pos) place_network_node(pos, node_name.."_plate_"..i) end, + on_destruct = remove_network_node, } def.node_box.fixed = { {-size, -size, -size, size, size, size}, @@ -254,7 +271,7 @@ function technic.register_cable(tier, size, description, prefix, override_cable, if num == nil then num = 1 end return item_place_override_node( itemstack, placer, pointed_thing, - {name = "technic:"..ltier..prefix.."_cable_plate_"..num} + {name = node_name.."_plate_"..num} ) end else @@ -271,39 +288,41 @@ function technic.register_cable(tier, size, description, prefix, override_cable, num = num + dir num = (num >= 1 and num) or num + 6 num = (num <= 6 and num) or num - 6 - minetest.swap_node(pos, {name = "technic:"..ltier..prefix.."_cable_plate_"..num}) + minetest.swap_node(pos, {name = node_name.."_plate_"..num}) end - minetest.register_node("technic:"..ltier..prefix.."_cable_plate_"..i, override_table(def, override_cable_plate)) - cable_tier["technic:"..ltier..prefix.."_cable_plate_"..i] = tier + minetest.register_node(node_name.."_plate_"..i, override_table(def, override_cable_plate)) + cable_tier[node_name.."_plate_"..i] = tier end - local c = "technic:"..ltier..prefix.."_cable" minetest.register_craft({ - output = "technic:"..ltier..prefix.."_cable_plate_1 5", + output = node_name.."_plate_1 5", recipe = { - {"", "", c}, - {c , c , c}, - {"", "", c}, + {"" , "" , node_name}, + {node_name, node_name, node_name}, + {"" , "" , node_name}, } }) minetest.register_craft({ - output = c, + output = node_name, recipe = { - {"technic:"..ltier..prefix.."_cable_plate_1"}, + {node_name.."_plate_1"}, } }) end - -local function clear_nets_if_machine(pos, node) +minetest.register_on_placenode(function(pos, node) for tier, machine_list in pairs(technic.machines) do if machine_list[node.name] ~= nil then - return clear_networks(pos) + return place_network_node(pos, node) end end -end - -minetest.register_on_placenode(clear_nets_if_machine) -minetest.register_on_dignode(clear_nets_if_machine) +end) +minetest.register_on_dignode(function(pos, node) + for tier, machine_list in pairs(technic.machines) do + if machine_list[node.name] ~= nil then + return remove_network_node(pos) + end + end +end) diff --git a/technic/machines/switching_station.lua b/technic/machines/switching_station.lua index 2953219..0bd8ef1 100644 --- a/technic/machines/switching_station.lua +++ b/technic/machines/switching_station.lua @@ -92,11 +92,19 @@ minetest.register_node("technic:switching_station",{ if channel ~= meta:get_string("channel") then return end - digilines.receptor_send(pos, technic.digilines.rules, channel, { - supply = meta:get_int("supply"), - demand = meta:get_int("demand"), - lag = meta:get_int("lag") - }) + local network_id = technic.sw_pos2network(pos) + local network = network_id and technic.networks[network_id] + if network then + digilines.receptor_send(pos, technic.digilines.rules, channel, { + supply = network.supply, + demand = network.demand, + lag = network.lag + }) + else + digilines.receptor_send(pos, technic.digilines.rules, channel, { + error = "No network", + }) + end end }, }, @@ -106,14 +114,6 @@ minetest.register_node("technic:switching_station",{ -- The action code for the switching station -- ----------------------------------------------- -function technic.switching_station_run(pos) - local network_id = technic.sw_pos2network(pos) - if network_id then - return technic.network_run(network_id) - end - --print(string.format("technic.switching_station_run(%s) failed, no network available", minetest.pos_to_string(pos))) -end - -- Timeout ABM -- Timeout for a node in case it was disconnected from the network -- A node must be touched by the station continuously in order to function @@ -168,9 +168,6 @@ minetest.register_abm({ local remaining = technic.reset_overloaded(network_id) if remaining > 0 then infotext = S("%s Network Overloaded, Restart in %dms"):format(S("Switching Station"), remaining / 1000) - -- Set switching station supply value to zero to clean up power monitor supply info - -- TODO: This should be saved with network and removed from metadata - meta:set_int("supply",0) else infotext = S("%s Restarting Network"):format(S("Switching Station")) end @@ -187,8 +184,3 @@ minetest.register_abm({ end end, }) - -for tier, machines in pairs(technic.machines) do - -- SPECIAL will not be traversed - technic.register_machine(tier, "technic:switching_station", "SPECIAL") -end diff --git a/technic/machines/switching_station_globalstep.lua b/technic/machines/switching_station_globalstep.lua index e83f0df..bed6f07 100644 --- a/technic/machines/switching_station_globalstep.lua +++ b/technic/machines/switching_station_globalstep.lua @@ -86,12 +86,13 @@ minetest.register_globalstep(function(dtime) for network_id, switch in pairs(switches) do local pos = technic.network2sw_pos(network_id) + local network = technic.networks[network_id] local diff = now - switch.time minetest.get_voxel_manip(pos, pos) local node = minetest.get_node(pos) - if node.name ~= "technic:switching_station" then + if network == nil or node.name ~= "technic:switching_station" then -- station vanished switches[network_id] = nil @@ -102,13 +103,11 @@ minetest.register_globalstep(function(dtime) if switch.skip < 1 then local start = minetest.get_us_time() - technic.switching_station_run(pos) + technic.network_run(network_id) local switch_diff = minetest.get_us_time() - start - local meta = minetest.get_meta(pos) - -- set lag in microseconds into the "lag" meta field - meta:set_int("lag", switch_diff) + network.lag = switch_diff -- overload detection if switch_diff > 250000 then diff --git a/technic/spec/fixtures/minetest.lua b/technic/spec/fixtures/minetest.lua index f035b28..b759cda 100644 --- a/technic/spec/fixtures/minetest.lua +++ b/technic/spec/fixtures/minetest.lua @@ -1,6 +1,13 @@ local function noop(...) end local function dummy_coords(...) return { x = 123, y = 123, z = 123 } end +_G.world = { nodes = {} } +local world = _G.world +_G.world.set_node = function(pos, node) + local hash = minetest.hash_node_position(pos) + world.nodes[hash] = node +end + _G.core = {} _G.minetest = _G.core @@ -64,12 +71,26 @@ _G.minetest.register_lbm = noop _G.minetest.register_abm = noop _G.minetest.register_chatcommand = noop _G.minetest.chat_send_player = noop +_G.minetest.register_alias = noop _G.minetest.register_craftitem = noop _G.minetest.register_craft = noop +_G.minetest.register_node = noop _G.minetest.register_on_placenode = noop _G.minetest.register_on_dignode = noop _G.minetest.item_drop = noop +_G.minetest.get_node = function(pos) + local hash = minetest.hash_node_position(pos) + return world.nodes[hash] or {name="IGNORE",param2=0} +end + _G.minetest.get_modpath = function(...) return "./unit_test_modpath" end _G.minetest.get_pointed_thing_position = dummy_coords + +-- +-- Minetest default noop table +-- +local default = { __index = function(...) return function(...)end end } +_G.default = {} +setmetatable(_G.default, default) diff --git a/technic/spec/fixtures/network.lua b/technic/spec/fixtures/network.lua index 7f1af94..ef06a92 100644 --- a/technic/spec/fixtures/network.lua +++ b/technic/spec/fixtures/network.lua @@ -1,5 +1,37 @@ +local world = { + {{x=100,y=100,z=100}, "technic:lv_cable"}, + {{x=101,y=100,z=100}, "technic:lv_cable"}, + {{x=102,y=100,z=100}, "technic:lv_cable"}, + {{x=103,y=100,z=100}, "technic:lv_cable"}, + {{x=100,y=101,z=100}, "technic:switching_station"}, + + {{x=100,y=200,z=100}, "technic:mv_cable"}, + {{x=101,y=200,z=100}, "technic:mv_cable"}, + {{x=102,y=200,z=100}, "technic:mv_cable"}, + {{x=103,y=200,z=100}, "technic:mv_cable"}, + {{x=100,y=201,z=100}, "technic:switching_station"}, + + {{x=100,y=300,z=100}, "technic:hv_cable"}, + {{x=101,y=300,z=100}, "technic:hv_cable"}, + {{x=102,y=300,z=100}, "technic:hv_cable"}, + {{x=103,y=300,z=100}, "technic:hv_cable"}, + {{x=100,y=301,z=100}, "technic:switching_station"}, +} + +-- Build world for tests +for _,node in ipairs(world) do + _G.world.set_node(node[1], {name=node[2], param2=0}) +end + _G.technic = {} _G.technic.S = string.format +_G.technic.getter = function(...) return "" end sourcefile("register") + +sourcefile("machines/register/cables") + +sourcefile("machines/LV/cables") +sourcefile("machines/MV/cables") +sourcefile("machines/HV/cables") diff --git a/technic/spec/network_spec.lua b/technic/spec/network_spec.lua index ffe1c23..575b150 100644 --- a/technic/spec/network_spec.lua +++ b/technic/spec/network_spec.lua @@ -37,6 +37,17 @@ describe("Power network helper", function() assert.same(net_id, technic.sw_pos2network(sw_pos) ) end) + it("returns nil tier for empty position", function() + assert.is_nil(technic.sw_pos2tier({x=9999,y=9999,z=9999})) + end) + + it("returns correct tier for switching station position", function() + -- World is defined in fixtures/network.lua + assert.same("LV", technic.sw_pos2tier({x=100,y=101,z=100})) + assert.same("MV", technic.sw_pos2tier({x=100,y=201,z=100})) + assert.same("HV", technic.sw_pos2tier({x=100,y=301,z=100})) + end) + end) --[[ TODO: