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