]> git.lizzy.rs Git - worldedit.git/blob - worldedit/functions.lua
2d949c65bf2fdcb43f6f6e061010941bbbcffaca
[worldedit.git] / worldedit / functions.lua
1 --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
2 worldedit.sort_pos = function(pos1, pos2)\r
3         pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
4         pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
5         if pos1.x > pos2.x then\r
6                 pos2.x, pos1.x = pos1.x, pos2.x\r
7         end\r
8         if pos1.y > pos2.y then\r
9                 pos2.y, pos1.y = pos1.y, pos2.y\r
10         end\r
11         if pos1.z > pos2.z then\r
12                 pos2.z, pos1.z = pos1.z, pos2.z\r
13         end\r
14         return pos1, pos2\r
15 end\r
16 \r
17 --determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
18 worldedit.volume = function(pos1, pos2)\r
19         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
20         return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
21 end\r
22 \r
23 --sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
24 worldedit.set = function(pos1, pos2, nodename)\r
25         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
26         local env = minetest.env\r
27 \r
28         local node = {name=nodename}\r
29         local pos = {x=pos1.x, y=0, z=0}\r
30         while pos.x <= pos2.x do\r
31                 pos.y = pos1.y\r
32                 while pos.y <= pos2.y do\r
33                         pos.z = pos1.z\r
34                         while pos.z <= pos2.z do\r
35                                 env:add_node(pos, node)\r
36                                 pos.z = pos.z + 1\r
37                         end\r
38                         pos.y = pos.y + 1\r
39                 end\r
40                 pos.x = pos.x + 1\r
41         end\r
42         return worldedit.volume(pos1, pos2)\r
43 end\r
44 \r
45 --replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
46 worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
47         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
48         local env = minetest.env\r
49 \r
50         if minetest.registered_nodes[searchnode] == nil then\r
51                 searchnode = "default:" .. searchnode\r
52         end\r
53         if minetest.registered_nodes[replacenode] == nil then\r
54                 replacenode = "default:" .. replacenode\r
55         end\r
56 \r
57         local pos = {x=pos1.x, y=0, z=0}\r
58         local node = {name=replacenode}\r
59         local count = 0\r
60         while pos.x <= pos2.x do\r
61                 pos.y = pos1.y\r
62                 while pos.y <= pos2.y do\r
63                         pos.z = pos1.z\r
64                         while pos.z <= pos2.z do\r
65                                 if env:get_node(pos).name == searchnode then\r
66                                         env:add_node(pos, node)\r
67                                         count = count + 1\r
68                                 end\r
69                                 pos.z = pos.z + 1\r
70                         end\r
71                         pos.y = pos.y + 1\r
72                 end\r
73                 pos.x = pos.x + 1\r
74         end\r
75         return count\r
76 end\r
77 \r
78 --adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
79 worldedit.hollow_sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
80         local node = {name=nodename}\r
81         local pos1 = {x=0, y=0, z=0}\r
82         local full_radius = radius * radius + radius\r
83         local env = minetest.env\r
84         for x = -radius, radius do\r
85                 pos1.x = pos.x + x\r
86                 for y = -radius, radius do\r
87                         pos1.y = pos.y + y\r
88                         for z = -radius, radius do\r
89                                 if x*x+y*y+z*z >= (radius-1) * (radius-1) + (radius-1) and x*x+y*y+z*z <= full_radius then\r
90                                         pos1.z = pos.z + z\r
91                                         env:add_node({x=pos.x+x,y=pos.y+y,z=pos.z+z}, node)\r
92                                 end\r
93                         end\r
94                 end\r
95         end\r
96 end\r
97 \r
98 --adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
99 worldedit.sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
100         local node = {name=nodename}\r
101         local pos1 = {x=0, y=0, z=0}\r
102         local full_radius = radius * radius + radius\r
103         local count = 0\r
104         local env = minetest.env\r
105         for x = -radius, radius do\r
106                 pos1.x = pos.x + x\r
107                 for y = -radius, radius do\r
108                         pos1.y = pos.y + y\r
109                         for z = -radius, radius do\r
110                                 if x*x+y*y+z*z <= full_radius then\r
111                                         pos1.z = pos.z + z\r
112                                         env:add_node(pos1, node)\r
113                                         count = count + 1\r
114                                 end\r
115                         end\r
116                 end\r
117         end\r
118         return count\r
119 end\r
120 \r
121 --adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added\r
122 worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)\r
123         local other1, other2\r
124         if axis == "x" then\r
125                 other1, other2 = "y", "z"\r
126         elseif axis == "y" then\r
127                 other1, other2 = "x", "z"\r
128         else --axis == "z"\r
129                 other1, other2 = "x", "y"\r
130         end\r
131 \r
132         local env = minetest.env\r
133         local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
134         local node = {name=nodename}\r
135         local count = 0\r
136         local step = 1\r
137         if length < 0 then\r
138                 length = -length\r
139                 step = -1\r
140         end\r
141         for i = 1, length do\r
142                 local offset1, offset2 = 0, radius\r
143                 local delta = -radius\r
144                 while offset1 <= offset2 do\r
145                         --add node at each octant\r
146                         local first1, first2 = pos[other1] + offset1, pos[other1] - offset1\r
147                         local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
148                         currentpos[other1], currentpos[other2] = first1, second1\r
149                         env:add_node(currentpos, node) --octant 1\r
150                         currentpos[other1] = first2\r
151                         env:add_node(currentpos, node) --octant 4\r
152                         currentpos[other2] = second2\r
153                         env:add_node(currentpos, node) --octant 5\r
154                         currentpos[other1] = first1\r
155                         env:add_node(currentpos, node) --octant 8\r
156                         local first1, first2 = pos[other1] + offset2, pos[other1] - offset2\r
157                         local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
158                         currentpos[other1], currentpos[other2] = first1, second1\r
159                         env:add_node(currentpos, node) --octant 2\r
160                         currentpos[other1] = first2\r
161                         env:add_node(currentpos, node) --octant 3\r
162                         currentpos[other2] = second2\r
163                         env:add_node(currentpos, node) --octant 6\r
164                         currentpos[other1] = first1\r
165                         env:add_node(currentpos, node) --octant 7\r
166 \r
167                         count = count + 8 --wip: broken\r
168 \r
169                         --move to next location\r
170                         delta = delta + (offset1 * 2) + 1\r
171                         if delta >= 0 then\r
172                                 offset2 = offset2 - 1\r
173                                 delta = delta - (offset2 * 2)\r
174                         end\r
175                         offset1 = offset1 + 1\r
176                 end\r
177                 currentpos[axis] = currentpos[axis] + step\r
178         end\r
179         return count\r
180 end\r
181 \r
182 --adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added\r
183 worldedit.cylinder = function(pos, axis, length, radius, nodename)\r
184         local other1, other2\r
185         if axis == "x" then\r
186                 other1, other2 = "y", "z"\r
187         elseif axis == "y" then\r
188                 other1, other2 = "x", "z"\r
189         else --axis == "z"\r
190                 other1, other2 = "x", "y"\r
191         end\r
192 \r
193         local env = minetest.env\r
194         local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
195         local node = {name=nodename}\r
196         local count = 0\r
197         local step = 1\r
198         if length < 0 then\r
199                 length = -length\r
200                 step = -1\r
201         end\r
202         for i = 1, length do\r
203                 local offset1, offset2 = 0, radius\r
204                 local delta = -radius\r
205                 while offset1 <= offset2 do\r
206                         --connect each pair of octants\r
207                         currentpos[other1] = pos[other1] - offset1\r
208                         local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
209                         for i = 0, offset1 * 2 do\r
210                                 currentpos[other2] = second1\r
211                                 env:add_node(currentpos, node) --octant 1 to 4\r
212                                 currentpos[other2] = second2\r
213                                 env:add_node(currentpos, node) --octant 5 to 8\r
214                                 currentpos[other1] = currentpos[other1] + 1\r
215                         end\r
216                         currentpos[other1] = pos[other1] - offset2\r
217                         local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
218                         for i = 0, offset2 * 2 do\r
219                                 currentpos[other2] = second1\r
220                                 env:add_node(currentpos, node) --octant 2 to 3\r
221                                 currentpos[other2] = second2\r
222                                 env:add_node(currentpos, node) --octant 6 to 7\r
223                                 currentpos[other1] = currentpos[other1] + 1\r
224                         end\r
225 \r
226                         count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken\r
227 \r
228                         --move to next location\r
229                         delta = delta + (offset1 * 2) + 1\r
230                         offset1 = offset1 + 1\r
231                         if delta >= 0 then\r
232                                 offset2 = offset2 - 1\r
233                                 delta = delta - (offset2 * 2)\r
234                         end\r
235                 end\r
236                 currentpos[axis] = currentpos[axis] + step\r
237         end\r
238         return count\r
239 end\r
240 \r
241 --adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added\r
242 worldedit.pyramid = function(pos, height, nodename)\r
243         local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height\r
244         local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height\r
245         local pos = {x=0, y=pos1y, z=0}\r
246 \r
247         local count = 0\r
248         local node = {name=nodename}\r
249         local env = minetest.env\r
250         while pos.y <= pos2y do --each vertical level of the pyramid\r
251                 pos.x = pos1x\r
252                 while pos.x <= pos2x do\r
253                         pos.z = pos1z\r
254                         while pos.z <= pos2z do\r
255                                 env:add_node(pos, node)\r
256                                 pos.z = pos.z + 1\r
257                         end\r
258                         pos.x = pos.x + 1\r
259                 end\r
260                 count = count + ((pos2y - pos.y) * 2 + 1) ^ 2\r
261                 pos.y = pos.y + 1\r
262 \r
263                 pos1x, pos2x = pos1x + 1, pos2x - 1\r
264                 pos1z, pos2z = pos1z + 1, pos2z - 1\r
265 \r
266         end\r
267         return count\r
268 end\r
269 \r
270 --adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added\r
271 worldedit.spiral = function(pos, width, height, spacer, nodename) --wip: clean this up\r
272         -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua\r
273         av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end\r
274         local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards\r
275                 if z == -x and z >= x then return (2*z+1)^2 end\r
276                 local l = math.max(av(z), av(x))\r
277                 return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT\r
278         end\r
279         local function spiralt(side)\r
280                 local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)\r
281                 for i = 1, side do\r
282                         for j = 1, side do\r
283                                 local id = side^2 - sindex(stop - i + 1,start + j - 1)\r
284                                 ret[id] = {x=i,z=j}\r
285                         end\r
286                 end\r
287                 return ret\r
288         end\r
289         -- connect the joined parts\r
290         local spiral = spiralt(width)\r
291         height = tonumber(height)\r
292         if height < 1 then height = 1 end\r
293         spacer = tonumber(spacer)-1\r
294         if spacer < 1 then spacer = 1 end\r
295         local count = 0\r
296         local node = {name=nodename}\r
297         local np,lp\r
298         for y=0,height do\r
299                 lp = nil\r
300                 for _,v in ipairs(spiral) do\r
301                         np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}\r
302                         if lp~=nil then\r
303                                 if lp.x~=np.x then \r
304                                         if lp.x<np.x then \r
305                                                 for i=lp.x+1,np.x do\r
306                                                         minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
307                                                         count = count + 1\r
308                                                 end\r
309                                         else\r
310                                                 for i=np.x,lp.x-1 do\r
311                                                         minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
312                                                         count = count + 1\r
313                                                 end\r
314                                         end\r
315                                 end\r
316                                 if lp.z~=np.z then \r
317                                         if lp.z<np.z then \r
318                                                 for i=lp.z+1,np.z do\r
319                                                         minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
320                                                         count = count + 1\r
321                                                 end\r
322                                         else\r
323                                                 for i=np.z,lp.z-1 do\r
324                                                         minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
325                                                         count = count + 1\r
326                                                 end\r
327                                         end\r
328                                 end\r
329                         end\r
330                         lp = np\r
331                 end\r
332         end\r
333         return count\r
334 end\r
335 \r
336 --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
337 worldedit.copy = function(pos1, pos2, axis, amount)\r
338         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
339         local env = minetest.env\r
340 \r
341         if amount < 0 then\r
342                 local pos = {x=pos1.x, y=0, z=0}\r
343                 while pos.x <= pos2.x do\r
344                         pos.y = pos1.y\r
345                         while pos.y <= pos2.y do\r
346                                 pos.z = pos1.z\r
347                                 while pos.z <= pos2.z do\r
348                                         local node = env:get_node(pos) --obtain current node\r
349                                         local meta = env:get_meta(pos):to_table() --get meta of current node\r
350                                         local value = pos[axis] --store current position\r
351                                         pos[axis] = value + amount --move along axis\r
352                                         env:add_node(pos, node) --copy node to new position\r
353                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
354                                         pos[axis] = value --restore old position\r
355                                         pos.z = pos.z + 1\r
356                                 end\r
357                                 pos.y = pos.y + 1\r
358                         end\r
359                         pos.x = pos.x + 1\r
360                 end\r
361         else\r
362                 local pos = {x=pos2.x, y=0, z=0}\r
363                 while pos.x >= pos1.x do\r
364                         pos.y = pos2.y\r
365                         while pos.y >= pos1.y do\r
366                                 pos.z = pos2.z\r
367                                 while pos.z >= pos1.z do\r
368                                         local node = minetest.env:get_node(pos) --obtain current node\r
369                                         local meta = env:get_meta(pos):to_table() --get meta of current node\r
370                                         local value = pos[axis] --store current position\r
371                                         pos[axis] = value + amount --move along axis\r
372                                         minetest.env:add_node(pos, node) --copy node to new position\r
373                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
374                                         pos[axis] = value --restore old position\r
375                                         pos.z = pos.z - 1\r
376                                 end\r
377                                 pos.y = pos.y - 1\r
378                         end\r
379                         pos.x = pos.x - 1\r
380                 end\r
381         end\r
382         return worldedit.volume(pos1, pos2)\r
383 end\r
384 \r
385 --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
386 worldedit.move = function(pos1, pos2, axis, amount)\r
387         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
388         local env = minetest.env\r
389 \r
390         if amount < 0 then\r
391                 local pos = {x=pos1.x, y=0, z=0}\r
392                 while pos.x <= pos2.x do\r
393                         pos.y = pos1.y\r
394                         while pos.y <= pos2.y do\r
395                                 pos.z = pos1.z\r
396                                 while pos.z <= pos2.z do\r
397                                         local node = env:get_node(pos) --obtain current node\r
398                                         local meta = env:get_meta(pos):to_table() --get metadata of current node\r
399                                         env:remove_node(pos)\r
400                                         local value = pos[axis] --store current position\r
401                                         pos[axis] = value + amount --move along axis\r
402                                         env:add_node(pos, node) --move node to new position\r
403                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
404                                         pos[axis] = value --restore old position\r
405                                         pos.z = pos.z + 1\r
406                                 end\r
407                                 pos.y = pos.y + 1\r
408                         end\r
409                         pos.x = pos.x + 1\r
410                 end\r
411         else\r
412                 local pos = {x=pos2.x, y=0, z=0}\r
413                 while pos.x >= pos1.x do\r
414                         pos.y = pos2.y\r
415                         while pos.y >= pos1.y do\r
416                                 pos.z = pos2.z\r
417                                 while pos.z >= pos1.z do\r
418                                         local node = env:get_node(pos) --obtain current node\r
419                                         local meta = env:get_meta(pos):to_table() --get metadata of current node\r
420                                         env:remove_node(pos)\r
421                                         local value = pos[axis] --store current position\r
422                                         pos[axis] = value + amount --move along axis\r
423                                         env:add_node(pos, node) --move node to new position\r
424                                         env:get_meta(pos):from_table(meta) --set metadata of new node\r
425                                         pos[axis] = value --restore old position\r
426                                         pos.z = pos.z - 1\r
427                                 end\r
428                                 pos.y = pos.y - 1\r
429                         end\r
430                         pos.x = pos.x - 1\r
431                 end\r
432         end\r
433         return worldedit.volume(pos1, pos2)\r
434 end\r
435 \r
436 --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
437 worldedit.stack = function(pos1, pos2, axis, count)\r
438         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
439         local length = pos2[axis] - pos1[axis] + 1\r
440         if count < 0 then\r
441                 count = -count\r
442                 length = -length\r
443         end\r
444         local amount = 0\r
445         local copy = worldedit.copy\r
446         for i = 1, count do\r
447                 amount = amount + length\r
448                 copy(pos1, pos2, axis, amount)\r
449         end\r
450         return worldedit.volume(pos1, pos2)\r
451 end\r
452 \r
453 --transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed\r
454 worldedit.transpose = function(pos1, pos2, axis1, axis2)\r
455         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
456 \r
457         local pos = {x=pos1.x, y=0, z=0}\r
458         local env = minetest.env\r
459         while pos.x <= pos2.x do\r
460                 pos.y = pos1.y\r
461                 while pos.y <= pos2.y do\r
462                         pos.z = pos1.z\r
463                         while pos.z <= pos2.z do\r
464                                 local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]\r
465                                 if extent1 < extent2 then\r
466                                         local node1 = env:get_node(pos)\r
467                                         local meta1 = env:get_meta(pos):to_table()\r
468                                         local value1, value2 = pos[axis1], pos[axis2]\r
469                                         pos[axis1], pos[axis2] = value1 + extent2, value2 + extent1\r
470                                         local node2 = env:get_node(pos)\r
471                                         local meta2 = env:get_meta(pos):to_table()\r
472                                         env:add_node(pos, node1)\r
473                                         env:get_meta(pos):from_table(meta1)\r
474                                         pos[axis1], pos[axis2] = value1, value2\r
475                                         env:add_node(pos, node2)\r
476                                         env:get_meta(pos):from_table(meta2)\r
477                                 end\r
478                                 pos.z = pos.z + 1\r
479                         end\r
480                         pos.y = pos.y + 1\r
481                 end\r
482                 pos.x = pos.x + 1\r
483         end\r
484         return worldedit.volume(pos1, pos2)\r
485 end\r
486 \r
487 --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
488 worldedit.flip = function(pos1, pos2, axis)\r
489         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
490 \r
491         local pos = {x=pos1.x, y=0, z=0}\r
492         local start = pos1[axis] + pos2[axis]\r
493         pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)\r
494         local env = minetest.env\r
495         while pos.x <= pos2.x do\r
496                 pos.y = pos1.y\r
497                 while pos.y <= pos2.y do\r
498                         pos.z = pos1.z\r
499                         while pos.z <= pos2.z do\r
500                                 local node1 = env:get_node(pos)\r
501                                 local meta1 = env:get_meta(pos):to_table()\r
502                                 local value = pos[axis]\r
503                                 pos[axis] = start - value\r
504                                 local node2 = env:get_node(pos)\r
505                                 local meta2 = env:get_meta(pos):to_table()\r
506                                 env:add_node(pos, node1)\r
507                                 env:get_meta(pos):from_table(meta1)\r
508                                 pos[axis] = value\r
509                                 env:add_node(pos, node2)\r
510                                 env:get_meta(pos):from_table(meta2)\r
511                                 pos.z = pos.z + 1\r
512                         end\r
513                         pos.y = pos.y + 1\r
514                 end\r
515                 pos.x = pos.x + 1\r
516         end\r
517         return worldedit.volume(pos1, pos2)\r
518 end\r
519 \r
520 --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
521 worldedit.rotate = function(pos1, pos2, axis, angle)\r
522         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
523 \r
524         local axis1, axis2\r
525         if axis == "x" then\r
526                 axis1, axis2 = "z", "y"\r
527         elseif axis == "y" then\r
528                 axis1, axis2 = "x", "z"\r
529         else --axis == "z"\r
530                 axis1, axis2 = "y", "x"\r
531         end\r
532         angle = angle % 360\r
533 \r
534         if angle == 90 then\r
535                 worldedit.transpose(pos1, pos2, axis1, axis2)\r
536                 worldedit.flip(pos1, pos2, axis2)\r
537         elseif angle == 180 then\r
538                 worldedit.flip(pos1, pos2, axis1)\r
539                 worldedit.flip(pos1, pos2, axis2)\r
540         elseif angle == 270 then\r
541                 worldedit.transpose(pos1, pos2, axis1, axis2)\r
542                 worldedit.flip(pos1, pos2, axis1)\r
543         end\r
544         return worldedit.volume(pos1, pos2)\r
545 end\r
546 \r
547 --digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug\r
548 worldedit.dig = function(pos1, pos2)\r
549         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
550         local env = minetest.env\r
551 \r
552         local pos = {x=pos1.x, y=0, z=0}\r
553         while pos.x <= pos2.x do\r
554                 pos.y = pos1.y\r
555                 while pos.y <= pos2.y do\r
556                         pos.z = pos1.z\r
557                         while pos.z <= pos2.z do\r
558                                 env:dig_node(pos)\r
559                                 pos.z = pos.z + 1\r
560                         end\r
561                         pos.y = pos.y + 1\r
562                 end\r
563                 pos.x = pos.x + 1\r
564         end\r
565         return worldedit.volume(pos1, pos2)\r
566 end\r
567 \r
568 --converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized\r
569 worldedit.serialize = function(pos1, pos2)\r
570         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
571         local pos = {x=pos1.x, y=0, z=0}\r
572         local count = 0\r
573         local result = {}\r
574         local env = minetest.env\r
575         while pos.x <= pos2.x do\r
576                 pos.y = pos1.y\r
577                 while pos.y <= pos2.y do\r
578                         pos.z = pos1.z\r
579                         while pos.z <= pos2.z do\r
580                                 local node = env:get_node(pos)\r
581                                 if node.name ~= "air" and node.name ~= "ignore" then\r
582                                         count = count + 1\r
583                                         result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2\r
584                                 end\r
585                                 pos.z = pos.z + 1\r
586                         end\r
587                         pos.y = pos.y + 1\r
588                 end\r
589                 pos.x = pos.x + 1\r
590         end\r
591         result = table.concat(result, "\n")\r
592         return result, count\r
593 end\r
594 \r
595 --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
596 worldedit.deserialize = function(originpos, value)\r
597         local pos = {x=0, y=0, z=0}\r
598         local node = {name="", param1=0, param2=0}\r
599         local count = 0\r
600         local env = minetest.env\r
601         for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do\r
602                 pos.x = originpos.x + tonumber(x)\r
603                 pos.y = originpos.y + tonumber(y)\r
604                 pos.z = originpos.z + tonumber(z)\r
605                 node.name = name\r
606                 node.param1 = param1\r
607                 node.param2 = param2\r
608                 env:add_node(pos, node)\r
609                 count = count + 1\r
610         end\r
611         return count\r
612 end\r
613 \r
614 --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
615 --based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)\r
616 worldedit.deserialize_old = function(originpos, value)\r
617         --obtain the node table\r
618         local count = 0\r
619         local get_tables = loadstring(value)\r
620         if get_tables == nil then --error loading value\r
621                 return count\r
622         end\r
623         local tables = get_tables()\r
624 \r
625         --transform the node table into an array of nodes\r
626         for i = 1, #tables do\r
627                 for j, v in pairs(tables[i]) do\r
628                         if type(v) == "table" then\r
629                                 tables[i][j] = tables[v[1]]\r
630                         end\r
631                 end\r
632         end\r
633 \r
634         --load the node array\r
635         local env = minetest.env\r
636         for i, v in ipairs(tables[1]) do\r
637                 local pos = v[1]\r
638                 pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z\r
639                 env:add_node(pos, v[2])\r
640                 count = count + 1\r
641         end\r
642         return count\r
643 end\r
644 \r
645 --saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved\r
646 worldedit.metasave = function(pos1, pos2, file) --wip: simply work with strings instead of doing IO\r
647         local path = minetest.get_worldpath() .. "/schems"\r
648         local filename = path .. "/" .. file .. ".wem"\r
649         os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
650         local rows = {}\r
651         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
652         local pos = {x=pos1.x, y=0, z=0}\r
653         local count = 0\r
654         local result = {}\r
655         local env = minetest.env\r
656         while pos.x <= pos2.x do\r
657                 pos.y = pos1.y\r
658                 while pos.y <= pos2.y do\r
659                         pos.z = pos1.z\r
660                         while pos.z <= pos2.z do\r
661                                 local node = env:get_node(pos)\r
662                                 if node.name ~= "air" and node.name ~= "ignore" then\r
663                                         count = count + 1\r
664                                         local row = {\r
665                                                 x = pos.x-pos1.x,\r
666                                                 y = pos.y-pos1.y,\r
667                                                 z = pos.z-pos1.z,\r
668                                                 name = node.name,\r
669                                                 param1 = node.param1,\r
670                                                 param2 = node.param2,\r
671                                                 meta = env:get_meta(pos):to_table(),\r
672                                         }\r
673                                         table.insert(rows, row)\r
674                                 end\r
675                                 pos.z = pos.z + 1\r
676                         end\r
677                         pos.y = pos.y + 1\r
678                 end\r
679                 pos.x = pos.x + 1\r
680         end\r
681         local err = table.save(rows,filename)\r
682         if err then return _,err end\r
683         return count\r
684 end\r
685 \r
686 --loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded\r
687 worldedit.metaload = function(pos1, file) --wip: simply work with strings instead of doing IO\r
688         local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"\r
689         local rows, err = table.load(filename)\r
690         if err then return _,err end\r
691         local pos = {x=0, y=0, z=0}\r
692         local node = {name="", param1=0, param2=0}\r
693         local count = 0\r
694         local env = minetest.env\r
695         for i,row in pairs(rows) do\r
696                 pos.x = pos1.x + tonumber(row.x)\r
697                 pos.y = pos1.y + tonumber(row.y)\r
698                 pos.z = pos1.z + tonumber(row.z)\r
699                 node.name = row.name\r
700                 node.param1 = row.param1\r
701                 node.param2 = row.param2\r
702                 env:add_node(pos, node)\r
703                 env:get_meta(pos):from_table(row.meta)\r
704                 count = count + 1\r
705         end\r
706         return count\r
707 end