2024-05-16 13:31:17 +02:00
|
|
|
|
local S = minetest.get_translator("worldedit_commands")
|
|
|
|
|
|
2024-04-21 23:33:55 +02:00
|
|
|
|
-- Strips any kind of escape codes (translation, colors) from a string
|
|
|
|
|
-- https://github.com/minetest/minetest/blob/53dd7819277c53954d1298dfffa5287c306db8d0/src/util/string.cpp#L777
|
|
|
|
|
local function strip_escapes(input)
|
|
|
|
|
local s = function(idx) return input:sub(idx, idx) end
|
|
|
|
|
local out = ""
|
|
|
|
|
local i = 1
|
|
|
|
|
while i <= #input do
|
|
|
|
|
if s(i) == "\027" then -- escape sequence
|
|
|
|
|
i = i + 1
|
|
|
|
|
if s(i) == "(" then -- enclosed
|
|
|
|
|
i = i + 1
|
|
|
|
|
while i <= #input and s(i) ~= ")" do
|
|
|
|
|
if s(i) == "\\" then
|
|
|
|
|
i = i + 2
|
|
|
|
|
else
|
|
|
|
|
i = i + 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
out = out .. s(i)
|
|
|
|
|
end
|
|
|
|
|
i = i + 1
|
|
|
|
|
end
|
|
|
|
|
--print(("%q -> %q"):format(input, out))
|
|
|
|
|
return out
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function string_endswith(full, part)
|
|
|
|
|
return full:find(part, 1, true) == #full - #part + 1
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local description_cache = nil
|
|
|
|
|
|
2024-05-16 13:31:17 +02:00
|
|
|
|
-- normalizes node "description" `nodename`. Return a string (or nil), with the second return value being the error message if the first value is nil.
|
|
|
|
|
-- playername contain the name of the player. It may be nil, in which case it won’t detect the wielded item when appropriate
|
|
|
|
|
worldedit.normalize_nodename = function(nodename, playername)
|
2024-04-21 23:33:55 +02:00
|
|
|
|
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
|
|
|
|
|
if nodename == "" then return nil end
|
|
|
|
|
|
2024-05-16 13:31:17 +02:00
|
|
|
|
if nodename == "wielded" or nodename == "w" then
|
|
|
|
|
if not playername then
|
|
|
|
|
return nil, S("no player executing command")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local player = minetest.get_player_by_name(playername)
|
|
|
|
|
if not player then
|
|
|
|
|
return nil, S("no player found: @1", playername)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local wielded = player:get_wielded_item()
|
|
|
|
|
if not wielded then
|
|
|
|
|
return nil, S("no wielded item: @1", playername)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if minetest.registered_nodes[wielded:get_name()] then
|
|
|
|
|
return wielded:get_name()
|
|
|
|
|
else
|
|
|
|
|
return nil, S("not a node: @1", wielded:get_name())
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-04-21 23:33:55 +02:00
|
|
|
|
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
|
|
|
|
|
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
|
|
|
|
|
return fullname
|
|
|
|
|
end
|
|
|
|
|
nodename = nodename:lower()
|
|
|
|
|
|
|
|
|
|
for key, _ in pairs(minetest.registered_nodes) do
|
|
|
|
|
if string_endswith(key:lower(), ":" .. nodename) then -- matches name (w/o mod part)
|
|
|
|
|
return key
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if description_cache == nil then
|
|
|
|
|
-- cache stripped descriptions
|
|
|
|
|
description_cache = {}
|
|
|
|
|
for key, value in pairs(minetest.registered_nodes) do
|
|
|
|
|
local desc = strip_escapes(value.description):gsub("\n.*", "", 1):lower()
|
|
|
|
|
if desc ~= "" then
|
|
|
|
|
description_cache[key] = desc
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
for key, desc in pairs(description_cache) do
|
|
|
|
|
if desc == nodename then -- matches description
|
|
|
|
|
return key
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for key, desc in pairs(description_cache) do
|
|
|
|
|
if desc == nodename .. " block" then
|
|
|
|
|
-- fuzzy description match (e.g. "Steel" == "Steel Block")
|
|
|
|
|
return key
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local match = nil
|
|
|
|
|
for key, value in pairs(description_cache) do
|
|
|
|
|
if value:find(nodename, 1, true) ~= nil then
|
|
|
|
|
if match ~= nil then
|
2024-05-16 13:31:17 +02:00
|
|
|
|
return nil, S("invalid node name: @1", nodename)
|
2024-04-21 23:33:55 +02:00
|
|
|
|
end
|
|
|
|
|
match = key -- substring description match (only if no ambiguities)
|
|
|
|
|
end
|
|
|
|
|
end
|
2024-05-16 13:31:17 +02:00
|
|
|
|
|
|
|
|
|
if match then
|
|
|
|
|
return match
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return nil, S("invalid node name: @1", nodename)
|
|
|
|
|
end
|