--[[ TechAge ======= Copyright (C) 2019-2020 Joachim Stolberg AGPL v3 See LICENSE.txt for more information Liquid transportation API via Pipe(s) (peer, put, take) ]]-- local P2S = minetest.pos_to_string local M = minetest.get_meta local N = function(pos) return minetest.get_node(pos).name end local LQD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).liquid end local Pipe = techage.LiquidPipe local S = techage.S local net_def = techage.networks.net_def local networks = techage.networks local liquid = techage.liquid -- -- Networks -- -- determine network ID (largest hash number of all pumps) local function determine_netID(pos, outdir) local netID = 0 networks.connection_walk(pos, outdir, Pipe, function(pos, indir, node) local ntype = net_def(pos, "pipe2").ntype if ntype and ntype == "pump" then local new = minetest.hash_node_position(pos) * 8 + outdir if netID <= new then netID = new end end end) return netID end -- store network ID on each pump like node local function store_netID(pos, outdir, netID) networks.connection_walk(pos, outdir, Pipe, function(pos, indir, node) local ntype = net_def(pos, "pipe2").ntype if ntype and ntype == "pump" then local nvm = techage.get_nvm(pos) local outdir = networks.Flip[indir] nvm.pipe2 = nvm.pipe2 or {} nvm.pipe2.netIDs = nvm.pipe2.netIDs or {} nvm.pipe2.netIDs[outdir] = netID end end) end -- delete network and ID on each pump like node local function delete_netID(pos, outdir) local netID = 0 networks.connection_walk(pos, outdir, Pipe, function(pos, indir, node) local ntype = net_def(pos, "pipe2").ntype if ntype and ntype == "pump" then local nvm = techage.get_nvm(pos) local outdir = networks.Flip[indir] if nvm.pipe2 and nvm.pipe2.netIDs and nvm.pipe2.netIDs[outdir] then netID = nvm.pipe2.netIDs[outdir] nvm.pipe2.netIDs[outdir] = nil end end end) networks.delete_network("pipe2", netID) end local function get_netID(pos, outdir) local nvm = techage.get_nvm(pos) if not nvm.pipe2 or not nvm.pipe2.netIDs or not nvm.pipe2.netIDs[outdir] then local netID = determine_netID(pos, outdir) store_netID(pos, outdir, netID) end return nvm.pipe2 and nvm.pipe2.netIDs and nvm.pipe2.netIDs[outdir] end -- return list of nodes {pos = ..., indir = ...} of given type local function get_network_table(pos, outdir, ntype) local netID = get_netID(pos, outdir) if netID then local netw = networks.get_network("pipe2", netID) if not netw then netw = networks.collect_network_nodes(pos, outdir, Pipe) networks.set_network("pipe2", netID, netw) end if not netw[ntype] then -- connection lost (e.g. tank cart)? -- reactivate network networks.node_connections(pos, Pipe) delete_netID(pos, outdir) end --print("netw", string.format("%012X", netID), dump(netw[ntype])) return netw[ntype] or {} end return {} end -- -- Client remote functions -- -- Determine and return liquid 'name' from the -- remote inventory. function liquid.peek(pos, outdir) for _,item in ipairs(get_network_table(pos, outdir, "tank")) do local liquid = LQD(item.pos) if liquid and liquid.peek then return liquid.peek(item.pos, item.indir) end end end -- Add given amount of liquid to the remote inventory. -- return leftover amount function liquid.put(pos, outdir, name, amount, player_name) for _,item in ipairs(get_network_table(pos, outdir, "tank")) do local liquid = LQD(item.pos) if liquid and liquid.put and liquid.peek then -- wrong items? local peek = liquid.peek(item.pos, item.indir) if peek and peek ~= name then return amount or 0 end if player_name then local num = techage.get_node_number(pos) or "000" techage.mark_position(player_name, item.pos, "("..num..") put", "", 1) end amount = liquid.put(item.pos, item.indir, name, amount) if not amount or amount == 0 then break end end end return amount or 0 end -- Take given amount of liquid from the remote inventory. -- return taken amount and item name function liquid.take(pos, outdir, name, amount, player_name) local taken = 0 local item_name = nil for _,item in ipairs(get_network_table(pos, outdir, "tank")) do local liquid = LQD(item.pos) if liquid and liquid.take then if player_name then local num = techage.get_node_number(pos) techage.mark_position(player_name, item.pos, "("..num..") take", "", 1) end local val, name = liquid.take(item.pos, item.indir, name, amount - taken) if val and name then taken = taken + val item_name = name if amount - taken == 0 then break end end end end return taken, item_name end function liquid.untake(pos, outdir, name, amount) for _,item in ipairs(get_network_table(pos, outdir, "tank")) do local liquid = LQD(item.pos) if liquid and liquid.untake then amount = liquid.untake(item.pos, item.indir, name, amount) if not amount or amount == 0 then break end end end return amount or 0 end -- -- Server local functions -- function liquid.srv_peek(pos, indir) local nvm = techage.get_nvm(pos) nvm.liquid = nvm.liquid or {} return nvm.liquid.name end function liquid.srv_put(pos, indir, name, amount) local nvm = techage.get_nvm(pos) nvm.liquid = nvm.liquid or {} amount = amount or 0 if not nvm.liquid.name then nvm.liquid.name = name nvm.liquid.amount = amount return 0 elseif nvm.liquid.name == name then nvm.liquid.amount = nvm.liquid.amount or 0 local capa = LQD(pos).capa if nvm.liquid.amount + amount <= capa then nvm.liquid.amount = nvm.liquid.amount + amount return 0 else local rest = nvm.liquid.amount + amount - capa nvm.liquid.amount = capa return rest end end return amount end function liquid.srv_take(pos, indir, name, amount) local nvm = techage.get_nvm(pos) nvm.liquid = nvm.liquid or {} amount = amount or 0 if not name or nvm.liquid.name == name then name = nvm.liquid.name nvm.liquid.amount = nvm.liquid.amount or 0 if nvm.liquid.amount > amount then nvm.liquid.amount = nvm.liquid.amount - amount return amount, name else local rest = nvm.liquid.amount local name = nvm.liquid.name nvm.liquid.amount = 0 nvm.liquid.name = nil return rest, name end end return 0 end -- 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 liquid.update_network(pos, outdir) networks.node_connections(pos, Pipe) delete_netID(pos, outdir) end -- To be called from each pump in 'after_dig_node' -- before calling 'techage.del_mem(pos)' function liquid.after_dig_pump(pos) local nvm = techage.get_nvm(pos) if nvm.pipe2 and nvm.pipe2.netIDs then for outdir, netID in pairs(nvm.pipe2.netIDs) do networks.delete_network("pipe2", netID) end end end