bug fixes and improvements

master
Joachim Stolberg 2021-05-29 20:57:48 +02:00
parent 3753b4aa92
commit 5a52d165c0
6 changed files with 223 additions and 123 deletions

View File

@ -15,7 +15,7 @@ Power networks consists of following node types:
- Consumers, nodes consuming power
- Storage nodes, nodes storing power
- Cables, to build power connections
- Junctions, to build power networks
- Junctions, to connect point to point connection to networks
- Switches, to turn on/off network segments
All storage nodes in a network form a storage system. Storage systems are
@ -40,15 +40,15 @@ tbd.
### Test Nodes
The file `test.lua` includes test nodes of each kind. It can be used to
play with the features and to study the use of `networks`.
The file `./test/test_power.lua` includes test nodes of each kind of power nodes.
It can be used to play with the features and to study the use of `networks`.
- [G] a generator, which provides 20 units of power every 2 s
- [C] a consumer, which need 5 units of power every 2 s
Both nodes can be turned on/off by right-clicking.
- [S] a storage with 500 units capacity
All three nodes can be turned on/off by right-clicking.
- cable node for power transportation
- junction node for power distribution
- a power switch to turn on/off consumers
@ -80,3 +80,6 @@ Required: tubelib2
**2021-05-25 V0.03**
- Add function `networks.get_power_data`
- bug fixes and improvements
**2021-05-29 V0.04**
- bug fixes and improvements

View File

@ -36,7 +36,6 @@ function networks.hidden_node(pos, netw_type)
if ndef and ndef.networks then
return ndef.networks[netw_type] or {}
end
return {}
end
function networks.hidden_name(pos)
@ -93,7 +92,10 @@ function networks.use_metadata(tlib2)
-- Needed for hidden nodes, cause they don't have a 'tubelib2_on_update2' callback
-- and is used for all kind of nodes without own 'tubelib2_on_update2'
tlib2:register_on_tube_update2(function(pos, outdir, tlib2, node)
networks.update_network(pos, outdir, tlib2)
if networks.is_junction(pos, node.name, tlib2) then
outdir = 0
end
networks.on_update_power_network(pos, outdir, tlib2)
end)
end

View File

@ -13,19 +13,20 @@
networks = {}
-- Version for compatibility checks, see readme.md/history
networks.version = 0.03
networks.version = 0.04
if minetest.global_exists("tubelib2") and tubelib2.version < 2.1 then
if not minetest.global_exists("tubelib2") or tubelib2.version < 2.1 then
minetest.log("error", "[networks] Networks requires tubelib2 version 2.1 or newer!")
return
end
local MP = minetest.get_modpath("networks")
dofile(MP .. "/hidden.lua")
dofile(MP .. "/networks.lua")
dofile(MP .. "/junction.lua")
dofile(MP .. "/power.lua")
--dofile(MP .. "/liquids.lua")
--dofile(MP .. "/liquid.lua")
-- Only for testing/demo purposes
dofile(MP .. "/test.lua")
dofile(MP .. "/test/test_power.lua")

View File

@ -66,19 +66,18 @@ local function debug()
end
tbl[#tbl+1] = "num_nodes = " .. network.num_nodes
print("Network " .. netw_num(netID) .. ": " .. table.concat(tbl, ", "))
end
for hash, item in pairs(NetIDs) do
tbl = {}
local tbl = {}
for dir = 0,6 do
netID = item[dir]
local netID = item[dir]
if netID then
tbl[#tbl+1] = "dir " .. dir .. " = netw " .. netw_num(netID)
end
end
print("NetIDs " .. N(minetest.get_position_from_hash(hash)).name .. ": " .. table.concat(tbl, ", "))
end
end
minetest.after(4, debug)
end
--minetest.after(4, debug)
@ -90,7 +89,7 @@ end
local function net_def(pos, netw_type)
local ndef = minetest.registered_nodes[N(pos).name]
if ndef and ndef.networks then
return ndef.networks[netw_type] or {}
return ndef.networks[netw_type]
else
return hidden_node(pos, netw_type)
end
@ -99,7 +98,7 @@ end
local function net_def2(pos, node_name, netw_type)
local ndef = minetest.registered_nodes[node_name]
if ndef and ndef.networks then
return ndef.networks[netw_type] or {}
return ndef.networks[netw_type]
else
return hidden_node(pos, netw_type)
end
@ -179,12 +178,11 @@ local function store_node_connection_sides(pos, tlib2)
local node = N(pos)
local val = 0
local ndef = net_def2(pos, node.name, tlib2.tube_type)
local sides = ndef.sides or ndef.get_sides and ndef.get_sides(pos, node)
if sides then
if ndef then
for dir = 1,6 do
val = val * 2
local side = DirToSide[outdir_to_dir(dir, node.param2)]
if sides[side] then
if ndef.sides[side] then
if connected(tlib2, pos, dir) then
val = val + 1
end
@ -218,15 +216,19 @@ end
-- check if the given tube dir into the node is valid
local function valid_indir(pos, indir, node, net_name)
local ndef = net_def2(pos, node.name, net_name)
local sides = ndef.sides or ndef.get_sides and ndef.get_sides(pos, node)
if ndef then
local side = DirToSide[indir_to_dir(indir, node.param2)]
if not sides or sides and not sides[side] then return false end
if ndef.sides[side] then
return true
end
end
end
local function is_junction(pos, name, tube_type)
local ndef = net_def2(pos, name, tube_type)
local function is_junction(pos, name, tlib2)
local ndef = net_def2(pos, name, tlib2.tube_type)
if ndef then
return ndef.ntype == "junc"
end
end
-- Do the walk through the tubelib2 network.
@ -235,7 +237,7 @@ end
-- if outdir is given, only this dir is used
local function connection_walk(pos, outdir, indir, node, tlib2, clbk)
if clbk then clbk(pos, indir, node) end
if outdir or is_junction(pos, node.name, tlib2.tube_type) then
if outdir or is_junction(pos, node.name, tlib2) then
for _,outdir in ipairs(get_outdirs(pos, tlib2, outdir)) do
local pos2, indir2 = tlib2:get_connected_node_pos(pos, outdir)
local node = N(pos2)
@ -255,9 +257,12 @@ local function collect_network_nodes(pos, tlib2, outdir)
local netw_type = tlib2.tube_type
-- outdir corresponds to the indir coming from
connection_walk(pos, outdir, Flip[outdir], node, tlib2, function(pos, indir, node)
local ntype = net_def2(pos, node.name, netw_type).ntype
local ndef = net_def2(pos, node.name, netw_type)
if ndef then
local ntype = ndef.ntype
if not netw[ntype] then netw[ntype] = {} end
netw[ntype][#netw[ntype] + 1] = {pos = pos, indir = indir}
end
end)
netw.ttl = minetest.get_gametime() + TTL
netw.num_nodes = NumNodes
@ -327,8 +332,10 @@ local function get_netID_and_network(pos, tlib2, outdir)
end
-- determine network ID (largest hash number of all nodes with given type)
local function determine_netID(tlib2, netw, node_type)
local function determine_netID(netw)
local netID = 0
for node_type, table in pairs(netw) do
if type(table) == "table" then
for _, item in ipairs(netw[node_type] or {}) do
local outdir = Flip[item.indir]
local new = minetest.hash_node_position(item.pos) * 8 + outdir
@ -336,6 +343,8 @@ local function determine_netID(tlib2, netw, node_type)
netID = new
end
end
end
end
return netID
end
@ -376,17 +385,41 @@ end
-- API Functions
-------------------------------------------------------------------------------
-- Table fo a 180 degree turn
-- Table fo a 180 degree turn: indir => outdir and vice versa
networks.Flip = Flip
-- networks.net_def(pos, netw_type)
networks.net_def = net_def
-- sides: outdir:
-- U
-- | B
-- | / 6 (N)
-- +--|-----+ | 1
-- / o /| | /
-- +--------+ | |/
-- L <----| |o----> R (W) 4 <-------+-------> 2 (O)
-- | o | | /|
-- | / | + / |
-- | / |/ 3 |
-- +-/------+ (S) 5
-- / |
-- F |
-- D
--
networks.AllSides = Sides -- table for all 6 node sides
-- networks.side_to_outdir(pos, side)
networks.side_to_outdir = side_to_outdir
-- networks.is_junction(pos, name, tlib2)
networks.is_junction = is_junction
-- Retunrn sa simple number instead of the netID
-- For debuging purposes only
-- networks.netw_num(netID)
networks.netw_num = netw_num
-- networks.node_connections(pos, tlib2)
--networks.node_connections = node_connections
@ -401,15 +434,14 @@ networks.MAX_NUM_NODES = MAX_NUM_NODES
-- To be called from each node via 'tubelib2_on_update2'
-- 'output' is optional and only needed for nodes with dedicated
-- pipe sides (e.g. pumps).
function networks.update_network(pos, outdir, tlib2)
-- pipe sides. Junctions have to provide 0 (= same network on all sides).
function networks.on_update_network(pos, outdir, tlib2)
store_node_connection_sides(pos, tlib2) -- update node internal data
delete_netID(pos, tlib2, outdir or 0) -- delete node netIDs and network
end
-- Provide or determine netID
-- `node_type` is nedded to determine the netID
function networks.get_netID(pos, tlib2, outdir, node_type)
function networks.get_netID(pos, tlib2, outdir)
local netID = get_netID_and_network(pos, tlib2, outdir)
if netID then
return netID
@ -417,7 +449,7 @@ function networks.get_netID(pos, tlib2, outdir, node_type)
local netw = collect_network_nodes(pos, tlib2, outdir)
if netw.num_nodes > 1 then
netID = determine_netID(tlib2, netw, node_type)
netID = determine_netID(netw)
if netID > 0 then
store_netID(tlib2, netw, netID)
return netID
@ -427,6 +459,6 @@ end
-- Provide network with all node tables
function networks.get_network_table(pos, tlib2, outdir)
local netID, netw = get_netID_and_network(pos, tlib2, outdir)
local _, netw = get_netID_and_network(pos, tlib2, outdir)
return netw or {}
end

131
power.lua
View File

@ -16,31 +16,57 @@ local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
local N = tubelib2.get_node_lvm
local DEFAULT_CAPA = 100
local Power = {} -- {netID = {curr_level, min_level, max_level, max_capa, sum_consumed, sum_provided, sum_available}}
-- Storage parameters:
-- capa = maximum value in power units
-- load = current value in power units
-- level = ratio value (load/capa) (0..1)
-- Determine level, capa and other network storage data
local function get_storage_data(pos, tlib2, outdir)
local Power = {} -- {netID = {curr_load, min_load, max_load, max_capa, consumed, provided, available}}
-- Determine load, capa and other power network data
local function get_power_data(pos, tlib2, outdir)
local netw = networks.get_network_table(pos, tlib2, outdir)
local max_capa = DEFAULT_CAPA
local curr_level = 0
local max_capa = 0
local curr_load = 0
-- Generators
for _,item in ipairs(netw.gen or {}) do
local ndef = minetest.registered_nodes[N(item.pos).name]
local data = ndef.get_generator_data(item.pos)
max_capa = max_capa + data.perf -- generator performance = capa
curr_load = curr_load + (data.level * data.perf)
end
-- Storage systems
for _,item in ipairs(netw.sto or {}) do
local ndef = minetest.registered_nodes[N(item.pos).name]
local level, capa = ndef.get_storage_level(item.pos)
curr_level = curr_level + level
max_capa = max_capa + capa
local data = ndef.get_storage_data(item.pos)
max_capa = max_capa + data.capa
curr_load = curr_load + (data.level * data.capa)
end
return {
curr_level = curr_level, -- network storage level
min_level = curr_level, -- minimal storage level
max_level = curr_level, -- maximal storage level
curr_load = curr_load, -- network storage value
min_load = curr_load, -- minimal storage value
max_load = curr_load, -- maximal storage value
max_capa = max_capa, -- network storage capacity
consumed = 0, -- consumed power over all consumers
provided = 0, -- provided power over all generators
available = 0, -- max. available power over all generators
num_nodes = netw.num_nodes,
}
end
-------------------------------------------------------------------------------
-- Consumer/Generator/Storage
-------------------------------------------------------------------------------
-- To be called for each power network change via
-- tubelib2_on_update2 or register_on_tube_update2
function networks.on_update_power_network(pos, outdir, tlib2)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
Power[netID] = nil
end
networks.on_update_network(pos, outdir, tlib2)
end
-------------------------------------------------------------------------------
-- Consumer
-------------------------------------------------------------------------------
@ -48,10 +74,10 @@ end
-- For consumers, outdir is optional
function networks.power_available(pos, tlib2, outdir)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
return pwr.curr_level > 0
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
return pwr.curr_load > 0
end
end
end
@ -59,19 +85,19 @@ end
-- For consumers, outdir is optional
function networks.consume_power(pos, tlib2, outdir, amount)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
if pwr.curr_level >= amount then
pwr.curr_level = pwr.curr_level - amount
pwr.min_level = math.min(pwr.min_level, pwr.curr_level)
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
if pwr.curr_load >= amount then
pwr.curr_load = pwr.curr_load - amount
pwr.min_load = math.min(pwr.min_load, pwr.curr_load)
pwr.consumed = pwr.consumed + amount
Power[netID] = pwr
return amount
else
local consumed = pwr.curr_level
pwr.curr_level = 0
pwr.min_level = 0
local consumed = pwr.curr_load
pwr.curr_load = 0
pwr.min_load = 0
pwr.consumed = pwr.consumed + consumed
Power[netID] = pwr
return consumed
@ -88,27 +114,27 @@ end
-- cp1 and cp2 are control points for the charge regulator.
-- From cp1 the charging power is reduced more and more and reaches zero at cp2.
function networks.provide_power(pos, tlib2, outdir, amount, cp1, cp2)
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
local x = pwr.curr_level / pwr.max_capa
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
local x = pwr.curr_load / pwr.max_capa
pwr.available = pwr.available + amount
amount = math.min(amount, pwr.max_capa - pwr.curr_level)
amount = math.min(amount, pwr.max_capa - pwr.curr_load)
cp1 = cp1 or 0.5
cp2 = cp2 or 1.0
if x < cp1 then -- charge with full power
pwr.curr_level = pwr.curr_level + amount
pwr.max_level = math.max(pwr.max_level, pwr.curr_level)
pwr.curr_load = pwr.curr_load + amount
pwr.max_load = math.max(pwr.max_load, pwr.curr_load)
pwr.provided = pwr.provided + amount
Power[netID] = pwr
return amount
elseif x < cp2 then -- charge with reduced power
local factor = 1 - ((x - cp1) / (cp2 - cp1))
local provided = amount * factor
pwr.curr_level = pwr.curr_level + provided
pwr.max_level = math.max(pwr.max_level, pwr.curr_level)
pwr.curr_load = pwr.curr_load + provided
pwr.max_load = math.max(pwr.max_load, pwr.curr_load)
pwr.provided = pwr.provided + provided
Power[netID] = pwr
return provided
@ -122,23 +148,25 @@ end
-------------------------------------------------------------------------------
-- Storage
-------------------------------------------------------------------------------
-- Function returns the level/charge as ratio (0..1)
-- Function returns a table with storage level as ratio (0..1) and the
-- charging state (1 = charging, -1 = uncharging, or 0)
-- Param outdir is optional
-- Function provides nil if no network is available
function networks.get_storage_level(pos, tlib2, outdir)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
return pwr.curr_level / pwr.max_capa
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
local charging = (pwr.provided > pwr.consumed and 1) or (pwr.provided < pwr.consumed and -1) or 0
return {level = pwr.curr_load / pwr.max_capa, charging = charging}
end
end
end
-- To be called for each network storage change (dig/place storage nodes)
function networks.reinit_storage(pos, tlib2, outdir)
-- To be called for each network storage change (turn on/off of storage/generator nodes)
function networks.start_storage_calc(pos, tlib2, outdir)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
Power[netID] = nil
end
@ -170,13 +198,13 @@ function networks.turn_switch_off(pos, tlib2, name_off, name_on)
if node.name == name_on then
node.name = name_off
minetest.swap_node(pos, node)
tlib2:after_dig_tube(pos, node)
meta:set_int("tl2_param2", 0)
tlib2:after_dig_tube(pos, node)
return true
elseif meta:contains("tl2_param2") then
meta:set_int("tl2_param2_copy", meta:get_int("tl2_param2"))
meta:set_int("tl2_param2", 0)
tlib2:i(pos, node)
tlib2:after_dig_tube(pos, node)
return true
end
end
@ -184,19 +212,20 @@ end
-------------------------------------------------------------------------------
-- Statistics
-------------------------------------------------------------------------------
function networks.get_storage_data(pos, tlib2, outdir)
function networks.get_power_data(pos, tlib2, outdir)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
local res = {
curr_level = pwr.curr_level,
min_level = pwr.min_level,
max_level = pwr.max_level,
curr_load = pwr.curr_load,
min_load = pwr.min_load,
max_load = pwr.max_load,
max_capa = pwr.max_capa,
consumed = pwr.consumed,
provided = pwr.provided,
available = pwr.available,
netw_num = networks.netw_num(netID),
}
pwr.consumed = 0
pwr.provided = 0
@ -206,13 +235,13 @@ function networks.get_storage_data(pos, tlib2, outdir)
end
end
function networks.reset_storage_min_max(pos, tlib2, outdir)
function networks.reset_min_max_load_values(pos, tlib2, outdir)
for _,outdir in ipairs(networks.get_outdirs(pos, tlib2, outdir)) do
local netID = networks.get_netID(pos, tlib2, outdir, "gen")
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_data(pos, tlib2, outdir)
pwr.min_level = pwr.curr_level
pwr.max_level = pwr.curr_level
local pwr = Power[netID] or get_power_data(pos, tlib2, outdir)
pwr.min_load = pwr.curr_load
pwr.max_load = pwr.curr_load
return
end
end

View File

@ -30,7 +30,7 @@ end
-------------------------------------------------------------------------------
local Cable = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 20,
max_tube_length = 100,
tube_type = "test",
primary_node_names = {"networks:cableS", "networks:cableA", "networks:switch_on"},
secondary_node_names = {
@ -86,7 +86,7 @@ if HIDDEN then
else
-- use own global callback
Cable:register_on_tube_update2(function(pos, outdir, tlib2, node)
networks.update_network(pos, outdir, tlib2)
networks.on_update_power_network(pos, outdir, tlib2)
end)
end
@ -177,11 +177,11 @@ networks.register_junction("networks:junction", size, Boxes, Cable, {
minetest.swap_node(pos, {name = name, param2 = 0})
Cable:after_place_node(pos)
end,
-- junctions need own 'tubelib2_on_update2', cause they provide 0 for outdir!
-- junction needs own 'tubelib2_on_update2', cause it provides 0 for outdir!
tubelib2_on_update2 = function(pos, outdir, tlib2, node)
local name = "networks:junction"..networks.junction_type(pos, Cable)
minetest.swap_node(pos, {name = name, param2 = 0})
networks.update_network(pos, 0, tlib2)
networks.on_update_power_network(pos, 0, tlib2)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_node(pos)
@ -245,6 +245,15 @@ minetest.register_node("networks:generator", {
M(pos):set_string("infotext", "providing "..round(mem.provided))
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
networks.start_storage_calc(pos, Cable)
end,
get_generator_data = function(pos)
local mem = tubelib2.get_mem(pos)
if mem.running then
return {level = (mem.load or 0) / GEN_MAX, perf = GEN_MAX}
else
return {level = 0, perf = 0}
end
end,
networks = {
test = {
@ -377,28 +386,45 @@ minetest.register_node("networks:storage", {
tiles = {"networks_sto.png"},
on_timer = function(pos, elapsed)
local mem = tubelib2.get_mem(pos)
local val = networks.get_storage_level(pos, Cable)
if val then
mem.level = val * STORAGE_CAPA
local data = networks.get_storage_level(pos, Cable)
if data then
mem.load = data.level * STORAGE_CAPA
local percent = data.level * 100
M(pos):set_string("infotext", "level = "..round(percent)..", charging = "..data.charging)
end
local percent = (mem.level or 0) / STORAGE_CAPA * 100
M(pos):set_string("infotext", "level = "..round(percent))
return true
end,
after_place_node = function(pos)
Cable:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
tubelib2.init_mem(pos)
networks.reinit_storage(pos, Cable)
M(pos):set_string("infotext", "off")
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
tubelib2.del_mem(pos)
networks.reinit_storage(pos, Cable)
end,
get_storage_level = function(pos)
on_rightclick = function(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
return mem.level or 0, STORAGE_CAPA
if mem.running then
mem.running = false
M(pos):set_string("infotext", "off")
minetest.get_node_timer(pos):stop()
else
mem.provided = mem.provided or 0
mem.running = true
local percent = (mem.load or 0) / STORAGE_CAPA * 100
M(pos):set_string("infotext", "level = "..round(percent))
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
networks.start_storage_calc(pos, Cable)
end,
get_storage_data = function(pos)
local mem = tubelib2.get_mem(pos)
if mem.running then
return {level = (mem.load or 0) / STORAGE_CAPA, capa = STORAGE_CAPA}
else
return {level = 0, capa = 0}
end
end,
networks = {
test = {
@ -436,7 +462,7 @@ local function replace_node(itemstack, placer, pointed_thing)
gain = 1,
max_hear_distance = 5})
elseif placer and placer.get_player_name then
minetest.chat_send_player(placer:get_player_name(), "Invalid fill material!")
minetest.chat_send_player(placer:get_player_name(), "Invalid fill material in inventory slot 1!")
end
end
end
@ -528,6 +554,12 @@ minetest.register_node("networks:switch_off", {
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_node(pos)
end,
networks = {
test = {
sides = {}, -- no connection sides
ntype = "con",
},
},
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = node_box,
@ -550,12 +582,13 @@ minetest.register_chatcommand("power_data", {
local pos = player:get_pos()
pos.y = pos.y - 0.5
pos = vector.round(pos)
local data = networks.get_storage_data(pos, Cable)
local data = networks.get_power_data(pos, Cable)
if data then
local s = string.format("generated = %u/%u, consumed = %u, storage level = %u/%u (min = %u, max = %u)",
round(data.provided), data.available, round(data.consumed),
round(data.curr_level), round(data.max_capa),
round(data.min_level), round(data.max_level))
local s = string.format("Netw %u: generated = %u/%u, consumed = %u, storage load = %u/%u (min = %u, max = %u)",
data.netw_num, round(data.provided),
data.available, round(data.consumed),
round(data.curr_load), round(data.max_capa),
round(data.min_load), round(data.max_load))
return true, s
end
return false, "No valid node position!"