]> git.lizzy.rs Git - worldedit.git/blob - init.lua
1948bcf5c4dfe374135a51eda47245a59d7224e0
[worldedit.git] / init.lua
1 minetest.register_privilege("worldedit", "Can use WorldEdit commands")\r
2 \r
3 worldedit = {}\r
4 \r
5 worldedit.set_pos = {}\r
6 \r
7 worldedit.pos1 = {}\r
8 worldedit.pos2 = {}\r
9 \r
10 dofile(minetest.get_modpath("worldedit") .. "/functions.lua")\r
11 dofile(minetest.get_modpath("worldedit") .. "/mark.lua")\r
12 \r
13 --determines whether `nodename` is a valid node name, returning a boolean\r
14 worldedit.node_is_valid = function(temp_pos, nodename)\r
15         return minetest.registered_nodes[nodename] ~= nil\r
16         or minetest.registered_nodes["default:" .. nodename] ~= nil\r
17 end\r
18 \r
19 --determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)\r
20 worldedit.player_axis = function(name)\r
21         local dir = minetest.env:get_player_by_name(name):get_look_dir()\r
22         local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)\r
23         if x > y then\r
24                 if x > z then\r
25                         return "x", dir.x > 0 and 1 or -1\r
26                 end\r
27         elseif y > z then\r
28                 return "y", dir.y > 0 and 1 or -1\r
29         end\r
30         return "z", dir.z > 0 and 1 or -1\r
31 end\r
32 \r
33 minetest.register_chatcommand("/reset", {\r
34         params = "",\r
35         description = "Reset the region so that it is empty",\r
36         privs = {worldedit=true},\r
37         func = function(name, param)\r
38                 worldedit.pos1[name] = nil\r
39                 worldedit.pos2[name] = nil\r
40                 worldedit.mark_pos1(name)\r
41                 worldedit.mark_pos2(name)\r
42                 minetest.chat_send_player(name, "WorldEdit region reset")\r
43         end,\r
44 })\r
45 \r
46 minetest.register_chatcommand("/mark", {\r
47         params = "",\r
48         description = "Show markers at the region positions",\r
49         privs = {worldedit=true},\r
50         func = function(name, param)\r
51                 worldedit.mark_pos1(name)\r
52                 worldedit.mark_pos2(name)\r
53                 minetest.chat_send_player(name, "WorldEdit region marked")\r
54         end,\r
55 })\r
56 \r
57 minetest.register_chatcommand("/pos1", {\r
58         params = "",\r
59         description = "Set WorldEdit region position 1 to the player's location",\r
60         privs = {worldedit=true},\r
61         func = function(name, param)\r
62                 local pos = minetest.env:get_player_by_name(name):getpos()\r
63                 pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
64                 worldedit.pos1[name] = pos\r
65                 worldedit.mark_pos1(name)\r
66                 minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos))\r
67         end,\r
68 })\r
69 \r
70 minetest.register_chatcommand("/pos2", {\r
71         params = "",\r
72         description = "Set WorldEdit region position 2 to the player's location",\r
73         privs = {worldedit=true},\r
74         func = function(name, param)\r
75                 local pos = minetest.env:get_player_by_name(name):getpos()\r
76                 pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
77                 worldedit.pos2[name] = pos\r
78                 worldedit.mark_pos2(name)\r
79                 minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos))\r
80         end,\r
81 })\r
82 \r
83 minetest.register_chatcommand("/p", {\r
84         params = "set/get",\r
85         description = "Set WorldEdit region by punching two nodes, or display the current WorldEdit region",\r
86         privs = {worldedit=true},\r
87         func = function(name, param)\r
88                 if param == "set" then --set both WorldEdit positions\r
89                         worldedit.set_pos[name] = 1\r
90                         minetest.chat_send_player(name, "Select positions by punching two nodes")\r
91                 elseif param == "get" then --display current WorldEdit positions\r
92                         if worldedit.pos1[name] ~= nil then\r
93                                 minetest.chat_send_player(name, "WorldEdit position 1: " .. minetest.pos_to_string(worldedit.pos1[name]))\r
94                         else\r
95                                 minetest.chat_send_player(name, "WorldEdit position 1 not set")\r
96                         end\r
97                         if worldedit.pos2[name] ~= nil then\r
98                                 minetest.chat_send_player(name, "WorldEdit position 2: " .. minetest.pos_to_string(worldedit.pos2[name]))\r
99                         else\r
100                                 minetest.chat_send_player(name, "WorldEdit position 2 not set")\r
101                         end\r
102                 else\r
103                         minetest.chat_send_player(name, "Unknown subcommand: " .. param)\r
104                 end\r
105         end,\r
106 })\r
107 \r
108 minetest.register_on_punchnode(function(pos, node, puncher)\r
109         local name = puncher:get_player_name()\r
110         if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position\r
111                 if worldedit.set_pos[name] == 1 then --setting position 1\r
112                         worldedit.set_pos[name] = 2 --set position 2 on the next invocation\r
113                         worldedit.pos1[name] = pos\r
114                         worldedit.mark_pos1(name)\r
115                         minetest.chat_send_player(name, "WorldEdit region position 1 set to " .. minetest.pos_to_string(pos))\r
116                 else --setting position 2\r
117                         worldedit.set_pos[name] = nil --finished setting positions\r
118                         worldedit.pos2[name] = pos\r
119                         worldedit.mark_pos2(name)\r
120                         minetest.chat_send_player(name, "WorldEdit region position 2 set to " .. minetest.pos_to_string(pos))\r
121                 end\r
122         end\r
123 end)\r
124 \r
125 minetest.register_chatcommand("/volume", {\r
126         params = "",\r
127         description = "Display the volume of the current WorldEdit region",\r
128         privs = {worldedit=true},\r
129         func = function(name, param)\r
130                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
131                 if pos1 == nil or pos2 == nil then\r
132                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
133                         return\r
134                 end\r
135 \r
136                 local volume = worldedit.volume(pos1, pos2)\r
137                 minetest.chat_send_player(name, "Current WorldEdit region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")")\r
138         end,\r
139 })\r
140 \r
141 minetest.register_chatcommand("/set", {\r
142         params = "<node>",\r
143         description = "Set the current WorldEdit region to <node>",\r
144         privs = {worldedit=true},\r
145         func = function(name, param)\r
146                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
147                 if pos1 == nil or pos2 == nil then\r
148                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
149                         return\r
150                 end\r
151 \r
152                 if param == "" or not worldedit.node_is_valid(pos1, param) then\r
153                         minetest.chat_send_player(name, "Invalid node name: " .. param)\r
154                         return\r
155                 end\r
156 \r
157                 local count = worldedit.set(pos1, pos2, param)\r
158                 minetest.chat_send_player(name, count .. " nodes set")\r
159         end,\r
160 })\r
161 \r
162 minetest.register_chatcommand("/replace", {\r
163         params = "<search node> <replace node>",\r
164         description = "Replace all instances of <search node> with <place node> in the current WorldEdit region",\r
165         privs = {worldedit=true},\r
166         func = function(name, param)\r
167                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
168                 if pos1 == nil or pos2 == nil then\r
169                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
170                         return\r
171                 end\r
172 \r
173                 local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")\r
174                 if found == nil then\r
175                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
176                         return\r
177                 end\r
178                 if not worldedit.node_is_valid(pos1, searchnode) then\r
179                         minetest.chat_send_player(name, "Invalid search node name: " .. searchnode)\r
180                         return\r
181                 end\r
182                 if not worldedit.node_is_valid(pos1, replacenode) then\r
183                         minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode)\r
184                         return\r
185                 end\r
186 \r
187                 local count = worldedit.replace(pos1, pos2, searchnode, replacenode)\r
188                 minetest.chat_send_player(name, count .. " nodes replaced")\r
189         end,\r
190 })\r
191 \r
192 minetest.register_chatcommand("/hollowcylinder", {\r
193         params = "x/y/z/? <length> <radius> <node>",\r
194         description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
195         privs = {worldedit=true},\r
196         func = function(name, param)\r
197                 local pos = worldedit.pos1[name]\r
198                 if pos == nil then\r
199                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
200                         return\r
201                 end\r
202 \r
203                 local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
204                 if found == nil then\r
205                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
206                         return\r
207                 end\r
208                 if axis == "?" then\r
209                         axis, sign = worldedit.player_axis(name)\r
210                         length = length * sign\r
211                 end\r
212                 if not worldedit.node_is_valid(pos, nodename) then\r
213                         minetest.chat_send_player(name, "Invalid node name: " .. param)\r
214                         return\r
215                 end\r
216 \r
217                 local count = worldedit.hollow_cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
218                 minetest.chat_send_player(name, count .. " nodes added")\r
219         end,\r
220 })\r
221 \r
222 minetest.register_chatcommand("/spiral", {\r
223         params = "<size> <node>",\r
224         description = "Add spiral at WorldEdit position 1 with size <size>, composed of <node>",\r
225         privs = {worldedit=true},\r
226         func = function(name, param)\r
227                 local pos = worldedit.pos1[name]\r
228                 if pos == nil then\r
229                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
230                         return\r
231                 end\r
232 \r
233                 local found, _, size, nodename = param:find("(%d+)%s+([^%s]+)$")\r
234                 if found == nil then\r
235                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
236                         return\r
237                 end\r
238                 if not worldedit.node_is_valid(pos, nodename) then\r
239                         minetest.chat_send_player(name, "Invalid node name: " .. param)\r
240                         return\r
241                 end\r
242 \r
243                 local count = worldedit.spiral(pos, tonumber(size), nodename)\r
244                 minetest.chat_send_player(name, count .. " nodes changed")\r
245         end,\r
246 })\r
247 \r
248 minetest.register_chatcommand("/cylinder", {\r
249         params = "x/y/z/? <length> <radius> <node>",\r
250         description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
251         privs = {worldedit=true},\r
252         func = function(name, param)\r
253                 local pos = worldedit.pos1[name]\r
254                 if pos == nil then\r
255                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
256                         return\r
257                 end\r
258 \r
259                 local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
260                 if found == nil then\r
261                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
262                         return\r
263                 end\r
264                 if axis == "?" then\r
265                         axis, sign = worldedit.player_axis(name)\r
266                         length = length * sign\r
267                 end\r
268                 if not worldedit.node_is_valid(pos, nodename) then\r
269                         minetest.chat_send_player(name, "Invalid node name: " .. param)\r
270                         return\r
271                 end\r
272 \r
273                 local count = worldedit.cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
274                 minetest.chat_send_player(name, count .. " nodes added")\r
275         end,\r
276 })\r
277 \r
278 minetest.register_chatcommand("/copy", {\r
279         params = "x/y/z/? <amount>",\r
280         description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
281         privs = {worldedit=true},\r
282         func = function(name, param)\r
283                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
284                 if pos1 == nil or pos2 == nil then\r
285                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
286                         return\r
287                 end\r
288 \r
289                 local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
290                 if found == nil then\r
291                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
292                         return\r
293                 end\r
294                 if axis == "?" then\r
295                         axis, sign = worldedit.player_axis(name)\r
296                         amount = amount * sign\r
297                 end\r
298 \r
299                 local count = worldedit.copy(pos1, pos2, axis, tonumber(amount))\r
300                 minetest.chat_send_player(name, count .. " nodes copied")\r
301         end,\r
302 })\r
303 \r
304 minetest.register_chatcommand("/move", {\r
305         params = "x/y/z/? <amount>",\r
306         description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
307         privs = {worldedit=true},\r
308         func = function(name, param)\r
309                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
310                 if pos1 == nil or pos2 == nil then\r
311                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
312                         return\r
313                 end\r
314 \r
315                 local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
316                 if found == nil then\r
317                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
318                         return\r
319                 end\r
320                 if axis == "?" then\r
321                         axis, sign = worldedit.player_axis(name)\r
322                         amount = amount * sign\r
323                 end\r
324 \r
325                 local count = worldedit.move(pos1, pos2, axis, tonumber(amount))\r
326 \r
327                 worldedit.pos1[name][axis] = worldedit.pos1[name][axis] + amount\r
328                 worldedit.pos2[name][axis] = worldedit.pos2[name][axis] + amount\r
329                 worldedit.mark_pos1(name)\r
330                 worldedit.mark_pos2(name)\r
331 \r
332                 minetest.chat_send_player(name, count .. " nodes moved")\r
333         end,\r
334 })\r
335 \r
336 minetest.register_chatcommand("/stack", {\r
337         params = "x/y/z/? <count>",\r
338         description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",\r
339         privs = {worldedit=true},\r
340         func = function(name, param)\r
341                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
342                 if pos1 == nil or pos2 == nil then\r
343                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
344                         return\r
345                 end\r
346 \r
347                 local found, _, axis, count = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
348                 if found == nil then\r
349                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
350                         return\r
351                 end\r
352                 if axis == "?" then\r
353                         axis, sign = worldedit.player_axis(name)\r
354                         count = count * sign\r
355                 end\r
356 \r
357                 local count = worldedit.stack(pos1, pos2, axis, tonumber(count))\r
358                 minetest.chat_send_player(name, count .. " nodes stacked")\r
359         end,\r
360 })\r
361 \r
362 minetest.register_chatcommand("/transpose", {\r
363         params = "x/y/z/? x/y/z/?",\r
364         description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",\r
365         privs = {worldedit=true},\r
366         func = function(name, param)\r
367                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
368                 if pos1 == nil or pos2 == nil then\r
369                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
370                         return\r
371                 end\r
372 \r
373                 local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")\r
374                 if found == nil then\r
375                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
376                         return\r
377                 end\r
378                 if axis1 == "?" then\r
379                         axis1 = worldedit.player_axis(name)\r
380                 end\r
381                 if axis2 == "?" then\r
382                         axis2 = worldedit.player_axis(name)\r
383                 end\r
384                 if axis1 == axis2 then\r
385                         minetest.chat_send_player(name, "Invalid usage: axes are the same")\r
386                         return\r
387                 end\r
388 \r
389                 local count = worldedit.transpose(pos1, pos2, axis1, axis2)\r
390                 minetest.chat_send_player(name, count .. " nodes transposed")\r
391         end,\r
392 })\r
393 \r
394 minetest.register_chatcommand("/flip", {\r
395         params = "x/y/z/?",\r
396         description = "Flip the current WorldEdit region along the x/y/z/? axis",\r
397         privs = {worldedit=true},\r
398         func = function(name, param)\r
399                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
400                 if pos1 == nil or pos2 == nil then\r
401                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
402                         return\r
403                 end\r
404 \r
405                 if param == "?" then\r
406                         param = worldedit.player_axis(name)\r
407                 end\r
408                 if param ~= "x" and param ~= "y" and param ~= "z" then\r
409                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
410                         return\r
411                 end\r
412 \r
413                 local count = worldedit.flip(pos1, pos2, param)\r
414                 minetest.chat_send_player(name, count .. " nodes flipped")\r
415         end,\r
416 })\r
417 \r
418 minetest.register_chatcommand("/rotate", {\r
419         params = "<axis> <angle>",\r
420         description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",\r
421         privs = {worldedit=true},\r
422         func = function(name, param)\r
423                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
424                 if pos1 == nil or pos2 == nil then\r
425                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
426                         return\r
427                 end\r
428 \r
429                 local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
430                 if found == nil then\r
431                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
432                         return\r
433                 end\r
434                 if axis == "?" then\r
435                         axis = worldedit.player_axis(name)\r
436                 end\r
437                 if angle % 90 ~= 0 then\r
438                         minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90")\r
439                         return\r
440                 end\r
441 \r
442                 local count = worldedit.rotate(pos1, pos2, axis, angle)\r
443                 minetest.chat_send_player(name, count .. " nodes rotated")\r
444         end,\r
445 })\r
446 \r
447 minetest.register_chatcommand("/dig", {\r
448         params = "",\r
449         description = "Dig the current WorldEdit region",\r
450         privs = {worldedit=true},\r
451         func = function(name, param)\r
452                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
453                 if pos1 == nil or pos2 == nil then\r
454                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
455                         return\r
456                 end\r
457 \r
458                 local count = worldedit.dig(pos1, pos2)\r
459                 minetest.chat_send_player(name, count .. " nodes dug")\r
460         end,\r
461 })\r
462 \r
463 minetest.register_chatcommand("/save", {\r
464         params = "<file>",\r
465         description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",\r
466         privs = {worldedit=true},\r
467         func = function(name, param)\r
468                 local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
469                 if pos1 == nil or pos2 == nil then\r
470                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
471                         return\r
472                 end\r
473 \r
474                 if param == "" then\r
475                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
476                         return\r
477                 end\r
478 \r
479                 local result, count = worldedit.serialize(pos1, pos2)\r
480 \r
481                 local path = minetest.get_worldpath() .. "/schems"\r
482                 local filename = path .. "/" .. param .. ".we"\r
483                 os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
484                 local file, err = io.open(filename, "wb")\r
485                 if err ~= nil then\r
486                         minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"")\r
487                         return\r
488                 end\r
489                 file:write(result)\r
490                 file:flush()\r
491                 file:close()\r
492 \r
493                 minetest.chat_send_player(name, count .. " nodes saved")\r
494         end,\r
495 })\r
496 \r
497 minetest.register_chatcommand("/load", {\r
498         params = "<file>",\r
499         description = "Load nodes from \"(world folder)/schems/<file>.we\" with position 1 of the current WorldEdit region as the origin",\r
500         privs = {worldedit=true},\r
501         func = function(name, param)\r
502                 local pos1 = worldedit.pos1[name]\r
503                 if pos1 == nil then\r
504                         minetest.chat_send_player(name, "No WorldEdit region selected")\r
505                         return\r
506                 end\r
507 \r
508                 if param == "" then\r
509                         minetest.chat_send_player(name, "Invalid usage: " .. param)\r
510                         return\r
511                 end\r
512 \r
513                 local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"\r
514                 local file, err = io.open(filename, "rb")\r
515                 if err ~= nil then\r
516                         minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"")\r
517                         return\r
518                 end\r
519                 local value = file:read("*a")\r
520                 file:close()\r
521 \r
522                 local count\r
523                 if value:find("{") then --old WorldEdit format\r
524                         count = worldedit.deserialize_old(pos1, value)\r
525                 else --new WorldEdit format\r
526                         count = worldedit.deserialize(pos1, value)\r
527                 end\r
528 \r
529                 minetest.chat_send_player(name, count .. " nodes loaded")\r
530         end,\r
531 })\r