]> git.lizzy.rs Git - worldedit.git/blob - worldedit/manipulations.lua
Improve node inspector to show player axis, replace //scale with //stretch, which...
[worldedit.git] / worldedit / manipulations.lua
1 worldedit = worldedit or {}\r
2 local minetest = minetest --local copy of global\r
3 \r
4 --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
5 worldedit.sort_pos = function(pos1, pos2)\r
6         pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
7         pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
8         if pos1.x > pos2.x then\r
9                 pos2.x, pos1.x = pos1.x, pos2.x\r
10         end\r
11         if pos1.y > pos2.y then\r
12                 pos2.y, pos1.y = pos1.y, pos2.y\r
13         end\r
14         if pos1.z > pos2.z then\r
15                 pos2.z, pos1.z = pos1.z, pos2.z\r
16         end\r
17         return pos1, pos2\r
18 end\r
19 \r
20 --determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
21 worldedit.volume = function(pos1, pos2)\r
22         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
23         return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
24 end\r
25 \r
26 --sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
27 worldedit.set = function(pos1, pos2, nodename)\r
28         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
29 \r
30         --set up voxel manipulator\r
31         local manip = minetest.get_voxel_manip()\r
32         local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)\r
33         local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})\r
34 \r
35         --fill emerged area with ignore\r
36         local nodes = {}\r
37         local ignore = minetest.get_content_id("ignore")\r
38         for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do\r
39                 nodes[i] = ignore\r
40         end\r
41 \r
42         --fill selected area with node\r
43         local node_id = minetest.get_content_id(nodename)\r
44         for i in area:iterp(pos1, pos2) do\r
45                 nodes[i] = node_id\r
46         end\r
47 \r
48         --update map nodes\r
49         manip:set_data(nodes)\r
50         manip:write_to_map()\r
51         manip:update_map()\r
52 \r
53         return worldedit.volume(pos1, pos2)\r
54 end\r
55 \r
56 --replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
57 worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
58         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
59 \r
60         --set up voxel manipulator\r
61         local manip = minetest.get_voxel_manip()\r
62         local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)\r
63         local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})\r
64 \r
65         local nodes = manip:get_data()\r
66         local searchnode_id = minetest.get_content_id(searchnode)\r
67         local replacenode_id = minetest.get_content_id(replacenode)\r
68         local count = 0\r
69         for i in area:iterp(pos1, pos2) do --replace searchnode with replacenode\r
70                 if nodes[i] == searchnode_id then\r
71                         nodes[i] = replacenode_id\r
72                         count = count + 1\r
73                 end\r
74         end\r
75 \r
76         --update map nodes\r
77         manip:set_data(nodes)\r
78         manip:write_to_map()\r
79         manip:update_map()\r
80 \r
81         return count\r
82 end\r
83 \r
84 --replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
85 worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode)\r
86         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
87 \r
88         --set up voxel manipulator\r
89         local manip = minetest.get_voxel_manip()\r
90         local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)\r
91         local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})\r
92 \r
93         local nodes = manip:get_data()\r
94         local searchnode_id = minetest.get_content_id(searchnode)\r
95         local replacenode_id = minetest.get_content_id(replacenode)\r
96         local count = 0\r
97         for i in area:iterp(pos1, pos2) do --replace anything that is not searchnode with replacenode\r
98                 if nodes[i] ~= searchnode_id then\r
99                         nodes[i] = replacenode_id\r
100                         count = count + 1\r
101                 end\r
102         end\r
103 \r
104         --update map nodes\r
105         manip:set_data(nodes)\r
106         manip:write_to_map()\r
107         manip:update_map()\r
108 \r
109         return count\r
110 end\r
111 \r
112 worldedit.copy = function(pos1, pos2, axis, amount) --wip: replace the old version below\r
113         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
114 \r
115         if amount == 0 then\r
116                 return\r
117         end\r
118 \r
119         local other1, other2\r
120         if axis == "x" then\r
121                 other1, other2 = "y", "z"\r
122         elseif axis == "y" then\r
123                 other1, other2 = "x", "z"\r
124         else --axis == "z"\r
125                 other1, other2 = "x", "y"\r
126         end\r
127 \r
128         --make area stay loaded\r
129         local manip = minetest.get_voxel_manip()\r
130         manip:read_from_map(pos1, pos2)\r
131 \r
132         --prepare slice along axis\r
133         local extent = {\r
134                 [axis] = 1,\r
135                 [other1]=pos2[other1] - pos1[other1] + 1,\r
136                 [other2]=pos2[other2] - pos1[other2] + 1,\r
137         }\r
138         local nodes = {}\r
139         local schematic = {size=extent, data=nodes}\r
140 \r
141         local currentpos = {x=pos1.x, y=pos1.y, z=pos1.z}\r
142         local stride = {x=1, y=extent.x, z=extent.x * extent.y}\r
143         local get_node = minetest.get_node\r
144         for index1 = 1, extent[axis] do --go through each slice\r
145                 --copy slice into schematic\r
146                 local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed\r
147                 for index2 = 1, extent[other1] do\r
148                         local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1]\r
149                         for index3 = 1, extent[other2] do\r
150                                 local i = newindex2 + (index3 + offset[other2]) * stride[other2]\r
151                                 local node = get_node(pos)\r
152                                 node.param1 = 255 --node will always appear\r
153                                 nodes[i] = node\r
154                         end\r
155                 end\r
156 \r
157                 --copy schematic to target\r
158                 currentpos[axis] = currentpos[axis] + amount\r
159                 place_schematic(currentpos, schematic)\r
160 \r
161                 --wip: copy meta\r
162 \r
163                 currentpos[axis] = currentpos[axis] + 1\r
164         end\r
165         return worldedit.volume(pos1, pos2)\r
166 end\r
167 \r
168 --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
169 worldedit.copy = function(pos1, pos2, axis, amount)\r
170         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
171 \r
172         --make area stay loaded\r
173         local manip = minetest.get_voxel_manip()\r
174         manip:read_from_map(pos1, pos2)\r
175 \r
176         local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node\r
177         if amount < 0 then\r
178                 local pos = {x=pos1.x, y=0, z=0}\r
179                 while pos.x <= pos2.x do\r
180                         pos.y = pos1.y\r
181                         while pos.y <= pos2.y do\r
182                                 pos.z = pos1.z\r
183                                 while pos.z <= pos2.z do\r
184                                         local node = get_node(pos) --obtain current node\r
185                                         local meta = get_meta(pos):to_table() --get meta of current node\r
186                                         local value = pos[axis] --store current position\r
187                                         pos[axis] = value + amount --move along axis\r
188                                         add_node(pos, node) --copy node to new position\r
189                                         get_meta(pos):from_table(meta) --set metadata of new node\r
190                                         pos[axis] = value --restore old position\r
191                                         pos.z = pos.z + 1\r
192                                 end\r
193                                 pos.y = pos.y + 1\r
194                         end\r
195                         pos.x = pos.x + 1\r
196                 end\r
197         else\r
198                 local pos = {x=pos2.x, y=0, z=0}\r
199                 while pos.x >= pos1.x do\r
200                         pos.y = pos2.y\r
201                         while pos.y >= pos1.y do\r
202                                 pos.z = pos2.z\r
203                                 while pos.z >= pos1.z do\r
204                                         local node = get_node(pos) --obtain current node\r
205                                         local meta = get_meta(pos):to_table() --get meta of current node\r
206                                         local value = pos[axis] --store current position\r
207                                         pos[axis] = value + amount --move along axis\r
208                                         add_node(pos, node) --copy node to new position\r
209                                         get_meta(pos):from_table(meta) --set metadata of new node\r
210                                         pos[axis] = value --restore old position\r
211                                         pos.z = pos.z - 1\r
212                                 end\r
213                                 pos.y = pos.y - 1\r
214                         end\r
215                         pos.x = pos.x - 1\r
216                 end\r
217         end\r
218         return worldedit.volume(pos1, pos2)\r
219 end\r
220 \r
221 --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
222 worldedit.move = function(pos1, pos2, axis, amount)\r
223         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
224 \r
225         --make area stay loaded\r
226         local manip = minetest.get_voxel_manip()\r
227         manip:read_from_map(pos1, pos2)\r
228 \r
229         --wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method)\r
230         local get_node, get_meta, add_node, remove_node = minetest.get_node, minetest.get_meta, minetest.add_node, minetest.remove_node\r
231         if amount < 0 then\r
232                 local pos = {x=pos1.x, y=0, z=0}\r
233                 while pos.x <= pos2.x do\r
234                         pos.y = pos1.y\r
235                         while pos.y <= pos2.y do\r
236                                 pos.z = pos1.z\r
237                                 while pos.z <= pos2.z do\r
238                                         local node = get_node(pos) --obtain current node\r
239                                         local meta = get_meta(pos):to_table() --get metadata of current node\r
240                                         remove_node(pos)\r
241                                         local value = pos[axis] --store current position\r
242                                         pos[axis] = value + amount --move along axis\r
243                                         add_node(pos, node) --move node to new position\r
244                                         get_meta(pos):from_table(meta) --set metadata of new node\r
245                                         pos[axis] = value --restore old position\r
246                                         pos.z = pos.z + 1\r
247                                 end\r
248                                 pos.y = pos.y + 1\r
249                         end\r
250                         pos.x = pos.x + 1\r
251                 end\r
252         else\r
253                 local pos = {x=pos2.x, y=0, z=0}\r
254                 while pos.x >= pos1.x do\r
255                         pos.y = pos2.y\r
256                         while pos.y >= pos1.y do\r
257                                 pos.z = pos2.z\r
258                                 while pos.z >= pos1.z do\r
259                                         local node = get_node(pos) --obtain current node\r
260                                         local meta = get_meta(pos):to_table() --get metadata of current node\r
261                                         remove_node(pos)\r
262                                         local value = pos[axis] --store current position\r
263                                         pos[axis] = value + amount --move along axis\r
264                                         add_node(pos, node) --move node to new position\r
265                                         get_meta(pos):from_table(meta) --set metadata of new node\r
266                                         pos[axis] = value --restore old position\r
267                                         pos.z = pos.z - 1\r
268                                 end\r
269                                 pos.y = pos.y - 1\r
270                         end\r
271                         pos.x = pos.x - 1\r
272                 end\r
273         end\r
274         return worldedit.volume(pos1, pos2)\r
275 end\r
276 \r
277 --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
278 worldedit.stack = function(pos1, pos2, axis, count)\r
279         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
280         local length = pos2[axis] - pos1[axis] + 1\r
281         if count < 0 then\r
282                 count = -count\r
283                 length = -length\r
284         end\r
285         local amount = 0\r
286         local copy = worldedit.copy\r
287         for i = 1, count do\r
288                 amount = amount + length\r
289                 copy(pos1, pos2, axis, amount)\r
290         end\r
291         return worldedit.volume(pos1, pos2) * count\r
292 end\r
293 \r
294 --stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2\r
295 worldedit.stretch = function(pos1, pos2, stretchx, stretchy, stretchz) --wip: test this\r
296         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
297 \r
298         --prepare schematic of large node\r
299         local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic\r
300         local placeholder_node = {name="", param1=255, param2=0}\r
301         local nodes = {}\r
302         for i = 1, stretchx * stretchy * stretchz do\r
303                 nodes[i] = placeholder_node\r
304         end\r
305         local schematic = {size={x=stretchx, y=stretchy, z=stretchz}, data=nodes}\r
306 \r
307         local sizex, sizey, sizez = stretchx - 1, stretchy - 1, stretchz - 1\r
308 \r
309         --make area stay loaded\r
310         local manip = minetest.get_voxel_manip()\r
311         local new_pos2 = {\r
312                 x=pos1.x + (pos2.x - pos1.x) * stretchx + sizex,\r
313                 y=pos1.y + (pos2.y - pos1.y) * stretchy + sizey,\r
314                 z=pos1.z + (pos2.z - pos1.z) * stretchz + sizez,\r
315         }\r
316         manip:read_from_map(pos1, new_pos2)\r
317 \r
318         local pos = {x=pos2.x, y=0, z=0}\r
319         local bigpos = {x=0, y=0, z=0}\r
320         while pos.x >= pos1.x do\r
321                 pos.y = pos2.y\r
322                 while pos.y >= pos1.y do\r
323                         pos.z = pos2.z\r
324                         while pos.z >= pos1.z do\r
325                                 local node = get_node(pos) --obtain current node\r
326                                 local meta = get_meta(pos):to_table() --get meta of current node\r
327 \r
328                                 --calculate far corner of the big node\r
329                                 local posx = pos1.x + (pos.x - pos1.x) * stretchx\r
330                                 local posy = pos1.y + (pos.y - pos1.y) * stretchy\r
331                                 local posz = pos1.z + (pos.z - pos1.z) * stretchz\r
332 \r
333                                 --create large node\r
334                                 placeholder_node.name = node.name\r
335                                 placeholder_node.param2 = node.param2\r
336                                 bigpos.x, bigpos.y, bigpos.z = posx, posy, posz\r
337                                 place_schematic(bigpos, schematic)\r
338 \r
339                                 --fill in large node meta\r
340                                 if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then --node has meta fields\r
341                                         for x = 0, sizex do\r
342                                                 for y = 0, sizey do\r
343                                                         for z = 0, sizez do\r
344                                                                 bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z\r
345                                                                 get_meta(bigpos):from_table(meta) --set metadata of new node\r
346                                                         end\r
347                                                 end\r
348                                         end\r
349                                 end\r
350                                 pos.z = pos.z - 1\r
351                         end\r
352                         pos.y = pos.y - 1\r
353                 end\r
354                 pos.x = pos.x - 1\r
355         end\r
356         return worldedit.volume(pos1, pos2) * stretchx * stretchy * stretchz, pos1, new_pos2\r
357 end\r
358 \r
359 --transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new transposed position 1, and the new transposed position 2\r
360 worldedit.transpose = function(pos1, pos2, axis1, axis2)\r
361         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
362 \r
363         local compare\r
364         local extent1, extent2 = pos2[axis1] - pos1[axis1], pos2[axis2] - pos1[axis2]\r
365 \r
366         if extent1 > extent2 then\r
367                 compare = function(extent1, extent2)\r
368                         return extent1 > extent2\r
369                 end\r
370         else\r
371                 compare = function(extent1, extent2)\r
372                         return extent1 < extent2\r
373                 end\r
374         end\r
375 \r
376         --calculate the new position 2 after transposition\r
377         local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
378         new_pos2[axis1] = pos1[axis1] + extent2\r
379         new_pos2[axis2] = pos1[axis2] + extent1\r
380 \r
381         --make area stay loaded\r
382         local manip = minetest.get_voxel_manip()\r
383         local upperbound = {x=pos2.x, y=pos2.y, z=pos2.z}\r
384         if upperbound[axis1] < new_pos2[axis1] then upperbound[axis1] = new_pos2[axis1] end\r
385         if upperbound[axis2] < new_pos2[axis2] then upperbound[axis2] = new_pos2[axis2] end\r
386         manip:read_from_map(pos1, upperbound)\r
387 \r
388         local pos = {x=pos1.x, y=0, z=0}\r
389         local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node\r
390         while pos.x <= pos2.x do\r
391                 pos.y = pos1.y\r
392                 while pos.y <= pos2.y do\r
393                         pos.z = pos1.z\r
394                         while pos.z <= pos2.z do\r
395                                 local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]\r
396                                 if compare(extent1, extent2) then --transpose only if below the diagonal\r
397                                         local node1 = get_node(pos)\r
398                                         local meta1 = get_meta(pos):to_table()\r
399                                         local value1, value2 = pos[axis1], pos[axis2] --save position values\r
400                                         pos[axis1], pos[axis2] = pos1[axis1] + extent2, pos1[axis2] + extent1 --swap axis extents\r
401                                         local node2 = get_node(pos)\r
402                                         local meta2 = get_meta(pos):to_table()\r
403                                         add_node(pos, node1)\r
404                                         get_meta(pos):from_table(meta1)\r
405                                         pos[axis1], pos[axis2] = value1, value2 --restore position values\r
406                                         add_node(pos, node2)\r
407                                         get_meta(pos):from_table(meta2)\r
408                                 end\r
409                                 pos.z = pos.z + 1\r
410                         end\r
411                         pos.y = pos.y + 1\r
412                 end\r
413                 pos.x = pos.x + 1\r
414         end\r
415         return worldedit.volume(pos1, pos2), pos1, new_pos2\r
416 end\r
417 \r
418 --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
419 worldedit.flip = function(pos1, pos2, axis)\r
420         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
421 \r
422         --make area stay loaded\r
423         local manip = minetest.get_voxel_manip()\r
424         manip:read_from_map(pos1, pos2)\r
425 \r
426         --wip: flip the region slice by slice along the flip axis using schematic method\r
427         local pos = {x=pos1.x, y=0, z=0}\r
428         local start = pos1[axis] + pos2[axis]\r
429         pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)\r
430         local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node\r
431         while pos.x <= pos2.x do\r
432                 pos.y = pos1.y\r
433                 while pos.y <= pos2.y do\r
434                         pos.z = pos1.z\r
435                         while pos.z <= pos2.z do\r
436                                 local node1 = get_node(pos)\r
437                                 local meta1 = get_meta(pos):to_table()\r
438                                 local value = pos[axis]\r
439                                 pos[axis] = start - value\r
440                                 local node2 = get_node(pos)\r
441                                 local meta2 = get_meta(pos):to_table()\r
442                                 add_node(pos, node1)\r
443                                 get_meta(pos):from_table(meta1)\r
444                                 pos[axis] = value\r
445                                 add_node(pos, node2)\r
446                                 get_meta(pos):from_table(meta2)\r
447                                 pos.z = pos.z + 1\r
448                         end\r
449                         pos.y = pos.y + 1\r
450                 end\r
451                 pos.x = pos.x + 1\r
452         end\r
453         return worldedit.volume(pos1, pos2)\r
454 end\r
455 \r
456 --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
457 worldedit.rotate = function(pos1, pos2, axis, angle)\r
458         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
459 \r
460         local axis1, axis2\r
461         if axis == "x" then\r
462                 axis1, axis2 = "z", "y"\r
463         elseif axis == "y" then\r
464                 axis1, axis2 = "x", "z"\r
465         else --axis == "z"\r
466                 axis1, axis2 = "y", "x"\r
467         end\r
468         angle = angle % 360\r
469 \r
470         local count\r
471         if angle == 90 then\r
472                 worldedit.flip(pos1, pos2, axis1)\r
473                 count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)\r
474         elseif angle == 180 then\r
475                 worldedit.flip(pos1, pos2, axis1)\r
476                 count = worldedit.flip(pos1, pos2, axis2)\r
477         elseif angle == 270 then\r
478                 worldedit.flip(pos1, pos2, axis2)\r
479                 count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)\r
480         end\r
481         return count, pos1, pos2\r
482 end\r
483 \r
484 --rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis, returning the number of nodes oriented\r
485 worldedit.orient = function(pos1, pos2, angle) --wip: support 6D facedir rotation along arbitrary axis\r
486         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
487         local registered_nodes = minetest.registered_nodes\r
488 \r
489         local wallmounted = {\r
490                 [90]={[0]=0, [1]=1, [2]=5, [3]=4, [4]=2, [5]=3},\r
491                 [180]={[0]=0, [1]=1, [2]=3, [3]=2, [4]=5, [5]=4},\r
492                 [270]={[0]=0, [1]=1, [2]=4, [3]=5, [4]=3, [5]=2}\r
493         }\r
494         local facedir = {\r
495                 [90]={[0]=1, [1]=2, [2]=3, [3]=0},\r
496                 [180]={[0]=2, [1]=3, [2]=0, [3]=1},\r
497                 [270]={[0]=3, [1]=0, [2]=1, [3]=2}\r
498         }\r
499 \r
500         angle = angle % 360\r
501         if angle == 0 then\r
502                 return 0\r
503         end\r
504         local wallmounted_substitution = wallmounted[angle]\r
505         local facedir_substitution = facedir[angle]\r
506 \r
507         --make area stay loaded\r
508         local manip = minetest.get_voxel_manip()\r
509         manip:read_from_map(pos1, pos2)\r
510 \r
511         local count = 0\r
512         local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node\r
513         local pos = {x=pos1.x, y=0, z=0}\r
514         while pos.x <= pos2.x do\r
515                 pos.y = pos1.y\r
516                 while pos.y <= pos2.y do\r
517                         pos.z = pos1.z\r
518                         while pos.z <= pos2.z do\r
519                                 local node = get_node(pos)\r
520                                 local def = registered_nodes[node.name]\r
521                                 if def then\r
522                                         if def.paramtype2 == "wallmounted" then\r
523                                                 node.param2 = wallmounted_substitution[node.param2]\r
524                                                 local meta = get_meta(pos):to_table()\r
525                                                 add_node(pos, node)\r
526                                                 get_meta(pos):from_table(meta)\r
527                                                 count = count + 1\r
528                                         elseif def.paramtype2 == "facedir" then\r
529                                                 node.param2 = facedir_substitution[node.param2]\r
530                                                 local meta = get_meta(pos):to_table()\r
531                                                 add_node(pos, node)\r
532                                                 get_meta(pos):from_table(meta)\r
533                                                 count = count + 1\r
534                                         end\r
535                                 end\r
536                                 pos.z = pos.z + 1\r
537                         end\r
538                         pos.y = pos.y + 1\r
539                 end\r
540                 pos.x = pos.x + 1\r
541         end\r
542         return count\r
543 end\r
544 \r
545 --fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated\r
546 worldedit.fixlight = function(pos1, pos2)\r
547         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
548 \r
549         --make area stay loaded\r
550         local manip = minetest.get_voxel_manip()\r
551         manip:read_from_map(pos1, pos2)\r
552 \r
553         local nodes = minetest.find_nodes_in_area(pos1, pos2, "air")\r
554         local dig_node = minetest.dig_node\r
555         for _, pos in ipairs(nodes) do\r
556                 dig_node(pos)\r
557         end\r
558         return #nodes\r
559 end\r
560 \r
561 --clears all objects in a region defined by the positions `pos1` and `pos2`, returning the number of objects cleared\r
562 worldedit.clearobjects = function(pos1, pos2)\r
563         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
564 \r
565         --make area stay loaded\r
566         local manip = minetest.get_voxel_manip()\r
567         manip:read_from_map(pos1, pos2)\r
568 \r
569         local pos1x, pos1y, pos1z = pos1.x, pos1.y, pos1.z\r
570         local pos2x, pos2y, pos2z = pos2.x + 1, pos2.y + 1, pos2.z + 1\r
571         local center = {x=(pos1x + pos2x) / 2, y=(pos1y + pos2y) / 2, z=(pos1z + pos2z) / 2} --center of region\r
572         local radius = ((center.x - pos1x + 0.5) + (center.y - pos1y + 0.5) + (center.z - pos1z + 0.5)) ^ 0.5 --bounding sphere radius\r
573         local count = 0\r
574         for _, obj in pairs(minetest.get_objects_inside_radius(center, radius)) do --all objects in bounding sphere\r
575                 local entity = obj:get_luaentity()\r
576                 if not (entity and entity.name:find("^worldedit:")) then --avoid WorldEdit entities\r
577                         local pos = obj:getpos()\r
578                         if pos.x >= pos1x and pos.x <= pos2x\r
579                         and pos.y >= pos1y and pos.y <= pos2y\r
580                         and pos.z >= pos1z and pos.z <= pos2z then --inside region\r
581                                 obj:remove()\r
582                                 count = count + 1\r
583                         end\r
584                 end\r
585         end\r
586         return count\r
587 end\r