]> git.lizzy.rs Git - worldedit.git/blob - worldedit/manipulations.lua
ad64df6118fe4e606c0954bd552be73a65983740
[worldedit.git] / worldedit / manipulations.lua
1 worldedit = worldedit or {}\r
2 \r
3 --modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions\r
4 worldedit.sort_pos = function(pos1, pos2)\r
5         pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
6         pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
7         if pos1.x > pos2.x then\r
8                 pos2.x, pos1.x = pos1.x, pos2.x\r
9         end\r
10         if pos1.y > pos2.y then\r
11                 pos2.y, pos1.y = pos1.y, pos2.y\r
12         end\r
13         if pos1.z > pos2.z then\r
14                 pos2.z, pos1.z = pos1.z, pos2.z\r
15         end\r
16         return pos1, pos2\r
17 end\r
18 \r
19 --determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
20 worldedit.volume = function(pos1, pos2)\r
21         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
22         return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
23 end\r
24 \r
25 --sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
26 worldedit.set = function(pos1, pos2, nodename)\r
27         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
28         local env = minetest.env\r
29 \r
30         local node = {name=nodename}\r
31         local pos = {x=pos1.x, y=0, z=0}\r
32         while pos.x <= pos2.x do\r
33                 pos.y = pos1.y\r
34                 while pos.y <= pos2.y do\r
35                         pos.z = pos1.z\r
36                         while pos.z <= pos2.z do\r
37                                 env:add_node(pos, node)\r
38                                 pos.z = pos.z + 1\r
39                         end\r
40                         pos.y = pos.y + 1\r
41                 end\r
42                 pos.x = pos.x + 1\r
43         end\r
44         return worldedit.volume(pos1, pos2)\r
45 end\r
46 \r
47 --replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
48 worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
49         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
50         local env = minetest.env\r
51 \r
52         if minetest.registered_nodes[searchnode] == nil then\r
53                 searchnode = "default:" .. searchnode\r
54         end\r
55 \r
56         local pos = {x=pos1.x, y=0, z=0}\r
57         local node = {name=replacenode}\r
58         local count = 0\r
59         while pos.x <= pos2.x do\r
60                 pos.y = pos1.y\r
61                 while pos.y <= pos2.y do\r
62                         pos.z = pos1.z\r
63                         while pos.z <= pos2.z do\r
64                                 if env:get_node(pos).name == searchnode then\r
65                                         env:add_node(pos, node)\r
66                                         count = count + 1\r
67                                 end\r
68                                 pos.z = pos.z + 1\r
69                         end\r
70                         pos.y = pos.y + 1\r
71                 end\r
72                 pos.x = pos.x + 1\r
73         end\r
74         return count\r
75 end\r
76 \r
77 --copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied\r
78 worldedit.copy = function(pos1, pos2, axis, amount)\r
79         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
80         local env = minetest.env\r
81 \r
82         if amount < 0 then\r
83                 local pos = {x=pos1.x, y=0, z=0}\r
84                 while pos.x <= pos2.x do\r
85                         pos.y = pos1.y\r
86                         while pos.y <= pos2.y do\r
87                                 pos.z = pos1.z\r
88                                 while pos.z <= pos2.z do\r
89                                         local node = env:get_node(pos) --obtain current node\r
90                                         local meta = env:get_meta(pos):to_table() --get meta of current node\r
91                                         local value = pos[axis] --store current position\r
92                                         pos[axis] = value + amount --move along axis\r
93                                         env:add_node(pos, node) --copy node to new position\r
94                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
95                                         pos[axis] = value --restore old position\r
96                                         pos.z = pos.z + 1\r
97                                 end\r
98                                 pos.y = pos.y + 1\r
99                         end\r
100                         pos.x = pos.x + 1\r
101                 end\r
102         else\r
103                 local pos = {x=pos2.x, y=0, z=0}\r
104                 while pos.x >= pos1.x do\r
105                         pos.y = pos2.y\r
106                         while pos.y >= pos1.y do\r
107                                 pos.z = pos2.z\r
108                                 while pos.z >= pos1.z do\r
109                                         local node = minetest.env:get_node(pos) --obtain current node\r
110                                         local meta = env:get_meta(pos):to_table() --get meta of current node\r
111                                         local value = pos[axis] --store current position\r
112                                         pos[axis] = value + amount --move along axis\r
113                                         minetest.env:add_node(pos, node) --copy node to new position\r
114                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
115                                         pos[axis] = value --restore old position\r
116                                         pos.z = pos.z - 1\r
117                                 end\r
118                                 pos.y = pos.y - 1\r
119                         end\r
120                         pos.x = pos.x - 1\r
121                 end\r
122         end\r
123         return worldedit.volume(pos1, pos2)\r
124 end\r
125 \r
126 --moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved\r
127 worldedit.move = function(pos1, pos2, axis, amount)\r
128         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
129         local env = minetest.env\r
130 \r
131         if amount < 0 then\r
132                 local pos = {x=pos1.x, y=0, z=0}\r
133                 while pos.x <= pos2.x do\r
134                         pos.y = pos1.y\r
135                         while pos.y <= pos2.y do\r
136                                 pos.z = pos1.z\r
137                                 while pos.z <= pos2.z do\r
138                                         local node = env:get_node(pos) --obtain current node\r
139                                         local meta = env:get_meta(pos):to_table() --get metadata of current node\r
140                                         env:remove_node(pos)\r
141                                         local value = pos[axis] --store current position\r
142                                         pos[axis] = value + amount --move along axis\r
143                                         env:add_node(pos, node) --move node to new position\r
144                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
145                                         pos[axis] = value --restore old position\r
146                                         pos.z = pos.z + 1\r
147                                 end\r
148                                 pos.y = pos.y + 1\r
149                         end\r
150                         pos.x = pos.x + 1\r
151                 end\r
152         else\r
153                 local pos = {x=pos2.x, y=0, z=0}\r
154                 while pos.x >= pos1.x do\r
155                         pos.y = pos2.y\r
156                         while pos.y >= pos1.y do\r
157                                 pos.z = pos2.z\r
158                                 while pos.z >= pos1.z do\r
159                                         local node = env:get_node(pos) --obtain current node\r
160                                         local meta = env:get_meta(pos):to_table() --get metadata of current node\r
161                                         env:remove_node(pos)\r
162                                         local value = pos[axis] --store current position\r
163                                         pos[axis] = value + amount --move along axis\r
164                                         env:add_node(pos, node) --move node to new position\r
165                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
166                                         pos[axis] = value --restore old position\r
167                                         pos.z = pos.z - 1\r
168                                 end\r
169                                 pos.y = pos.y - 1\r
170                         end\r
171                         pos.x = pos.x - 1\r
172                 end\r
173         end\r
174         return worldedit.volume(pos1, pos2)\r
175 end\r
176 \r
177 --duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked\r
178 worldedit.stack = function(pos1, pos2, axis, count)\r
179         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
180         local length = pos2[axis] - pos1[axis] + 1\r
181         if count < 0 then\r
182                 count = -count\r
183                 length = -length\r
184         end\r
185         local amount = 0\r
186         local copy = worldedit.copy\r
187         for i = 1, count do\r
188                 amount = amount + length\r
189                 copy(pos1, pos2, axis, amount)\r
190         end\r
191         return worldedit.volume(pos1, pos2)\r
192 end\r
193 \r
194 --transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed\r
195 worldedit.transpose = function(pos1, pos2, axis1, axis2)\r
196         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
197 \r
198         local pos = {x=pos1.x, y=0, z=0}\r
199         local env = minetest.env\r
200         while pos.x <= pos2.x do\r
201                 pos.y = pos1.y\r
202                 while pos.y <= pos2.y do\r
203                         pos.z = pos1.z\r
204                         while pos.z <= pos2.z do\r
205                                 local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]\r
206                                 if extent1 < extent2 then\r
207                                         local node1 = env:get_node(pos)\r
208                                         local meta1 = env:get_meta(pos):to_table()\r
209                                         local value1, value2 = pos[axis1], pos[axis2]\r
210                                         pos[axis1], pos[axis2] = value1 + extent2, value2 + extent1\r
211                                         local node2 = env:get_node(pos)\r
212                                         local meta2 = env:get_meta(pos):to_table()\r
213                                         env:add_node(pos, node1)\r
214                                         env:get_meta(pos):from_table(meta1)\r
215                                         pos[axis1], pos[axis2] = value1, value2\r
216                                         env:add_node(pos, node2)\r
217                                         env:get_meta(pos):from_table(meta2)\r
218                                 end\r
219                                 pos.z = pos.z + 1\r
220                         end\r
221                         pos.y = pos.y + 1\r
222                 end\r
223                 pos.x = pos.x + 1\r
224         end\r
225         return worldedit.volume(pos1, pos2)\r
226 end\r
227 \r
228 --flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped\r
229 worldedit.flip = function(pos1, pos2, axis)\r
230         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
231 \r
232         local pos = {x=pos1.x, y=0, z=0}\r
233         local start = pos1[axis] + pos2[axis]\r
234         pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)\r
235         local env = minetest.env\r
236         while pos.x <= pos2.x do\r
237                 pos.y = pos1.y\r
238                 while pos.y <= pos2.y do\r
239                         pos.z = pos1.z\r
240                         while pos.z <= pos2.z do\r
241                                 local node1 = env:get_node(pos)\r
242                                 local meta1 = env:get_meta(pos):to_table()\r
243                                 local value = pos[axis]\r
244                                 pos[axis] = start - value\r
245                                 local node2 = env:get_node(pos)\r
246                                 local meta2 = env:get_meta(pos):to_table()\r
247                                 env:add_node(pos, node1)\r
248                                 env:get_meta(pos):from_table(meta1)\r
249                                 pos[axis] = value\r
250                                 env:add_node(pos, node2)\r
251                                 env:get_meta(pos):from_table(meta2)\r
252                                 pos.z = pos.z + 1\r
253                         end\r
254                         pos.y = pos.y + 1\r
255                 end\r
256                 pos.x = pos.x + 1\r
257         end\r
258         return worldedit.volume(pos1, pos2)\r
259 end\r
260 \r
261 --rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated\r
262 worldedit.rotate = function(pos1, pos2, axis, angle)\r
263         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
264 \r
265         local axis1, axis2\r
266         if axis == "x" then\r
267                 axis1, axis2 = "z", "y"\r
268         elseif axis == "y" then\r
269                 axis1, axis2 = "x", "z"\r
270         else --axis == "z"\r
271                 axis1, axis2 = "y", "x"\r
272         end\r
273         angle = angle % 360\r
274 \r
275         if angle == 90 then\r
276                 worldedit.transpose(pos1, pos2, axis1, axis2)\r
277                 worldedit.flip(pos1, pos2, axis2)\r
278         elseif angle == 180 then\r
279                 worldedit.flip(pos1, pos2, axis1)\r
280                 worldedit.flip(pos1, pos2, axis2)\r
281         elseif angle == 270 then\r
282                 worldedit.transpose(pos1, pos2, axis1, axis2)\r
283                 worldedit.flip(pos1, pos2, axis1)\r
284         end\r
285         return worldedit.volume(pos1, pos2)\r
286 end\r
287 \r
288 --digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug\r
289 worldedit.dig = function(pos1, pos2)\r
290         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
291         local env = minetest.env\r
292 \r
293         local pos = {x=pos1.x, y=0, z=0}\r
294         while pos.x <= pos2.x do\r
295                 pos.y = pos1.y\r
296                 while pos.y <= pos2.y do\r
297                         pos.z = pos1.z\r
298                         while pos.z <= pos2.z do\r
299                                 env:dig_node(pos)\r
300                                 pos.z = pos.z + 1\r
301                         end\r
302                         pos.y = pos.y + 1\r
303                 end\r
304                 pos.x = pos.x + 1\r
305         end\r
306         return worldedit.volume(pos1, pos2)\r
307 end