637 lines
14 KiB
Lua
637 lines
14 KiB
Lua
-- pipelines are like pipes except much larger and more performant
|
|
-- pipelines are also only point-to-point; there are no joints
|
|
-- pipelines need pumps to force the fluid through, even downhill
|
|
|
|
|
|
local networks = {}
|
|
local net_members = {}
|
|
local storage = {}
|
|
local netname = 1
|
|
|
|
--local mod_storage = minetest.get_mod_storage()
|
|
local mod_storage = bitumen.mod_storage -- minetest.get_mod_storage()
|
|
|
|
|
|
|
|
networks = minetest.deserialize(mod_storage:get_string("pl_networks")) or {}
|
|
net_members = minetest.deserialize(mod_storage:get_string("pl_net_members")) or {}
|
|
storage = minetest.deserialize(mod_storage:get_string("pl_storage")) or {}
|
|
netname = mod_storage:get_int("pl_netname") or 1
|
|
|
|
local function save_data()
|
|
--print("saving")
|
|
|
|
mod_storage:set_string("pl_networks", minetest.serialize(networks))
|
|
mod_storage:set_string("pl_net_members", minetest.serialize(net_members))
|
|
mod_storage:set_string("pl_storage", minetest.serialize(storage))
|
|
mod_storage:set_int("pl_netname", netname)
|
|
end
|
|
|
|
|
|
-- centralized network creation for consistency
|
|
local function new_network(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
print("new pipeline network: hash: ".. hash .." name: " ..netname);
|
|
|
|
networks[hash] = {
|
|
hash = hash,
|
|
pos = {x=pos.x, y=pos.y, z=pos.z},
|
|
fluid = 'air',
|
|
name = netname,
|
|
count = 1,
|
|
inputs = {
|
|
[hash] = 1,
|
|
},
|
|
outputs = {},
|
|
buffer = 0,
|
|
in_pressure = -32000,
|
|
|
|
storage = {
|
|
--[[
|
|
[entry_hash] = < storage_center_hash >
|
|
]]
|
|
}
|
|
}
|
|
|
|
net_members[hash] = hash
|
|
|
|
netname = netname + 1
|
|
|
|
return networks[hash], hash
|
|
end
|
|
|
|
|
|
local function pnet_for(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
local ph = net_members[hash]
|
|
if ph == nil then
|
|
return nil, hash
|
|
end
|
|
|
|
return networks[ph], hash
|
|
end
|
|
|
|
|
|
|
|
-- merge a list of networks, if the are multiple nets in the list
|
|
local function try_merge(merge_list)
|
|
if #merge_list > 1 then
|
|
print("\n merging "..#merge_list.." networks")
|
|
|
|
local biggest = {count = 0}
|
|
local mlookup = {}
|
|
|
|
for _,n in ipairs(merge_list) do
|
|
mlookup[n.hash] = 1
|
|
if n.count > biggest.count then
|
|
biggest = n
|
|
end
|
|
end
|
|
|
|
mlookup[biggest.hash] = 0
|
|
|
|
for k,v in pairs(net_members) do
|
|
if mlookup[v] == 1 then
|
|
net_members[k] = biggest.hash
|
|
end
|
|
end
|
|
|
|
|
|
for _,n in ipairs(merge_list) do
|
|
if n.hash ~= biggest.hash then
|
|
biggest.count = biggest.count + n.count
|
|
networks[n.hash] = nil -- delete old networks
|
|
end
|
|
end
|
|
|
|
return biggest
|
|
end
|
|
|
|
return merge_list[1]
|
|
end
|
|
|
|
|
|
|
|
-- check specific nearby nodes for existing networks
|
|
local function check_merge(pos, npos1, npos2)
|
|
local hash = minetest.hash_node_position(pos)
|
|
|
|
local merge_list = {}
|
|
local current_net = nil
|
|
local found_net = 0
|
|
|
|
local check_net = function(npos)
|
|
local nhash = minetest.hash_node_position(npos)
|
|
local nphash = net_members[nhash]
|
|
if nphash ~= nil then
|
|
local pnet = networks[nphash]
|
|
|
|
if nil == current_net then
|
|
print("joining existing network: ".. pnet.name)
|
|
net_members[hash] = nphash
|
|
current_net = nphash
|
|
pnet.count = pnet.count + 1
|
|
pnet.inputs[hash] = 1
|
|
table.insert(merge_list, pnet)
|
|
elseif current_net == nphash then
|
|
print("alternate connection to existing network")
|
|
else
|
|
print("found seconday network: "..pnet.name)
|
|
table.insert(merge_list, pnet)
|
|
end
|
|
|
|
found_net = 1
|
|
end
|
|
end
|
|
|
|
check_net(npos1)
|
|
check_net(npos2)
|
|
|
|
return found_net, merge_list
|
|
end
|
|
|
|
|
|
|
|
|
|
bitumen.pipelines = {}
|
|
|
|
-- used by external machines to find the network for a node
|
|
bitumen.pipelines.get_net = function(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
local phash = net_members[hash]
|
|
if phash == nil then
|
|
return nil, nil, hash
|
|
end
|
|
|
|
return networks[phash], phash, hash
|
|
end
|
|
|
|
|
|
|
|
bitumen.pipes.after_change = function(pos, opos1, opos2, npos1, npos2)
|
|
|
|
local o1net, o1phash, o1hash = bitumen.pipelines.get_net(opos1)
|
|
local o2net, o2phash, o2hash = bitumen.pipelines.get_net(opos2)
|
|
local n1net, n1phash, n1hash = bitumen.pipelines.get_net(npos1)
|
|
local n2net, n2phash, n2hash = bitumen.pipelines.get_net(npos2)
|
|
|
|
local check_o1 = true
|
|
local check_o2 = true
|
|
local check_n1 = true
|
|
local check_n2 = true
|
|
|
|
-- check if one of the nodes is still in the network. this will often be the case
|
|
if vector.equals(opos1, npos1) then
|
|
print("old pos 1 is new pos 1")
|
|
check_o1 = false
|
|
check_n1 = false
|
|
elseif vector.equals(opos1, npos2) then
|
|
print("old pos 1 is new pos 1")
|
|
check_o1 = false
|
|
check_n2 = false
|
|
end
|
|
|
|
if vector.equals(opos2, npos1) then
|
|
print("old pos 1 is new pos 1")
|
|
check_o2 = false
|
|
check_n1 = false
|
|
elseif vector.equals(opos2, npos2) then
|
|
print("old pos 1 is new pos 1")
|
|
check_o2 = false
|
|
check_n2 = false
|
|
end
|
|
|
|
-- remove o1 from the network
|
|
if check_o1 then
|
|
|
|
|
|
end
|
|
|
|
|
|
-- merge with n1's network
|
|
if check_o1 then
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local hash = minetest.hash_node_position(pos)
|
|
local phash = net_members[hash]
|
|
if phash == nil then
|
|
print("wtf: pipe has no network in after_destruct")
|
|
return
|
|
end
|
|
local pnet = networks[phash]
|
|
if pnet == nil then
|
|
print("wtf: no network in after_destruct for pipe")
|
|
return
|
|
end
|
|
|
|
-- remove this node from the network
|
|
net_members[hash] = nil
|
|
pnet.count = pnet.count - 1
|
|
|
|
-- neighboring nodes
|
|
local check_pos = {
|
|
{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},
|
|
}
|
|
|
|
local stack = {}
|
|
local found = 0
|
|
-- check neighbors for network membership
|
|
for _,p in ipairs(check_pos) do
|
|
local h = minetest.hash_node_position(p)
|
|
|
|
local lphash = net_members[h]
|
|
if lphash ~= nil then
|
|
local lpnet = networks[lphash]
|
|
|
|
-- only process pipes/fixtures on the same network as the destroyed pipe
|
|
if lpnet and lpnet.name == pnet.name then
|
|
stack[h] = vector.new(p)
|
|
found = found + 1
|
|
--print("check stack: "..p.x..","..p.y..","..p.z)
|
|
else
|
|
print("no lpnet")
|
|
end
|
|
else
|
|
print("no lphash "..p.x..","..p.y..","..p.z)
|
|
end
|
|
end
|
|
|
|
-- don't need to split the network if this was just on the end
|
|
if found > 1 then
|
|
--print("check to split the network")
|
|
for h,p in pairs(stack) do
|
|
print(dump(p))
|
|
print(dump(h))
|
|
-- BUG: spouts and intakes can be counted as pipes when walking the network
|
|
|
|
-- just rename the net
|
|
local new_pnet = rebase_network(p)
|
|
-- print("split off pnet ".. new_pnet.name .. " at " .. minetest.pos_to_string(p))
|
|
-- all fluid is lost in the network atm
|
|
-- some networks might get orphaned, for example, the first
|
|
-- net to be rebased in a loop
|
|
end
|
|
|
|
|
|
end
|
|
|
|
save_data()
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_node("bitumen:pipeline", {
|
|
description = "Petroleum pipeline segment",
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-.3, -.35, -.5, .3, .35, .5},
|
|
{-.35, -.3, -.5, .35, .3, .5},
|
|
-- {-.4, -.4, -.4, .4, .4, .4},
|
|
-- {-.4, -.4, -.4, .4, .4, .4},
|
|
},
|
|
},
|
|
paramtype = "light",
|
|
is_ground_content = false,
|
|
paramtype2 = "facedir",
|
|
is_ground_content = false,
|
|
tiles = { "default_gold_block.png" },
|
|
walkable = true,
|
|
groups = { cracky = 3, petroleum_pipeline = 1, },
|
|
on_place = minetest.rotate_node,
|
|
|
|
on_construct = function(pos)
|
|
print("\npipeline placed at "..pos.x..","..pos.y..","..pos.z)
|
|
|
|
|
|
local node = minetest.get_node(pos)
|
|
|
|
local back_dir = minetest.facedir_to_dir(node.param2)
|
|
local backpos = vector.add(pos, back_dir)
|
|
local frontpos = vector.subtract(pos, back_dir)
|
|
|
|
-- minetest.set_node(backpos, {name="default:dirt"})
|
|
|
|
-- local found_net, merge_list = check_merge(pos)
|
|
|
|
--if found_net == 0 then
|
|
-- local net = new_network(pos)
|
|
--end
|
|
|
|
-- try_merge(merge_list)
|
|
|
|
--save_data()
|
|
end,
|
|
|
|
--after_destruct = bitumen.pipes.after_destruct,
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_node("bitumen:pipeline_elbow", {
|
|
description = "Petroleum pipeline elbow",
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-.3, -.35, -.5, .3, .35, .3},
|
|
{-.35, -.3, -.5, .35, .3, .3},
|
|
|
|
{-.3, -.3, -.35, .3, .5, .35},
|
|
{-.35, -.3, -.3, .35, .5, .3},
|
|
-- {-.4, -.4, -.4, .4, .4, .4},
|
|
-- {-.4, -.4, -.4, .4, .4, .4},
|
|
},
|
|
},
|
|
paramtype = "light",
|
|
is_ground_content = false,
|
|
paramtype2 = "facedir",
|
|
is_ground_content = false,
|
|
tiles = { "default_gold_block.png" },
|
|
walkable = true,
|
|
groups = { cracky = 3, petroleum_pipeline = 1, },
|
|
on_place = minetest.rotate_node,
|
|
|
|
on_rotate = function(pos, node, player, mode, new_param2)
|
|
|
|
|
|
|
|
local oldback_dir = minetest.facedir_to_dir(node.param2)
|
|
local oldfrontpos = vector.subtract(pos, oldback_dir)
|
|
|
|
local oldtop_dir = ({[0]={x=0, y=1, z=0},
|
|
{x=0, y=0, z=1},
|
|
{x=0, y=0, z=-1},
|
|
{x=1, y=0, z=0},
|
|
{x=-1, y=0, z=0},
|
|
{x=0, y=-1, z=0}})[math.floor(node.param2/4)]
|
|
|
|
local oldtoppos = vector.add(pos, oldtop_dir)
|
|
|
|
minetest.set_node(oldfrontpos, {name="default:glass"})
|
|
minetest.set_node(oldtoppos, {name="default:glass"})
|
|
|
|
|
|
|
|
local back_dir = minetest.facedir_to_dir(new_param2)
|
|
local frontpos = vector.subtract(pos, back_dir)
|
|
|
|
local top_dir = ({[0]={x=0, y=1, z=0},
|
|
{x=0, y=0, z=1},
|
|
{x=0, y=0, z=-1},
|
|
{x=1, y=0, z=0},
|
|
{x=-1, y=0, z=0},
|
|
{x=0, y=-1, z=0}})[math.floor(new_param2/4)]
|
|
|
|
local toppos = vector.add(pos, top_dir)
|
|
|
|
minetest.set_node(frontpos, {name="default:dirt"})
|
|
minetest.set_node(toppos, {name="default:cobble"})
|
|
end,
|
|
|
|
on_construct = function(pos)
|
|
print("\npipeline elbow placed at "..pos.x..","..pos.y..","..pos.z)
|
|
|
|
|
|
local node = minetest.get_node(pos)
|
|
|
|
|
|
local back_dir = minetest.facedir_to_dir(node.param2)
|
|
local frontpos = vector.subtract(pos, back_dir)
|
|
|
|
local top_dir = ({[0]={x=0, y=1, z=0},
|
|
{x=0, y=0, z=1},
|
|
{x=0, y=0, z=-1},
|
|
{x=1, y=0, z=0},
|
|
{x=-1, y=0, z=0},
|
|
{x=0, y=-1, z=0}})[math.floor(node.param2/4)]
|
|
|
|
local toppos = vector.add(pos, top_dir)
|
|
|
|
minetest.set_node(frontpos, {name="default:dirt"})
|
|
minetest.set_node(toppos, {name="default:cobble"})
|
|
|
|
-- local found_net, merge_list = check_merge(pos)
|
|
|
|
--if found_net == 0 then
|
|
-- local net = new_network(pos)
|
|
--end
|
|
|
|
-- try_merge(merge_list)
|
|
|
|
--save_data()
|
|
end,
|
|
|
|
--after_destruct = bitumen.pipelines.after_destruct,
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local storage_tank_builder_formspec =
|
|
"size[10,8;]" ..
|
|
default.gui_bg ..
|
|
default.gui_bg_img ..
|
|
default.gui_slots ..
|
|
"list[context;main;0,0.3;4,3;]" ..
|
|
"button[5,1;1,4;build;Build]" ..
|
|
"list[current_player;main;0,3.85;8,1;]" ..
|
|
"list[current_player;main;0,5.08;8,3;8]" ..
|
|
"listring[context;main]" ..
|
|
"listring[current_player;main]" ..
|
|
default.get_hotbar_bg(0, 3.85)
|
|
|
|
|
|
minetest.register_node("bitumen:storage_tank_constructor", {
|
|
description = "Storage Tank Constructor",
|
|
drawtype = "normal",
|
|
paramtype2 = "facedir",
|
|
on_rotate = screwdriver.rotate_simple,
|
|
groups = {cracky=1},
|
|
tiles = {
|
|
"default_copper_block.png","default_tin_block.png",
|
|
},
|
|
|
|
on_construct = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
inv:set_size("main", 12)
|
|
|
|
meta:set_string("formspec", storage_tank_builder_formspec);
|
|
end,
|
|
|
|
|
|
on_receive_fields = function(pos, form, fields, player)
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
if fields.build then
|
|
-- tanks can only be built on thick foundations
|
|
local ret = bitumen.check_foundation(
|
|
{x = pos.x - 15, y = pos.y - 3, z = pos.z - 15},
|
|
{x = pos.x + 15, y = pos.y - 1, z = pos.z + 15},
|
|
{
|
|
["default:steelblock"] = 1,
|
|
["bitumen:concrete"] = 1,
|
|
}
|
|
)
|
|
|
|
if ret == false then
|
|
minetest.chat_send_player(player:get_player_name(), "Foundation is incomplete: 30x3x30")
|
|
return
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(), "Foundation is complete.")
|
|
end
|
|
|
|
-- tanks need room
|
|
local ret = bitumen.check_foundation(
|
|
{x = pos.x - 16, y = pos.y , z = pos.z - 16},
|
|
{x = pos.x + 16, y = pos.y + 12, z = pos.z + 16},
|
|
{
|
|
["air"] = 1,
|
|
["bitumen:storage_tank_constructor"] = 1,
|
|
}
|
|
)
|
|
|
|
if ret == false then
|
|
minetest.chat_send_player(player:get_player_name(), "Area is not clear: 32x12x32")
|
|
return
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(), "Area is clear.")
|
|
end
|
|
|
|
local inv = meta:get_inventory();
|
|
|
|
-- should be ~1500 sheets
|
|
if (inv:contains_item("main", "bitumen:galv_steel_sheet 99") and
|
|
inv:contains_item("main", "default:coal_lump 20")) then
|
|
|
|
inv:remove_item("main", "bitumen:galv_steel_sheet 99")
|
|
inv:remove_item("main", "default:coal_lump 20")
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(), "Not enough materials: 99x Galvanized Steel Sheet, 20x Coal Lump")
|
|
return
|
|
end
|
|
|
|
-- ready to go
|
|
minetest.chat_send_player(player:get_player_name(), "Clear area, construction starting...")
|
|
|
|
for i = 9,1,-1 do
|
|
minetest.after(10-i, (function(n)
|
|
return function()
|
|
minetest.chat_send_player(
|
|
player:get_player_name(),
|
|
"Storage Tank construction in "..n.."..."
|
|
)
|
|
end
|
|
end)(i))
|
|
end
|
|
|
|
minetest.after(10, function()
|
|
minetest.set_node(pos, {name="bitumen:storage_tank"})
|
|
end)
|
|
|
|
end
|
|
end,
|
|
})
|
|
|
|
|
|
|
|
bitumen.register_blueprint({
|
|
name = "bitumen:storage_tank",
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_node("bitumen:storage_tank", {
|
|
paramtype = "light",
|
|
drawtype = "mesh",
|
|
mesh = "storage_tank.obj",
|
|
description = "Storage Tank",
|
|
tiles = {
|
|
"default_sand.png",
|
|
},
|
|
inventory_image = "default_sand.png",
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{ -.5, -.5, -.5, .5, 1.5, .5 },
|
|
-- { -8.2, -.5, -.2, -7.8, 10, .2 },
|
|
-- { -.2, -.5, -8.2, .2, 10, -7.8 },
|
|
-- { 8.2, -.5, -.2, 7.8, 10, .2 },
|
|
-- { -.2, -.5, 8.2, .2, 10, 7.8 },
|
|
},
|
|
},
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{ -.5, -.5, -.5, .5, 1.5, .5 },
|
|
}
|
|
},
|
|
paramtype2 = "facedir",
|
|
groups = {choppy=1, petroleum_fixture=1, bitumen_magic_proof=1 },
|
|
sounds = default.node_sound_wood_defaults(),
|
|
|
|
on_construct = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
if placer then
|
|
local owner = placer:get_player_name()
|
|
meta:set_string("owner", owner)
|
|
end
|
|
-- meta:set_float("fluid_level", 0)
|
|
-- meta:set_float("capacity", math.floor(3.14159 * .75 * 9 * 9 * 9 * 64))
|
|
-- meta:set_string("infotext", "0%")
|
|
|
|
bitumen.magic.set_collision_nodes(pos, bitumen.magic.gencylinder({0, 0, 0}, 14.99, 9))
|
|
|
|
-- bitumen.pipes.on_construct(pos)
|
|
end,
|
|
|
|
on_destruct = bitumen.magic.on_destruct,
|
|
|
|
can_dig = function(pos, player)
|
|
-- local meta = minetest.get_meta(pos);
|
|
-- local owner = meta:get_string("owner")
|
|
-- local fluid_level = meta:get_float("fluid_level") or 0
|
|
-- return player:get_player_name() ~= owner and fluid_level <= 0.01
|
|
return true
|
|
end,
|
|
})
|
|
|