]> git.lizzy.rs Git - worldedit.git/blob - worldedit_commands/cuboid.lua
Implement //cubeapply with three side lengths
[worldedit.git] / worldedit_commands / cuboid.lua
1 worldedit.register_command("outset", {
2         params = "[h|v] <amount>",
3         description = "Outset the selected region.",
4         privs = {worldedit=true},
5         require_pos = 2,
6         parse = function(param)
7                 local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
8                 if find == nil then
9                         return false
10                 end
11
12                 local hv_test = dir:find("[^hv]+")
13                 if hv_test ~= nil then
14                         return false, "Invalid direction."
15                 end
16
17                 return true, dir, tonumber(amount)
18         end,
19         func = function(name, dir, amount)
20                 if dir == "" or dir == "hv" or dir == "vh" then
21                         assert(worldedit.cuboid_volumetric_expand(name, amount))
22                 elseif dir == "h" then
23                         assert(worldedit.cuboid_linear_expand(name, 'x', 1, amount))
24                         assert(worldedit.cuboid_linear_expand(name, 'x', -1, amount))
25                         assert(worldedit.cuboid_linear_expand(name, 'z', 1, amount))
26                         assert(worldedit.cuboid_linear_expand(name, 'z', -1, amount))
27                 elseif dir == "v" then
28                         assert(worldedit.cuboid_linear_expand(name, 'y', 1, amount))
29                         assert(worldedit.cuboid_linear_expand(name, 'y', -1, amount))
30                 else
31                         return false, "Invalid number of arguments"
32                 end
33
34                 worldedit.marker_update(name)
35                 return true, "Region outset by " .. amount .. " blocks"
36       end,
37 })
38
39
40 worldedit.register_command("inset", {
41         params = "[h|v] <amount>",
42         description = "Inset the selected region.",
43         privs = {worldedit=true},
44         require_pos = 2,
45         parse = function(param)
46                 local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
47                 if find == nil then
48                         return false
49                 end
50
51                 local hv_test = dir:find("[^hv]+")
52                 if hv_test ~= nil then
53                         return false, "Invalid direction."
54                 end
55
56                 return true, dir, tonumber(amount)
57         end,
58         func = function(name, dir, amount)
59                 if dir == "" or dir == "vh" or dir == "hv" then
60                         assert(worldedit.cuboid_volumetric_expand(name, -amount))
61                 elseif dir == "h" then
62                         assert(worldedit.cuboid_linear_expand(name, 'x', 1, -amount))
63                         assert(worldedit.cuboid_linear_expand(name, 'x', -1, -amount))
64                         assert(worldedit.cuboid_linear_expand(name, 'z', 1, -amount))
65                         assert(worldedit.cuboid_linear_expand(name, 'z', -1, -amount))
66                 elseif dir == "v" then
67                         assert(worldedit.cuboid_linear_expand(name, 'y', 1, -amount))
68                         assert(worldedit.cuboid_linear_expand(name, 'y', -1, -amount))
69                 else
70                         return false, "Invalid number of arguments"
71                 end
72
73                 worldedit.marker_update(name)
74                 return true, "Region inset by " .. amount .. " blocks"
75       end,
76 })
77
78
79 worldedit.register_command("shift", {
80         params = "[x|y|z|?|up|down|left|right|front|back] [+|-]<amount>",
81         description = "Moves the selection region. Does not move contents.",
82         privs = {worldedit=true},
83         require_pos = 2,
84         parse = function(param)
85                 local find, _, direction, amount = param:find("([%?%l]+)%s*([+-]?%d+)")
86                 if find == nil then
87                         return false
88                 end
89
90                 return true, direction, tonumber(amount)
91         end,
92         func = function(name, direction, amount)
93                 local axis, dir
94                 if direction == "x" or direction == "y" or direction == "z" then
95                         axis, dir = direction, 1
96                 elseif direction == "?" then
97                         axis, dir = worldedit.player_axis(name)
98                 else
99                         axis, dir = worldedit.translate_direction(name, direction)
100                 end
101
102                 if axis == nil or dir == nil then
103                         return false, "Invalid if looking straight up or down"
104                 end
105
106                 assert(worldedit.cuboid_shift(name, axis, amount * dir))
107                 worldedit.marker_update(name)
108
109                 return true, "Region shifted by " .. amount .. " nodes"
110       end,
111 })
112
113
114 worldedit.register_command("expand", {
115         params = "[+|-]<x|y|z|?|up|down|left|right|front|back> <amount> [reverse-amount]",
116         description = "expand the selection in one or two directions at once",
117         privs = {worldedit=true},
118         require_pos = 2,
119         parse = function(param)
120                 local find, _, sign, direction, amount,
121                                 rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
122                 if find == nil then
123                         return false
124                 end
125
126                 if rev_amount == "" then
127                         rev_amount = "0"
128                 end
129
130                 return true, sign, direction, tonumber(amount), tonumber(rev_amount)
131         end,
132         func = function(name, sign, direction, amount, rev_amount)
133                 local absolute = direction:find("[xyz?]")
134                 local dir, axis
135
136                 if absolute == nil then
137                         axis, dir = worldedit.translate_direction(name, direction)
138
139                         if axis == nil or dir == nil then
140                                 return false, "Invalid if looking straight up or down"
141                         end
142                 else
143                         if direction == "?" then
144                                 axis, dir = worldedit.player_axis(name)
145                         else
146                                 axis = direction
147                                 dir = 1
148                         end
149                 end
150
151                 if sign == "-" then
152                         dir = -dir
153                 end
154
155                 worldedit.cuboid_linear_expand(name, axis, dir, amount)
156                 worldedit.cuboid_linear_expand(name, axis, -dir, rev_amount)
157                 worldedit.marker_update(name)
158                 return true, "Region expanded by " .. (amount + rev_amount) .. " nodes"
159         end,
160 })
161
162
163 worldedit.register_command("contract", {
164         params = "[+|-]<x|y|z|?|up|down|left|right|front|back> <amount> [reverse-amount]",
165         description = "contract the selection in one or two directions at once",
166         privs = {worldedit=true},
167         require_pos = 2,
168         parse = function(param)
169                 local find, _, sign, direction, amount,
170                                 rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
171                 if find == nil then
172                         return false
173                 end
174
175                 if rev_amount == "" then
176                         rev_amount = "0"
177                 end
178
179                 return true, sign, direction, tonumber(amount), tonumber(rev_amount)
180         end,
181         func = function(name, sign, direction, amount, rev_amount)
182                 local absolute = direction:find("[xyz?]")
183                 local dir, axis
184
185                 if absolute == nil then
186                         axis, dir = worldedit.translate_direction(name, direction)
187
188                         if axis == nil or dir == nil then
189                                 return false, "Invalid if looking straight up or down"
190                         end
191                 else
192                         if direction == "?" then
193                                 axis, dir = worldedit.player_axis(name)
194                         else
195                                 axis = direction
196                                 dir = 1
197                         end
198                 end
199
200                 if sign == "-" then
201                         dir = -dir
202                 end
203
204                 worldedit.cuboid_linear_expand(name, axis, dir, -amount)
205                 worldedit.cuboid_linear_expand(name, axis, -dir, -rev_amount)
206                 worldedit.marker_update(name)
207                 return true, "Region contracted by " .. (amount + rev_amount) .. " nodes"
208         end,
209 })
210
211 worldedit.register_command("cubeapply", {
212         params = "<size>/(<sizex> <sizey> <sizez>) <command> [parameters]",
213         description = "Select a cube with side length <size> around position 1 and run <command> on region",
214         privs = {worldedit=true},
215         require_pos = 1,
216         parse = function(param)
217                 local found, _, sidex, sidey, sidez, cmd, args =
218                         param:find("^(%d+)%s+(%d+)%s+(%d+)%s+([^%s]+)%s*(.*)$")
219                 if found == nil then
220                         found, _, sidex, cmd, args = param:find("^(%d+)%s+([^%s]+)%s*(.*)$")
221                         if found == nil then
222                                 return false
223                         end
224                         sidey = sidex
225                         sidez = sidex
226                 end
227                 sidex = tonumber(sidex)
228                 sidey = tonumber(sidey)
229                 sidez = tonumber(sidez)
230                 if sidex < 1 or sidey < 1 or sidez < 1 then
231                         return false
232                 end
233                 local cmddef = worldedit.registered_commands[cmd]
234                 if cmddef == nil or cmddef.require_pos ~= 2 then
235                         return false, "invalid usage: //" .. cmd .. " cannot be used with cubeapply"
236                 end
237                 -- run parsing of target command
238                 local parsed = {cmddef.parse(args)}
239                 if not table.remove(parsed, 1) then
240                         return false, parsed[1]
241                 end
242                 return true, sidex, sidey, sidez, cmd, parsed
243         end,
244         nodes_needed = function(name, sidex, sidey, sidez, cmd, parsed)
245                 -- its not possible to defer to the target command at this point
246                 return sidex * sidey * sidez
247         end,
248         func = function(name, sidex, sidey, sidez, cmd, parsed)
249                 local cmddef = assert(worldedit.registered_commands[cmd])
250                 local success, missing_privs = minetest.check_player_privs(name, cmddef.privs)
251                 if not success then
252                         worldedit.player_notify(name, "Missing privileges: " ..
253                                 table.concat(missing_privs, ", "))
254                         return
255                 end
256
257                 -- update region to be the cuboid the user wanted
258                 local half = vector.divide(vector.new(sidex, sidey, sidez), 2)
259                 local sizea, sizeb = vector.apply(half, math.floor), vector.apply(half, math.ceil)
260                 local center = worldedit.pos1[name]
261                 worldedit.pos1[name] = vector.subtract(center, sizea)
262                 worldedit.pos2[name] = vector.add(center, vector.subtract(sizeb, 1))
263                 worldedit.marker_update(name)
264
265                 -- actually run target command
266                 return cmddef.func(name, unpack(parsed))
267         end,
268 })