]> git.lizzy.rs Git - worldedit.git/blob - worldedit_brush/init.lua
389693141d47340aef8d354cd5cd789901869bd7
[worldedit.git] / worldedit_brush / init.lua
1 if minetest.raycast == nil then
2         error(
3                 "worldedit_brush requires at least Minetest 5.0"
4         )
5 end
6
7 local BRUSH_MAX_DIST = 150
8 local BRUSH_ALLOWED_COMMANDS = {
9         -- basically everything that only needs pos1
10         -- TODO: determine automatically now that `require_pos` exists
11         "cube",
12         "cylinder",
13         "dome",
14         "hollowcube",
15         "hollowcylinder",
16         "hollowdome",
17         "hollowpyramid",
18         "hollowsphere",
19         "load",
20         "pyramid",
21         "sphere",
22         "spiral",
23
24         "cyl",
25         "do",
26         "hcube",
27         "hcyl",
28         "hdo",
29         "hpyr",
30         "hspr",
31         "l",
32         "pyr",
33         "spr",
34         "spl",
35 }
36 local brush_on_use = function(itemstack, placer)
37         local meta = itemstack:get_meta()
38         local name = placer:get_player_name()
39
40         local cmd = meta:get_string("command")
41         if cmd == "" then
42                 worldedit.player_notify(name,
43                         "This brush is not bound, use //brush to bind a command to it.")
44                 return false
45         end
46
47         local cmddef = worldedit.registered_commands[cmd]
48         if cmddef == nil then return false end -- shouldn't happen as //brush checks this
49
50         local has_privs, missing_privs = minetest.check_player_privs(name, cmddef.privs)
51         if not has_privs then
52                 worldedit.player_notify(name,
53                         "Missing privileges: " .. table.concat(missing_privs, ", "))
54                 return false
55         end
56
57         local raybegin = vector.add(placer:get_pos(),
58                 {x=0, y=placer:get_properties().eye_height, z=0})
59         local rayend = vector.add(raybegin, vector.multiply(placer:get_look_dir(), BRUSH_MAX_DIST))
60         local ray = minetest.raycast(raybegin, rayend, false, true)
61         local pointed_thing = ray:next()
62         if pointed_thing == nil then
63                 worldedit.player_notify(name, "Too far away.")
64                 return false
65         end
66
67         assert(pointed_thing.type == "node")
68         worldedit.pos1[name] = pointed_thing.under
69         worldedit.pos2[name] = nil
70         worldedit.mark_region(name)
71
72         -- this isn't really clean...
73         local player_notify_old = worldedit.player_notify
74         worldedit.player_notify = function(name, msg)
75                 if string.match(msg, "^%d") then return end -- discard "1234 nodes added."
76                 return player_notify_old(name, msg)
77         end
78
79         assert(cmddef.require_pos < 2)
80         local parsed = {cmddef.parse(meta:get_string("params"))}
81         if not table.remove(parsed, 1) then return false end -- shouldn't happen
82
83         minetest.log("action", string.format("%s uses WorldEdit brush (//%s) at %s",
84                 name, cmd, minetest.pos_to_string(pointed_thing.under)))
85         cmddef.func(name, unpack(parsed))
86
87         worldedit.player_notify = player_notify_old
88         return true
89 end
90
91 minetest.register_tool(":worldedit:brush", {
92         description = "WorldEdit Brush",
93         inventory_image = "worldedit_brush.png",
94         stack_max = 1, -- no need to stack these (metadata prevents this anyway)
95         range = 0,
96         on_use = function(itemstack, placer, pointed_thing)
97                 brush_on_use(itemstack, placer)
98                 return itemstack -- nothing consumed, nothing changed
99         end,
100 })
101
102 worldedit.register_command("brush", {
103         privs = {worldedit=true},
104         params = "none/<cmd> [parameters]",
105         description = "Assign command to WorldEdit brush item",
106         parse = function(param)
107                 local found, _, cmd, params = param:find("^([^%s]+)%s+(.+)$")
108                 if not found then
109                         params = ""
110                         found, _, cmd = param:find("^(.+)$")
111                 end
112                 if not found then
113                         return false
114                 end
115                 return true, cmd, params
116         end,
117         func = function(name, cmd, params)
118                 local itemstack = minetest.get_player_by_name(name):get_wielded_item()
119                 if itemstack == nil or itemstack:get_name() ~= "worldedit:brush" then
120                         worldedit.player_notify(name, "Not holding brush item.")
121                         return
122                 end
123
124                 cmd = cmd:lower()
125                 local meta = itemstack:get_meta()
126                 if cmd == "none" then
127                         meta:from_table(nil)
128                         worldedit.player_notify(name, "Brush assignment cleared.")
129                 else
130                         local cmddef
131                         if table.indexof(BRUSH_ALLOWED_COMMANDS, cmd) ~= -1 then
132                                 cmddef = worldedit.registered_commands[cmd]
133                         end
134                         if cmddef == nil then
135                                 worldedit.player_notify(name, "Invalid command for brush use: //" .. cmd)
136                                 return
137                         end
138
139                         -- Try parsing command params so we can give the user feedback
140                         local ok, err = cmddef.parse(params)
141                         if not ok then
142                                 err = err or "invalid usage"
143                                 worldedit.player_notify(name, "Brush command: " .. err)
144                                 return
145                         end
146
147                         meta:set_string("command", cmd)
148                         meta:set_string("params", params)
149                         local fullcmd = "//" .. cmd .. " " .. params
150                         meta:set_string("description",
151                                 minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
152                         worldedit.player_notify(name, "Brush assigned to command: " .. fullcmd)
153                 end
154                 minetest.get_player_by_name(name):set_wielded_item(itemstack)
155         end,
156 })