fluid_lib now implements transfer ducts

This commit is contained in:
Evert Prants 2018-12-12 21:06:10 +02:00
parent 00a34b173a
commit dbcaf78044
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
13 changed files with 640 additions and 6 deletions

View File

@ -1,5 +1,6 @@
# Universal Fluid API
This API adds support for `fluid_buffers` inside nodes. This means that nodes can contain fluid.
This API adds support for `fluid_buffers` inside nodes. This means that nodes can contain fluid. Simple fluid transfer is also implemented in `fluid_transfer`.
This mod implements [node_io](https://github.com/auouymous/node_io). Note that while it is recommended that you install this mod also, it is not required in order to function. **Enable ALL the mods provided by this "modpack"!**
## How to Use
1. Add the node to the `fluid_container` group.
@ -18,6 +19,10 @@ This API adds support for `fluid_buffers` inside nodes. This means that nodes ca
* **buffer_name_fluid** = `string` - Source node of the fluid.
* **buffer_name_fluid_storage** = `int` - How much fluid there is in this buffer.
4. Register your node **(DO NOT MISS THIS STEP! TRANSFER WILL NOT WORK OTHERWISE!)**.
Just call `fluid_lib.register_node(nodename)`.
## API
All numbers are in **milli-buckets** (1 bucket = 1000 mB).
@ -51,6 +56,17 @@ All numbers are in **milli-buckets** (1 bucket = 1000 mB).
* `fluid_lib.take_from_buffer(pos, buffer, count)`
* Actually takes the fluid. On success, returns the source block that was taken and how much was actually taken.
* `fluid_lib.register_node(nodename)`
* Registers a node that has fluid buffers. This is IMPORTANT!
* `fluid_lib.register_extractor_node(nodename, nodedef)`
* Registers a node that can extract fluid from another node (in front of self) and put it into ducts.
* `fluid_pump_capacity` variable in nodedef determines how much fluid (in mB) this node can "pump" every second.
* `fluid_lib.register_transfer_node(nodename, nodedef)`
* Registers a node that can transfer fluids. This is effectively a fluid duct.
* `duct_density` variable in nodedef determines the diameter of the duct (custom node_box is created).
* `bucket.register_liquid(source, flowing, itemname, inventory_image, name, groups, force_renew)`
* Works exactly the same as the default `bucket` mod, except it adds callbacks to insert/take fluid from nodes.
* `inventory_image` can be a **ColorString**.

View File

@ -1,6 +1,8 @@
-- Fluid Tanks
-- Copyright (c) 2018 Evert "Diamond" Prants <evert@lunasqu.ee>
local modpath = minetest.get_modpath(minetest.get_current_modname())
fluid_tanks = {}
-- Preserve fluid count in the item stack dropped
@ -199,8 +201,4 @@ function fluid_tanks.register_tank(tankname, def)
end
end
fluid_tanks.register_tank("fluid_tanks:tank", {
description = "Fluid Tank",
capacity = 16000,
accepts = true,
})
dofile(modpath.."/register.lua")

15
fluid_tanks/register.lua Normal file
View File

@ -0,0 +1,15 @@
fluid_tanks.register_tank("fluid_tanks:tank", {
description = "Fluid Tank",
capacity = 8000,
accepts = true,
})
minetest.register_craft({
output = "fluid_tanks:tank",
recipe = {
{"default:glass", "default:glass", "default:glass"},
{"default:glass", "default:steel_ingot", "default:glass"},
{"default:glass", "default:glass", "default:glass"},
}
})

104
fluid_transfer/api.lua Normal file
View File

@ -0,0 +1,104 @@
-- Nodes for transferring fluids
-- All units are in millibuckets (1 bucket)
-- This is the node that takes fluid from another node.
function fluid_lib.register_extractor_node(nodename, nodedef)
if not nodedef.groups then
nodedef.groups = {}
end
nodedef.groups["fluid_transport_source"] = 1
nodedef.paramtype2 = "facedir"
nodedef.legacy_facedir_simple = true
nodedef.on_timer = fluid_lib.transfer_timer_tick
local orig_construct = nodedef.on_construct
nodedef.on_construct = function (pos)
local meta = minetest.get_meta(pos)
meta:set_int("fluid_store", 0)
meta:set_string("fluid", "")
fluid_lib.refresh_node(pos)
if orig_construct then
orig_construct(pos)
end
end
nodedef.on_punch = function (pos, node, puncher, pointed_thing)
minetest.get_node_timer(pos):start(1.0)
minetest.node_punch(pos, node, puncher, pointed_thing)
end
-- Default transfer capacity
if not nodedef.fluid_pump_capacity then
nodedef.fluid_pump_capacity = 1000
end
minetest.register_node(nodename, nodedef)
end
-- This is the node that allows for fluid transfer.
function fluid_lib.register_transfer_node(nodename, nodedef)
if not nodedef.groups then
nodedef.groups = {}
end
nodedef.groups["fluid_transport"] = 1
-- Duct node density
local cd = 1/7
if nodedef.duct_density then
cd = math.abs(nodedef.duct_density)
nodedef.duct_density = nil
end
-- Default values, including the nodebox
local defaults = {
drawtype = "nodebox",
node_box = {
type = "connected",
fixed = {
{-cd, -cd, -cd, cd, cd, cd}
},
connect_front = {
{-cd, -cd, -1/2, cd, cd, -cd}
},
connect_back = {
{-cd, -cd, cd, cd, cd, 1/2}
},
connect_top = {
{-cd, cd, -cd, cd, 1/2, cd}
},
connect_bottom = {
{-cd, -1/2, -cd, cd, -cd, cd}
},
connect_left = {
{-1/2, -cd, -cd, cd, cd, cd}
},
connect_right = {
{cd, -cd, -cd, 1/2, cd, cd}
},
},
paramtype = "light",
connect_sides = { "top", "bottom", "front", "left", "back", "right" },
is_ground_content = false,
connects_to = {
"group:fluid_transport",
"group:fluid_transport_source",
"group:fluid_container"
},
}
for k,v in pairs(defaults) do
if not nodedef[k] then
nodedef[k] = v
end
end
nodedef.on_construct = fluid_lib.refresh_node
nodedef.after_destruct = fluid_lib.refresh_node
minetest.register_node(nodename, nodedef)
end

View File

@ -0,0 +1,20 @@
-- Duct
minetest.register_craft({
output = "fluid_transfer:fluid_duct 8",
recipe = {
{"default:glass", "default:glass", "default:glass"},
{"", "", ""},
{"default:glass", "default:glass", "default:glass"},
}
})
-- Pump
minetest.register_craft({
output = "fluid_transfer:fluid_transfer_pump",
recipe = {
{"", "fluid_transfer:fluid_duct", ""},
{"default:glass", "default:mese_crystal", "default:glass"},
{"default:stone", "default:stone", "default:stone"},
}
})

View File

@ -0,0 +1,2 @@
fluid_lib
node_io?

16
fluid_transfer/init.lua Normal file
View File

@ -0,0 +1,16 @@
-- Universal Fluid API implementation
-- Copyright (c) 2018 Evert "Diamond" Prants <evert@lunasqu.ee>
local modpath = minetest.get_modpath(minetest.get_current_modname())
-- Transfer network
dofile(modpath.."/network.lua")
-- API for ducts and pumps
dofile(modpath.."/api.lua")
-- Simple duct and pump
dofile(modpath.."/register.lua")
-- Crafting recipes
dofile(modpath.."/crafting.lua")

3
fluid_transfer/mod.conf Normal file
View File

@ -0,0 +1,3 @@
name = fluid_transfer
depends = fluid_lib
optional_depends = node_io

View File

@ -0,0 +1,185 @@
o Node
v 0.400000 0.400000 -0.370263
v 0.400000 0.400000 -0.497499
v -0.400000 0.400000 -0.497499
v -0.400000 0.400000 -0.370263
v 0.400000 -0.400000 -0.370263
v 0.400000 -0.400000 -0.497499
v -0.400000 -0.400000 -0.497499
v -0.400000 -0.400000 -0.370263
v 0.320000 0.320000 -0.243027
v 0.320000 0.320000 -0.370263
v -0.320000 0.320000 -0.370263
v -0.320000 0.320000 -0.243027
v 0.320000 -0.320000 -0.243027
v 0.320000 -0.320000 -0.370263
v -0.320000 -0.320000 -0.370263
v -0.320000 -0.320000 -0.243027
v 0.256000 0.256000 -0.115790
v 0.256000 0.256000 -0.243027
v -0.256000 0.256000 -0.243027
v -0.256000 0.256000 -0.115790
v 0.256000 -0.256000 -0.115790
v 0.256000 -0.256000 -0.243026
v -0.256000 -0.256000 -0.243026
v -0.256000 -0.256000 -0.115790
v 0.204800 0.204800 0.008210
v 0.204800 0.204800 -0.119027
v -0.204800 0.204800 -0.119027
v -0.204800 0.204800 0.008210
v 0.204800 -0.204800 0.008210
v 0.204800 -0.204800 -0.119026
v -0.204800 -0.204800 -0.119026
v -0.204800 -0.204800 0.008210
v 0.146894 0.146894 0.503596
v 0.146894 0.146894 -0.002413
v -0.146894 0.146894 -0.002413
v -0.146894 0.146894 0.503596
v 0.146894 -0.146894 0.503596
v 0.146894 -0.146894 -0.002413
v -0.146894 -0.146894 -0.002413
v -0.146894 -0.146894 0.503596
v 0.320665 0.320665 -0.497499
v -0.320665 0.320665 -0.497499
v 0.320664 -0.320665 -0.497499
v -0.320665 -0.320665 -0.497499
vt 0.712514 0.681510
vt 0.975774 0.681510
vt 0.975774 0.944770
vt 0.712514 0.944770
vt 0.712514 0.681510
vt 0.975774 0.681510
vt 0.975774 0.944770
vt 0.712514 0.944770
vt 0.975774 0.681510
vt 0.975774 0.944770
vt 0.712514 0.944770
vt 0.315390 0.302988
vt 0.315390 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.712514 0.681510
vt 0.975774 0.681510
vt 0.975774 0.944770
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.052130 0.302988
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.315390 0.039728
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.113358 0.155808
vt 0.139491 0.183677
vt 0.052150 0.175815
vt 0.070263 0.158170
vt 0.118317 0.113646
vt 0.075071 0.114371
vt 0.052211 0.096257
vt 0.139491 0.086694
vt 0.975306 0.069495
vt 0.371324 0.069495
vt 0.371324 0.276848
vt 0.975306 0.276848
vt 0.975306 0.069495
vt 0.975306 0.276848
vt 0.371324 0.276849
vt 0.371324 0.069495
vt 0.975125 0.070933
vt 0.975125 0.278286
vt 0.371143 0.278286
vt 0.371143 0.070933
vt 0.371143 0.070933
vt 0.371143 0.278286
vt 0.975125 0.278286
vt 0.975125 0.070933
vt 0.043937 0.339371
vt 0.658425 0.339371
vt 0.658425 0.953858
vt 0.043937 0.953858
vt 0.052130 0.302988
vt 0.315390 0.302988
vt 0.315390 0.302988
vt 0.052130 0.302988
vt 0.315390 0.039728
vt 0.052130 0.039728
vt 0.052130 0.039728
vt 0.315390 0.039728
vt 0.052130 0.302988
vt 0.315390 0.302988
vt 0.315390 0.302988
vt 0.052130 0.302988
vn 0.0000 1.0000 -0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
s off
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 8/6/2 7/7/2 6/8/2
f 1/1/3 5/9/3 6/10/3 2/11/3
f 3/12/4 2/13/4 41/14/4 42/15/4
f 3/16/5 7/17/5 8/18/5 4/4/5
f 5/19/6 1/20/6 4/21/6 8/22/6
f 9/23/1 10/24/1 11/25/1 12/26/1
f 13/27/2 16/28/2 15/29/2 14/30/2
f 9/23/3 13/31/3 14/32/3 10/33/3
f 10/34/4 14/35/4 15/29/4 11/36/4
f 11/37/5 15/38/5 16/39/5 12/26/5
f 13/27/6 9/40/6 12/41/6 16/42/6
f 17/43/1 18/44/1 19/45/1 20/46/1
f 21/47/2 24/48/2 23/49/2 22/50/2
f 17/43/3 21/51/3 22/52/3 18/53/3
f 18/54/4 22/55/4 23/49/4 19/56/4
f 19/57/5 23/58/5 24/59/5 20/46/5
f 21/47/6 17/60/6 20/61/6 24/62/6
f 25/63/1 26/64/1 27/65/1 28/66/1
f 29/67/2 32/68/2 31/69/2 30/70/2
f 25/63/3 29/67/3 30/70/3 26/64/3
f 27/65/5 31/69/5 32/68/5 28/66/5
f 29/67/6 25/63/6 28/66/6 32/68/6
f 33/71/1 34/72/1 35/73/1 36/74/1
f 37/75/2 40/76/2 39/77/2 38/78/2
f 33/79/3 37/80/3 38/81/3 34/82/3
f 35/83/5 39/84/5 40/85/5 36/86/5
f 41/87/4 43/88/4 44/89/4 42/90/4
f 6/91/4 7/92/4 44/93/4 43/94/4
f 7/95/4 3/96/4 42/97/4 44/98/4
f 2/99/4 6/100/4 43/101/4 41/102/4

252
fluid_transfer/network.lua Normal file
View File

@ -0,0 +1,252 @@
local node_io_present = minetest.get_modpath("node_io") ~= nil
-- Network graphs are built eminating from provider nodes.
-- TODO: Caching
---------------------
-- Graph Functions --
---------------------
local function flatten(map)
local list = {}
for key, value in pairs(map) do
list[#list + 1] = value
end
return list
end
local function get_node_property(meta, pos, prop)
local value = meta:get_int(prop)
if value == 0 or value == nil then
local nname = minetest.get_node(pos).name
local ndef = minetest.registered_nodes[nname]
value = ndef[prop]
end
if not value then return 0 end
return value
end
local function face_front(pos, fd)
local back = minetest.facedir_to_dir(fd)
local front = table.copy(back)
front.x = front.x * -1 + pos.x
front.y = front.y * -1 + pos.y
front.z = front.z * -1 + pos.z
return front
end
local function clear_networks_from_node(pos)
local meta = minetest.get_meta(pos)
meta:set_string("network_id", "")
end
local function add_node(nodes, pos, pnodeid)
local node_id = minetest.hash_node_position(pos)
if nodes[node_id] then
return false
end
nodes[node_id] = pos
return true
end
local function add_duct_node(nodes, pos, pnodeid, queue)
if add_node(nodes, pos, pnodeid) then
queue[#queue + 1] = pos
end
end
local function check_node(targets, all_nodes, pos, p_pos, pnodeid, queue)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local ndef = minetest.registered_nodes[node.name]
if minetest.get_item_group(node.name, "fluid_transport") > 0 then
add_duct_node(all_nodes, pos, pnodeid, queue)
return
end
if not ndef['node_io_can_put_liquid'] or not ndef['node_io_can_put_liquid'](pos, node, "") then
return
end
add_node(targets, pos, pnodeid)
end
local function traverse_network(targets, all_nodes, pos, p_pos, pnodeid, queue)
local positions = {
{x=pos.x+1, y=pos.y, z=pos.z},
{x=pos.x-1, y=pos.y, z=pos.z},
{x=pos.x, y=pos.y+1, z=pos.z},
{x=pos.x, y=pos.y-1, z=pos.z},
{x=pos.x, y=pos.y, z=pos.z+1},
{x=pos.x, y=pos.y, z=pos.z-1}}
for _, cur_pos in pairs(positions) do
check_node(targets, all_nodes, cur_pos, p_pos, pnodeid, queue)
end
end
local function fluid_targets(p_pos, pos)
local provider = minetest.get_node(p_pos)
local pnodeid = minetest.pos_to_string(p_pos)
local targets = {}
local queue = {}
local all_nodes = {}
local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name]
if node and minetest.get_item_group(node.name, "fluid_transport") > 0 then
add_duct_node(all_nodes, pos, pnodeid, queue)
elseif node and ndef['node_io_can_put_liquid'] and ndef['node_io_can_put_liquid'](pos, node, "") then
queue = {p_pos}
end
while next(queue) do
local to_visit = {}
for _, posi in ipairs(queue) do
traverse_network(targets, all_nodes, posi, p_pos, pnodeid, to_visit)
end
queue = to_visit
end
targets = flatten(targets)
all_nodes = flatten(all_nodes)
return targets
end
function fluid_lib.transfer_timer_tick(pos, elapsed)
local refresh = true
local node = minetest.get_node_or_nil(pos)
if not node then
return false
end
local meta = minetest.get_meta(pos)
local targets = {}
-- Only allow the node directly behind to be a start of a network
local tpos = vector.add(minetest.facedir_to_dir(node.param2), pos)
local tnode = minetest.get_node(tpos)
local ndef = minetest.registered_nodes[tnode.name]
if minetest.get_item_group(tnode.name, "fluid_transport") == 0 and
(not ndef['node_io_can_put_liquid'] or not ndef['node_io_can_put_liquid'](tpos, tnode, "")) then
minetest.forceload_free_block(pos)
return
end
-- Retrieve network
targets = fluid_targets(pos, tpos)
-- No targets, don't proceed
if #targets == 0 then
return true
end
-- Begin transfer
local srcpos = face_front(pos, node.param2)
local srcnode = minetest.get_node(srcpos)
-- Make sure source node is not air
if not srcnode or srcnode.name == "air" then
return true
end
local srcdef = minetest.registered_nodes[srcnode.name]
-- Make sure source node is a registered fluid container
if not srcdef['node_io_can_take_liquid'] then
return false
end
local c = srcdef.node_io_can_take_liquid(srcpos, srcnode, "")
if not c then return false end
local srcmeta = minetest.get_meta(srcpos)
local srcdef = minetest.registered_nodes[srcnode.name]
local fl_size = srcdef.node_io_get_liquid_size(srcpos, srcnode, "")
local buffers = {}
for i = 1, fl_size do
buffers[i] = srcdef.node_io_get_liquid_name(srcpos, srcnode, "", i)
end
if not #buffers then return true end
-- Limit the amount of fluid pumped per cycle
local pcapability = get_node_property(meta, pos, "fluid_pump_capacity")
local pumped = 0
-- Transfer some fluid here
for _,pos in pairs(targets) do
if not vector.equals(pos, srcpos) then
if pumped >= pcapability then break end
local destnode = minetest.get_node(pos)
local destdef = minetest.registered_nodes[destnode.name]
local pp = nil
if destdef['node_io_can_put_liquid'] then
if destdef.node_io_can_put_liquid(pos, destnode, "") then
pp = {}
local fl_size = destdef.node_io_get_liquid_size(pos, destnode, "")
for i = 1, fl_size do
pp[i] = destdef.node_io_get_liquid_name(pos, destnode, "", i)
end
if not #pp then pp = nil end
end
end
local changed = false
if pp ~= nil then
for bindex,bfluid in pairs(pp) do
for aindex,afluid in pairs(buffers) do
if pumped >= pcapability then break end
if (afluid == bfluid or bfluid == "") then
local idef = destdef.node_io_room_for_liquid(pos, destnode, "", afluid, pcapability)
if idef > 0 then
local fluidcount = srcdef.node_io_get_liquid_stack(srcpos, srcnode, "", aindex):get_count()
local defc = math.min(fluidcount, idef)
local defi = srcdef.node_io_take_liquid(srcpos, srcnode, "", nil, afluid, defc)
if defi.millibuckets > 0 then
local lo = destdef.node_io_put_liquid(pos, destnode, "", nil, afluid, defi.millibuckets)
pumped = pumped + (defi.millibuckets - lo)
changed = true
end
end
end
end
end
end
if changed then
minetest.get_node_timer(srcpos):start(1.0)
minetest.get_node_timer(pos):start(1.0)
end
end
end
return refresh
end
function fluid_lib.refresh_node(pos)
local t = minetest.get_node_timer(pos)
if t and not t:is_started() then
t:start(1.0)
end
if node_io_present then
node_io.update_neighbors(pos)
end
end
minetest.register_lbm({
label = "Fluid Transfer Tick",
name = "fluid_transfer:fluid_transfer_tick",
nodenames = {"group:fluid_transport_source", "group:fluid_pump"},
run_at_every_load = true,
action = fluid_lib.refresh_node,
})

View File

@ -0,0 +1,23 @@
fluid_lib.register_extractor_node("fluid_transfer:fluid_transfer_pump", {
description = "Fluid Transfer Pump\nPunch to start pumping",
tiles = {"fluid_transfer_pump.png"},
drawtype = "mesh",
mesh = "fluid_transfer_pump.obj",
groups = {oddly_breakable_by_hand = 1, cracky = 1},
paramtype = "light",
selection_box = {
type = "fixed",
fixed = {
{-0.4375, -0.4375, -0.5000, 0.4375, 0.4375, 0.000},
{-0.1875, -0.1875, 0.000, 0.1875, 0.1875, 0.5000}
}
}
})
fluid_lib.register_transfer_node("fluid_transfer:fluid_duct", {
description = "Fluid Duct",
tiles = {"fluid_transfer_duct.png"},
groups = {oddly_breakable_by_hand = 1, cracky = 1}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB