-- By making this table of all possible permutations of horizontal direction we can avoid -- lots of redundant calculations. local all_direction_permutations = { {{x=0,z=1},{x=0,z=-1},{x=1,z=0},{x=-1,z=0}}, {{x=0,z=1},{x=0,z=-1},{x=-1,z=0},{x=1,z=0}}, {{x=0,z=1},{x=1,z=0},{x=0,z=-1},{x=-1,z=0}}, {{x=0,z=1},{x=1,z=0},{x=-1,z=0},{x=0,z=-1}}, {{x=0,z=1},{x=-1,z=0},{x=0,z=-1},{x=1,z=0}}, {{x=0,z=1},{x=-1,z=0},{x=1,z=0},{x=0,z=-1}}, {{x=0,z=-1},{x=0,z=1},{x=-1,z=0},{x=1,z=0}}, {{x=0,z=-1},{x=0,z=1},{x=1,z=0},{x=-1,z=0}}, {{x=0,z=-1},{x=1,z=0},{x=-1,z=0},{x=0,z=1}}, {{x=0,z=-1},{x=1,z=0},{x=0,z=1},{x=-1,z=0}}, {{x=0,z=-1},{x=-1,z=0},{x=1,z=0},{x=0,z=1}}, {{x=0,z=-1},{x=-1,z=0},{x=0,z=1},{x=1,z=0}}, {{x=1,z=0},{x=0,z=1},{x=0,z=-1},{x=-1,z=0}}, {{x=1,z=0},{x=0,z=1},{x=-1,z=0},{x=0,z=-1}}, {{x=1,z=0},{x=0,z=-1},{x=0,z=1},{x=-1,z=0}}, {{x=1,z=0},{x=0,z=-1},{x=-1,z=0},{x=0,z=1}}, {{x=1,z=0},{x=-1,z=0},{x=0,z=1},{x=0,z=-1}}, {{x=1,z=0},{x=-1,z=0},{x=0,z=-1},{x=0,z=1}}, {{x=-1,z=0},{x=0,z=1},{x=1,z=0},{x=0,z=-1}}, {{x=-1,z=0},{x=0,z=1},{x=0,z=-1},{x=1,z=0}}, {{x=-1,z=0},{x=0,z=-1},{x=1,z=0},{x=0,z=1}}, {{x=-1,z=0},{x=0,z=-1},{x=0,z=1},{x=1,z=0}}, {{x=-1,z=0},{x=1,z=0},{x=0,z=-1},{x=0,z=1}}, {{x=-1,z=0},{x=1,z=0},{x=0,z=1},{x=0,z=-1}}, } local get_node = minetest.get_node local set_node = minetest.swap_node -- Dynamic liquids ----------------------------------------------------------------------------------------------------------------------- local disable_flow_above = dynamic_liquid.config.disable_flow_above or 32767 dynamic_liquid.liquid_abm = function(liquid, flowing_liquid, chance) minetest.register_abm({ label = "dynamic_liquid " .. liquid .. " and " .. flowing_liquid, nodenames = {liquid}, neighbors = {flowing_liquid}, interval = 1, chance = chance or 1, y_max = disable_flow_above, catch_up = false, action = function(pos,node) -- Do everything possible to optimize this method local check_pos = {x=pos.x, y=pos.y-1, z=pos.z} local check_node = get_node(check_pos) local check_node_name = check_node.name if check_node_name == flowing_liquid or check_node_name == "air" then set_node(pos, check_node) set_node(check_pos, node) return end local perm = all_direction_permutations[math.random(24)] local dirs -- declare outside of loop so it won't keep entering/exiting scope for i=1,4 do dirs = perm[i] -- reuse check_pos to avoid allocating a new table check_pos.x = pos.x + dirs.x check_pos.y = pos.y check_pos.z = pos.z + dirs.z check_node = get_node(check_pos) check_node_name = check_node.name if check_node_name == flowing_liquid or check_node_name == "air" then set_node(pos, check_node) set_node(check_pos, node) return end end end }) dynamic_liquid.registered_liquids[liquid] = flowing_liquid table.insert(dynamic_liquid.registered_liquid_neighbors, liquid) end if dynamic_liquid.config.displace_liquid then local cardinal_dirs = { {x= 0, y=0, z= 1}, {x= 1, y=0, z= 0}, {x= 0, y=0, z=-1}, {x=-1, y=0, z= 0}, {x= 0, y=-1, z= 0}, {x= 0, y=1, z= 0}, } -- breadth-first search passing through liquid searching for air or flowing liquid. local flood_search_outlet = function(start_pos, source, flowing) local start_node = minetest.get_node(start_pos) local start_node_name = start_node.name if start_node_name == "air" or start_node_name == flowing then return start_pos end local visited = {} visited[minetest.hash_node_position(start_pos)] = true local queue = {start_pos} local queue_pointer = 1 while #queue >= queue_pointer do local current_pos = queue[queue_pointer] queue_pointer = queue_pointer + 1 for _, cardinal_dir in ipairs(cardinal_dirs) do local new_pos = vector.add(current_pos, cardinal_dir) local new_hash = minetest.hash_node_position(new_pos) if visited[new_hash] == nil then local new_node = minetest.get_node(new_pos) local new_node_name = new_node.name if new_node_name == "air" or new_node_name == flowing then return new_pos end visited[new_hash] = true if new_node_name == source then table.insert(queue, new_pos) end end end end return nil end -- Conserve liquids, when placing nodes in liquids try to find a place to displace the liquid to. minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing) local flowing = dynamic_liquid.registered_liquids[oldnode.name] if flowing ~= nil then local dest = flood_search_outlet(pos, oldnode.name, flowing) if dest ~= nil then minetest.swap_node(dest, oldnode) end end end) end