From 24ff13d7db9fab896c8d2e79574c3647823d7b35 Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz Date: Wed, 1 Jan 2014 15:57:51 -0500 Subject: [PATCH] complete rewrite of water flowing logic also implements leak-down in "off" pumps fixes failure to remove water source when digging active spigot/fountain --- devices.lua | 75 ++++-------- flowing_logic.lua | 289 +++++++++++++++++++++++++++++----------------- init.lua | 2 + pipes.lua | 54 +-------- 4 files changed, 205 insertions(+), 215 deletions(-) diff --git a/devices.lua b/devices.lua index 52f3002..81a5ca6 100644 --- a/devices.lua +++ b/devices.lua @@ -241,6 +241,11 @@ minetest.register_node("pipeworks:spigot_pouring", { end, after_dig_node = function(pos) pipeworks.scan_for_pipe_objects(pos) + local pos_below = {x = pos.x, y = pos.y-1, z = pos.z} + local below_node = minetest.get_node(pos_below) + if below_node.name == "default:water_source" then + minetest.set_node(pos_below, { name = "air" }) + end end, selection_box = { type = "fixed", @@ -264,7 +269,7 @@ local panel_cbox = { } } -minetest.register_node("pipeworks:entry_panel_empty", { +minetest.register_node("pipeworks:entry_panel", { description = "Airtight Pipe entry/exit", drawtype = "mesh", mesh = "pipeworks_entry_panel.obj", @@ -321,7 +326,7 @@ minetest.register_node("pipeworks:entry_panel_empty", { if not minetest.registered_nodes[minetest.get_node(pos1).name]["buildable_to"] then return end - minetest.add_node(pos1, {name = "pipeworks:entry_panel_empty", param2 = fdir }) + minetest.add_node(pos1, {name = "pipeworks:entry_panel", param2 = fdir }) pipeworks.scan_for_pipe_objects(pos1) if not pipeworks.expect_infinite_stacks then @@ -336,26 +341,10 @@ minetest.register_node("pipeworks:entry_panel_empty", { end }) -minetest.register_node("pipeworks:entry_panel_loaded", { - description = "Airtight Pipe entry/exit", - drawtype = "mesh", - mesh = "pipeworks_entry_panel.obj", - tiles = { "pipeworks_entry_panel.png" }, - paramtype = "light", - paramtype2 = "facedir", - groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, - sounds = default.node_sound_wood_defaults(), - walkable = true, - after_place_node = function(pos) - pipeworks.scan_for_pipe_objects(pos) - end, - after_dig_node = function(pos) - pipeworks.scan_for_pipe_objects(pos) - end, - selection_box = panel_cbox, - collision_box = panel_cbox, - drop = "pipeworks:entry_panel_empty" -}) +local sensorboxes = {} +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_leftstub) +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_sensorbody) +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_rightstub) minetest.register_node("pipeworks:flow_sensor_empty", { description = "Flow Sensor", @@ -519,6 +508,11 @@ minetest.register_node("pipeworks:fountainhead", { end, after_dig_node = function(pos) pipeworks.scan_for_pipe_objects(pos) + local pos_above = {x = pos.x, y = pos.y+1, z = pos.z} + local node_above = minetest.get_node(pos_above) + if node_above.name == "default:water_source" then + minetest.set_node(pos_above, { name = "air" }) + end end, on_construct = function(pos) if mesecon then @@ -535,38 +529,11 @@ minetest.register_node("pipeworks:fountainhead", { }, }) -minetest.register_node("pipeworks:fountainhead_pouring", { - description = "Fountainhead", - drawtype = "mesh", - mesh = "pipeworks_fountainhead.obj", - tiles = { "pipeworks_fountainhead.png" }, - sunlight_propagates = true, - paramtype = "light", - groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, - sounds = default.node_sound_wood_defaults(), - walkable = true, - after_place_node = function(pos) - pipeworks.scan_for_pipe_objects(pos) - end, - after_dig_node = function(pos) - pipeworks.scan_for_pipe_objects(pos) - end, - on_construct = function(pos) - if mesecon then - mesecon.receptor_on(pos, rules) - end - end, - selection_box = { - type = "fixed", - fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 } - }, - collision_box = { - type = "fixed", - fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 } - }, - drop = "pipeworks:fountainhead" -}) +-- compatibility minetest.register_alias("pipeworks:valve_off_loaded", "pipeworks:valve_off_empty") -minetest.register_alias("pipeworks:entry_panel", "pipeworks:entry_panel_empty") +minetest.register_alias("pipeworks:fountainhead_pouring", "pipeworks:fountainhead") +minetest.register_alias("pipeworks:entry_panel", "pipeworks:entry_panel_empty") +minetest.register_alias("pipeworks:entry_panel_empty", "pipeworks:entry_panel") +minetest.register_alias("pipeworks:entry_panel_loaded", "pipeworks:entry_panel") diff --git a/flowing_logic.lua b/flowing_logic.lua index e0a6236..7dbfa08 100644 --- a/flowing_logic.lua +++ b/flowing_logic.lua @@ -1,121 +1,192 @@ --- This file provides the actual flow and pathfinding logic that makes water +-- This file provides the actual flow logic that makes liquids -- move through the pipes. --- --- Contributed by mauvebic, 2013-01-03, rewritten a bit by Vanessa Ezekowitz --- -local finitewater = minetest.setting_getbool("liquid_finite") +local finite_liquids = minetest.setting_getbool("liquid_finite") +local pipe_liquid_max = 8 +local pipe_liquid_shows_loaded = 2 -pipeworks.check_for_liquids = function(pos) - local coords = { - {x=pos.x,y=pos.y-1,z=pos.z}, - {x=pos.x,y=pos.y+1,z=pos.z}, - {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,z=pos.z-1}, - {x=pos.x,y=pos.y,z=pos.z+1}, } - for i =1,6 do - local name = minetest.get_node(coords[i]).name - if name and string.find(name,"water") then - if finitewater then minetest.remove_node(coords[i]) end - return true - end - end - return false -end +-- Evaluate and balance liquid in all pipes -pipeworks.check_for_inflows = function(pos,node) - local coords = { - {x=pos.x,y=pos.y-1,z=pos.z}, - {x=pos.x,y=pos.y+1,z=pos.z}, - {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,z=pos.z-1}, - {x=pos.x,y=pos.y,z=pos.z+1}, } - local newnode = false - local source = false - for i =1,6 do - if newnode then break end - local name = minetest.get_node(coords[i]).name - if name and (name == "pipeworks:pump_on" and pipeworks.check_for_liquids(coords[i])) or string.find(name,"_loaded") then - if string.find(name,"_loaded") then - source = minetest.get_meta(coords[i]):get_string("source") - if source == minetest.pos_to_string(pos) then break end - end - newnode = string.gsub(node.name,"empty","loaded") - source = {x=coords[i].x,y=coords[i].y,z=coords[i].z} - end - end - if newnode then - minetest.add_node(pos,{name=newnode, param2 = node.param2}) - minetest.get_meta(pos):set_string("source",minetest.pos_to_string(source)) - end -end - -pipeworks.check_sources = function(pos,node) - local sourcepos = minetest.string_to_pos(minetest.get_meta(pos):get_string("source")) - if not sourcepos then return end - local source = minetest.get_node(sourcepos).name - local newnode = false - if source and not ((source == "pipeworks:pump_on" and pipeworks.check_for_liquids(sourcepos)) or string.find(source,"_loaded") or source == "ignore" ) then - newnode = string.gsub(node.name,"loaded","empty") - end - - if newnode then - minetest.add_node(pos,{name=newnode, param2 = node.param2}) - minetest.get_meta(pos):set_string("source","") - end -end - -pipeworks.spigot_check = function(pos, node) - local belowname = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name - if belowname and (belowname == "air" or belowname == "default:water_flowing" or belowname == "default:water_source") then - local spigotname = minetest.get_node(pos).name - local fdir=node.param2 - local check = { - {x=pos.x,y=pos.y,z=pos.z+1}, - {x=pos.x+1,y=pos.y,z=pos.z}, - {x=pos.x,y=pos.y,z=pos.z-1}, - {x=pos.x-1,y=pos.y,z=pos.z} +minetest.register_abm({ + nodenames = pipeworks.pipe_nodenames, + interval = 2, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local coords = { + {x = pos.x, 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-1, y = pos.y, z = pos.z}, + {x = pos.x+1, y = pos.y, z = pos.z}, + {x = pos.x, y = pos.y, z = pos.z-1}, + {x = pos.x, y = pos.y, z = pos.z+1}, } - local near_node = minetest.get_node(check[fdir+1]) - if near_node and string.find(near_node.name, "_loaded") then - if spigotname and spigotname == "pipeworks:spigot" then - minetest.add_node(pos,{name = "pipeworks:spigot_pouring", param2 = fdir}) - if finitewater or belowname ~= "default:water_source" then - minetest.add_node({x=pos.x,y=pos.y-1,z=pos.z},{name = "default:water_source"}) - end - end - else - if spigotname == "pipeworks:spigot_pouring" then - minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:spigot", param2 = fdir}) - if belowname == "default:water_source" and not finitewater then - minetest.remove_node({x=pos.x,y=pos.y-1,z=pos.z}) - end - end - end - end -end -pipeworks.fountainhead_check = function(pos, node) - local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name - if abovename and (abovename == "air" or abovename == "default:water_flowing" or abovename == "default:water_source") then - local fountainhead_name = minetest.get_node(pos).name - local near_node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}) - if near_node and string.find(near_node.name, "_loaded") then - if fountainhead_name and fountainhead_name == "pipeworks:fountainhead" then - minetest.add_node(pos,{name = "pipeworks:fountainhead_pouring"}) - if finitewater or abovename ~= "default:water_source" then - minetest.add_node({x=pos.x,y=pos.y+1,z=pos.z},{name = "default:water_source"}) + local num_connections = 0 + local connection_list = {} + local total_level = 0 + + for _,adjacentpos in ipairs(coords) do + local adjacent_node = minetest.get_node(adjacentpos) + if adjacent_node and string.find(dump(pipeworks.pipe_nodenames), adjacent_node.name) then + + local node_level = (minetest.get_meta(adjacentpos):get_float("liquid_level")) or 0 + if node_level < 0 then node_level = 0 end + + total_level = total_level + node_level + num_connections = num_connections + 1 + table.insert(connection_list, adjacentpos) + end + end + + local average_level = total_level / num_connections + + for _, connected_pipe_pos in ipairs(connection_list) do + + local newnode + local connected_pipe = minetest.get_node(connected_pipe_pos) + local pipe_name = string.match(connected_pipe.name, "pipeworks:pipe_%d.*_") + + if connected_pipe and pipe_name then + minetest.get_meta(connected_pipe_pos):set_float("liquid_level", average_level) + + if average_level > pipe_liquid_shows_loaded then + newnode = pipe_name.."loaded" + else + newnode = pipe_name.."empty" end end - else - if fountainhead_name == "pipeworks:fountainhead_pouring" then - minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:fountainhead"}) - if abovename == "default:water_source" and not finitewater then - minetest.remove_node({x=pos.x,y=pos.y+1,z=pos.z}) + + if newnode and connected_pipe.name ~= newnode then + minetest.swap_node(connected_pipe_pos, {name = newnode, param2 = connected_pipe.param2}) + end + end + end +}) + +-- Process all pumps in the area + +minetest.register_abm({ + nodenames = {"pipeworks:pump_on", "pipeworks:pump_off"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local minp = {x = pos.x-1, y = pos.y-1, z = pos.z-1} + local maxp = {x = pos.x+1, y = pos.y, z = pos.z+1} + local pos_above = {x = pos.x, y = pos.y+1, z = pos.z} + local node_above = minetest.get_node(pos_above) + if not node_above then return end + + local meta = minetest.get_meta(pos_above) + local node_level_above = meta:get_float("liquid_level") + if node_level_above == nil then node_level_above = 0 end + local pipe_name = string.match(node_above.name, "pipeworks:pipe_%d.*_") + + if pipe_name then + if node.name == "pipeworks:pump_on" then + local water_nodes = minetest.find_nodes_in_area(minp, maxp, + {"default:water_source", "default:water_flowing"}) + if (node_level_above < pipe_liquid_max) and #water_nodes > 1 then + meta:set_float("liquid_level", node_level_above + 4) -- add water to the pipe + end + else + if node_level_above > 0 then + meta:set_float("liquid_level", node_level_above - 1) -- leak the pipe down end end end end -end +}) + +-- Process all fountainheads in the area + +minetest.register_abm({ + nodenames = {"pipeworks:fountainhead"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local pos_above = {x = pos.x, y = pos.y+1, z = pos.z} + local node_above = minetest.get_node(pos_above) + if not node_above then return end + + local pos_below = {x = pos.x, y = pos.y-1, z = pos.z} + local node_below = minetest.get_node(pos_below) + if not node_below then return end + + local node_level_below = (minetest.get_meta(pos_below):get_float("liquid_level")) or 0 + print(node_level_below) + print(dump(node_above.name)) + + if node_level_below > 2 + and (node_above.name == "air" or node_above.name == "default:water_flowing") then + minetest.set_node(pos_above, {name = "default:water_source"}) + elseif node_level_below < 1 and node_above.name == "default:water_source" then + minetest.set_node(pos_above, {name = "air"}) + end + + if node_level_below > 1 + and (node_above.name == "air" or node_above.name == "default:water_source") then + minetest.get_meta(pos_below):set_float("liquid_level", node_level_below - 1) + end + end +}) + +-- Process all spigots in the area + +minetest.register_abm({ + nodenames = {"pipeworks:spigot","pipeworks:spigot_pouring"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local pos_below = {x = pos.x, y = pos.y-1, z = pos.z} + local below_node = minetest.get_node(pos_below) + if not below_node then return end + + if below_node.name == "air" or below_node.name == "default:water_flowing" + or below_node.name == "default:water_source" then + local fdir = node.param2 + local fdir_to_pos = { + {x = pos.x, y = pos.y, z = pos.z+1}, + {x = pos.x+1, y = pos.y, z = pos.z }, + {x = pos.x, y = pos.y, z = pos.z-1}, + {x = pos.x-1, y = pos.y, z = pos.z } + } + + local pos_adjacent = fdir_to_pos[fdir+1] + local adjacent_node = minetest.get_node(pos_adjacent) + if not adjacent_node then return end + local adjacent_node_level = (minetest.get_meta(pos_adjacent):get_float("liquid_level")) or 0 + local pipe_name = string.match(adjacent_node.name, "pipeworks:pipe_%d.*_") + + if pipe_name and adjacent_node_level > 2 + and (below_node.name == "air" or below_node.name == "default:water_flowing") then + minetest.set_node(pos, {name = "pipeworks:spigot_pouring", param2 = fdir}) + minetest.set_node(pos_below, {name = "default:water_source"}) + end + + if (pipe_name and adjacent_node_level < 1) + or (node.name ~= "pipeworks:spigot" and not pipe_name) then + minetest.set_node(pos,{name = "pipeworks:spigot", param2 = fdir}) + if below_node.name == "default:water_source" then + minetest.set_node(pos_below, {name = "air"}) + end + end + + if adjacent_node_level > 1 + and (below_node.name == "air" or below_node.name == "default:water_source") then + minetest.get_meta(pos_adjacent):set_float("liquid_level", adjacent_node_level - 1) + end + end + end +}) + +--[[ +other nodes that need processed separately: +table.insert(pipeworks.pipe_nodenames,"pipeworks:valve_on_empty") +table.insert(pipeworks.pipe_nodenames,"pipeworks:valve_off_empty") +table.insert(pipeworks.pipe_nodenames,"pipeworks:entry_panel_empty") +table.insert(pipeworks.pipe_nodenames,"pipeworks:flow_sensor_empty") +table.insert(pipeworks.pipe_nodenames,"pipeworks:valve_on_loaded") +table.insert(pipeworks.pipe_nodenames,"pipeworks:entry_panel_loaded") +table.insert(pipeworks.pipe_nodenames,"pipeworks:flow_sensor_loaded") +]]-- diff --git a/init.lua b/init.lua index 92ce02c..7c7befa 100644 --- a/init.lua +++ b/init.lua @@ -39,6 +39,8 @@ pipeworks.mesecons_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z pipeworks.liquid_texture = "default_water.png" +pipeworks.pipe_nodenames = {} + -- Helper functions function pipeworks.fix_image_names(table, replacement) diff --git a/pipes.lua b/pipes.lua index 2056fdf..79d6d58 100644 --- a/pipes.lua +++ b/pipes.lua @@ -2,9 +2,6 @@ local REGISTER_COMPATIBILITY = true -local pipes_empty_nodenames = {} -local pipes_full_nodenames = {} - local vti = {4, 3, 2, 1, 6, 5} local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}} for index, connects in ipairs(cconnects) do @@ -113,12 +110,10 @@ for index, connects in ipairs(cconnects) do end }) - table.insert(pipes_empty_nodenames, "pipeworks:pipe_"..index.."_empty") - table.insert(pipes_full_nodenames, "pipeworks:pipe_"..index.."_loaded") + table.insert(pipeworks.pipe_nodenames, "pipeworks:pipe_"..index.."_empty") + table.insert(pipeworks.pipe_nodenames, "pipeworks:pipe_"..index.."_loaded") end - - if REGISTER_COMPATIBILITY then local cempty = "pipeworks:pipe_compatibility_empty" local cloaded = "pipeworks:pipe_compatibility_loaded" @@ -175,48 +170,3 @@ if REGISTER_COMPATIBILITY then }) end -table.insert(pipes_empty_nodenames,"pipeworks:valve_on_empty") -table.insert(pipes_empty_nodenames,"pipeworks:valve_off_empty") -table.insert(pipes_empty_nodenames,"pipeworks:entry_panel_empty") -table.insert(pipes_empty_nodenames,"pipeworks:flow_sensor_empty") - -table.insert(pipes_full_nodenames,"pipeworks:valve_on_loaded") -table.insert(pipes_full_nodenames,"pipeworks:entry_panel_loaded") -table.insert(pipes_full_nodenames,"pipeworks:flow_sensor_loaded") - -minetest.register_abm({ - nodenames = pipes_empty_nodenames, - interval = 1, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - pipeworks.check_for_inflows(pos,node) - end -}) - -minetest.register_abm({ - nodenames = pipes_full_nodenames, - interval = 1, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - pipeworks.check_sources(pos,node) - end -}) - -minetest.register_abm({ - nodenames = {"pipeworks:spigot","pipeworks:spigot_pouring"}, - interval = 1, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - pipeworks.spigot_check(pos,node) - end -}) - -minetest.register_abm({ - nodenames = {"pipeworks:fountainhead","pipeworks:fountainhead_pouring"}, - interval = 1, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - pipeworks.fountainhead_check(pos,node) - end -}) -