1 local modname = minetest.get_current_modname()
4 if minetest.raycast == nil then
5 function log_unavailable_error()
7 "[MOD] " .. modname .. " is not compatible with current game version, " ..
8 "you can disable it in the game settings!"
10 minetest.log("verbose",
11 "[MOD] " .. modname .. " requires a suitable version of 0.4.16-dev or higher, " ..
12 "that includes support for minetest.raycast() [since 7th July 2017]"
16 if minetest.is_singleplayer() then
17 -- delay message until player is connected
18 minetest.register_on_joinplayer(log_unavailable_error)
20 log_unavailable_error()
23 -- exit here / do not load this mod
27 local BRUSH_MAX_DIST = 150
28 local BRUSH_ALLOWED_COMMANDS = {
29 -- basically everything that only needs pos1
55 local brush_on_use = function(itemstack, placer)
56 local meta = itemstack:get_meta()
57 local name = placer:get_player_name()
59 local cmd = meta:get_string("command")
61 worldedit.player_notify(name,
62 "This brush is not bound, use //brush to bind a command to it.")
65 local cmddef = minetest.registered_chatcommands["/" .. cmd]
66 if cmddef == nil then return false end -- shouldn't happen as //brush checks this
67 local has_privs, missing_privs = minetest.check_player_privs(name, cmddef.privs)
69 worldedit.player_notify(name,
70 "Missing privileges: " .. table.concat(missing_privs, ", "))
74 local raybegin = vector.add(placer:get_pos(), {x=0, y=2, z=0}) -- player head
75 local rayend = vector.add(raybegin, vector.multiply(placer:get_look_dir(), BRUSH_MAX_DIST))
76 local ray = minetest.raycast(raybegin, rayend, false, true)
77 local pointed_thing = ray:next()
78 if pointed_thing == nil then
79 worldedit.player_notify(name, "Too far away.")
83 assert(pointed_thing.type == "node")
84 worldedit.pos1[name] = pointed_thing.under
85 worldedit.pos2[name] = nil
86 worldedit.mark_region(name)
87 -- is this a horrible hack? oh yes.
88 worldedit._override_safe_regions = true
89 local player_notify_old = worldedit.player_notify
90 worldedit.player_notify = function(name, msg)
91 if string.match(msg, "^%d") then return end -- discard "1234 nodes added."
92 return player_notify_old(name, msg)
95 minetest.log("action", string.format("%s uses WorldEdit brush (//%s) at %s",
96 name, cmd, minetest.pos_to_string(pointed_thing.under)))
97 cmddef.func(name, meta:get_string("params"))
99 worldedit._override_safe_regions = false
100 worldedit.player_notify = player_notify_old
104 minetest.register_tool(":worldedit:brush", {
105 description = "WorldEdit Brush",
106 inventory_image = "worldedit_brush.png",
107 stack_max = 1, -- no need to stack these (metadata prevents this anyway)
109 on_use = function(itemstack, placer, pointed_thing)
110 brush_on_use(itemstack, placer)
111 return itemstack -- nothing consumed, nothing changed
115 minetest.register_chatcommand("/brush", {
116 privs = {worldedit=true},
117 params = "none/<cmd> [parameters]",
118 description = "Assign command to WorldEdit brush item",
119 func = function(name, param)
120 local found, _, cmd, params = param:find("^([^%s]+)%s+(.+)$")
123 found, _, cmd = param:find("^(.+)$")
126 worldedit.player_notify(name, "Invalid usage.")
130 local itemstack = minetest.get_player_by_name(name):get_wielded_item()
131 if itemstack == nil or itemstack:get_name() ~= "worldedit:brush" then
132 worldedit.player_notify(name, "Not holding brush item.")
137 local meta = itemstack:get_meta()
138 if cmd == "none" then
140 worldedit.player_notify(name, "Brush assignment cleared.")
143 if table.indexof(BRUSH_ALLOWED_COMMANDS, cmd) ~= -1 then
144 cmddef = minetest.registered_chatcommands["/" .. cmd]
148 if cmddef == nil then
149 worldedit.player_notify(name, "Invalid command for brush use: //" .. cmd)
152 meta:set_string("command", cmd)
153 meta:set_string("params", params)
154 local fullcmd = "//" .. cmd .. " " .. params
155 meta:set_string("description",
156 minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
157 worldedit.player_notify(name, "Brush assigned to command: " .. fullcmd)
159 minetest.get_player_by_name(name):set_wielded_item(itemstack)