diff options
author | Vanessa Ezekowitz <vanessaezekowitz@gmail.com> | 2014-01-01 15:57:51 -0500 |
---|---|---|
committer | Vanessa Ezekowitz <vanessaezekowitz@gmail.com> | 2015-06-18 12:42:19 -0400 |
commit | 24ff13d7db9fab896c8d2e79574c3647823d7b35 (patch) | |
tree | 94e73f5f5895f22ad3650615c827dc6292fd79bd /flowing_logic.lua | |
parent | 5822f60ba9cbebe45c1f82fa06dc93b747ba71a6 (diff) |
complete rewrite of water flowing logic
also implements leak-down in "off" pumps
fixes failure to remove water source when digging active spigot/fountain
Diffstat (limited to 'flowing_logic.lua')
-rw-r--r-- | flowing_logic.lua | 281 |
1 files changed, 176 insertions, 105 deletions
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") - -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 + +local finite_liquids = minetest.setting_getbool("liquid_finite") +local pipe_liquid_max = 8 +local pipe_liquid_shows_loaded = 2 + +-- Evaluate and balance liquid in all pipes + +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 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 - end - return false -end - -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 + + 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 + + if newnode and connected_pipe.name ~= newnode then + minetest.swap_node(connected_pipe_pos, {name = newnode, param2 = connected_pipe.param2}) 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} - } - 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"}) +-- 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 - 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}) + 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 - -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"}) - 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 - 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 (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 -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") +]]-- |