-
Notifications
You must be signed in to change notification settings - Fork 11
/
dynamic_liquids.lua
136 lines (124 loc) · 4.6 KB
/
dynamic_liquids.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
-- 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