summaryrefslogtreecommitdiff
path: root/flowing_logic.lua
diff options
context:
space:
mode:
authorVanessa Ezekowitz <vanessaezekowitz@gmail.com>2014-01-01 15:57:51 -0500
committerVanessa Ezekowitz <vanessaezekowitz@gmail.com>2015-06-18 12:42:19 -0400
commit24ff13d7db9fab896c8d2e79574c3647823d7b35 (patch)
tree94e73f5f5895f22ad3650615c827dc6292fd79bd /flowing_logic.lua
parent5822f60ba9cbebe45c1f82fa06dc93b747ba71a6 (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.lua281
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")
+]]--