]> git.lizzy.rs Git - worldedit.git/blob - worldedit_commands/init.lua
Revert "Use "we-" prefix for commands"
[worldedit.git] / worldedit_commands / init.lua
1 minetest.register_privilege("worldedit", "Can use WorldEdit commands")\r
2 \r
3 --wip: fold the hollow stuff into the main functions and add a hollow flag at the end, then add the compatibility stuff\r
4 \r
5 worldedit.set_pos = {}\r
6 worldedit.inspect = {}\r
7 \r
8 worldedit.pos1 = {}\r
9 worldedit.pos2 = {}\r
10 if minetest.place_schematic then\r
11         worldedit.prob_pos = {}\r
12         worldedit.prob_list = {}\r
13 end\r
14 \r
15 dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua")\r
16 dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua")\r
17 \r
18 local get_position = function(name) --position 1 retrieval function for when not using `safe_region`\r
19         local pos1 = worldedit.pos1[name]\r
20         if pos1 == nil then\r
21                 worldedit.player_notify(name, "no position 1 selected")\r
22         end\r
23         return pos1\r
24 end\r
25 \r
26 local get_node = function(name, nodename)\r
27         local node = worldedit.normalize_nodename(nodename)\r
28         if not node then\r
29                 worldedit.player_notify(name, "invalid node name: " .. nodename)\r
30                 return nil\r
31         end\r
32         return node\r
33 end\r
34 \r
35 worldedit.player_notify = function(name, message)\r
36         minetest.chat_send_player(name, "WorldEdit -!- " .. message, false)\r
37 end\r
38 \r
39 --determines whether `nodename` is a valid node name, returning a boolean\r
40 worldedit.normalize_nodename = function(nodename)\r
41         nodename = nodename:gsub("^%s*(.-)%s*$", "%1")\r
42         if nodename == "" then return nil end\r
43         local fullname = ItemStack({name=nodename}):get_name() --resolve aliases of node names to full names\r
44         if minetest.registered_nodes[fullname] or fullname == "air" then --directly found node name or alias of nodename\r
45                 return fullname\r
46         end\r
47         for key, value in pairs(minetest.registered_nodes) do\r
48                 if key:find(":" .. nodename, 1, true) then --found in mod\r
49                         return key\r
50                 end\r
51         end\r
52         nodename = nodename:lower() --lowercase both for case insensitive comparison\r
53         for key, value in pairs(minetest.registered_nodes) do\r
54                 if value.description:lower() == nodename then --found in description\r
55                         return key\r
56                 end\r
57         end\r
58         return nil\r
59 end\r
60 \r
61 --determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)\r
62 worldedit.player_axis = function(name)\r
63         local dir = minetest.get_player_by_name(name):get_look_dir()\r
64         local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)\r
65         if x > y then\r
66                 if x > z then\r
67                         return "x", dir.x > 0 and 1 or -1\r
68                 end\r
69         elseif y > z then\r
70                 return "y", dir.y > 0 and 1 or -1\r
71         end\r
72         return "z", dir.z > 0 and 1 or -1\r
73 end\r
74 \r
75 minetest.register_chatcommand("/about", {\r
76         params = "",\r
77         description = "Get information about the mod",\r
78         func = function(name, param)\r
79                 worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/MineTest-WorldEdit/")\r
80         end,\r
81 })\r
82 \r
83 minetest.register_chatcommand("/inspect", {\r
84         params = "on/off/1/0/true/false/yes/no/enable/disable/<blank>",\r
85         description = "Enable or disable node inspection",\r
86         privs = {worldedit=true},\r
87         func = function(name, param)\r
88                 if param == "on" or param == "1" or param == "true" or param == "yes" or param == "enable" or param == "" then\r
89                         worldedit.inspect[name] = true\r
90                         local axis, sign = worldedit.player_axis(name)\r
91                         worldedit.player_notify(name, string.format("inspector: inspection enabled for %s, currently facing the %s axis",\r
92                                 name, axis .. (sign > 0 and "+" or "-")))\r
93                 elseif param == "off" or param == "0" or param == "false" or param == "no" or param == "disable" then\r
94                         worldedit.inspect[name] = nil\r
95                         worldedit.player_notify(name, "inspector: inspection disabled")\r
96                 else\r
97                         worldedit.player_notify(name, "invalid usage: " .. param)\r
98                 end\r
99         end,\r
100 })\r
101 \r
102 minetest.register_on_punchnode(function(pos, node, puncher)\r
103         local name = puncher:get_player_name()\r
104         if worldedit.inspect[name] then\r
105                 if minetest.check_player_privs(name, {worldedit=true}) then\r
106                         local axis, sign = worldedit.player_axis(name)\r
107                         message = string.format("inspector: %s at %s (param1=%d, param2=%d) punched by %s facing the %s axis",\r
108                                 node.name, minetest.pos_to_string(pos), node.param1, node.param2, name, axis .. (sign > 0 and "+" or "-"))\r
109                 else\r
110                         message = "inspector: worldedit privileges required"\r
111                 end\r
112                 worldedit.player_notify(name, message)\r
113         end\r
114 end)\r
115 \r
116 minetest.register_chatcommand("/reset", {\r
117         params = "",\r
118         description = "Reset the region so that it is empty",\r
119         privs = {worldedit=true},\r
120         func = function(name, param)\r
121                 worldedit.pos1[name] = nil\r
122                 worldedit.pos2[name] = nil\r
123                 worldedit.mark_pos1(name)\r
124                 worldedit.mark_pos2(name)\r
125                 worldedit.set_pos[name] = nil\r
126                 worldedit.player_notify(name, "region reset")\r
127         end,\r
128 })\r
129 \r
130 minetest.register_chatcommand("/mark", {\r
131         params = "",\r
132         description = "Show markers at the region positions",\r
133         privs = {worldedit=true},\r
134         func = function(name, param)\r
135                 worldedit.mark_pos1(name)\r
136                 worldedit.mark_pos2(name)\r
137                 worldedit.player_notify(name, "region marked")\r
138         end,\r
139 })\r
140 \r
141 minetest.register_chatcommand("/unmark", {\r
142         params = "",\r
143         description = "Hide markers if currently shown",\r
144         privs = {worldedit=true},\r
145         func = function(name, param)\r
146                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
147                 worldedit.pos1[name] = nil\r
148                 worldedit.pos2[name] = nil\r
149                 worldedit.mark_pos1(name)\r
150                 worldedit.mark_pos2(name)\r
151                 worldedit.pos1[name] = pos1\r
152                 worldedit.pos2[name] = pos2\r
153                 worldedit.player_notify(name, "region unmarked")\r
154         end,\r
155 })\r
156 \r
157 minetest.register_chatcommand("/pos1", {\r
158         params = "",\r
159         description = "Set WorldEdit region position 1 to the player's location",\r
160         privs = {worldedit=true},\r
161         func = function(name, param)\r
162                 local pos = minetest.get_player_by_name(name):getpos()\r
163                 pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5)\r
164                 worldedit.pos1[name] = pos\r
165                 worldedit.mark_pos1(name)\r
166                 worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos))\r
167         end,\r
168 })\r
169 \r
170 minetest.register_chatcommand("/pos2", {\r
171         params = "",\r
172         description = "Set WorldEdit region position 2 to the player's location",\r
173         privs = {worldedit=true},\r
174         func = function(name, param)\r
175                 local pos = minetest.get_player_by_name(name):getpos()\r
176                 pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5)\r
177                 worldedit.pos2[name] = pos\r
178                 worldedit.mark_pos2(name)\r
179                 worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos))\r
180         end,\r
181 })\r
182 \r
183 minetest.register_chatcommand("/p", {\r
184         params = "set/set1/set2/get",\r
185         description = "Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region",\r
186         privs = {worldedit=true},\r
187         func = function(name, param)\r
188                 if param == "set" then --set both WorldEdit positions\r
189                         worldedit.set_pos[name] = "pos1"\r
190                         worldedit.player_notify(name, "select positions by punching two nodes")\r
191                 elseif param == "set1" then --set WorldEdit position 1\r
192                         worldedit.set_pos[name] = "pos1only"\r
193                         worldedit.player_notify(name, "select position 1 by punching a node")\r
194                 elseif param == "set2" then --set WorldEdit position 2\r
195                         worldedit.set_pos[name] = "pos2"\r
196                         worldedit.player_notify(name, "select position 2 by punching a node")\r
197                 elseif param == "get" then --display current WorldEdit positions\r
198                         if worldedit.pos1[name] ~= nil then\r
199                                 worldedit.player_notify(name, "position 1: " .. minetest.pos_to_string(worldedit.pos1[name]))\r
200                         else\r
201                                 worldedit.player_notify(name, "position 1 not set")\r
202                         end\r
203                         if worldedit.pos2[name] ~= nil then\r
204                                 worldedit.player_notify(name, "position 2: " .. minetest.pos_to_string(worldedit.pos2[name]))\r
205                         else\r
206                                 worldedit.player_notify(name, "position 2 not set")\r
207                         end\r
208                 else\r
209                         worldedit.player_notify(name, "unknown subcommand: " .. param)\r
210                 end\r
211         end,\r
212 })\r
213 \r
214 minetest.register_chatcommand("/fixedpos", {\r
215         params = "set1/set2 x y z",\r
216         description = "Set a WorldEdit region position to the position at (<x>, <y>, <z>)",\r
217         privs = {worldedit=true},\r
218         func = function(name, param)\r
219                 local found, _, flag, x, y, z = param:find("^(set[12])%s+([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)$")\r
220                 if found == nil then\r
221                         worldedit.player_notify(name, "invalid usage: " .. param)\r
222                         return\r
223                 end\r
224                 local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}\r
225                 if flag == "set1" then\r
226                         worldedit.pos1[name] = pos\r
227                         worldedit.mark_pos1(name)\r
228                         worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos))\r
229                 else --flag == "set2"\r
230                         worldedit.pos2[name] = pos\r
231                         worldedit.mark_pos2(name)\r
232                         worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos))\r
233                 end\r
234         end,\r
235 })\r
236 \r
237 minetest.register_on_punchnode(function(pos, node, puncher)\r
238         local name = puncher:get_player_name()\r
239         if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position\r
240                 if worldedit.set_pos[name] == "pos1" then --setting position 1\r
241                         worldedit.pos1[name] = pos\r
242                         worldedit.mark_pos1(name)\r
243                         worldedit.set_pos[name] = "pos2" --set position 2 on the next invocation\r
244                         worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos))\r
245                 elseif worldedit.set_pos[name] == "pos1only" then --setting position 1 only\r
246                         worldedit.pos1[name] = pos\r
247                         worldedit.mark_pos1(name)\r
248                         worldedit.set_pos[name] = nil --finished setting positions\r
249                         worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos))\r
250                 elseif worldedit.set_pos[name] == "pos2" then --setting position 2\r
251                         worldedit.pos2[name] = pos\r
252                         worldedit.mark_pos2(name)\r
253                         worldedit.set_pos[name] = nil --finished setting positions\r
254                         worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos))\r
255                 elseif worldedit.set_pos[name] == "prob" then --setting Minetest schematic node probabilities\r
256                         worldedit.prob_pos[name] = pos\r
257                         minetest.show_formspec(puncher:get_player_name(), "prob_val_enter", "field[text;;]")\r
258                 end\r
259         end\r
260 end)\r
261 \r
262 minetest.register_chatcommand("/volume", {\r
263         params = "",\r
264         description = "Display the volume of the current WorldEdit region",\r
265         privs = {worldedit=true},\r
266         func = function(name, param)\r
267                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
268                 if pos1 == nil or pos2 == nil then\r
269                         worldedit.player_notify(name, "no region selected")\r
270                         return nil\r
271                 end\r
272 \r
273                 local volume = worldedit.volume(pos1, pos2)\r
274                 local abs = math.abs\r
275                 worldedit.player_notify(name, "current region has a volume of " .. volume .. " nodes ("\r
276                         .. abs(pos2.x - pos1.x) + 1 .. "*"\r
277                         .. abs(pos2.y - pos1.y) + 1 .. "*"\r
278                         .. abs(pos2.z - pos1.z) + 1 .. ")")\r
279         end,\r
280 })\r
281 \r
282 minetest.register_chatcommand("/set", {\r
283         params = "<node>",\r
284         description = "Set the current WorldEdit region to <node>",\r
285         privs = {worldedit=true},\r
286         func = safe_region(function(name, param)\r
287                 local node = get_node(name, param)\r
288                 if not node then\r
289                         worldedit.player_notify(name, "Could not identify node \"" .. param .. "\"")\r
290                         return\r
291                 end\r
292 \r
293                 local count = worldedit.set(worldedit.pos1[name], worldedit.pos2[name], node)\r
294                 worldedit.player_notify(name, count .. " nodes set")\r
295         end, check_region),\r
296 })\r
297 \r
298 minetest.register_chatcommand("/mix", {\r
299         params = "<node1> ...",\r
300         description = "Fill the current WorldEdit region with a random mix of <node1>, ...",\r
301         privs = {worldedit=true},\r
302         func = safe_region(function(name, param)\r
303                 local nodes = {}\r
304                 for nodename in param:gmatch("[^%s]+") do\r
305                         local node = get_node(name, nodename)\r
306                         if not node then\r
307                                 worldedit.player_notify(name, "Could not identify node \"" .. name .. "\"")\r
308                                 return\r
309                         end\r
310                         nodes[#nodes + 1] = node\r
311                 end\r
312 \r
313                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
314                 local count = worldedit.set(pos1, pos2, nodes)\r
315                 worldedit.player_notify(name, count .. " nodes set")\r
316         end, check_region),\r
317 })\r
318 \r
319 local check_replace = function(name, param)\r
320         local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")\r
321         if found == nil then\r
322                 worldedit.player_notify(name, "invalid usage: " .. param)\r
323                 return nil\r
324         end\r
325         local newsearchnode = worldedit.normalize_nodename(searchnode)\r
326         if not newsearchnode then\r
327                 worldedit.player_notify(name, "invalid search node name: " .. searchnode)\r
328                 return nil\r
329         end\r
330         local newreplacenode = worldedit.normalize_nodename(replacenode)\r
331         if not newreplacenode then\r
332                 worldedit.player_notify(name, "invalid replace node name: " .. replacenode)\r
333                 return nil\r
334         end\r
335         return check_region(name, param)\r
336 end\r
337 \r
338 minetest.register_chatcommand("/replace", {\r
339         params = "<search node> <replace node>",\r
340         description = "Replace all instances of <search node> with <replace node> in the current WorldEdit region",\r
341         privs = {worldedit=true},\r
342         func = safe_region(function(name, param)\r
343                 local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")\r
344                 local newsearchnode = worldedit.normalize_nodename(searchnode)\r
345                 local newreplacenode = worldedit.normalize_nodename(replacenode)\r
346                 local count = worldedit.replace(worldedit.pos1[name], worldedit.pos2[name], newsearchnode, newreplacenode)\r
347                 worldedit.player_notify(name, count .. " nodes replaced")\r
348         end, check_replace),\r
349 })\r
350 \r
351 minetest.register_chatcommand("/replaceinverse", {\r
352         params = "<search node> <replace node>",\r
353         description = "Replace all nodes other than <search node> with <replace node> in the current WorldEdit region",\r
354         privs = {worldedit=true},\r
355         func = safe_region(function(name, param)\r
356                 local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")\r
357                 local newsearchnode = worldedit.normalize_nodename(searchnode)\r
358                 local newreplacenode = worldedit.normalize_nodename(replacenode)\r
359                 local count = worldedit.replaceinverse(worldedit.pos1[name], worldedit.pos2[name], searchnode, replacenode)\r
360                 worldedit.player_notify(name, count .. " nodes replaced")\r
361         end, check_replace),\r
362 })\r
363 \r
364 local check_sphere = function(name, param)\r
365         if worldedit.pos1[name] == nil then\r
366                 worldedit.player_notify(name, "no position 1 selected")\r
367                 return nil\r
368         end\r
369         local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
370         if found == nil then\r
371                 worldedit.player_notify(name, "invalid usage: " .. param)\r
372                 return nil\r
373         end\r
374         local node = get_node(name, nodename)\r
375         if not node then return nil end\r
376         return math.ceil((4 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of sphere\r
377 end\r
378 \r
379 minetest.register_chatcommand("/hollowsphere", {\r
380         params = "<radius> <node>",\r
381         description = "Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>",\r
382         privs = {worldedit=true},\r
383         func = safe_region(function(name, param)\r
384                 local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
385                 local node = get_node(name, nodename)\r
386                 local count = worldedit.hollow_sphere(worldedit.pos1[name], tonumber(radius), node)\r
387                 worldedit.player_notify(name, count .. " nodes added")\r
388         end, check_sphere),\r
389 })\r
390 \r
391 minetest.register_chatcommand("/sphere", {\r
392         params = "<radius> <node>",\r
393         description = "Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>",\r
394         privs = {worldedit=true},\r
395         func = safe_region(function(name, param)\r
396                 local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
397                 local node = get_node(name, nodename)\r
398                 local count = worldedit.sphere(worldedit.pos1[name], tonumber(radius), node)\r
399                 worldedit.player_notify(name, count .. " nodes added")\r
400         end, check_sphere),\r
401 })\r
402 \r
403 local check_dome = function(name, param)\r
404         if worldedit.pos1[name] == nil then\r
405                 worldedit.player_notify(name, "no position 1 selected")\r
406                 return nil\r
407         end\r
408         local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
409         if found == nil then\r
410                 worldedit.player_notify(name, "invalid usage: " .. param)\r
411                 return nil\r
412         end\r
413         local node = get_node(name, nodename)\r
414         if not node then return nil end\r
415         return math.ceil((2 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of dome\r
416 end\r
417 \r
418 minetest.register_chatcommand("/hollowdome", {\r
419         params = "<radius> <node>",\r
420         description = "Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>",\r
421         privs = {worldedit=true},\r
422         func = safe_region(function(name, param)\r
423                 local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
424                 local node = get_node(name, nodename)\r
425                 local count = worldedit.hollow_dome(worldedit.pos1[name], tonumber(radius), node)\r
426                 worldedit.player_notify(name, count .. " nodes added")\r
427         end, check_dome),\r
428 })\r
429 \r
430 minetest.register_chatcommand("/dome", {\r
431         params = "<radius> <node>",\r
432         description = "Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>",\r
433         privs = {worldedit=true},\r
434         func = safe_region(function(name, param)\r
435                 local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")\r
436                 local node = get_node(name, nodename)\r
437                 local count = worldedit.dome(worldedit.pos1[name], tonumber(radius), node)\r
438                 worldedit.player_notify(name, count .. " nodes added")\r
439         end, check_dome),\r
440 })\r
441 \r
442 local check_cylinder = function(name, param)\r
443         if worldedit.pos1[name] == nil then\r
444                 worldedit.player_notify(name, "no position 1 selected")\r
445                 return nil\r
446         end\r
447         local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")\r
448         if found == nil then\r
449                 worldedit.player_notify(name, "invalid usage: " .. param)\r
450                 return nil\r
451         end\r
452         local node = get_node(name, nodename)\r
453         if not node then return nil end\r
454         return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length))\r
455 end\r
456 \r
457 minetest.register_chatcommand("/hollowcylinder", {\r
458         params = "x/y/z/? <length> <radius> <node>",\r
459         description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
460         privs = {worldedit=true},\r
461         func = safe_region(function(name, param)\r
462                 local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")\r
463                 length = tonumber(length)\r
464                 if axis == "?" then\r
465                         axis, sign = worldedit.player_axis(name)\r
466                         length = length * sign\r
467                 end\r
468                 local node = get_node(name, nodename)\r
469                 local count = worldedit.hollow_cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node)\r
470                 worldedit.player_notify(name, count .. " nodes added")\r
471         end, check_cylinder),\r
472 })\r
473 \r
474 minetest.register_chatcommand("/cylinder", {\r
475         params = "x/y/z/? <length> <radius> <node>",\r
476         description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
477         privs = {worldedit=true},\r
478         func = safe_region(function(name, param)\r
479                 local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")\r
480                 length = tonumber(length)\r
481                 if axis == "?" then\r
482                         axis, sign = worldedit.player_axis(name)\r
483                         length = length * sign\r
484                 end\r
485                 local node = get_node(name, nodename)\r
486                 local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node)\r
487                 worldedit.player_notify(name, count .. " nodes added")\r
488         end, check_cylinder),\r
489 })\r
490 \r
491 minetest.register_chatcommand("/pyramid", {\r
492         params = "x/y/z/? <height> <node>",\r
493         description = "Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>",\r
494         privs = {worldedit=true},\r
495         func = safe_region(function(name, param)\r
496                 local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")\r
497                 height = tonumber(height)\r
498                 if axis == "?" then\r
499                         axis, sign = worldedit.player_axis(name)\r
500                         height = height * sign\r
501                 end\r
502                 local node = get_node(name, nodename)\r
503                 local count = worldedit.pyramid(worldedit.pos1[name], axis, height, node)\r
504                 worldedit.player_notify(name, count .. " nodes added")\r
505         end,\r
506         function(name, param)\r
507                 if worldedit.pos1[name] == nil then\r
508                         worldedit.player_notify(name, "no position 1 selected")\r
509                         return nil\r
510                 end\r
511                 local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")\r
512                 if found == nil then\r
513                         worldedit.player_notify(name, "invalid usage: " .. param)\r
514                         return nil\r
515                 end\r
516                 local node = get_node(name, nodename)\r
517                 if not node then return nil end\r
518                 height = tonumber(height)\r
519                 return math.ceil(((height * 2 + 1) ^ 2) * height / 3)\r
520         end),\r
521 })\r
522 \r
523 minetest.register_chatcommand("/spiral", {\r
524         params = "<length> <height> <space> <node>",\r
525         description = "Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>",\r
526         privs = {worldedit=true},\r
527         func = safe_region(function(name, param)\r
528                 local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")\r
529                 local node = get_node(name, nodename)\r
530                 local count = worldedit.spiral(worldedit.pos1[name], tonumber(length), tonumber(height), tonumber(space), node)\r
531                 worldedit.player_notify(name, count .. " nodes added")\r
532         end,\r
533         function(name, param)\r
534                 if worldedit.pos1[name] == nil then\r
535                         worldedit.player_notify(name, "no position 1 selected")\r
536                         return nil\r
537                 end\r
538                 local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")\r
539                 if found == nil then\r
540                         worldedit.player_notify(name, "invalid usage: " .. param)\r
541                         return nil\r
542                 end\r
543                 local node = get_node(name, nodename)\r
544                 if not node then return nil end\r
545                 return check_region(name, param)\r
546         end),\r
547 })\r
548 \r
549 minetest.register_chatcommand("/copy", {\r
550         params = "x/y/z/? <amount>",\r
551         description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
552         privs = {worldedit=true},\r
553         func = safe_region(function(name, param)\r
554                 local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
555                 if found == nil then\r
556                         worldedit.player_notify(name, "invalid usage: " .. param)\r
557                         return\r
558                 end\r
559                 amount = tonumber(amount)\r
560                 if axis == "?" then\r
561                         axis, sign = worldedit.player_axis(name)\r
562                         amount = amount * sign\r
563                 end\r
564 \r
565                 local count = worldedit.copy(worldedit.pos1[name], worldedit.pos2[name], axis, amount)\r
566                 worldedit.player_notify(name, count .. " nodes copied")\r
567         end,\r
568         function(name, param)\r
569                 local volume = check_region(name, param)\r
570                 return volume and volume * 2 or volume\r
571         end),\r
572 })\r
573 \r
574 minetest.register_chatcommand("/move", {\r
575         params = "x/y/z/? <amount>",\r
576         description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
577         privs = {worldedit=true},\r
578         func = safe_region(function(name, param)\r
579                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
580                 local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
581                 if found == nil then\r
582                         worldedit.player_notify(name, "invalid usage: " .. param)\r
583                         return\r
584                 end\r
585                 amount = tonumber(amount)\r
586                 if axis == "?" then\r
587                         axis, sign = worldedit.player_axis(name)\r
588                         amount = amount * sign\r
589                 end\r
590 \r
591                 local count = worldedit.move(pos1, pos2, axis, amount)\r
592 \r
593                 pos1[axis] = pos1[axis] + amount\r
594                 pos2[axis] = pos2[axis] + amount\r
595                 worldedit.mark_pos1(name)\r
596                 worldedit.mark_pos2(name)\r
597                 worldedit.player_notify(name, count .. " nodes moved")\r
598         end, check_region),\r
599 })\r
600 \r
601 minetest.register_chatcommand("/stack", {\r
602         params = "x/y/z/? <count>",\r
603         description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",\r
604         privs = {worldedit=true},\r
605         func = safe_region(function(name, param)\r
606                 local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
607                 repetitions = tonumber(repetitions)\r
608                 if axis == "?" then\r
609                         axis, sign = worldedit.player_axis(name)\r
610                         repetitions = repetitions * sign\r
611                 end\r
612                 local count = worldedit.stack(worldedit.pos1[name], worldedit.pos2[name], axis, repetitions)\r
613                 worldedit.player_notify(name, count .. " nodes stacked")\r
614         end,\r
615         function(name, param)\r
616                 local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
617                 if found == nil then\r
618                         worldedit.player_notify(name, "invalid usage: " .. param)\r
619                         return\r
620                 end\r
621                 local count = check_region(name, param)\r
622                 if count then return (tonumber(repetitions) + 1) * count end\r
623                 return nil\r
624         end),\r
625 })\r
626 \r
627 minetest.register_chatcommand("/stack2", {\r
628         params = "<count> <x> <y> <z>",\r
629         description = "Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>",\r
630         privs = {worldedit=true},\r
631         func = function(name, param)\r
632                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
633                 if pos1 == nil or pos2 == nil then\r
634                         worldedit.player_notify(name, "Select a position first!")\r
635                         return\r
636                 end\r
637                 local repetitions, incs = param:match("(%d+)%s*(.+)")\r
638                 if repetitions == nil then\r
639                         worldedit.player_notify(name, "invalid count: " .. param)\r
640                         return\r
641                 end\r
642                 repetitions = tonumber(repetitions)\r
643 \r
644                 local x, y, z = incs:match("([+-]?%d+) ([+-]%d+) ([+-]%d+)")\r
645                 if x == nil then\r
646                         worldedit.player_notify(name, "invalid increments: " .. param)\r
647                         return\r
648                 end\r
649                 x, y, z = tonumber(x), tonumber(y), tonumber(z)\r
650 \r
651                 local count = worldedit.volume(pos1, pos2) * repetitions\r
652 \r
653                 return safe_region(function()\r
654                         worldedit.stack2(pos1, pos2, {x=x, y=y, z=z}, repetitions,\r
655                                 function() worldedit.player_notify(name, count .. " nodes stacked") end)\r
656                 end, function()\r
657                         return count\r
658                 end)(name,param) -- more hax --wip: clean this up a little bit\r
659         end\r
660 })\r
661 \r
662 \r
663 minetest.register_chatcommand("/stretch", {\r
664         params = "<stretchx> <stretchy> <stretchz>",\r
665         description = "Scale the current WorldEdit positions and region by a factor of <stretchx>, <stretchy>, <stretchz> along the X, Y, and Z axes, repectively, with position 1 as the origin",\r
666         privs = {worldedit=true},\r
667         func = safe_region(function(name, param)\r
668                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
669                 local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$")\r
670                 stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)\r
671                 local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)\r
672 \r
673                 --reset markers to scaled positions\r
674                 worldedit.pos1[name] = pos1\r
675                 worldedit.pos2[name] = pos2\r
676                 worldedit.mark_pos1(name)\r
677                 worldedit.mark_pos2(name)\r
678 \r
679                 worldedit.player_notify(name, count .. " nodes stretched")\r
680         end,\r
681         function(name, param)\r
682                 local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$")\r
683                 if found == nil then\r
684                         worldedit.player_notify(name, "invalid usage: " .. param)\r
685                         return nil\r
686                 end\r
687                 stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)\r
688                 if stretchx == 0 or stretchy == 0 or stretchz == 0 then\r
689                         worldedit.player_notify(name, "invalid scaling factors: " .. param)\r
690                 end\r
691                 local count = check_region(name, param)\r
692                 if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end\r
693                 return nil\r
694         end),\r
695 })\r
696 \r
697 minetest.register_chatcommand("/transpose", {\r
698         params = "x/y/z/? x/y/z/?",\r
699         description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",\r
700         privs = {worldedit=true},\r
701         func = safe_region(function(name, param)\r
702                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
703                 local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")\r
704                 if axis1 == "?" then axis1 = worldedit.player_axis(name) end\r
705                 if axis2 == "?" then axis2 = worldedit.player_axis(name) end\r
706                 local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)\r
707 \r
708                 --reset markers to transposed positions\r
709                 worldedit.pos1[name] = pos1\r
710                 worldedit.pos2[name] = pos2\r
711                 worldedit.mark_pos1(name)\r
712                 worldedit.mark_pos2(name)\r
713 \r
714                 worldedit.player_notify(name, count .. " nodes transposed")\r
715         end,\r
716         function(name, param)\r
717                 local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")\r
718                 if found == nil then\r
719                         worldedit.player_notify(name, "invalid usage: " .. param)\r
720                         return nil\r
721                 end\r
722                 if axis1 == axis2 then\r
723                         worldedit.player_notify(name, "invalid usage: axes must be different")\r
724                         return nil\r
725                 end\r
726                 return check_region(name, param)\r
727         end),\r
728 })\r
729 \r
730 minetest.register_chatcommand("/flip", {\r
731         params = "x/y/z/?",\r
732         description = "Flip the current WorldEdit region along the x/y/z/? axis",\r
733         privs = {worldedit=true},\r
734         func = safe_region(function(name, param)\r
735                 if param == "?" then param = worldedit.player_axis(name) end\r
736                 local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[name], param)\r
737                 worldedit.player_notify(name, count .. " nodes flipped")\r
738         end,\r
739         function(name, param)\r
740                 if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then\r
741                         worldedit.player_notify(name, "invalid usage: " .. param)\r
742                         return nil\r
743                 end\r
744                 return check_region(name, param)\r
745         end),\r
746 })\r
747 \r
748 minetest.register_chatcommand("/rotate", {\r
749         params = "<axis> <angle>",\r
750         description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",\r
751         privs = {worldedit=true},\r
752         func = safe_region(function(name, param)\r
753                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
754                 local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
755                 if axis == "?" then axis = worldedit.player_axis(name) end\r
756                 local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)\r
757 \r
758                 --reset markers to rotated positions\r
759                 worldedit.pos1[name] = pos1\r
760                 worldedit.pos2[name] = pos2\r
761                 worldedit.mark_pos1(name)\r
762                 worldedit.mark_pos2(name)\r
763 \r
764                 worldedit.player_notify(name, count .. " nodes rotated")\r
765         end,\r
766         function(name, param)\r
767                 local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
768                 if found == nil then\r
769                         worldedit.player_notify(name, "invalid usage: " .. param)\r
770                         return nil\r
771                 end\r
772                 if angle % 90 ~= 0 then\r
773                         worldedit.player_notify(name, "invalid usage: angle must be multiple of 90")\r
774                         return nil\r
775                 end\r
776                 return check_region(name, param)\r
777         end),\r
778 })\r
779 \r
780 minetest.register_chatcommand("/orient", {\r
781         params = "<angle>",\r
782         description = "Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)",\r
783         privs = {worldedit=true},\r
784         func = safe_region(function(name, param)\r
785                 local found, _, angle = param:find("^([+-]?%d+)$")\r
786                 local count = worldedit.orient(worldedit.pos1[name], worldedit.pos2[name], angle)\r
787                 worldedit.player_notify(name, count .. " nodes oriented")\r
788         end,\r
789         function(name, param)\r
790                 local found, _, angle = param:find("^([+-]?%d+)$")\r
791                 if found == nil then\r
792                         worldedit.player_notify(name, "invalid usage: " .. param)\r
793                         return nil\r
794                 end\r
795                 if angle % 90 ~= 0 then\r
796                         worldedit.player_notify(name, "invalid usage: angle must be multiple of 90")\r
797                         return nil\r
798                 end\r
799                 return check_region(name, param)\r
800         end),\r
801 })\r
802 \r
803 minetest.register_chatcommand("/fixlight", {\r
804         params = "",\r
805         description = "Fix the lighting in the current WorldEdit region",\r
806         privs = {worldedit=true},\r
807         func = safe_region(function(name, param)\r
808                 local count = worldedit.fixlight(worldedit.pos1[name], worldedit.pos2[name])\r
809                 worldedit.player_notify(name, count .. " nodes updated")\r
810         end),\r
811 })\r
812 \r
813 minetest.register_chatcommand("/hide", {\r
814         params = "",\r
815         description = "Hide all nodes in the current WorldEdit region non-destructively",\r
816         privs = {worldedit=true},\r
817         func = safe_region(function(name, param)\r
818                 local count = worldedit.hide(worldedit.pos1[name], worldedit.pos2[name])\r
819                 worldedit.player_notify(name, count .. " nodes hidden")\r
820         end),\r
821 })\r
822 \r
823 minetest.register_chatcommand("/suppress", {\r
824         params = "<node>",\r
825         description = "Suppress all <node> in the current WorldEdit region non-destructively",\r
826         privs = {worldedit=true},\r
827         func = safe_region(function(name, param)\r
828                 local node = get_node(name, param)\r
829                 local count = worldedit.suppress(worldedit.pos1[name], worldedit.pos2[name], node)\r
830                 worldedit.player_notify(name, count .. " nodes suppressed")\r
831         end, check_set),\r
832 })\r
833 \r
834 minetest.register_chatcommand("/highlight", {\r
835         params = "<node>",\r
836         description = "Highlight <node> in the current WorldEdit region by hiding everything else non-destructively",\r
837         privs = {worldedit=true},\r
838         func = safe_region(function(name, param)\r
839                 local node = get_node(name, param)\r
840                 local count = worldedit.highlight(worldedit.pos1[name], worldedit.pos2[name], node)\r
841                 worldedit.player_notify(name, count .. " nodes highlighted")\r
842         end, check_set),\r
843 })\r
844 \r
845 minetest.register_chatcommand("/restore", {\r
846         params = "",\r
847         description = "Restores nodes hidden with WorldEdit in the current WorldEdit region",\r
848         privs = {worldedit=true},\r
849         func = safe_region(function(name, param)\r
850                 local count = worldedit.restore(worldedit.pos1[name], worldedit.pos2[name])\r
851                 worldedit.player_notify(name, count .. " nodes restored")\r
852         end),\r
853 })\r
854 \r
855 minetest.register_chatcommand("/save", {\r
856         params = "<file>",\r
857         description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",\r
858         privs = {worldedit=true},\r
859         func = safe_region(function(name, param)\r
860                 if param == "" then\r
861                         worldedit.player_notify(name, "invalid usage: " .. param)\r
862                         return\r
863                 end\r
864                 if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then\r
865                         worldedit.player_notify(name, "invalid file name: " .. param)\r
866                         return\r
867                 end\r
868 \r
869                 local result, count = worldedit.serialize(worldedit.pos1[name], worldedit.pos2[name])\r
870 \r
871                 local path = minetest.get_worldpath() .. "/schems"\r
872                 local filename = path .. "/" .. param .. ".we"\r
873                 filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters\r
874                 os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
875                 local file, err = io.open(filename, "wb")\r
876                 if err ~= nil then\r
877                         worldedit.player_notify(name, "could not save file to \"" .. filename .. "\"")\r
878                         return\r
879                 end\r
880                 file:write(result)\r
881                 file:flush()\r
882                 file:close()\r
883 \r
884                 worldedit.player_notify(name, count .. " nodes saved")\r
885         end),\r
886 })\r
887 \r
888 minetest.register_chatcommand("/allocate", {\r
889         params = "<file>",\r
890         description = "Set the region defined by nodes from \"(world folder)/schems/<file>.we\" as the current WorldEdit region",\r
891         privs = {worldedit=true},\r
892         func = function(name, param)\r
893                 local pos = get_position(name)\r
894                 if pos == nil then return end\r
895 \r
896                 if param == "" then\r
897                         worldedit.player_notify(name, "invalid usage: " .. param)\r
898                         return\r
899                 end\r
900                 if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then\r
901                         worldedit.player_notify(name, "invalid file name: " .. param)\r
902                         return\r
903                 end\r
904 \r
905                 local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"\r
906                 local file, err = io.open(filename, "rb")\r
907                 if err ~= nil then\r
908                         worldedit.player_notify(name, "could not open file \"" .. filename .. "\"")\r
909                         return\r
910                 end\r
911                 local value = file:read("*a")\r
912                 file:close()\r
913 \r
914                 local version = worldedit.read_header(value)\r
915                 if version == 0 then\r
916                         worldedit.player_notify(name, "File is invalid!")\r
917                         return\r
918                 elseif version > worldedit.LATEST_SERIALIZATION_VERSION then\r
919                         worldedit.player_notify(name, "File was created with newer version of WorldEdit!")\r
920                 end\r
921                 local nodepos1, nodepos2, count = worldedit.allocate(pos, value)\r
922 \r
923                 worldedit.pos1[name] = nodepos1\r
924                 worldedit.mark_pos1(name)\r
925                 worldedit.pos2[name] = nodepos2\r
926                 worldedit.mark_pos2(name)\r
927 \r
928                 worldedit.player_notify(name, count .. " nodes allocated")\r
929         end,\r
930 })\r
931 \r
932 minetest.register_chatcommand("/load", {\r
933         params = "<file>",\r
934         description = "Load nodes from \"(world folder)/schems/<file>[.we[m]]\" with position 1 of the current WorldEdit region as the origin",\r
935         privs = {worldedit=true},\r
936         func = function(name, param)\r
937                 local pos = get_position(name)\r
938                 if pos == nil then return end\r
939 \r
940                 if param == "" then\r
941                         worldedit.player_notify(name, "invalid usage: " .. param)\r
942                         return\r
943                 end\r
944                 if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then\r
945                         worldedit.player_notify(name, "invalid file name: " .. param)\r
946                         return\r
947                 end\r
948 \r
949                 --find the file in the world path\r
950                 local testpaths = {\r
951                         minetest.get_worldpath() .. "/schems/" .. param,\r
952                         minetest.get_worldpath() .. "/schems/" .. param .. ".we",\r
953                         minetest.get_worldpath() .. "/schems/" .. param .. ".wem",\r
954                 }\r
955                 local file, err\r
956                 for index, path in ipairs(testpaths) do\r
957                         file, err = io.open(path, "rb")\r
958                         if not err then\r
959                                 break\r
960                         end\r
961                 end\r
962                 if err then\r
963                         worldedit.player_notify(name, "could not open file \"" .. param .. "\"")\r
964                         return\r
965                 end\r
966                 local value = file:read("*a")\r
967                 file:close()\r
968 \r
969                 local version = worldedit.read_header(value)\r
970                 if version == 0 then\r
971                         worldedit.player_notify(name, "File is invalid!")\r
972                         return\r
973                 elseif version > worldedit.LATEST_SERIALIZATION_VERSION then\r
974                         worldedit.player_notify(name, "File was created with newer version of WorldEdit!")\r
975                         return\r
976                 end\r
977 \r
978                 local count = worldedit.deserialize(pos, value)\r
979 \r
980                 worldedit.player_notify(name, count .. " nodes loaded")\r
981         end,\r
982 })\r
983 \r
984 minetest.register_chatcommand("/lua", {\r
985         params = "<code>",\r
986         description = "Executes <code> as a Lua chunk in the global namespace",\r
987         privs = {worldedit=true, server=true},\r
988         func = function(name, param)\r
989                 local admin = minetest.setting_get("name")\r
990                 if not admin or not name == admin then\r
991                         worldedit.player_notify(name, "this command can only be run by the server administrator")\r
992                         return\r
993                 end\r
994                 local err = worldedit.lua(param)\r
995                 if err then\r
996                         worldedit.player_notify(name, "code error: " .. err)\r
997                 else\r
998                         worldedit.player_notify(name, "code successfully executed", false)\r
999                 end\r
1000         end,\r
1001 })\r
1002 \r
1003 minetest.register_chatcommand("/luatransform", {\r
1004         params = "<code>",\r
1005         description = "Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region",\r
1006         privs = {worldedit=true, server=true},\r
1007         func = safe_region(function(name, param)\r
1008                 local admin = minetest.setting_get("name")\r
1009                 if not admin or not name == admin then\r
1010                         worldedit.player_notify(name, "this command can only be run by the server administrator")\r
1011                         return\r
1012                 end\r
1013 \r
1014                 local err = worldedit.luatransform(worldedit.pos1[name], worldedit.pos2[name], param)\r
1015                 if err then\r
1016                         worldedit.player_notify(name, "code error: " .. err, false)\r
1017                 else\r
1018                         worldedit.player_notify(name, "code successfully executed", false)\r
1019                 end\r
1020         end),\r
1021 })\r
1022 \r
1023 minetest.register_chatcommand("/mtschemcreate", {\r
1024         params = "<file>",\r
1025         description = "Save the current WorldEdit region using the Minetest Schematic format to \"(world folder)/schems/<filename>.mts\"",\r
1026         privs = {worldedit=true},\r
1027         func = safe_region(function(name, param)\r
1028                 if param == nil then\r
1029                         worldedit.player_notify(name, "No filename specified")\r
1030                         return\r
1031                 end\r
1032 \r
1033                 local path = minetest.get_worldpath() .. "/schems"\r
1034                 local filename = path .. "/" .. param .. ".mts"\r
1035                 filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters\r
1036                 os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
1037 \r
1038                 local ret = minetest.create_schematic(worldedit.pos1[name], worldedit.pos2[name], worldedit.prob_list[name], filename)\r
1039                 if ret == nil then\r
1040                         worldedit.player_notify(name, "failed to create Minetest schematic", false)\r
1041                 else\r
1042                         worldedit.player_notify(name, "saved Minetest schematic to " .. param, false)\r
1043                 end\r
1044                 worldedit.prob_list[name] = {}\r
1045         end),\r
1046 })\r
1047 \r
1048 minetest.register_chatcommand("/mtschemplace", {\r
1049         params = "<file>",\r
1050         description = "Load nodes from \"(world folder)/schems/<file>.mts\" with position 1 of the current WorldEdit region as the origin",\r
1051         privs = {worldedit=true},\r
1052         func = function(name, param)\r
1053                 if param == nil then\r
1054                         worldedit.player_notify(name, "no filename specified")\r
1055                         return\r
1056                 end\r
1057 \r
1058                 local pos = get_position(name)\r
1059                 if pos == nil then return end\r
1060 \r
1061                 local path = minetest.get_worldpath() .. "/schems/" .. param .. ".mts"\r
1062                 if minetest.place_schematic(pos, path) == nil then\r
1063                         worldedit.player_notify(name, "failed to place Minetest schematic", false)\r
1064                 else\r
1065                         worldedit.player_notify(name, "placed Minetest schematic " .. param ..\r
1066                                 " at " .. minetest.pos_to_string(pos), false)\r
1067                 end\r
1068         end,\r
1069 })\r
1070 \r
1071 minetest.register_chatcommand("/mtschemprob", {\r
1072         params = "start/finish/get",\r
1073         description = "Begins node probability entry for Minetest schematics, gets the nodes that have probabilities set, or ends node probability entry",\r
1074         privs = {worldedit=true},\r
1075         func = function(name, param)\r
1076                 if param == "start" then --start probability setting\r
1077                         worldedit.set_pos[name] = "prob"\r
1078                         worldedit.prob_list[name] = {}\r
1079                         worldedit.player_notify(name, "select Minetest schematic probability values by punching nodes")\r
1080                 elseif param == "finish" then --finish probability setting\r
1081                         worldedit.set_pos[name] = nil\r
1082                         worldedit.player_notify(name, "finished Minetest schematic probability selection")\r
1083                 elseif param == "get" then --get all nodes that had probabilities set on them\r
1084                         local text = ""\r
1085                         local problist = worldedit.prob_list[name]\r
1086                         if problist == nil then\r
1087                                 return\r
1088                         end\r
1089                         for k,v in pairs(problist) do\r
1090                                 local prob = math.floor(((v["prob"] / 256) * 100) * 100 + 0.5) / 100\r
1091                                 text = text .. minetest.pos_to_string(v["pos"]) .. ": " .. prob .. "% | "\r
1092                         end\r
1093                         worldedit.player_notify(name, "currently set node probabilities:")\r
1094                         worldedit.player_notify(name, text)\r
1095                 else\r
1096                         worldedit.player_notify(name, "unknown subcommand: " .. param)\r
1097                 end\r
1098         end,\r
1099 })\r
1100 \r
1101 minetest.register_on_player_receive_fields(\r
1102         function(player, formname, fields)\r
1103                 if (formname == "prob_val_enter") and (fields.text ~= "") then\r
1104                         local name = player:get_player_name()\r
1105                         local prob_entry = {pos=worldedit.prob_pos[name], prob=tonumber(fields.text)}\r
1106                         local index = table.getn(worldedit.prob_list[name]) + 1\r
1107                         worldedit.prob_list[name][index] = prob_entry\r
1108                 end\r
1109         end\r
1110 )\r
1111 \r
1112 minetest.register_chatcommand("/clearobjects", {\r
1113         params = "",\r
1114         description = "Clears all objects within the WorldEdit region",\r
1115         privs = {worldedit=true},\r
1116         func = safe_region(function(name, param)\r
1117                 local count = worldedit.clearobjects(worldedit.pos1[name], worldedit.pos2[name])\r
1118                 worldedit.player_notify(name, count .. " objects cleared")\r
1119         end),\r
1120 })\r