first shot

master
Joachim Stolberg 2021-05-23 21:55:39 +02:00
commit c5008160d4
15 changed files with 1165 additions and 0 deletions

21
README.md Normal file
View File

@ -0,0 +1,21 @@
# Networks [networks]
A library to build and manage networks based on tubelib2 tubes, pipes, or cables.
### License
Copyright (C) 2021 Joachim Stolberg
Code: Licensed under the GNU AGPL version 3 or later. See LICENSE.txt
Textures: CC BY-SA 3.0
### Dependencies
Required: tubelib2
### History
**2021-05-23 V0.25**
- First shot

30
init.lua Normal file
View File

@ -0,0 +1,30 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
networks = {}
-- Version for compatibility checks, see readme.md/history
networks.version = 1.00
if minetest.global_exists("tubelib2") and tubelib2.version < 2.0 then
minetest.log("error", "[networks] Networks requires tubelib2 version 2.0 or newer!")
return
end
local MP = minetest.get_modpath("networks")
dofile(MP .. "/networks.lua")
dofile(MP .. "/junction.lua")
dofile(MP .. "/storage.lua")
dofile(MP .. "/power.lua")
--dofile(MP .. "/liquids.lua")
-- Only for testing/demo purposes
dofile(MP .. "/test.lua")

117
junction.lua Normal file
View File

@ -0,0 +1,117 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
local function bit(p)
return 2 ^ (p - 1) -- 1-based indexing
end
-- Typical call: if hasbit(x, bit(3)) then ...
local function hasbit(x, p)
return x % (p + p) >= p
end
local function setbit(x, p)
return hasbit(x, p) and x or x + p
end
local function get_node_box(val, size, boxes)
local fixed = {{-size, -size, -size, size, size, size}}
for i = 1,6 do
if hasbit(val, bit(i)) then
for _,box in ipairs(boxes[i]) do
table.insert(fixed, box)
end
end
end
return {
type = "fixed",
fixed = fixed,
}
end
-- 'size' is the size of the junction cube without any connection, e.g. 1/8
-- 'boxes' is a table with 6 table elements for the 6 possible connection arms
-- 'tlib2' is the tubelib2 instance
-- 'node' is the node definition with tiles, callback functions, and so on
-- 'index' number for the inventory node (default 0)
function networks.register_junction(name, size, boxes, tlib2, node, index)
local names = {}
for idx = 0,63 do
local ndef = table.copy(node)
if idx == (index or 0) then
ndef.groups.not_in_creative_inventory = 0
else
ndef.groups.not_in_creative_inventory = 1
end
ndef.drawtype = "nodebox"
ndef.node_box = get_node_box(idx, size, boxes)
ndef.paramtype2 = "facedir"
ndef.on_rotate = screwdriver.disallow -- TODO: allow controlled rotation
ndef.drop = name..(index or "0")
minetest.register_node(name..idx, ndef)
tlib2:add_secondary_node_names({name..idx})
-- for the case that 'tlib2.force_to_use_tubes' is set
tlib2:add_special_node_names({name..idx})
names[#names + 1] = name..idx
end
return names
end
local SideToDir = {B=1, R=2, F=3, L=4}
local function dir_to_dir2(dir, param2)
if param2 == 0 then
return dir
elseif param2 == 1 then
return ({4,1,2,3,5,6})[dir]
elseif param2 == 2 then
return ({3,4,1,2,5,6})[dir]
elseif param2 == 3 then
return ({2,3,4,1,5,6})[dir]
end
return dir
end
function networks.junction_type(pos, network, default_side, param2)
local connected = function(self, pos, dir)
if network:is_primary_node(pos, dir) then
local param2, npos = self:get_primary_node_param2(pos, dir)
if param2 then
local d1, d2, _ = self:decode_param2(npos, param2)
dir = networks.Flip[dir]
return d1 == dir or dir == d2
end
end
end
local val = 0
if default_side then
val = setbit(val, bit(SideToDir[default_side]))
end
for dir = 1,6 do
local dir2 = dir_to_dir2(dir, param2)
if network.force_to_use_tubes then
if connected(network, pos, dir) then
val = setbit(val, bit(dir2))
elseif network:is_special_node(pos, dir) then
val = setbit(val, bit(dir2))
end
else
if connected(network, pos, dir) then
val = setbit(val, bit(dir2))
elseif network:is_secondary_node(pos, dir) then
val = setbit(val, bit(dir2))
end
end
end
return val
end

4
mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = networks
depends = screwdriver,tubelib2
description = Build and manage networks based on tubelib2 tubes/pipes/cables

464
networks.lua Normal file
View File

@ -0,0 +1,464 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
-- Networks definition table for each node definition
--
-- networks = {
-- ele3 = { -- network type
-- sides = networks.AllSides, -- node connection sides
-- ntype = "con", -- node type(s) (can be a list)
-- },
-- }
-- for lazy programmers
local S2P = minetest.string_to_pos
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 Networks = {} -- cache for networks: {netw_type = {netID = <network>, ...}, ...}
local NetIDs = {} -- cache for netw IDs: {pos_hash = {outdir = netID, ...}, ...}
local MAX_NUM_NODES = 1000
local TTL = 5 * 60 -- 5 minutes
local Route = {} -- Used to determine the already passed nodes while walking
local NumNodes = 0
local DirToSide = {"B", "R", "F", "L", "D", "U"}
local Sides = {B = true, R = true, F = true, L = true, D = true, U = true}
local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6}
local Flip = {[0]=0,3,4,1,2,6,5} -- 180 degree turn
-------------------------------------------------------------------------------
-- Debugging
-------------------------------------------------------------------------------
--local function error(pos, msg)
-- minetest.log("error", "[networks] "..msg.." at "..P2S(pos).." "..N(pos).name)
--end
--local function count_nodes(node_type, nodes)
-- local num = 0
-- for _,pos in ipairs(nodes or {}) do
-- num = num + 1
-- end
-- return node_type.."="..num
--end
local function output(network)
local tbl = {}
for node_type,table in pairs(network) do
if type(table) == "table" then
tbl[#tbl+1] = "#" .. node_type .. " = " .. #table
end
end
print("Network: "..table.concat(tbl, ", "))
end
local function debug(node_type)
local tbl = {}
for netID,netw in pairs(Networks[node_type] or {}) do
if type(netw) == "table" then
tbl[#tbl+1] = string.format("%X", netID)
end
end
return "Networks: "..table.concat(tbl, ", ")
end
-------------------------------------------------------------------------------
-- Helper
-------------------------------------------------------------------------------
local function hidden_node(pos, netw_type)
-- legacy name
local name = M(pos):get_string("techage_hidden_nodename")
local ndef = minetest.registered_nodes[name]
if ndef and ndef.networks then
return ndef.networks[netw_type] or {}
end
-- new name
name = M(pos):get_string("networks_hidden_nodename")
ndef = minetest.registered_nodes[name]
if ndef and ndef.networks then
return ndef.networks[netw_type] or {}
end
return {}
end
-- return the networks table from the node definition
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 {}
else -- hidden junction
return hidden_node(pos, netw_type)
end
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 {}
else -- hidden junction
return hidden_node(pos, netw_type)
end
end
local function connected(tlib2, pos, dir)
local param2, npos = tlib2:get_primary_node_param2(pos, dir)
if param2 then
local d1, d2, num = tlib2:decode_param2(npos, param2)
if not num then return end
return Flip[dir] == d1 or Flip[dir] == d2
end
-- secondary nodes allowed?
if tlib2.force_to_use_tubes then
return tlib2:is_special_node(pos, dir)
else
return tlib2:is_secondary_node(pos, dir)
end
return false
end
-- Calculate the node outdir based on node.param2 and nominal dir (according to side)
local function dir_to_outdir(dir, param2)
if dir < 5 then
return ((dir + param2 - 1) % 4) + 1
end
return dir
end
local function indir_to_dir(indir, param2)
if indir < 5 then
return ((indir - param2 + 5) % 4) + 1
end
return Flip[indir]
end
local function outdir_to_dir(outdir, param2)
if outdir < 5 then
return ((outdir - param2 + 3) % 4) + 1
end
return outdir
end
local function side_to_outdir(pos, side)
return dir_to_outdir(SideToDir[side], N(pos).param2)
end
-------------------------------------------------------------------------------
-- Node Connections
-------------------------------------------------------------------------------
-- Get tlib2 connection dirs as table
-- used e.g. for the connection walk
local function get_node_connection_dirs(pos, netw_type)
local val = M(pos):get_int(netw_type.."_conn")
local tbl = {}
if val % 0x40 >= 0x20 then tbl[#tbl+1] = 1 end
if val % 0x20 >= 0x10 then tbl[#tbl+1] = 2 end
if val % 0x10 >= 0x08 then tbl[#tbl+1] = 3 end
if val % 0x08 >= 0x04 then tbl[#tbl+1] = 4 end
if val % 0x04 >= 0x02 then tbl[#tbl+1] = 5 end
if val % 0x02 >= 0x01 then tbl[#tbl+1] = 6 end
return tbl
end
-- store all node sides with tube connections as nodemeta
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
for dir = 1,6 do
val = val * 2
local side = DirToSide[outdir_to_dir(dir, node.param2)]
if sides[side] then
if connected(tlib2, pos, dir) then
val = val + 1
end
end
end
M(pos):set_int(tlib2.tube_type.."_conn", val)
end
end
-------------------------------------------------------------------------------
-- Connection Walk
-------------------------------------------------------------------------------
local function pos_already_reached(pos)
local key = minetest.hash_node_position(pos)
if not Route[key] and NumNodes < MAX_NUM_NODES then
Route[key] = true
NumNodes = NumNodes + 1
return false
end
return true
end
-- check if the given pipe 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)
local side = DirToSide[indir_to_dir(indir, node.param2)]
if not sides or sides and not sides[side] then return false end
return true
end
local function is_junction(pos, name, tube_type)
local ndef = net_def2(pos, name, tube_type)
-- ntype can be a string or an array of strings or nil
if ndef.ntype == "junc" then
return true
end
if type(ndef.ntype) == "table" then
for _,ntype in ipairs(ndef.ntype) do
if ntype == "junc" then
return true
end
end
end
return false
end
-- do the walk through the tubelib2 network
-- indir is the direction which should not be covered by the walk
-- (coming from there)
-- if outdirs is given, only this dirs are used
local function connection_walk(pos, outdirs, indir, node, tlib2, clbk)
if clbk then clbk(pos, indir, node) end
if outdirs or is_junction(pos, node.name, tlib2.tube_type) then
for _,outdir in pairs(outdirs or get_node_connection_dirs(pos, tlib2.tube_type)) do
local pos2, indir2 = tlib2:get_connected_node_pos(pos, outdir)
local node = N(pos2)
if pos2 and not pos_already_reached(pos2) and valid_indir(pos2, indir2, node, tlib2.tube_type) then
connection_walk(pos2, nil, indir2, node, tlib2, clbk)
end
end
end
end
local function collect_network_nodes(pos, tlib2, outdir)
Route = {}
NumNodes = 0
pos_already_reached(pos)
local netw = {}
local node = N(pos)
local net_name = tlib2.tube_type
-- outdir corresponds to the indir coming from
connection_walk(pos, outdir and {outdir}, nil, node, tlib2, function(pos, indir, node)
local ndef = net_def2(pos, node.name, net_name)
-- ntype can be a string or an array of strings or nil
local ntypes = ndef.ntype or {}
if type(ntypes) == "string" then
ntypes = {ntypes}
end
for _,ntype in ipairs(ntypes) do
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
return netw
end
-------------------------------------------------------------------------------
-- Maintain Network
-------------------------------------------------------------------------------
local function set_network(netw_type, netID, network)
if netID then
Networks[netw_type] = Networks[netw_type] or {}
Networks[netw_type][netID] = network
Networks[netw_type][netID].ttl = minetest.get_gametime() + TTL
end
end
local function get_network(netw_type, netID)
local netw = Networks[netw_type] and Networks[netw_type][netID]
if netw then
netw.ttl = minetest.get_gametime() + TTL
return netw
end
end
local function delete_network(netw_type, netID)
if Networks[netw_type] and Networks[netw_type][netID] then
Networks[netw_type][netID] = nil
end
end
-- keep data base small and valid
-- needed for networks without scheduler
local function remove_outdated_networks()
local to_be_deleted = {}
local t = minetest.get_gametime()
for net_name,tbl in pairs(Networks) do
for netID,network in pairs(tbl) do
local valid = (network.ttl or 0) - t
if valid < 0 then
to_be_deleted[#to_be_deleted+1] = {net_name, netID}
end
end
end
for _,item in ipairs(to_be_deleted) do
local net_name, netID = unpack(item)
Networks[net_name][netID] = nil
end
minetest.after(60, remove_outdated_networks)
end
minetest.after(60, remove_outdated_networks)
-------------------------------------------------------------------------------
-- Maintain netID
-------------------------------------------------------------------------------
-- Return node netID if available
local function get_netID(pos, tlib2, outdir)
local hash = minetest.hash_node_position(pos)
NetIDs[hash] = NetIDs[hash] or {}
local netID = NetIDs[hash][outdir]
if netID and get_network(tlib2.tube_type, netID) then
return netID
end
end
-- determine network ID (largest hash number of all nodes with given type)
local function determine_netID(tlib2, netw)
local netID = 0
for _, item in ipairs(netw[tlib2.tube_type] or {}) do
local outdir = Flip[item.indir]
local new = minetest.hash_node_position(item.pos) * 8 + outdir
if netID <= new then
netID = new
end
end
return netID
end
-- store network ID for each network node
local function store_netID(tlib2, netw, netID)
for _, item in ipairs(netw[tlib2.tube_type] or {}) do
local hash = minetest.hash_node_position(item.pos)
local outdir = Flip[item.indir]
NetIDs[hash] = NetIDs[hash] or {}
NetIDs[hash][outdir] = netID
end
set_network(tlib2.tube_type, netID, netw)
end
-- delete network and netID for given pos
local function delete_netID(pos, tlib2, outdir)
local netID = get_netID(pos, tlib2, outdir)
if netID then
local hash = minetest.hash_node_position(pos)
NetIDs[hash][outdir] = nil
delete_network(tlib2.tube_type, netID)
end
end
-------------------------------------------------------------------------------
-- API Functions
-------------------------------------------------------------------------------
-- Table fo a 180 degree turn
networks.Flip = Flip
-- networks.net_def(pos, netw_type)
networks.net_def = net_def
networks.AllSides = Sides -- table for all 6 node sides
-- networks.side_to_outdir(pos, side)
networks.side_to_outdir = side_to_outdir
-- networks.node_connections(pos, tlib2)
--networks.node_connections = node_connections
-- networks.collect_network_nodes(pos, tlib2, outdir)
--networks.collect_network_nodes = collect_network_nodes
-- Get node tubelib2 connections as table of outdirs
-- networks.get_node_connection_dirs(pos, netw_type)
networks.get_node_connection_dirs = get_node_connection_dirs
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)
store_node_connection_sides(pos, tlib2) -- update node internal data
delete_netID(pos, tlib2, outdir) -- delete node netID and network
end
-- Make sure the block has a network and return netID
function networks.get_netID(pos, tlib2, outdir)
local netID = get_netID(pos, tlib2, outdir)
if netID then
return netID
end
local netw = collect_network_nodes(pos, tlib2, outdir)
output(netw, true)
netID = determine_netID(tlib2, netw)
if netID > 0 then
store_netID(tlib2, netw, netID)
return netID
end
end
-- return list of nodes {pos = ..., indir = ...} of given network
function networks.get_network_table(pos, tlib2, outdir)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local netw = get_network(tlib2.tube_type, netID)
return netw or {}
end
return {}
end
function networks.get_default_outdir(pos, tlib2)
local dirs = networks.get_node_connection_dirs(pos, tlib2.tube_type)
if #dirs > 0 then
return dirs[1]
end
return 1
end
---- Overridden method of tubelib2!
--function Cable:get_primary_node_param2(pos, dir)
-- return techage.get_primary_node_param2(pos, dir)
--end
--function Cable:is_primary_node(pos, dir)
-- return techage.is_primary_node(pos, dir)
--end
--function Cable:get_secondary_node(pos, dir)
-- local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
-- local node = self:get_node_lvm(npos)
-- if self.secondary_node_names[node.name] or
-- self.secondary_node_names[M(npos):get_string("techage_hidden_nodename")] then
-- return node, npos, true
-- end
--end
--function Cable:is_secondary_node(pos, dir)
-- local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
-- local node = self:get_node_lvm(npos)
-- return self.secondary_node_names[node.name] or
-- self.secondary_node_names[M(npos):get_string("techage_hidden_nodename")]
--end

100
power.lua Normal file
View File

@ -0,0 +1,100 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
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 = networks.Power -- {netID = {curr_load, max_capa}}
-- Determine load and capa for the all network storage systems
local function get_storage_load(pos, tlib2, outdir)
local netw = networks.get_network_table(pos, tlib2, outdir)
local max_capa = DEFAULT_CAPA
local curr_load = 0
for _,item in ipairs(netw.sto or {}) do
local ndef = networks.net_def(pos, tlib2.tube_type)
local cload, mcapa = N(pos).get_storage_load(pos)
curr_load = curr_load + cload
max_capa = max_capa + mcapa
end
return {curr_load = curr_load, max_capa = max_capa}
end
-- Function checks for a power grid, not for enough power
-- For consumers, outdir is optional
function networks.power_available(pos, tlib2, outdir)
outdir = outdir or networks.get_default_outdir(pos, tlib2)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_load(pos, tlib2, outdir)
return pwr.curr_load > 0
end
end
-- For consumers, outdir is optional
function networks.consume_power(pos, tlib2, outdir, amount)
outdir = outdir or networks.get_default_outdir(pos, tlib2)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_load(pos, tlib2, outdir)
if pwr.curr_load >= amount then
pwr.curr_load = pwr.curr_load - amount
Power[netID] = pwr
return amount
else
local consumed = pwr.curr_load
pwr.curr_load = 0
Power[netID] = pwr
return consumed
end
end
return 0
end
function networks.provide_power(pos, tlib2, outdir, amount)
print(1)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
print(2)
local pwr = Power[netID] or get_storage_load(pos, tlib2, outdir)
if pwr.curr_load + amount <= pwr.max_capa then
print(3)
pwr.curr_load = pwr.curr_load + amount
Power[netID] = pwr
return amount
else
print(4)
local provided = pwr.max_capa - pwr.curr_load
pwr.curr_load = pwr.max_capa
Power[netID] = pwr
return provided
end
end
return 0
end
-- Function returns the load/charge as ratio (0..1)
-- Param outdir is optional
function networks.get_storage_load(pos, tlib2, outdir)
outdir = outdir or networks.get_default_outdir(pos, tlib2)
local netID = networks.get_netID(pos, tlib2, outdir)
if netID then
local pwr = Power[netID] or get_storage_load(pos, tlib2, outdir)
return pwr.curr_load / pwr.max_capa
end
return 0
end

32
storage.lua Normal file
View File

@ -0,0 +1,32 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
local storage = minetest.get_mod_storage()
local function update_mod_storage()
storage:set_int("Version", 1)
storage:set_string("Power", minetest.serialize(networks.Power or {}))
-- run every 10 minutes
minetest.after(600, update_mod_storage)
end
minetest.register_on_mods_loaded(function()
local version = storage:get_int("Version")
networks.Power = minetest.deserialize(storage:get_string("Power")) or {}
minetest.after(600, update_mod_storage)
end)
minetest.register_on_shutdown(function()
update_mod_storage()
end)

397
test.lua Normal file
View File

@ -0,0 +1,397 @@
--[[
Networks
========
Copyright (C) 2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
local CYCLE_TIME = 2
local STORAGE_CAPA = 500
local GEN_MAX = 20
local CON_MAX = 5
-------------------------------------------------------------------------------
-- Debugging
-------------------------------------------------------------------------------
local function debug_info(pos, text)
local marker = minetest.add_entity(pos, "networks:marker_cube")
if marker ~= nil then
if text == "add" then
marker:set_nametag_attributes({color = "#FF0000", text = "add__________"})
elseif text == "del" then
marker:set_nametag_attributes({color = "#00FF00", text = "_____del_____"})
elseif text == "noc" then
marker:set_nametag_attributes({color = "#0000FF", text = "__________noc"})
end
minetest.after(6, marker.remove, marker)
end
end
minetest.register_entity(":networks:marker_cube", {
initial_properties = {
visual = "cube",
textures = {
"networks_marker.png",
"networks_marker.png",
"networks_marker.png",
"networks_marker.png",
"networks_marker.png",
"networks_marker.png",
},
physical = false,
visual_size = {x = 1.1, y = 1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8,
},
on_punch = function(self)
self.object:remove()
end,
})
-------------------------------------------------------------------------------
-- Cable
-------------------------------------------------------------------------------
local Cable = tubelib2.Tube:new({
-- North, East, South, West, Down, Up
-- dirs_to_check = {1,2,3,4}, -- horizontal only
-- dirs_to_check = {5,6}, -- vertical only
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 20,
show_infotext = true,
tube_type = "ele",
primary_node_names = {"networks:cableS", "networks:cableA"},
secondary_node_names = {
"networks:generator", "networks:consumer",
"networks:junction", "networks:storage"},
after_place_tube = function(pos, param2, tube_type, num_tubes, tbl)
minetest.swap_node(pos, {name = "networks:cable"..tube_type, param2 = param2})
end,
})
minetest.register_node("networks:cableS", {
description = "Cable",
tiles = { -- Top, base, right, left, front, back
"networks_cable.png",
"networks_cable.png",
"networks_cable.png",
"networks_cable.png",
"networks_hole.png",
"networks_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Cable:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/16, -3/16, -4/8, 3/16, 3/16, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3},
sounds = default.node_sound_defaults(),
})
minetest.register_node("networks:cableA", {
description = "Cable",
tiles = { -- Top, base, right, left, front, back
"networks_cable.png",
"networks_hole.png",
"networks_cable.png",
"networks_cable.png",
"networks_cable.png",
"networks_hole.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/16, -4/8, -3/16, 3/16, 3/16, 3/16},
{-3/16, -3/16, -4/8, 3/16, 3/16, -3/16},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3, not_in_creative_inventory=1},
sounds = default.node_sound_defaults(),
drop = "networks:cableS",
})
local size = 3/16
local Boxes = {
{{-size, -size, size, size, size, 0.5 }}, -- z+
{{-size, -size, -size, 0.5, size, size}}, -- x+
{{-size, -size, -0.5, size, size, size}}, -- z-
{{-0.5, -size, -size, size, size, size}}, -- x-
{{-size, -0.5, -size, size, size, size}}, -- y-
{{-size, -size, -size, size, 0.5, size}}, -- y+
}
networks.register_junction("networks:junction", size, Boxes, Cable, {
description = "Junction",
tiles = {"networks_cable.png"},
after_place_node = function(pos, placer, itemstack, pointed_thing)
local name = "networks:junction"..networks.junction_type(pos, Cable)
minetest.swap_node(pos, {name = name, param2 = 0})
Cable:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir1, tlib2, node)
local name = "networks:junction"..networks.junction_type(pos, Cable)
minetest.swap_node(pos, {name = name, param2 = 0})
networks.update_network(pos, nil, tlib2)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_node(pos)
end,
networks = {
ele = {
sides = networks.AllSides, -- connection sides for cables
ntype = "junc",
},
},
paramtype = "light",
use_texture_alpha = "clip",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3},
sounds = default.node_sound_defaults(),
})
-------------------------------------------------------------------------------
-- Generator
-------------------------------------------------------------------------------
minetest.register_node("networks:generator", {
description = "Generator",
tiles = {
-- up, down, right, left, back, front
'networks_gen.png',
'networks_gen.png',
'networks_gen.png',
'networks_gen.png',
'networks_gen.png',
'networks_conn.png',
},
after_place_node = function(pos, placer)
local outdir = networks.side_to_outdir(pos, "F")
M(pos):set_int("outdir", outdir)
Cable:after_place_node(pos, {outdir})
minetest.get_node_timer(pos):start(2)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local outdir = tonumber(oldmetadata.fields.outdir or 0)
Cable:after_dig_node(pos, {outdir})
end,
on_timer = function(pos, elapsed)
local outdir = M(pos):get_int("outdir")
local mem = tubelib2.get_mem(pos)
mem.provided = networks.provide_power(pos, Cable, outdir, GEN_MAX)
M(pos):set_string("infotext", "running "..mem.provided)
return true
end,
on_rightclick = function(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
if mem.running then
mem.running = false
M(pos):set_string("infotext", "stopped")
minetest.get_node_timer(pos):stop()
else
mem.provided = mem.provided or 0
mem.running = true
M(pos):set_string("infotext", "running "..mem.provided)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
end,
networks = {
ele = {
sides = networks.AllSides,
ntype = "gen",
},
},
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3},
sounds = default.node_sound_glass_defaults(),
})
-------------------------------------------------------------------------------
-- Consumer
-------------------------------------------------------------------------------
local function swap_node(pos, name)
local node = tubelib2.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function on_turn_on(pos, tlib2)
swap_node(pos, "networks:consumer_on")
M(pos):set_string("infotext", "on")
local mem = tubelib2.get_mem(pos)
mem.running = true
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
local function on_turn_off(pos, tlib2)
swap_node(pos, "networks:consumer")
M(pos):set_string("infotext", "off")
local mem = tubelib2.get_mem(pos)
mem.running = false
minetest.get_node_timer(pos):stop()
end
local function node_timer(pos, elapsed)
local consumed = networks.consume_power(pos, Cable, nil, CON_MAX)
if consumed < CON_MAX then
on_turn_off(pos, Cable)
return false
end
return true
end
local function on_rightclick(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
if not mem.running and networks.power_available(pos, Cable) then
on_turn_on(pos, Cable)
else
on_turn_off(pos, Cable)
end
end
local function after_place_node(pos)
M(pos):set_string("infotext", "off")
Cable:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
Cable:after_dig_node(pos)
tubelib2.del_mem(pos)
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
networks.update_network(pos, outdir, tlib2)
end
local netdef = {
ele = {
sides = networks.AllSides, -- connection sides for cables
ntype = "con",
},
}
minetest.register_node("networks:consumer", {
description = "Consumer",
tiles = {'networks_con.png'},
on_turn_on = on_turn_on,
on_timer = node_timer,
on_rightclick = on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
tubelib2_on_update2 = tubelib2_on_update2,
networks = netdef,
paramtype = "light",
light_source = 0,
paramtype2 = "facedir",
groups = {choppy = 2, cracky = 2, crumbly = 2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("networks:consumer_on", {
description = "Consumer",
tiles = {'networks_con.png'},
on_turn_off = on_turn_off,
on_timer = node_timer,
on_rightclick = on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
tubelib2_on_update2 = tubelib2_on_update2,
networks = netdef,
paramtype = "light",
light_source = minetest.LIGHT_MAX,
paramtype2 = "facedir",
diggable = false,
drop = "",
groups = {not_in_creative_inventory = 1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
-------------------------------------------------------------------------------
-- Storage
-------------------------------------------------------------------------------
minetest.register_node("networks:storage", {
description = "Storage",
tiles = {"networks_sto.png"},
on_timer = function(pos, elapsed)
local mem = tubelib2.get_mem(pos)
mem.load = networks.get_storage_load(pos, Cable)
M(pos):set_string("infotext", "load = "..math.floor(mem.load * 100))
return true
end,
after_place_node = function(pos)
Cable:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
tubelib2.del_mem(pos)
end,
tubelib2_on_update2 = function(pos, outdir, tlib2, node)
networks.update_network(pos, outdir, tlib2)
end,
get_storage_load = function(pos)
local mem = tubelib2.get_mem(pos)
return mem.load or 0, STORAGE_CAPA
end,
networks = {
ele = {
sides = networks.AllSides,
ntype = "sto",
},
},
paramtype2 = "facedir",
groups = {choppy = 2, cracky = 2, crumbly = 2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})

BIN
textures/networks_cable.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
textures/networks_con.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/networks_conn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/networks_gen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

BIN
textures/networks_hole.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

BIN
textures/networks_sto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B