cuboid.lua 7.8 KB

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