summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/client/chatcommands.lua9
-rw-r--r--builtin/client/death_formspec.lua2
-rw-r--r--builtin/common/chatcommands.lua69
-rw-r--r--builtin/common/information_formspecs.lua30
-rw-r--r--builtin/fstk/tabview.lua50
-rw-r--r--builtin/game/chat.lua715
-rw-r--r--builtin/game/item.lua2
-rw-r--r--builtin/game/knockback.lua2
-rw-r--r--builtin/game/misc.lua8
-rw-r--r--builtin/game/privileges.lua40
-rw-r--r--builtin/game/register.lua15
-rw-r--r--builtin/game/statbars.lua4
-rw-r--r--builtin/init.lua15
-rw-r--r--builtin/locale/__builtin.de.tr225
-rw-r--r--builtin/locale/__builtin.it.tr224
-rw-r--r--builtin/locale/template.txt224
-rw-r--r--builtin/mainmenu/common.lua108
-rw-r--r--builtin/mainmenu/dlg_config_world.lua2
-rw-r--r--builtin/mainmenu/dlg_contentstore.lua18
-rw-r--r--builtin/mainmenu/dlg_create_world.lua2
-rw-r--r--builtin/mainmenu/pkgmgr.lua49
-rw-r--r--builtin/mainmenu/serverlistmgr.lua9
-rw-r--r--builtin/mainmenu/tab_content.lua15
-rw-r--r--builtin/mainmenu/tab_credits.lua54
-rw-r--r--builtin/mainmenu/tab_online.lua456
-rw-r--r--builtin/profiler/init.lua18
-rw-r--r--builtin/profiler/reporter.lua19
-rw-r--r--builtin/settingtypes.txt24
28 files changed, 1588 insertions, 820 deletions
diff --git a/builtin/client/chatcommands.lua b/builtin/client/chatcommands.lua
index 0e8d4dd03..a563a6627 100644
--- a/builtin/client/chatcommands.lua
+++ b/builtin/client/chatcommands.lua
@@ -1,6 +1,5 @@
-- Minetest: builtin/client/chatcommands.lua
-
core.register_on_sending_chat_message(function(message)
if message:sub(1,2) == ".." then
return false
@@ -8,7 +7,7 @@ core.register_on_sending_chat_message(function(message)
local first_char = message:sub(1,1)
if first_char == "/" or first_char == "." then
- core.display_chat_message(core.gettext("issued command: ") .. message)
+ core.display_chat_message(core.gettext("Issued command: ") .. message)
end
if first_char ~= "." then
@@ -19,7 +18,7 @@ core.register_on_sending_chat_message(function(message)
param = param or ""
if not cmd then
- core.display_chat_message(core.gettext("-!- Empty command"))
+ core.display_chat_message("-!- " .. core.gettext("Empty command."))
return true
end
@@ -36,7 +35,7 @@ core.register_on_sending_chat_message(function(message)
core.display_chat_message(result)
end
else
- core.display_chat_message(core.gettext("-!- Invalid command: ") .. cmd)
+ core.display_chat_message("-!- " .. core.gettext("Invalid command: ") .. cmd)
end
return true
@@ -66,7 +65,7 @@ core.register_chatcommand("clear_chat_queue", {
description = core.gettext("Clear the out chat queue"),
func = function(param)
core.clear_out_chat_queue()
- return true, core.gettext("The out chat queue is now empty")
+ return true, core.gettext("The out chat queue is now empty.")
end,
})
diff --git a/builtin/client/death_formspec.lua b/builtin/client/death_formspec.lua
index e755ac5c1..7df0cbd75 100644
--- a/builtin/client/death_formspec.lua
+++ b/builtin/client/death_formspec.lua
@@ -2,7 +2,7 @@
-- handled by the engine.
core.register_on_death(function()
- core.display_chat_message("You died.")
+ core.display_chat_message(core.gettext("You died."))
local formspec = "size[11,5.5]bgcolor[#320000b4;true]" ..
"label[4.85,1.35;" .. fgettext("You died") ..
"]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]"
diff --git a/builtin/common/chatcommands.lua b/builtin/common/chatcommands.lua
index 52edda659..c945e7bdb 100644
--- a/builtin/common/chatcommands.lua
+++ b/builtin/common/chatcommands.lua
@@ -1,5 +1,9 @@
-- Minetest: builtin/common/chatcommands.lua
+-- For server-side translations (if INIT == "game")
+-- Otherwise, use core.gettext
+local S = core.get_translator("__builtin")
+
core.registered_chatcommands = {}
function core.register_chatcommand(cmd, def)
@@ -29,25 +33,12 @@ function core.override_chatcommand(name, redefinition)
core.registered_chatcommands[name] = chatcommand
end
-local cmd_marker = "/"
-
-local function gettext(...)
- return ...
-end
-
-local function gettext_replace(text, replace)
- return text:gsub("$1", replace)
-end
-
-
-if INIT == "client" then
- cmd_marker = "."
- gettext = core.gettext
- gettext_replace = fgettext_ne
-end
-
local function do_help_cmd(name, param)
local function format_help_line(cmd, def)
+ local cmd_marker = "/"
+ if INIT == "client" then
+ cmd_marker = "."
+ end
local msg = core.colorize("#00ffff", cmd_marker .. cmd)
if def.params and def.params ~= "" then
msg = msg .. " " .. def.params
@@ -65,9 +56,21 @@ local function do_help_cmd(name, param)
end
end
table.sort(cmds)
- return true, gettext("Available commands: ") .. table.concat(cmds, " ") .. "\n"
- .. gettext_replace("Use '$1help <cmd>' to get more information,"
- .. " or '$1help all' to list everything.", cmd_marker)
+ local msg
+ if INIT == "game" then
+ msg = S("Available commands: @1",
+ table.concat(cmds, " ")) .. "\n"
+ .. S("Use '/help <cmd>' to get more "
+ .. "information, or '/help all' to list "
+ .. "everything.")
+ else
+ msg = core.gettext("Available commands: ")
+ .. table.concat(cmds, " ") .. "\n"
+ .. core.gettext("Use '.help <cmd>' to get more "
+ .. "information, or '.help all' to list "
+ .. "everything.")
+ end
+ return true, msg
elseif param == "all" then
local cmds = {}
for cmd, def in pairs(core.registered_chatcommands) do
@@ -76,19 +79,31 @@ local function do_help_cmd(name, param)
end
end
table.sort(cmds)
- return true, gettext("Available commands:").."\n"..table.concat(cmds, "\n")
+ local msg
+ if INIT == "game" then
+ msg = S("Available commands:")
+ else
+ msg = core.gettext("Available commands:")
+ end
+ return true, msg.."\n"..table.concat(cmds, "\n")
elseif INIT == "game" and param == "privs" then
local privs = {}
for priv, def in pairs(core.registered_privileges) do
privs[#privs + 1] = priv .. ": " .. def.description
end
table.sort(privs)
- return true, "Available privileges:\n"..table.concat(privs, "\n")
+ return true, S("Available privileges:").."\n"..table.concat(privs, "\n")
else
local cmd = param
local def = core.registered_chatcommands[cmd]
if not def then
- return false, gettext("Command not available: ")..cmd
+ local msg
+ if INIT == "game" then
+ msg = S("Command not available: @1", cmd)
+ else
+ msg = core.gettext("Command not available: ") .. cmd
+ end
+ return false, msg
else
return true, format_help_line(cmd, def)
end
@@ -97,16 +112,16 @@ end
if INIT == "client" then
core.register_chatcommand("help", {
- params = gettext("[all | <cmd>]"),
- description = gettext("Get help for commands"),
+ params = core.gettext("[all | <cmd>]"),
+ description = core.gettext("Get help for commands"),
func = function(param)
return do_help_cmd(nil, param)
end,
})
else
core.register_chatcommand("help", {
- params = "[all | privs | <cmd>]",
- description = "Get help for commands or list privileges",
+ params = S("[all | privs | <cmd>]"),
+ description = S("Get help for commands or list privileges"),
func = do_help_cmd,
})
end
diff --git a/builtin/common/information_formspecs.lua b/builtin/common/information_formspecs.lua
index 8afa5bc87..e814b4c43 100644
--- a/builtin/common/information_formspecs.lua
+++ b/builtin/common/information_formspecs.lua
@@ -20,7 +20,8 @@ local LIST_FORMSPEC_DESCRIPTION = [[
button_exit[5,7;3,1;quit;%s]
]]
-local formspec_escape = core.formspec_escape
+local F = core.formspec_escape
+local S = core.get_translator("__builtin")
local check_player_privs = core.check_player_privs
@@ -51,22 +52,23 @@ core.after(0, load_mod_command_tree)
local function build_chatcommands_formspec(name, sel, copy)
local rows = {}
- rows[1] = "#FFF,0,Command,Parameters"
+ rows[1] = "#FFF,0,"..F(S("Command"))..","..F(S("Parameters"))
- local description = "For more information, click on any entry in the list.\n" ..
- "Double-click to copy the entry to the chat history."
+ local description = S("For more information, click on "
+ .. "any entry in the list.").. "\n" ..
+ S("Double-click to copy the entry to the chat history.")
for i, data in ipairs(mod_cmds) do
- rows[#rows + 1] = COLOR_BLUE .. ",0," .. formspec_escape(data[1]) .. ","
+ rows[#rows + 1] = COLOR_BLUE .. ",0," .. F(data[1]) .. ","
for j, cmds in ipairs(data[2]) do
local has_priv = check_player_privs(name, cmds[2].privs)
rows[#rows + 1] = ("%s,1,%s,%s"):format(
has_priv and COLOR_GREEN or COLOR_GRAY,
- cmds[1], formspec_escape(cmds[2].params))
+ cmds[1], F(cmds[2].params))
if sel == #rows then
description = cmds[2].description
if copy then
- core.chat_send_player(name, ("Command: %s %s"):format(
+ core.chat_send_player(name, S("Command: @1 @2",
core.colorize("#0FF", "/" .. cmds[1]), cmds[2].params))
end
end
@@ -74,9 +76,9 @@ local function build_chatcommands_formspec(name, sel, copy)
end
return LIST_FORMSPEC_DESCRIPTION:format(
- "Available commands: (see also: /help <cmd>)",
+ F(S("Available commands: (see also: /help <cmd>)")),
table.concat(rows, ","), sel or 0,
- description, "Close"
+ F(description), F(S("Close"))
)
end
@@ -91,19 +93,19 @@ local function build_privs_formspec(name)
table.sort(privs, function(a, b) return a[1] < b[1] end)
local rows = {}
- rows[1] = "#FFF,0,Privilege,Description"
+ rows[1] = "#FFF,0,"..F(S("Privilege"))..","..F(S("Description"))
local player_privs = core.get_player_privs(name)
for i, data in ipairs(privs) do
rows[#rows + 1] = ("%s,0,%s,%s"):format(
player_privs[data[1]] and COLOR_GREEN or COLOR_GRAY,
- data[1], formspec_escape(data[2].description))
+ data[1], F(data[2].description))
end
return LIST_FORMSPEC:format(
- "Available privileges:",
+ F(S("Available privileges:")),
table.concat(rows, ","),
- "Close"
+ F(S("Close"))
)
end
@@ -115,7 +117,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
return
end
- local event = minetest.explode_table_event(fields.list)
+ local event = core.explode_table_event(fields.list)
if event.type ~= "INV" then
local name = player:get_player_name()
core.show_formspec(name, "__builtin:help_cmds",
diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua
index 3715e231b..424d329fb 100644
--- a/builtin/fstk/tabview.lua
+++ b/builtin/fstk/tabview.lua
@@ -58,26 +58,20 @@ end
--------------------------------------------------------------------------------
local function get_formspec(self)
- local formspec = ""
+ if self.hidden or (self.parent ~= nil and self.parent.hidden) then
+ return ""
+ end
+ local tab = self.tablist[self.last_tab_index]
- if not self.hidden and (self.parent == nil or not self.parent.hidden) then
+ local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
- if self.parent == nil then
- local tsize = self.tablist[self.last_tab_index].tabsize or
- {width=self.width, height=self.height}
- formspec = formspec ..
- string.format("size[%f,%f,%s]",tsize.width,tsize.height,
- dump(self.fixed_size))
- end
- formspec = formspec .. self:tab_header()
- formspec = formspec ..
- self.tablist[self.last_tab_index].get_formspec(
- self,
- self.tablist[self.last_tab_index].name,
- self.tablist[self.last_tab_index].tabdata,
- self.tablist[self.last_tab_index].tabsize
- )
+ if self.parent == nil and not prepend then
+ local tsize = tab.tabsize or {width=self.width, height=self.height}
+ prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height,
+ dump(self.fixed_size))
end
+
+ local formspec = (prepend or "") .. self:tab_header() .. content
return formspec
end
@@ -97,14 +91,9 @@ local function handle_buttons(self,fields)
return true
end
- if self.tablist[self.last_tab_index].button_handler ~= nil then
- return
- self.tablist[self.last_tab_index].button_handler(
- self,
- fields,
- self.tablist[self.last_tab_index].name,
- self.tablist[self.last_tab_index].tabdata
- )
+ local tab = self.tablist[self.last_tab_index]
+ if tab.button_handler ~= nil then
+ return tab.button_handler(self, fields, tab.name, tab.tabdata)
end
return false
@@ -122,14 +111,9 @@ local function handle_events(self,event)
return true
end
- if self.tablist[self.last_tab_index].evt_handler ~= nil then
- return
- self.tablist[self.last_tab_index].evt_handler(
- self,
- event,
- self.tablist[self.last_tab_index].name,
- self.tablist[self.last_tab_index].tabdata
- )
+ local tab = self.tablist[self.last_tab_index]
+ if tab.evt_handler ~= nil then
+ return tab.evt_handler(self, event, tab.name, tab.tabdata)
end
return false
diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua
index 945707623..bf2d7851e 100644
--- a/builtin/game/chat.lua
+++ b/builtin/game/chat.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/game/chat.lua
+local S = core.get_translator("__builtin")
+
-- Helper function that implements search and replace without pattern matching
-- Returns the string and a boolean indicating whether or not the string was modified
local function safe_gsub(s, replace, with)
@@ -45,6 +47,8 @@ end
core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY
+local msg_time_threshold =
+ tonumber(core.settings:get("chatcommand_msg_time_threshold")) or 0.1
core.register_on_chat_message(function(name, message)
if message:sub(1,1) ~= "/" then
return
@@ -52,7 +56,7 @@ core.register_on_chat_message(function(name, message)
local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
if not cmd then
- core.chat_send_player(name, "-!- Empty command")
+ core.chat_send_player(name, "-!- "..S("Empty command."))
return true
end
@@ -65,15 +69,17 @@ core.register_on_chat_message(function(name, message)
local cmd_def = core.registered_chatcommands[cmd]
if not cmd_def then
- core.chat_send_player(name, "-!- Invalid command: " .. cmd)
+ core.chat_send_player(name, "-!- "..S("Invalid command: @1", cmd))
return true
end
local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
if has_privs then
core.set_last_run_mod(cmd_def.mod_origin)
+ local t_before = minetest.get_us_time()
local success, result = cmd_def.func(name, param)
+ local delay = (minetest.get_us_time() - t_before) / 1000000
if success == false and result == nil then
- core.chat_send_player(name, "-!- Invalid command usage")
+ core.chat_send_player(name, "-!- "..S("Invalid command usage."))
local help_def = core.registered_chatcommands["help"]
if help_def then
local _, helpmsg = help_def.func(name, cmd)
@@ -81,13 +87,26 @@ core.register_on_chat_message(function(name, message)
core.chat_send_player(name, helpmsg)
end
end
- elseif result then
- core.chat_send_player(name, result)
+ else
+ if delay > msg_time_threshold then
+ -- Show how much time it took to execute the command
+ if result then
+ result = result ..
+ minetest.colorize("#f3d2ff", " (%.5g s)"):format(delay)
+ else
+ result = minetest.colorize("#f3d2ff",
+ "Command execution took %.5f s"):format(delay)
+ end
+ end
+ if result then
+ core.chat_send_player(name, result)
+ end
end
else
- core.chat_send_player(name, "You don't have permission"
- .. " to run this command (missing privileges: "
- .. table.concat(missing_privs, ", ") .. ")")
+ core.chat_send_player(name,
+ S("You don't have permission to run this command "
+ .. "(missing privileges: @1).",
+ table.concat(missing_privs, ", ")))
end
return true -- Handled chat message
end)
@@ -107,12 +126,13 @@ local function parse_range_str(player_name, str)
if args[1] == "here" then
p1, p2 = core.get_player_radius_area(player_name, tonumber(args[2]))
if p1 == nil then
- return false, "Unable to get player " .. player_name .. " position"
+ return false, S("Unable to get position of player @1.", player_name)
end
else
p1, p2 = core.string_to_area(str)
if p1 == nil then
- return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
+ return false, S("Incorrect area format. "
+ .. "Expected: (x1,y1,z1) (x2,y2,z2)")
end
end
@@ -123,9 +143,9 @@ end
-- Chat commands
--
core.register_chatcommand("me", {
- params = "<action>",
- description = "Show chat action (e.g., '/me orders a pizza' displays"
- .. " '<player name> orders a pizza')",
+ params = S("<action>"),
+ description = S("Show chat action (e.g., '/me orders a pizza' "
+ .. "displays '<player name> orders a pizza')"),
privs = {shout=true},
func = function(name, param)
core.chat_send_all("* " .. name .. " " .. param)
@@ -134,43 +154,44 @@ core.register_chatcommand("me", {
})
core.register_chatcommand("admin", {
- description = "Show the name of the server owner",
+ description = S("Show the name of the server owner"),
func = function(name)
local admin = core.settings:get("name")
if admin then
- return true, "The administrator of this server is " .. admin .. "."
+ return true, S("The administrator of this server is @1.", admin)
else
- return false, "There's no administrator named in the config file."
+ return false, S("There's no administrator named "
+ .. "in the config file.")
end
end,
})
core.register_chatcommand("privs", {
- params = "[<name>]",
- description = "Show privileges of yourself or another player",
+ params = S("[<name>]"),
+ description = S("Show privileges of yourself or another player"),
func = function(caller, param)
param = param:trim()
local name = (param ~= "" and param or caller)
if not core.player_exists(name) then
- return false, "Player " .. name .. " does not exist."
+ return false, S("Player @1 does not exist.", name)
end
- return true, "Privileges of " .. name .. ": "
- .. core.privs_to_string(
- core.get_player_privs(name), ", ")
+ return true, S("Privileges of @1: @2", name,
+ core.privs_to_string(
+ core.get_player_privs(name), ", "))
end,
})
core.register_chatcommand("haspriv", {
- params = "<privilege>",
- description = "Return list of all online players with privilege.",
+ params = S("<privilege>"),
+ description = S("Return list of all online players with privilege"),
privs = {basic_privs = true},
func = function(caller, param)
param = param:trim()
if param == "" then
- return false, "Invalid parameters (see /help haspriv)"
+ return false, S("Invalid parameters (see /help haspriv).")
end
if not core.registered_privileges[param] then
- return false, "Unknown privilege!"
+ return false, S("Unknown privilege!")
end
local privs = core.string_to_privs(param)
local players_with_priv = {}
@@ -180,19 +201,20 @@ core.register_chatcommand("haspriv", {
table.insert(players_with_priv, player_name)
end
end
- return true, "Players online with the \"" .. param .. "\" privilege: " ..
- table.concat(players_with_priv, ", ")
+ return true, S("Players online with the \"@1\" privilege: @2",
+ param,
+ table.concat(players_with_priv, ", "))
end
})
local function handle_grant_command(caller, grantname, grantprivstr)
local caller_privs = core.get_player_privs(caller)
if not (caller_privs.privs or caller_privs.basic_privs) then
- return false, "Your privileges are insufficient."
+ return false, S("Your privileges are insufficient.")
end
if not core.get_auth_handler().get_auth(grantname) then
- return false, "Player " .. grantname .. " does not exist."
+ return false, S("Player @1 does not exist.", grantname)
end
local grantprivs = core.string_to_privs(grantprivstr)
if grantprivstr == "all" then
@@ -204,10 +226,10 @@ local function handle_grant_command(caller, grantname, grantprivstr)
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
for priv, _ in pairs(grantprivs) do
if not basic_privs[priv] and not caller_privs.privs then
- return false, "Your privileges are insufficient."
+ return false, S("Your privileges are insufficient.")
end
if not core.registered_privileges[priv] then
- privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
+ privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n"
end
privs[priv] = true
end
@@ -221,33 +243,33 @@ local function handle_grant_command(caller, grantname, grantprivstr)
core.set_player_privs(grantname, privs)
core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
if grantname ~= caller then
- core.chat_send_player(grantname, caller
- .. " granted you privileges: "
- .. core.privs_to_string(grantprivs, ' '))
+ core.chat_send_player(grantname,
+ S("@1 granted you privileges: @2", caller,
+ core.privs_to_string(grantprivs, ' ')))
end
- return true, "Privileges of " .. grantname .. ": "
- .. core.privs_to_string(
- core.get_player_privs(grantname), ' ')
+ return true, S("Privileges of @1: @2", grantname,
+ core.privs_to_string(
+ core.get_player_privs(grantname), ' '))
end
core.register_chatcommand("grant", {
- params = "<name> (<privilege> | all)",
- description = "Give privileges to player",
+ params = S("<name> (<privilege> | all)"),
+ description = S("Give privileges to player"),
func = function(name, param)
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
if not grantname or not grantprivstr then
- return false, "Invalid parameters (see /help grant)"
+ return false, S("Invalid parameters (see /help grant).")
end
return handle_grant_command(name, grantname, grantprivstr)
end,
})
core.register_chatcommand("grantme", {
- params = "<privilege> | all",
- description = "Grant privileges to yourself",
+ params = S("<privilege> | all"),
+ description = S("Grant privileges to yourself"),
func = function(name, param)
if param == "" then
- return false, "Invalid parameters (see /help grantme)"
+ return false, S("Invalid parameters (see /help grantme).")
end
return handle_grant_command(name, name, param)
end,
@@ -256,11 +278,11 @@ core.register_chatcommand("grantme", {
local function handle_revoke_command(caller, revokename, revokeprivstr)
local caller_privs = core.get_player_privs(caller)
if not (caller_privs.privs or caller_privs.basic_privs) then
- return false, "Your privileges are insufficient."
+ return false, S("Your privileges are insufficient.")
end
if not core.get_auth_handler().get_auth(revokename) then
- return false, "Player " .. revokename .. " does not exist."
+ return false, S("Player @1 does not exist.", revokename)
end
local revokeprivs = core.string_to_privs(revokeprivstr)
@@ -269,7 +291,7 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
for priv, _ in pairs(revokeprivs) do
if not basic_privs[priv] and not caller_privs.privs then
- return false, "Your privileges are insufficient."
+ return false, S("Your privileges are insufficient.")
end
end
@@ -292,43 +314,43 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
..core.privs_to_string(revokeprivs, ', ')
..') privileges from '..revokename)
if revokename ~= caller then
- core.chat_send_player(revokename, caller
- .. " revoked privileges from you: "
- .. core.privs_to_string(revokeprivs, ' '))
+ core.chat_send_player(revokename,
+ S("@1 revoked privileges from you: @2", caller,
+ core.privs_to_string(revokeprivs, ' ')))
end
- return true, "Privileges of " .. revokename .. ": "
- .. core.privs_to_string(
- core.get_player_privs(revokename), ' ')
+ return true, S("Privileges of @1: @2", revokename,
+ core.privs_to_string(
+ core.get_player_privs(revokename), ' '))
end
core.register_chatcommand("revoke", {
- params = "<name> (<privilege> | all)",
- description = "Remove privileges from player",
+ params = S("<name> (<privilege> | all)"),
+ description = S("Remove privileges from player"),
privs = {},
func = function(name, param)
local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
if not revokename or not revokeprivstr then
- return false, "Invalid parameters (see /help revoke)"
+ return false, S("Invalid parameters (see /help revoke).")
end
return handle_revoke_command(name, revokename, revokeprivstr)
end,
})
core.register_chatcommand("revokeme", {
- params = "<privilege> | all",
- description = "Revoke privileges from yourself",
+ params = S("<privilege> | all"),
+ description = S("Revoke privileges from yourself"),
privs = {},
func = function(name, param)
if param == "" then
- return false, "Invalid parameters (see /help revokeme)"
+ return false, S("Invalid parameters (see /help revokeme).")
end
return handle_revoke_command(name, name, param)
end,
})
core.register_chatcommand("setpassword", {
- params = "<name> <password>",
- description = "Set player's password",
+ params = S("<name> <password>"),
+ description = S("Set player's password"),
privs = {password=true},
func = function(name, param)
local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
@@ -338,207 +360,197 @@ core.register_chatcommand("setpassword", {
end
if not toname then
- return false, "Name field required"
+ return false, S("Name field required.")
end
- local act_str_past, act_str_pres
+ local msg_chat, msg_log, msg_ret
if not raw_password then
core.set_player_password(toname, "")
- act_str_past = "cleared"
- act_str_pres = "clears"
+ msg_chat = S("Your password was cleared by @1.", name)
+ msg_log = name .. " clears password of " .. toname .. "."
+ msg_ret = S("Password of player \"@1\" cleared.", toname)
else
core.set_player_password(toname,
core.get_password_hash(toname,
raw_password))
- act_str_past = "set"
- act_str_pres = "sets"
+ msg_chat = S("Your password was set by @1.", name)
+ msg_log = name .. " sets password of " .. toname .. "."
+ msg_ret = S("Password of player \"@1\" set.", toname)
end
if toname ~= name then
- core.chat_send_player(toname, "Your password was "
- .. act_str_past .. " by " .. name)
+ core.chat_send_player(toname, msg_chat)
end
- core.log("action", name .. " " .. act_str_pres ..
- " password of " .. toname .. ".")
+ core.log("action", msg_log)
- return true, "Password of player \"" .. toname .. "\" " .. act_str_past
+ return true, msg_ret
end,
})
core.register_chatcommand("clearpassword", {
- params = "<name>",
- description = "Set empty password for a player",
+ params = S("<name>"),
+ description = S("Set empty password for a player"),
privs = {password=true},
func = function(name, param)
local toname = param
if toname == "" then
- return false, "Name field required"
+ return false, S("Name field required.")
end
core.set_player_password(toname, '')
core.log("action", name .. " clears password of " .. toname .. ".")
- return true, "Password of player \"" .. toname .. "\" cleared"
+ return true, S("Password of player \"@1\" cleared.", toname)
end,
})
core.register_chatcommand("auth_reload", {
params = "",
- description = "Reload authentication data",
+ description = S("Reload authentication data"),
privs = {server=true},
func = function(name, param)
local done = core.auth_reload()
- return done, (done and "Done." or "Failed.")
+ return done, (done and S("Done.") or S("Failed."))
end,
})
core.register_chatcommand("remove_player", {
- params = "<name>",
- description = "Remove a player's data",
+ params = S("<name>"),
+ description = S("Remove a player's data"),
privs = {server=true},
func = function(name, param)
local toname = param
if toname == "" then
- return false, "Name field required"
+ return false, S("Name field required.")
end
local rc = core.remove_player(toname)
if rc == 0 then
core.log("action", name .. " removed player data of " .. toname .. ".")
- return true, "Player \"" .. toname .. "\" removed."
+ return true, S("Player \"@1\" removed.", toname)
elseif rc == 1 then
- return true, "No such player \"" .. toname .. "\" to remove."
+ return true, S("No such player \"@1\" to remove.", toname)
elseif rc == 2 then
- return true, "Player \"" .. toname .. "\" is connected, cannot remove."
+ return true, S("Player \"@1\" is connected, cannot remove.", toname)
end
- return false, "Unhandled remove_player return code " .. rc .. ""
+ return false, S("Unhandled remove_player return code @1.", tostring(rc))
end,
})
-core.register_chatcommand("teleport", {
- params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)",
- description = "Teleport to position or player",
- privs = {teleport=true},
- func = function(name, param)
- -- Returns (pos, true) if found, otherwise (pos, false)
- local function find_free_position_near(pos)
- local tries = {
- {x=1,y=0,z=0},
- {x=-1,y=0,z=0},
- {x=0,y=0,z=1},
- {x=0,y=0,z=-1},
- }
- for _, d in ipairs(tries) do
- local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
- local n = core.get_node_or_nil(p)
- if n and n.name then
- local def = core.registered_nodes[n.name]
- if def and not def.walkable then
- return p, true
- end
- end
+
+-- pos may be a non-integer position
+local function find_free_position_near(pos)
+ local tries = {
+ {x=1, y=0, z=0},
+ {x=-1, y=0, z=0},
+ {x=0, y=0, z=1},
+ {x=0, y=0, z=-1},
+ }
+ for _, d in ipairs(tries) do
+ local p = vector.add(pos, d)
+ local n = core.get_node_or_nil(p)
+ if n then
+ local def = core.registered_nodes[n.name]
+ if def and not def.walkable then
+ return p
end
- return pos, false
end
+ end
+ return pos
+end
+
+-- Teleports player <name> to <p> if possible
+local function teleport_to_pos(name, p)
+ local lm = 31000
+ if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm
+ or p.z < -lm or p.z > lm then
+ return false, S("Cannot teleport out of map bounds!")
+ end
+ local teleportee = core.get_player_by_name(name)
+ if not teleportee then
+ return false, S("Cannot get player with name @1.", name)
+ end
+ if teleportee:get_attach() then
+ return false, S("Cannot teleport, @1 " ..
+ "is attached to an object!", name)
+ end
+ teleportee:set_pos(p)
+ return true, S("Teleporting @1 to @2.", name, core.pos_to_string(p, 1))
+end
+
+-- Teleports player <name> next to player <target_name> if possible
+local function teleport_to_player(name, target_name)
+ if name == target_name then
+ return false, S("One does not teleport to oneself.")
+ end
+ local teleportee = core.get_player_by_name(name)
+ if not teleportee then
+ return false, S("Cannot get teleportee with name @1.", name)
+ end
+ if teleportee:get_attach() then
+ return false, S("Cannot teleport, @1 " ..
+ "is attached to an object!", name)
+ end
+ local target = core.get_player_by_name(target_name)
+ if not target then
+ return false, S("Cannot get target player with name @1.", target_name)
+ end
+ local p = find_free_position_near(target:get_pos())
+ teleportee:set_pos(p)
+ return true, S("Teleporting @1 to @2 at @3.", name, target_name,
+ core.pos_to_string(p, 1))
+end
+core.register_chatcommand("teleport", {
+ params = S("<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>"),
+ description = S("Teleport to position or player"),
+ privs = {teleport=true},
+ func = function(name, param)
local p = {}
- p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
- p.x = tonumber(p.x)
- p.y = tonumber(p.y)
- p.z = tonumber(p.z)
+ p.x, p.y, p.z = param:match("^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
+ p = vector.apply(p, tonumber)
if p.x and p.y and p.z then
-
- local lm = 31000
- if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm or p.z < -lm or p.z > lm then
- return false, "Cannot teleport out of map bounds!"
- end
- local teleportee = core.get_player_by_name(name)
- if teleportee then
- if teleportee:get_attach() then
- return false, "Can't teleport, you're attached to an object!"
- end
- teleportee:set_pos(p)
- return true, "Teleporting to "..core.pos_to_string(p)
- end
+ return teleport_to_pos(name, p)
end
local target_name = param:match("^([^ ]+)$")
- local teleportee = core.get_player_by_name(name)
-
- p = nil
if target_name then
- local target = core.get_player_by_name(target_name)
- if target then
- p = target:get_pos()
- end
- end
-
- if teleportee and p then
- if teleportee:get_attach() then
- return false, "Can't teleport, you're attached to an object!"
- end
- p = find_free_position_near(p)
- teleportee:set_pos(p)
- return true, "Teleporting to " .. target_name
- .. " at "..core.pos_to_string(p)
+ return teleport_to_player(name, target_name)
end
- if not core.check_player_privs(name, {bring=true}) then
- return false, "You don't have permission to teleport other players (missing bring privilege)"
- end
+ local has_bring_priv = core.check_player_privs(name, {bring=true})
+ local missing_bring_msg = S("You don't have permission to teleport " ..
+ "other players (missing privilege: @1).", "bring")
- teleportee = nil
- p = {}
local teleportee_name
teleportee_name, p.x, p.y, p.z = param:match(
"^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
- p.x, p.y, p.z = tonumber(p.x), tonumber(p.y), tonumber(p.z)
- if teleportee_name then
- teleportee = core.get_player_by_name(teleportee_name)
- end
- if teleportee and p.x and p.y and p.z then
- if teleportee:get_attach() then
- return false, "Can't teleport, player is attached to an object!"
+ p = vector.apply(p, tonumber)
+ if teleportee_name and p.x and p.y and p.z then
+ if not has_bring_priv then
+ return false, missing_bring_msg
end
- teleportee:set_pos(p)
- return true, "Teleporting " .. teleportee_name
- .. " to " .. core.pos_to_string(p)
+ return teleport_to_pos(teleportee_name, p)
end
- teleportee = nil
- p = nil
teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
- if teleportee_name then
- teleportee = core.get_player_by_name(teleportee_name)
- end
- if target_name then
- local target = core.get_player_by_name(target_name)
- if target then
- p = target:get_pos()
+ if teleportee_name and target_name then
+ if not has_bring_priv then
+ return false, missing_bring_msg
end
- end
- if teleportee and p then
- if teleportee:get_attach() then
- return false, "Can't teleport, player is attached to an object!"
- end
- p = find_free_position_near(p)
- teleportee:set_pos(p)
- return true, "Teleporting " .. teleportee_name
- .. " to " .. target_name
- .. " at " .. core.pos_to_string(p)
+ return teleport_to_player(teleportee_name, target_name)
end
- return false, 'Invalid parameters ("' .. param
- .. '") or player not found (see /help teleport)'
+ return false
end,
})
core.register_chatcommand("set", {
- params = "([-n] <name> <value>) | <name>",
- description = "Set or read server configuration setting",
+ params = S("([-n] <name> <value>) | <name>"),
+ description = S("Set or read server configuration setting"),
privs = {server=true},
func = function(name, param)
local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
@@ -550,22 +562,23 @@ core.register_chatcommand("set", {
setname, setvalue = string.match(param, "([^ ]+) (.+)")
if setname and setvalue then
if not core.settings:get(setname) then
- return false, "Failed. Use '/set -n <name> <value>' to create a new setting."
+ return false, S("Failed. Use '/set -n <name> <value>' "
+ .. "to create a new setting.")
end
core.settings:set(setname, setvalue)
- return true, setname .. " = " .. setvalue
+ return true, S("@1 = @2", setname, setvalue)
end
setname = string.match(param, "([^ ]+)")
if setname then
setvalue = core.settings:get(setname)
if not setvalue then
- setvalue = "<not set>"
+ setvalue = S("<not set>")
end
- return true, setname .. " = " .. setvalue
+ return true, S("@1 = @2", setname, setvalue)
end
- return false, "Invalid parameters (see /help set)."
+ return false, S("Invalid parameters (see /help set).")
end,
})
@@ -578,26 +591,27 @@ local function emergeblocks_callback(pos, action, num_calls_remaining, ctx)
if ctx.current_blocks == ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
- string.format("Finished emerging %d blocks in %.2fms.",
- ctx.total_blocks, (os.clock() - ctx.start_time) * 1000))
+ S("Finished emerging @1 blocks in @2ms.",
+ ctx.total_blocks,
+ string.format("%.2f", (os.clock() - ctx.start_time) * 1000)))
end
end
local function emergeblocks_progress_update(ctx)
if ctx.current_blocks ~= ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
- string.format("emergeblocks update: %d/%d blocks emerged (%.1f%%)",
+ S("emergeblocks update: @1/@2 blocks emerged (@3%)",
ctx.current_blocks, ctx.total_blocks,
- (ctx.current_blocks / ctx.total_blocks) * 100))
+ string.format("%.1f", (ctx.current_blocks / ctx.total_blocks) * 100)))
core.after(2, emergeblocks_progress_update, ctx)
end
end
core.register_chatcommand("emergeblocks", {
- params = "(here [<radius>]) | (<pos1> <pos2>)",
- description = "Load (or, if nonexistent, generate) map blocks "
- .. "contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)",
+ params = S("(here [<radius>]) | (<pos1> <pos2>)"),
+ description = S("Load (or, if nonexistent, generate) map blocks contained in "
+ .. "area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)"),
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -615,15 +629,15 @@ core.register_chatcommand("emergeblocks", {
core.emerge_area(p1, p2, emergeblocks_callback, context)
core.after(2, emergeblocks_progress_update, context)
- return true, "Started emerge of area ranging from " ..
- core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
+ return true, S("Started emerge of area ranging from @1 to @2.",
+ core.pos_to_string(p1, 1), core.pos_to_string(p2, 1))
end,
})
core.register_chatcommand("deleteblocks", {
- params = "(here [<radius>]) | (<pos1> <pos2>)",
- description = "Delete map blocks contained in area pos1 to pos2 "
- .. "(<pos1> and <pos2> must be in parentheses)",
+ params = S("(here [<radius>]) | (<pos1> <pos2>)"),
+ description = S("Delete map blocks contained in area pos1 to pos2 "
+ .. "(<pos1> and <pos2> must be in parentheses)"),
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -632,18 +646,20 @@ core.register_chatcommand("deleteblocks", {
end
if core.delete_area(p1, p2) then
- return true, "Successfully cleared area ranging from " ..
- core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
+ return true, S("Successfully cleared area "
+ .. "ranging from @1 to @2.",
+ core.pos_to_string(p1, 1), core.pos_to_string(p2, 1))
else
- return false, "Failed to clear one or more blocks in area"
+ return false, S("Failed to clear one or more "
+ .. "blocks in area.")
end
end,
})
core.register_chatcommand("fixlight", {
- params = "(here [<radius>]) | (<pos1> <pos2>)",
- description = "Resets lighting in the area between pos1 and pos2 "
- .. "(<pos1> and <pos2> must be in parentheses)",
+ params = S("(here [<radius>]) | (<pos1> <pos2>)"),
+ description = S("Resets lighting in the area between pos1 and pos2 "
+ .. "(<pos1> and <pos2> must be in parentheses)"),
privs = {server = true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -652,17 +668,18 @@ core.register_chatcommand("fixlight", {
end
if core.fix_light(p1, p2) then
- return true, "Successfully reset light in the area ranging from " ..
- core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
+ return true, S("Successfully reset light in the area "
+ .. "ranging from @1 to @2.",
+ core.pos_to_string(p1, 1), core.pos_to_string(p2, 1))
else
- return false, "Failed to load one or more blocks in area"
+ return false, S("Failed to load one or more blocks in area.")
end
end,
})
core.register_chatcommand("mods", {
params = "",
- description = "List mods installed on the server",
+ description = S("List mods installed on the server"),
privs = {},
func = function(name, param)
return true, table.concat(core.get_modnames(), ", ")
@@ -674,117 +691,136 @@ local function handle_give_command(cmd, giver, receiver, stackstring)
.. ', stackstring="' .. stackstring .. '"')
local itemstack = ItemStack(stackstring)
if itemstack:is_empty() then
- return false, "Cannot give an empty item"
+ return false, S("Cannot give an empty item.")
elseif (not itemstack:is_known()) or (itemstack:get_name() == "unknown") then
- return false, "Cannot give an unknown item"
+ return false, S("Cannot give an unknown item.")
-- Forbid giving 'ignore' due to unwanted side effects
elseif itemstack:get_name() == "ignore" then
- return false, "Giving 'ignore' is not allowed"
+ return false, S("Giving 'ignore' is not allowed.")
end
local receiverref = core.get_player_by_name(receiver)
if receiverref == nil then
- return false, receiver .. " is not a known player"
+ return false, S("@1 is not a known player.", receiver)
end
local leftover = receiverref:get_inventory():add_item("main", itemstack)
local partiality
if leftover:is_empty() then
- partiality = ""
+ partiality = nil
elseif leftover:get_count() == itemstack:get_count() then
- partiality = "could not be "
+ partiality = false
else
- partiality = "partially "
+ partiality = true
end
-- The actual item stack string may be different from what the "giver"
-- entered (e.g. big numbers are always interpreted as 2^16-1).
stackstring = itemstack:to_string()
+ local msg
+ if partiality == true then
+ msg = S("@1 partially added to inventory.", stackstring)
+ elseif partiality == false then
+ msg = S("@1 could not be added to inventory.", stackstring)
+ else
+ msg = S("@1 added to inventory.", stackstring)
+ end
if giver == receiver then
- local msg = "%q %sadded to inventory."
- return true, msg:format(stackstring, partiality)
+ return true, msg
else
- core.chat_send_player(receiver, ("%q %sadded to inventory.")
- :format(stackstring, partiality))
- local msg = "%q %sadded to %s's inventory."
- return true, msg:format(stackstring, partiality, receiver)
+ core.chat_send_player(receiver, msg)
+ local msg_other
+ if partiality == true then
+ msg_other = S("@1 partially added to inventory of @2.",
+ stackstring, receiver)
+ elseif partiality == false then
+ msg_other = S("@1 could not be added to inventory of @2.",
+ stackstring, receiver)
+ else
+ msg_other = S("@1 added to inventory of @2.",
+ stackstring, receiver)
+ end
+ return true, msg_other
end
end
core.register_chatcommand("give", {
- params = "<name> <ItemString> [<count> [<wear>]]",
- description = "Give item to player",
+ params = S("<name> <ItemString> [<count> [<wear>]]"),
+ description = S("Give item to player"),
privs = {give=true},
func = function(name, param)
local toname, itemstring = string.match(param, "^([^ ]+) +(.+)$")
if not toname or not itemstring then
- return false, "Name and ItemString required"
+ return false, S("Name and ItemString required.")
end
return handle_give_command("/give", name, toname, itemstring)
end,
})
core.register_chatcommand("giveme", {
- params = "<ItemString> [<count> [<wear>]]",
- description = "Give item to yourself",
+ params = S("<ItemString> [<count> [<wear>]]"),
+ description = S("Give item to yourself"),
privs = {give=true},
func = function(name, param)
local itemstring = string.match(param, "(.+)$")
if not itemstring then
- return false, "ItemString required"
+ return false, S("ItemString required.")
end
return handle_give_command("/giveme", name, name, itemstring)
end,
})
core.register_chatcommand("spawnentity", {
- params = "<EntityName> [<X>,<Y>,<Z>]",
- description = "Spawn entity at given (or your) position",
+ params = S("<EntityName> [<X>,<Y>,<Z>]"),
+ description = S("Spawn entity at given (or your) position"),
privs = {give=true, interact=true},
func = function(name, param)
local entityname, p = string.match(param, "^([^ ]+) *(.*)$")
if not entityname then
- return false, "EntityName required"
+ return false, S("EntityName required.")
end
core.log("action", ("%s invokes /spawnentity, entityname=%q")
:format(name, entityname))
local player = core.get_player_by_name(name)
if player == nil then
core.log("error", "Unable to spawn entity, player is nil")
- return false, "Unable to spawn entity, player is nil"
+ return false, S("Unable to spawn entity, player is nil.")
end
if not core.registered_entities[entityname] then
- return false, "Cannot spawn an unknown entity"
+ return false, S("Cannot spawn an unknown entity.")
end
if p == "" then
p = player:get_pos()
else
p = core.string_to_pos(p)
if p == nil then
- return false, "Invalid parameters ('" .. param .. "')"
+ return false, S("Invalid parameters (@1).", param)
end
end
p.y = p.y + 1
local obj = core.add_entity(p, entityname)
- local msg = obj and "%q spawned." or "%q failed to spawn."
- return true, msg:format(entityname)
+ if obj then
+ return true, S("@1 spawned.", entityname)
+ else
+ return true, S("@1 failed to spawn.", entityname)
+ end
end,
})
core.register_chatcommand("pulverize", {
params = "",
- description = "Destroy item in hand",
+ description = S("Destroy item in hand"),
func = function(name, param)
local player = core.get_player_by_name(name)
if not player then
core.log("error", "Unable to pulverize, no player.")
- return false, "Unable to pulverize, no player."
+ return false, S("Unable to pulverize, no player.")
end
local wielded_item = player:get_wielded_item()
if wielded_item:is_empty() then
- return false, "Unable to pulverize, no item in hand."
+ return false, S("Unable to pulverize, no item in hand.")
end
core.log("action", name .. " pulverized \"" ..
wielded_item:get_name() .. " " .. wielded_item:get_count() .. "\"")
player:set_wielded_item(nil)
- return true, "An item was pulverized."
+ return true, S("An item was pulverized.")
end,
})
@@ -800,14 +836,15 @@ core.register_on_punchnode(function(pos, node, puncher)
end)
core.register_chatcommand("rollback_check", {
- params = "[<range>] [<seconds>] [<limit>]",
- description = "Check who last touched a node or a node near it"
- .. " within the time specified by <seconds>. Default: range = 0,"
- .. " seconds = 86400 = 24h, limit = 5. Set <seconds> to inf for no time limit",
+ params = S("[<range>] [<seconds>] [<limit>]"),
+ description = S("Check who last touched a node or a node near it "
+ .. "within the time specified by <seconds>. "
+ .. "Default: range = 0, seconds = 86400 = 24h, limit = 5. "
+ .. "Set <seconds> to inf for no time limit"),
privs = {rollback=true},
func = function(name, param)
if not core.settings:get_bool("enable_rollback_recording") then
- return false, "Rollback functions are disabled."
+ return false, S("Rollback functions are disabled.")
end
local range, seconds, limit =
param:match("(%d+) *(%d*) *(%d*)")
@@ -815,30 +852,30 @@ core.register_chatcommand("rollback_check", {
seconds = tonumber(seconds) or 86400
limit = tonumber(limit) or 5
if limit > 100 then
- return false, "That limit is too high!"
+ return false, S("That limit is too high!")
end
core.rollback_punch_callbacks[name] = function(pos, node, puncher)
local name = puncher:get_player_name()
- core.chat_send_player(name, "Checking " .. core.pos_to_string(pos) .. "...")
+ core.chat_send_player(name, S("Checking @1 ...", core.pos_to_string(pos)))
local actions = core.rollback_get_node_actions(pos, range, seconds, limit)
if not actions then
- core.chat_send_player(name, "Rollback functions are disabled")
+ core.chat_send_player(name, S("Rollback functions are disabled."))
return
end
local num_actions = #actions
if num_actions == 0 then
- core.chat_send_player(name, "Nobody has touched"
- .. " the specified location in "
- .. seconds .. " seconds")
+ core.chat_send_player(name,
+ S("Nobody has touched the specified "
+ .. "location in @1 seconds.",
+ seconds))
return
end
local time = os.time()
for i = num_actions, 1, -1 do
local action = actions[i]
core.chat_send_player(name,
- ("%s %s %s -> %s %d seconds ago.")
- :format(
+ S("@1 @2 @3 -> @4 @5 seconds ago.",
core.pos_to_string(action.pos),
action.actor,
action.oldnode.name,
@@ -847,110 +884,123 @@ core.register_chatcommand("rollback_check", {
end
end
- return true, "Punch a node (range=" .. range .. ", seconds="
- .. seconds .. "s, limit=" .. limit .. ")"
+ return true, S("Punch a node (range=@1, seconds=@2, limit=@3).",
+ range, seconds, limit)
end,
})
core.register_chatcommand("rollback", {
- params = "(<name> [<seconds>]) | (:<actor> [<seconds>])",
- description = "Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit",
+ params = S("(<name> [<seconds>]) | (:<actor> [<seconds>])"),
+ description = S("Revert actions of a player. "
+ .. "Default for <seconds> is 60. "
+ .. "Set <seconds> to inf for no time limit"),
privs = {rollback=true},
func = function(name, param)
if not core.settings:get_bool("enable_rollback_recording") then
- return false, "Rollback functions are disabled."
+ return false, S("Rollback functions are disabled.")
end
local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
+ local rev_msg
if not target_name then
local player_name
player_name, seconds = string.match(param, "([^ ]+) *(%d*)")
if not player_name then
- return false, "Invalid parameters. See /help rollback"
- .. " and /help rollback_check."
+ return false, S("Invalid parameters. "
+ .. "See /help rollback and "
+ .. "/help rollback_check.")
end
+ seconds = tonumber(seconds) or 60
target_name = "player:"..player_name
+ rev_msg = S("Reverting actions of player '@1' since @2 seconds.",
+ player_name, seconds)
+ else
+ seconds = tonumber(seconds) or 60
+ rev_msg = S("Reverting actions of @1 since @2 seconds.",
+ target_name, seconds)
end
- seconds = tonumber(seconds) or 60
- core.chat_send_player(name, "Reverting actions of "
- .. target_name .. " since "
- .. seconds .. " seconds.")
+ core.chat_send_player(name, rev_msg)
local success, log = core.rollback_revert_actions_by(
target_name, seconds)
local response = ""
if #log > 100 then
- response = "(log is too long to show)\n"
+ response = S("(log is too long to show)").."\n"
else
for _, line in pairs(log) do
response = response .. line .. "\n"
end
end
- response = response .. "Reverting actions "
- .. (success and "succeeded." or "FAILED.")
+ if success then
+ response = response .. S("Reverting actions succeeded.")
+ else
+ response = response .. S("Reverting actions FAILED.")
+ end
return success, response
end,
})
core.register_chatcommand("status", {
- description = "Show server status",
+ description = S("Show server status"),
func = function(name, param)
local status = core.get_server_status(name, false)
if status and status ~= "" then
return true, status
end
- return false, "This command was disabled by a mod or game"
+ return false, S("This command was disabled by a mod or game.")
end,
})
core.register_chatcommand("time", {
- params = "[<0..23>:<0..59> | <0..24000>]",
- description = "Show or set time of day",
+ params = S("[<0..23>:<0..59> | <0..24000>]"),
+ description = S("Show or set time of day"),
privs = {},
func = function(name, param)
if param == "" then
local current_time = math.floor(core.get_timeofday() * 1440)
local minutes = current_time % 60
local hour = (current_time - minutes) / 60
- return true, ("Current time is %d:%02d"):format(hour, minutes)
+ return true, S("Current time is @1:@2.",
+ string.format("%d", hour),
+ string.format("%02d", minutes))
end
local player_privs = core.get_player_privs(name)
if not player_privs.settime then
- return false, "You don't have permission to run this command " ..
- "(missing privilege: settime)."
+ return false, S("You don't have permission to run "
+ .. "this command (missing privilege: @1).", "settime")
end
local hour, minute = param:match("^(%d+):(%d+)$")
if not hour then
local new_time = tonumber(param)
if not new_time then
- return false, "Invalid time."
+ return false, S("Invalid time.")
end
-- Backward compatibility.
core.set_timeofday((new_time % 24000) / 24000)
core.log("action", name .. " sets time to " .. new_time)
- return true, "Time of day changed."
+ return true, S("Time of day changed.")
end
hour = tonumber(hour)
minute = tonumber(minute)
if hour < 0 or hour > 23 then
- return false, "Invalid hour (must be between 0 and 23 inclusive)."
+ return false, S("Invalid hour (must be between 0 and 23 inclusive).")
elseif minute < 0 or minute > 59 then
- return false, "Invalid minute (must be between 0 and 59 inclusive)."
+ return false, S("Invalid minute (must be between 0 and 59 inclusive).")
end
core.set_timeofday((hour * 60 + minute) / 1440)
core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute))
- return true, "Time of day changed."
+ return true, S("Time of day changed.")
end,
})
core.register_chatcommand("days", {
- description = "Show day count since world creation",
+ description = S("Show day count since world creation"),
func = function(name, param)
- return true, "Current day is " .. core.get_day_count()
+ return true, S("Current day is @1.", core.get_day_count())
end
})
core.register_chatcommand("shutdown", {
- params = "[<delay_in_seconds> | -1] [reconnect] [<message>]",
- description = "Shutdown server (-1 cancels a delayed shutdown)",
+ params = S("[<delay_in_seconds> | -1] [reconnect] [<message>]"),
+ description = S("Shutdown server (-1 cancels a delayed shutdown)"),
privs = {server=true},
func = function(name, param)
local delay, reconnect, message
@@ -963,7 +1013,7 @@ core.register_chatcommand("shutdown", {
if delay == 0 then
core.log("action", name .. " shuts down server")
- core.chat_send_all("*** Server shutting down (operator request).")
+ core.chat_send_all("*** "..S("Server shutting down (operator request)."))
end
core.request_shutdown(message:trim(), core.is_yes(reconnect), delay)
return true
@@ -971,65 +1021,65 @@ core.register_chatcommand("shutdown", {
})
core.register_chatcommand("ban", {
- params = "[<name>]",
- description = "Ban the IP of a player or show the ban list",
+ params = S("[<name>]"),
+ description = S("Ban the IP of a player or show the ban list"),
privs = {ban=true},
func = function(name, param)
if param == "" then
local ban_list = core.get_ban_list()
if ban_list == "" then
- return true, "The ban list is empty."
+ return true, S("The ban list is empty.")
else
- return true, "Ban list: " .. ban_list
+ return true, S("Ban list: @1", ban_list)
end
end
if not core.get_player_by_name(param) then
- return false, "Player is not online."
+ return false, S("Player is not online.")
end
if not core.ban_player(param) then
- return false, "Failed to ban player."
+ return false, S("Failed to ban player.")
end
local desc = core.get_ban_description(param)
core.log("action", name .. " bans " .. desc .. ".")
- return true, "Banned " .. desc .. "."
+ return true, S("Banned @1.", desc)
end,
})
core.register_chatcommand("unban", {
- params = "<name> | <IP_address>",
- description = "Remove IP ban belonging to a player/IP",
+ params = S("<name> | <IP_address>"),
+ description = S("Remove IP ban belonging to a player/IP"),
privs = {ban=true},
func = function(name, param)
if not core.unban_player_or_ip(param) then
- return false, "Failed to unban player/IP."
+ return false, S("Failed to unban player/IP.")
end
core.log("action", name .. " unbans " .. param)
- return true, "Unbanned " .. param
+ return true, S("Unbanned @1.", param)
end,
})
core.register_chatcommand("kick", {
- params = "<name> [<reason>]",
- description = "Kick a player",
+ params = S("<name> [<reason>]"),
+ description = S("Kick a player"),
privs = {kick=true},
func = function(name, param)
local tokick, reason = param:match("([^ ]+) (.+)")
tokick = tokick or param
if not core.kick_player(tokick, reason) then
- return false, "Failed to kick player " .. tokick
+ return false, S("Failed to kick player @1.", tokick)
end
local log_reason = ""
if reason then
log_reason = " with reason \"" .. reason .. "\""
end
core.log("action", name .. " kicks " .. tokick .. log_reason)
- return true, "Kicked " .. tokick
+ return true, S("Kicked @1.", tokick)
end,
})
core.register_chatcommand("clearobjects", {
- params = "[full | quick]",
- description = "Clear all objects in world",
+ params = S("[full | quick]"),
+ description = S("Clear all objects in world"),
privs = {server=true},
func = function(name, param)
local options = {}
@@ -1038,45 +1088,44 @@ core.register_chatcommand("clearobjects", {
elseif param == "full" then
options.mode = "full"
else
- return false, "Invalid usage, see /help clearobjects."
+ return false, S("Invalid usage, see /help clearobjects.")
end
- core.log("action", name .. " clears all objects ("
+ core.log("action", name .. " clears objects ("
.. options.mode .. " mode).")
- core.chat_send_all("Clearing all objects. This may take a long time."
- .. " You may experience a timeout. (by "
- .. name .. ")")
+ if options.mode == "full" then
+ core.chat_send_all(S("Clearing all objects. This may take a long time. "
+ .. "You may experience a timeout. (by @1)", name))
+ end
core.clear_objects(options)
core.log("action", "Object clearing done.")
- core.chat_send_all("*** Cleared all objects.")
+ core.chat_send_all("*** "..S("Cleared all objects."))
return true
end,
})
core.register_chatcommand("msg", {
- params = "<name> <message>",
- description = "Send a direct message to a player",
+ params = S("<name> <message>"),
+ description = S("Send a direct message to a player"),
privs = {shout=true},
func = function(name, param)
local sendto, message = param:match("^(%S+)%s(.+)$")
if not sendto then
- return false, "Invalid usage, see /help msg."
+ return false, S("Invalid usage, see /help msg.")
end
if not core.get_player_by_name(sendto) then
- return false, "The player " .. sendto
- .. " is not online."
+ return false, S("The player @1 is not online.", sendto)
end
core.log("action", "DM from " .. name .. " to " .. sendto
.. ": " .. message)
- core.chat_send_player(sendto, "DM from " .. name .. ": "
- .. message)
- return true, "Message sent."
+ core.chat_send_player(sendto, S("DM from @1: @2", name, message))
+ return true, S("Message sent.")
end,
})
core.register_chatcommand("last-login", {
- params = "[<name>]",
- description = "Get the last login time of a player or yourself",
+ params = S("[<name>]"),
+ description = S("Get the last login time of a player or yourself"),
func = function(name, param)
if param == "" then
param = name
@@ -1084,25 +1133,27 @@ core.register_chatcommand("last-login", {
local pauth = core.get_auth_handler().get_auth(param)
if pauth and pauth.last_login and pauth.last_login ~= -1 then
-- Time in UTC, ISO 8601 format
- return true, param.."'s last login time was " ..
- os.date("!%Y-%m-%dT%H:%M:%SZ", pauth.last_login)
+ return true, S("@1's last login time was @2.",
+ param,
+ os.date("!%Y-%m-%dT%H:%M:%SZ", pauth.last_login))
end
- return false, param.."'s last login time is unknown"
+ return false, S("@1's last login time is unknown.", param)
end,
})
core.register_chatcommand("clearinv", {
- params = "[<name>]",
- description = "Clear the inventory of yourself or another player",
+ params = S("[<name>]"),
+ description = S("Clear the inventory of yourself or another player"),
func = function(name, param)
local player
if param and param ~= "" and param ~= name then
if not core.check_player_privs(name, {server=true}) then
- return false, "You don't have permission"
- .. " to clear another player's inventory (missing privilege: server)"
+ return false, S("You don't have permission to "
+ .. "clear another player's inventory "
+ .. "(missing privilege: @1).", "server")
end
player = core.get_player_by_name(param)
- core.chat_send_player(param, name.." cleared your inventory.")
+ core.chat_send_player(param, S("@1 cleared your inventory.", name))
else
player = core.get_player_by_name(name)
end
@@ -1112,25 +1163,25 @@ core.register_chatcommand("clearinv", {
player:get_inventory():set_list("craft", {})
player:get_inventory():set_list("craftpreview", {})
core.log("action", name.." clears "..player:get_player_name().."'s inventory")
- return true, "Cleared "..player:get_player_name().."'s inventory."
+ return true, S("Cleared @1's inventory.", player:get_player_name())
else
- return false, "Player must be online to clear inventory!"
+ return false, S("Player must be online to clear inventory!")
end
end,
})
local function handle_kill_command(killer, victim)
if core.settings:get_bool("enable_damage") == false then
- return false, "Players can't be killed, damage has been disabled."
+ return false, S("Players can't be killed, damage has been disabled.")
end
local victimref = core.get_player_by_name(victim)
if victimref == nil then
- return false, string.format("Player %s is not online.", victim)
+ return false, S("Player @1 is not online.", victim)
elseif victimref:get_hp() <= 0 then
if killer == victim then
- return false, "You are already dead."
+ return false, S("You are already dead.")
else
- return false, string.format("%s is already dead.", victim)
+ return false, S("@1 is already dead.", victim)
end
end
if not killer == victim then
@@ -1138,12 +1189,12 @@ local function handle_kill_command(killer, victim)
end
-- Kill victim
victimref:set_hp(0)
- return true, string.format("%s has been killed.", victim)
+ return true, S("@1 has been killed.", victim)
end
core.register_chatcommand("kill", {
- params = "[<name>]",
- description = "Kill player or yourself",
+ params = S("[<name>]"),
+ description = S("Kill player or yourself"),
privs = {server=true},
func = function(name, param)
return handle_kill_command(name, param == "" and name or param)
diff --git a/builtin/game/item.lua b/builtin/game/item.lua
index 881aff52e..b68177c22 100644
--- a/builtin/game/item.lua
+++ b/builtin/game/item.lua
@@ -678,7 +678,7 @@ end
-- Item definition defaults
--
-local default_stack_max = tonumber(minetest.settings:get("default_stack_max")) or 99
+local default_stack_max = tonumber(core.settings:get("default_stack_max")) or 99
core.nodedef_default = {
-- Item properties
diff --git a/builtin/game/knockback.lua b/builtin/game/knockback.lua
index b5c4cbc5a..a937aa186 100644
--- a/builtin/game/knockback.lua
+++ b/builtin/game/knockback.lua
@@ -42,5 +42,5 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool
return -- barely noticeable, so don't even send
end
- player:add_player_velocity(kdir)
+ player:add_velocity(kdir)
end)
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index b8c5e16a9..fcb86146d 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/misc.lua
+local S = core.get_translator("__builtin")
+
--
-- Misc. API functions
--
@@ -42,15 +44,15 @@ end
function core.send_join_message(player_name)
if not core.is_singleplayer() then
- core.chat_send_all("*** " .. player_name .. " joined the game.")
+ core.chat_send_all("*** " .. S("@1 joined the game.", player_name))
end
end
function core.send_leave_message(player_name, timed_out)
- local announcement = "*** " .. player_name .. " left the game."
+ local announcement = "*** " .. S("@1 left the game.", player_name)
if timed_out then
- announcement = announcement .. " (timed out)"
+ announcement = "*** " .. S("@1 left the game (timed out).", player_name)
end
core.chat_send_all(announcement)
end
diff --git a/builtin/game/privileges.lua b/builtin/game/privileges.lua
index c7417d2f4..aee32a34e 100644
--- a/builtin/game/privileges.lua
+++ b/builtin/game/privileges.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/privileges.lua
+local S = core.get_translator("__builtin")
+
--
-- Privileges
--
@@ -15,7 +17,7 @@ function core.register_privilege(name, param)
def.give_to_admin = def.give_to_singleplayer
end
if def.description == nil then
- def.description = "(no description)"
+ def.description = S("(no description)")
end
end
local def
@@ -28,69 +30,69 @@ function core.register_privilege(name, param)
core.registered_privileges[name] = def
end
-core.register_privilege("interact", "Can interact with things and modify the world")
-core.register_privilege("shout", "Can speak in chat")
-core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
-core.register_privilege("privs", "Can modify privileges")
+core.register_privilege("interact", S("Can interact with things and modify the world"))
+core.register_privilege("shout", S("Can speak in chat"))
+core.register_privilege("basic_privs", S("Can modify 'shout' and 'interact' privileges"))
+core.register_privilege("privs", S("Can modify privileges"))
core.register_privilege("teleport", {
- description = "Can teleport self",
+ description = S("Can teleport self"),
give_to_singleplayer = false,
})
core.register_privilege("bring", {
- description = "Can teleport other players",
+ description = S("Can teleport other players"),
give_to_singleplayer = false,
})
core.register_privilege("settime", {
- description = "Can set the time of day using /time",
+ description = S("Can set the time of day using /time"),
give_to_singleplayer = false,
})
core.register_privilege("server", {
- description = "Can do server maintenance stuff",
+ description = S("Can do server maintenance stuff"),
give_to_singleplayer = false,
give_to_admin = true,
})
core.register_privilege("protection_bypass", {
- description = "Can bypass node protection in the world",
+ description = S("Can bypass node protection in the world"),
give_to_singleplayer = false,
})
core.register_privilege("ban", {
- description = "Can ban and unban players",
+ description = S("Can ban and unban players"),
give_to_singleplayer = false,
give_to_admin = true,
})
core.register_privilege("kick", {
- description = "Can kick players",
+ description = S("Can kick players"),
give_to_singleplayer = false,
give_to_admin = true,
})
core.register_privilege("give", {
- description = "Can use /give and /giveme",
+ description = S("Can use /give and /giveme"),
give_to_singleplayer = false,
})
core.register_privilege("password", {
- description = "Can use /setpassword and /clearpassword",
+ description = S("Can use /setpassword and /clearpassword"),
give_to_singleplayer = false,
give_to_admin = true,
})
core.register_privilege("fly", {
- description = "Can use fly mode",
+ description = S("Can use fly mode"),
give_to_singleplayer = false,
})
core.register_privilege("fast", {
- description = "Can use fast mode",
+ description = S("Can use fast mode"),
give_to_singleplayer = false,
})
core.register_privilege("noclip", {
- description = "Can fly through solid nodes using noclip mode",
+ description = S("Can fly through solid nodes using noclip mode"),
give_to_singleplayer = false,
})
core.register_privilege("rollback", {
- description = "Can use the rollback functionality",
+ description = S("Can use the rollback functionality"),
give_to_singleplayer = false,
})
core.register_privilege("debug", {
- description = "Allows enabling various debug options that may affect gameplay",
+ description = S("Allows enabling various debug options that may affect gameplay"),
give_to_singleplayer = false,
give_to_admin = true,
})
diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index b006957e9..c07535855 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/misc_register.lua
+local S = core.get_translator("__builtin")
+
--
-- Make raw registration functions inaccessible to anyone except this file
--
@@ -118,10 +120,6 @@ function core.register_item(name, itemdef)
end
itemdef.name = name
- -- default short_description to first line of description
- itemdef.short_description = itemdef.short_description or
- (itemdef.description or ""):gsub("\n.*","")
-
-- Apply defaults and add to registered_* table
if itemdef.type == "node" then
-- Use the nodebox as selection box if it's not set manually
@@ -330,7 +328,7 @@ end
core.register_item(":unknown", {
type = "none",
- description = "Unknown Item",
+ description = S("Unknown Item"),
inventory_image = "unknown_item.png",
on_place = core.item_place,
on_secondary_use = core.item_secondary_use,
@@ -340,7 +338,7 @@ core.register_item(":unknown", {
})
core.register_node(":air", {
- description = "Air",
+ description = S("Air"),
inventory_image = "air.png",
wield_image = "air.png",
drawtype = "airlike",
@@ -357,7 +355,7 @@ core.register_node(":air", {
})
core.register_node(":ignore", {
- description = "Ignore",
+ description = S("Ignore"),
inventory_image = "ignore.png",
wield_image = "ignore.png",
drawtype = "airlike",
@@ -370,11 +368,12 @@ core.register_node(":ignore", {
air_equivalent = true,
drop = "",
groups = {not_in_creative_inventory=1},
+ node_placement_prediction = "",
on_place = function(itemstack, placer, pointed_thing)
core.chat_send_player(
placer:get_player_name(),
core.colorize("#FF0000",
- "You can't place 'ignore' nodes!"))
+ S("You can't place 'ignore' nodes!")))
return ""
end,
})
diff --git a/builtin/game/statbars.lua b/builtin/game/statbars.lua
index d192029c5..db5087a16 100644
--- a/builtin/game/statbars.lua
+++ b/builtin/game/statbars.lua
@@ -84,8 +84,8 @@ local function update_builtin_statbars(player)
end
if hud.id_breathbar and (not show_breathbar or breath == breath_max) then
- minetest.after(1, function(player_name, breath_bar)
- local player = minetest.get_player_by_name(player_name)
+ core.after(1, function(player_name, breath_bar)
+ local player = core.get_player_by_name(player_name)
if player then
player:hud_remove(breath_bar)
end
diff --git a/builtin/init.lua b/builtin/init.lua
index 75bb3db85..89b1fdc64 100644
--- a/builtin/init.lua
+++ b/builtin/init.lua
@@ -39,9 +39,20 @@ if INIT == "game" then
assert(not core.get_http_api)
elseif INIT == "mainmenu" then
local mm_script = core.settings:get("main_menu_script")
+ local custom_loaded = false
if mm_script and mm_script ~= "" then
- dofile(mm_script)
- else
+ local testfile = io.open(mm_script, "r")
+ if testfile then
+ testfile:close()
+ dofile(mm_script)
+ custom_loaded = true
+ core.log("info", "Loaded custom main menu script: "..mm_script)
+ else
+ core.log("error", "Failed to load custom main menu script: "..mm_script)
+ core.log("info", "Falling back to default main menu script")
+ end
+ end
+ if not custom_loaded then
dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
end
elseif INIT == "async" then
diff --git a/builtin/locale/__builtin.de.tr b/builtin/locale/__builtin.de.tr
new file mode 100644
index 000000000..eaadf611b
--- /dev/null
+++ b/builtin/locale/__builtin.de.tr
@@ -0,0 +1,225 @@
+# textdomain: __builtin
+Empty command.=Leerer Befehl.
+Invalid command: @1=Ungültiger Befehl: @1
+Invalid command usage.=Ungültige Befehlsverwendung.
+You don't have permission to run this command (missing privileges: @1).=Sie haben keine Erlaubnis, diesen Befehl auszuführen (fehlende Privilegien: @1).
+Unable to get position of player @1.=Konnte Position vom Spieler @1 nicht ermitteln.
+Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Ungültiges Gebietsformat. Erwartet: (x1,y1,z1) (x2,y2,z2)
+<action>=<Aktion>
+Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=Chataktion zeigen (z.B. wird „/me isst Pizza“ zu „<Spielername> isst Pizza“)
+Show the name of the server owner=Den Namen des Servereigentümers zeigen
+The administrator of this server is @1.=Der Administrator dieses Servers ist @1.
+There's no administrator named in the config file.=In der Konfigurationsdatei wurde kein Administrator angegeben.
+[<name>]=[<Name>]
+Show privileges of yourself or another player=Ihre eigenen Privilegien oder die eines anderen Spielers anzeigen
+Player @1 does not exist.=Spieler @1 existiert nicht.
+Privileges of @1: @2=Privilegien von @1: @2
+<privilege>=<Privileg>
+Return list of all online players with privilege=Liste aller Spieler mit einem Privileg ausgeben
+Invalid parameters (see /help haspriv).=Ungültige Parameter (siehe „/help haspriv“).
+Unknown privilege!=Unbekanntes Privileg!
+Players online with the "@1" privilege: @2=Derzeit online spielende Spieler mit dem „@1“-Privileg: @2
+Your privileges are insufficient.=Ihre Privilegien sind unzureichend.
+Unknown privilege: @1=Unbekanntes Privileg: @1
+@1 granted you privileges: @2=@1 gewährte Ihnen Privilegien: @2
+<name> (<privilege> | all)=<Name> (<Privileg> | all)
+Give privileges to player=Privileg an Spieler vergeben
+Invalid parameters (see /help grant).=Ungültige Parameter (siehe „/help grant“).
+<privilege> | all=<Privileg> | all
+Grant privileges to yourself=Privilegien an Ihnen selbst vergeben
+Invalid parameters (see /help grantme).=Ungültige Parameter (siehe „/help grantme“).
+@1 revoked privileges from you: @2=@1 entfernte Privilegien von Ihnen: @2
+Remove privileges from player=Privilegien von Spieler entfernen
+Invalid parameters (see /help revoke).=Ungültige Parameter (siehe „/help revoke“).
+Revoke privileges from yourself=Privilegien von Ihnen selbst entfernen
+Invalid parameters (see /help revokeme).=Ungültige Parameter (siehe „/help revokeme“).
+<name> <password>=<Name> <Passwort>
+Set player's password=Passwort von Spieler setzen
+Name field required.=Namensfeld benötigt.
+Your password was cleared by @1.=Ihr Passwort wurde von @1 geleert.
+Password of player "@1" cleared.=Passwort von Spieler „@1“ geleert.
+Your password was set by @1.=Ihr Passwort wurde von @1 gesetzt.
+Password of player "@1" set.=Passwort von Spieler „@1“ gesetzt.
+<name>=<Name>
+Set empty password for a player=Leeres Passwort für einen Spieler setzen
+Reload authentication data=Authentifizierungsdaten erneut laden
+Done.=Fertig.
+Failed.=Fehlgeschlagen.
+Remove a player's data=Daten eines Spielers löschen
+Player "@1" removed.=Spieler „@1“ gelöscht.
+No such player "@1" to remove.=Es gibt keinen Spieler „@1“, der gelöscht werden könnte.
+Player "@1" is connected, cannot remove.=Spieler „@1“ ist verbunden, er kann nicht gelöscht werden.
+Unhandled remove_player return code @1.=Nicht berücksichtigter remove_player-Rückgabewert @1.
+Cannot teleport out of map bounds!=Eine Teleportation außerhalb der Kartengrenzen ist nicht möglich!
+Cannot get player with name @1.=Spieler mit Namen @1 kann nicht gefunden werden.
+Cannot teleport, @1 is attached to an object!=Teleportation nicht möglich, @1 ist an einem Objekt befestigt!
+Teleporting @1 to @2.=Teleportation von @1 nach @2
+One does not teleport to oneself.=Man teleportiert sich doch nicht zu sich selbst.
+Cannot get teleportee with name @1.=Der zu teleportierende Spieler mit Namen @1 kann nicht gefunden werden.
+Cannot get target player with name @1.=Zielspieler mit Namen @1 kann nicht gefunden werden.
+Teleporting @1 to @2 at @3.=Teleportation von @1 zu @2 bei @3
+<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=<X>,<Y>,<Z> | <zu_Name> | <Name> <X>,<Y>,<Z> | <Name> <zu_Name>
+Teleport to position or player=Zu Position oder Spieler teleportieren
+You don't have permission to teleport other players (missing privilege: @1).=Sie haben nicht die Erlaubnis, andere Spieler zu teleportieren (fehlendes Privileg: @1).
+([-n] <name> <value>) | <name>=([-n] <Name> <Wert>) | <Name>
+Set or read server configuration setting=Serverkonfigurationseinstellung setzen oder lesen
+Failed. Use '/set -n <name> <value>' to create a new setting.=Fehlgeschlagen. Benutzen Sie „/set -n <Name> <Wert>“, um eine neue Einstellung zu erstellen.
+@1 @= @2=@1 @= @2
+<not set>=<nicht gesetzt>
+Invalid parameters (see /help set).=Ungültige Parameter (siehe „/help set“).
+Finished emerging @1 blocks in @2ms.=Fertig mit Erzeugung von @1 Blöcken in @2 ms.
+emergeblocks update: @1/@2 blocks emerged (@3%)=emergeblocks-Update: @1/@2 Kartenblöcke geladen (@3%)
+(here [<radius>]) | (<pos1> <pos2>)=(here [<Radius>]) | (<Pos1> <Pos2>)
+Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Lade (oder, wenn nicht existent, generiere) Kartenblöcke im Gebiet zwischen Pos1 und Pos2 (<Pos1> und <Pos2> müssen in Klammern stehen)
+Started emerge of area ranging from @1 to @2.=Start des Ladevorgangs des Gebiets zwischen @1 und @2.
+Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Kartenblöcke innerhalb des Gebiets zwischen Pos1 und Pos2 löschen (<Pos1> und <Pos2> müssen in Klammern stehen)
+Successfully cleared area ranging from @1 to @2.=Gebiet zwischen @1 und @2 erfolgreich geleert.
+Failed to clear one or more blocks in area.=Fehlgeschlagen: Ein oder mehrere Kartenblöcke im Gebiet konnten nicht geleert werden.
+Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=Setzt das Licht im Gebiet zwischen Pos1 und Pos2 zurück (<Pos1> und <Pos2> müssen in Klammern stehen)
+Successfully reset light in the area ranging from @1 to @2.=Das Licht im Gebiet zwischen @1 und @2 wurde erfolgreich zurückgesetzt.
+Failed to load one or more blocks in area.=Fehlgeschlagen: Ein oder mehrere Kartenblöcke im Gebiet konnten nicht geladen werden.
+List mods installed on the server=Installierte Mods auf dem Server auflisten
+Cannot give an empty item.=Ein leerer Gegenstand kann nicht gegeben werden.
+Cannot give an unknown item.=Ein unbekannter Gegenstand kann nicht gegeben werden.
+Giving 'ignore' is not allowed.=„ignore“ darf nicht gegeben werden.
+@1 is not a known player.=@1 ist kein bekannter Spieler.
+@1 partially added to inventory.=@1 teilweise ins Inventar eingefügt.
+@1 could not be added to inventory.=@1 konnte nicht ins Inventar eingefügt werden.
+@1 added to inventory.=@1 zum Inventar hinzugefügt.
+@1 partially added to inventory of @2.=@1 teilweise ins Inventar von @2 eingefügt.
+@1 could not be added to inventory of @2.=@1 konnte nicht ins Inventar von @2 eingefügt werden.
+@1 added to inventory of @2.=@1 ins Inventar von @2 eingefügt.
+<name> <ItemString> [<count> [<wear>]]=<Name> <ItemString> [<Anzahl> [<Abnutzung>]]
+Give item to player=Gegenstand an Spieler geben
+Name and ItemString required.=Name und ItemString benötigt.
+<ItemString> [<count> [<wear>]]=<ItemString> [<Anzahl> [<Abnutzung>]]
+Give item to yourself=Gegenstand Ihnen selbst geben
+ItemString required.=ItemString benötigt.
+<EntityName> [<X>,<Y>,<Z>]=<EntityName> [<X>,<Y>,<Z>]
+Spawn entity at given (or your) position=Entity an angegebener (oder Ihrer eigenen) Position spawnen
+EntityName required.=EntityName benötigt.
+Unable to spawn entity, player is nil.=Entity konnte nicht gespawnt werden, Spieler ist nil.
+Cannot spawn an unknown entity.=Ein unbekanntes Entity kann nicht gespawnt werden.
+Invalid parameters (@1).=Ungültige Parameter (@1).
+@1 spawned.=@1 gespawnt.
+@1 failed to spawn.=@1 konnte nicht gespawnt werden.
+Destroy item in hand=Gegenstand in der Hand zerstören
+Unable to pulverize, no player.=Konnte nicht pulverisieren, kein Spieler.
+Unable to pulverize, no item in hand.=Konnte nicht pulverisieren, kein Gegenstand in der Hand.
+An item was pulverized.=Ein Gegenstand wurde pulverisiert.
+[<range>] [<seconds>] [<limit>]=[<Reichweite>] [<Sekunden>] [<Limit>]
+Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=Überprüfen, wer als letztes einen Node oder einen Node in der Nähe innerhalb der in <Sekunden> angegebenen Zeitspanne angefasst hat. Standard: Reichweite @= 0, Sekunden @= 86400 @= 24h, Limit @= 5. <Sekunden> auf „inf“ setzen, um Zeitlimit zu deaktivieren.
+Rollback functions are disabled.=Rollback-Funktionen sind deaktiviert.
+That limit is too high!=Dieses Limit ist zu hoch!
+Checking @1 ...=Überprüfe @1 ...
+Nobody has touched the specified location in @1 seconds.=Niemand hat die angegebene Position seit @1 Sekunden angefasst.
+@1 @2 @3 -> @4 @5 seconds ago.=@1 @2 @3 -> @4 vor @5 Sekunden.
+Punch a node (range@=@1, seconds@=@2, limit@=@3).=Hauen Sie einen Node (Reichweite@=@1, Sekunden@=@2, Limit@=@3).
+(<name> [<seconds>]) | (:<actor> [<seconds>])=(<Name> [<Sekunden>]) | (:<Akteur> [<Sekunden>])
+Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=Aktionen eines Spielers zurückrollen. Standard für <Sekunden> ist 60. <Sekunden> auf „inf“ setzen, um Zeitlimit zu deaktivieren
+Invalid parameters. See /help rollback and /help rollback_check.=Ungültige Parameter. Siehe /help rollback und /help rollback_check.
+Reverting actions of player '@1' since @2 seconds.=Die Aktionen des Spielers „@1“ seit @2 Sekunden werden rückgängig gemacht.
+Reverting actions of @1 since @2 seconds.=Die Aktionen von @1 seit @2 Sekunden werden rückgängig gemacht.
+(log is too long to show)=(Protokoll ist zu lang für die Anzeige)
+Reverting actions succeeded.=Die Aktionen wurden erfolgreich rückgängig gemacht.
+Reverting actions FAILED.=FEHLGESCHLAGEN: Die Aktionen konnten nicht rückgängig gemacht werden.
+Show server status=Serverstatus anzeigen
+This command was disabled by a mod or game.=Dieser Befehl wurde von einer Mod oder einem Spiel deaktiviert.
+[<0..23>:<0..59> | <0..24000>]=[<0..23>:<0..59> | <0..24000>]
+Show or set time of day=Tageszeit anzeigen oder setzen
+Current time is @1:@2.=Es ist jetzt @1:@2 Uhr.
+You don't have permission to run this command (missing privilege: @1).=Sie haben nicht die Erlaubnis, diesen Befehl auszuführen (fehlendes Privileg: @1).
+Invalid time.=Ungültige Zeit.
+Time of day changed.=Tageszeit geändert.
+Invalid hour (must be between 0 and 23 inclusive).=Ungültige Stunde (muss zwischen 0 und 23 inklusive liegen).
+Invalid minute (must be between 0 and 59 inclusive).=Ungültige Minute (muss zwischen 0 und 59 inklusive liegen).
+Show day count since world creation=Anzahl Tage seit der Erschaffung der Welt anzeigen
+Current day is @1.=Aktueller Tag ist @1.
+[<delay_in_seconds> | -1] [reconnect] [<message>]=[<Verzögerung_in_Sekunden> | -1] [reconnect] [<Nachricht>]
+Shutdown server (-1 cancels a delayed shutdown)=Server herunterfahren (-1 bricht einen verzögerten Abschaltvorgang ab)
+Server shutting down (operator request).=Server wird heruntergefahren (Betreiberanfrage).
+Ban the IP of a player or show the ban list=Die IP eines Spielers verbannen oder die Bannliste anzeigen
+The ban list is empty.=Die Bannliste ist leer.
+Ban list: @1=Bannliste: @1
+Player is not online.=Spieler ist nicht online.
+Failed to ban player.=Konnte Spieler nicht verbannen.
+Banned @1.=@1 verbannt.
+<name> | <IP_address>=<Name> | <IP_Adresse>
+Remove IP ban belonging to a player/IP=Einen IP-Bann auf einen Spieler zurücknehmen
+Failed to unban player/IP.=Konnte Bann auf Spieler/IP nicht zurücknehmen.
+Unbanned @1.=Bann auf @1 zurückgenommen.
+<name> [<reason>]=<Name> [<Grund>]
+Kick a player=Spieler hinauswerfen
+Failed to kick player @1.=Spieler @1 konnte nicht hinausgeworfen werden.
+Kicked @1.=@1 hinausgeworfen.
+[full | quick]=[full | quick]
+Clear all objects in world=Alle Objekte in der Welt löschen
+Invalid usage, see /help clearobjects.=Ungültige Verwendung, siehe /help clearobjects.
+Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Lösche alle Objekte. Dies kann eine lange Zeit dauern. Eine Netzwerkzeitüberschreitung könnte für Sie auftreten. (von @1)
+Objects cleared.=Objekte gelöscht.
+Cleared all objects.=Alle Objekte gelöscht.
+<name> <message>=<Name> <Nachricht>
+Send a direct message to a player=Eine Direktnachricht an einen Spieler senden
+Invalid usage, see /help msg.=Ungültige Verwendung, siehe /help msg.
+The player @1 is not online.=Der Spieler @1 ist nicht online.
+DM from @1: @2=DN von @1: @2
+Message sent.=Nachricht gesendet.
+Get the last login time of a player or yourself=Den letzten Loginzeitpunkt eines Spielers oder Ihren eigenen anfragen
+@1's last login time was @2.=Letzter Loginzeitpunkt von @1 war @2.
+@1's last login time is unknown.=Letzter Loginzeitpunkt von @1 ist unbekannt.
+Clear the inventory of yourself or another player=Das Inventar von Ihnen oder einem anderen Spieler leeren
+You don't have permission to clear another player's inventory (missing privilege: @1).=Sie haben nicht die Erlaubnis, das Inventar eines anderen Spielers zu leeren (fehlendes Privileg: @1).
+@1 cleared your inventory.=@1 hat Ihr Inventar geleert.
+Cleared @1's inventory.=Inventar von @1 geleert.
+Player must be online to clear inventory!=Spieler muss online sein, um das Inventar leeren zu können!
+Players can't be killed, damage has been disabled.=Spieler können nicht getötet werden, Schaden ist deaktiviert.
+Player @1 is not online.=Spieler @1 ist nicht online.
+You are already dead.=Sie sind schon tot.
+@1 is already dead.=@1 ist bereits tot.
+@1 has been killed.=@1 wurde getötet.
+Kill player or yourself=Einen Spieler oder Sie selbst töten
+Available commands: @1=Verfügbare Befehle: @1
+Use '/help <cmd>' to get more information, or '/help all' to list everything.=„/help <Befehl>“ benutzen, um mehr Informationen zu erhalten, oder „/help all“, um alles aufzulisten.
+Available commands:=Verfügbare Befehle:
+Command not available: @1=Befehl nicht verfügbar: @1
+[all | privs | <cmd>]=[all | privs | <Befehl>]
+Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten
+Available privileges:=Verfügbare Privilegien:
+Command=Befehl
+Parameters=Parameter
+For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
+Double-click to copy the entry to the chat history.=Doppelklicken, um den Eintrag in die Chathistorie einzufügen.
+Command: @1 @2=Befehl: @1 @2
+Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /help <Befehl>)
+Close=Schließen
+Privilege=Privileg
+Description=Beschreibung
+print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
+Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
+Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
+Statistics were reset.=Statistiken wurden zurückgesetzt.
+Usage: @1=Verwendung: @1
+Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
+(no description)=(keine Beschreibung)
+Can interact with things and modify the world=Kann mit Dingen interagieren und die Welt verändern
+Can speak in chat=Kann im Chat sprechen
+Can modify 'shout' and 'interact' privileges=Kann die „shout“- und „interact“-Privilegien anpassen
+Can modify privileges=Kann Privilegien anpassen
+Can teleport self=Kann sich selbst teleportieren
+Can teleport other players=Kann andere Spieler teleportieren
+Can set the time of day using /time=Kann die Tageszeit mit /time setzen
+Can do server maintenance stuff=Kann Serverwartungsdinge machen
+Can bypass node protection in the world=Kann den Schutz auf Blöcken in der Welt umgehen
+Can ban and unban players=Kann Spieler verbannen und entbannen
+Can kick players=Kann Spieler hinauswerfen
+Can use /give and /giveme=Kann /give und /giveme benutzen
+Can use /setpassword and /clearpassword=Kann /setpassword und /clearpassword benutzen
+Can use fly mode=Kann den Flugmodus benutzen
+Can use fast mode=Kann den Schnellmodus benutzen
+Can fly through solid nodes using noclip mode=Kann durch feste Blöcke mit dem Geistmodus fliegen
+Can use the rollback functionality=Kann die Rollback-Funktionalität benutzen
+Allows enabling various debug options that may affect gameplay=Erlaubt die Aktivierung diverser Debugoptionen, die das Spielgeschehen beeinflussen könnten
+Unknown Item=Unbekannter Gegenstand
+Air=Luft
+Ignore=Ignorieren
+You can't place 'ignore' nodes!=Sie können keine „ignore“-Blöcke platzieren!
diff --git a/builtin/locale/__builtin.it.tr b/builtin/locale/__builtin.it.tr
new file mode 100644
index 000000000..94bc870c8
--- /dev/null
+++ b/builtin/locale/__builtin.it.tr
@@ -0,0 +1,224 @@
+# textdomain: __builtin
+Empty command.=Comando vuoto.
+Invalid command: @1=Comando non valido: @1
+Invalid command usage.=Utilizzo del comando non valido.
+You don't have permission to run this command (missing privileges: @1).=Non hai il permesso di eseguire questo comando (privilegi mancanti: @1).
+Unable to get position of player @1.=Impossibile ottenere la posizione del giocatore @1.
+Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Formato dell'area non corretto. Richiesto: (x1,y1,z1) (x2,y2,z2)
+<action>=<azione>
+Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=Mostra un'azione in chat (es. `/me ordina una pizza` mostra `<nome giocatore> ordina una pizza`)
+Show the name of the server owner=Mostra il nome del proprietario del server
+The administrator of this server is @1.=L'amministratore di questo server è @1.
+There's no administrator named in the config file.=Non c'è nessun amministratore nel file di configurazione.
+[<name>]=[<nome>]
+Show privileges of yourself or another player=Mostra i privilegi propri o di un altro giocatore
+Player @1 does not exist.=Il giocatore @1 non esiste.
+Privileges of @1: @2=Privilegi di @1: @2
+<privilege>=<privilegio>
+Return list of all online players with privilege=Ritorna una lista di tutti i giocatori connessi col tale privilegio
+Invalid parameters (see /help haspriv).=Parametri non validi (vedi /help haspriv).
+Unknown privilege!=Privilegio sconosciuto!
+Players online with the "@1" privilege: @2=Giocatori connessi con il privilegio "@1": @2
+Your privileges are insufficient.=I tuoi privilegi sono insufficienti.
+Unknown privilege: @1=Privilegio sconosciuto: @1
+@1 granted you privileges: @2=@1 ti ha assegnato i seguenti privilegi: @2
+<name> (<privilege> | all)=<nome> (<privilegio> | all)
+Give privileges to player=Dà privilegi al giocatore
+Invalid parameters (see /help grant).=Parametri non validi (vedi /help grant).
+<privilege> | all=<privilegio> | all
+Grant privileges to yourself=Assegna dei privilegi a te stessǝ
+Invalid parameters (see /help grantme).=Parametri non validi (vedi /help grantme).
+@1 revoked privileges from you: @2=@1 ti ha revocato i seguenti privilegi: @2
+Remove privileges from player=Rimuove privilegi dal giocatore
+Invalid parameters (see /help revoke).=Parametri non validi (vedi /help revoke).
+Revoke privileges from yourself=Revoca privilegi a te stessǝ
+Invalid parameters (see /help revokeme).=Parametri non validi (vedi /help revokeme).
+<name> <password>=<nome> <password>
+Set player's password=Imposta la password del giocatore
+Name field required.=Campo "nome" richiesto.
+Your password was cleared by @1.=La tua password è stata resettata da @1.
+Password of player "@1" cleared.=Password del giocatore "@1" resettata.
+Your password was set by @1.=La tua password è stata impostata da @1.
+Password of player "@1" set.=Password del giocatore "@1" impostata.
+<name>=<nome>
+Set empty password for a player=Imposta una password vuota a un giocatore
+Reload authentication data=Ricarica i dati d'autenticazione
+Done.=Fatto.
+Failed.=Errore.
+Remove a player's data=Rimuove i dati di un giocatore
+Player "@1" removed.=Giocatore "@1" rimosso.
+No such player "@1" to remove.=Non è presente nessun giocatore "@1" da rimuovere.
+Player "@1" is connected, cannot remove.=Il giocatore "@1" è connesso, non può essere rimosso.
+Unhandled remove_player return code @1.=Codice ritornato da remove_player non gestito (@1).
+Cannot teleport out of map bounds!=Non ci si può teletrasportare fuori dai limiti della mappa!
+Cannot get player with name @1.=Impossibile trovare il giocatore chiamato @1.
+Cannot teleport, @1 is attached to an object!=Impossibile teletrasportare, @1 è attaccato a un oggetto!
+Teleporting @1 to @2.=Teletrasportando @1 da @2.
+One does not teleport to oneself.=Non ci si può teletrasportare su se stessi.
+Cannot get teleportee with name @1.=Impossibile trovare il giocatore chiamato @1 per il teletrasporto
+Cannot get target player with name @1.=Impossibile trovare il giocatore chiamato @1 per il teletrasporto
+Teleporting @1 to @2 at @3.=Teletrasportando @1 da @2 a @3
+<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=<X>,<Y>,<Z> | <da_nome> | <nome> <X>,<Y>,<Z> | <nome> <da_nome>
+Teleport to position or player=Teletrasporta a una posizione o da un giocatore
+You don't have permission to teleport other players (missing privilege: @1).=Non hai il permesso di teletrasportare altri giocatori (privilegio mancante: @1).
+([-n] <name> <value>) | <name>=([-n] <nome> <valore>) | <nome>
+Set or read server configuration setting=Imposta o ottieni le configurazioni del server
+Failed. Use '/set -n <name> <value>' to create a new setting.=Errore. Usa 'set -n <nome> <valore>' per creare una nuova impostazione
+@1 @= @2=@1 @= @2
+<not set>=<non impostato>
+Invalid parameters (see /help set).=Parametri non validi (vedi /help set).
+Finished emerging @1 blocks in @2ms.=Finito di emergere @1 blocchi in @2ms
+emergeblocks update: @1/@2 blocks emerged (@3%)=aggiornamento emergeblocks: @1/@2 blocchi emersi (@3%)
+(here [<radius>]) | (<pos1> <pos2>)=(here [<raggio>]) | (<pos1> <pos2>)
+Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Carica (o, se non esiste, genera) blocchi mappa contenuti nell'area tra pos1 e pos2 (<pos1> e <pos2> vanno tra parentesi)
+Started emerge of area ranging from @1 to @2.=Iniziata emersione dell'area tra @1 e @2.
+Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Cancella i blocchi mappa contenuti nell'area tra pos1 e pos2 (<pos1> e <pos2> vanno tra parentesi)
+Successfully cleared area ranging from @1 to @2.=Area tra @1 e @2 ripulita con successo.
+Failed to clear one or more blocks in area.=Errore nel ripulire uno o più blocchi mappa nell'area
+Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=Reimposta l'illuminazione nell'area tra pos1 e po2 (<pos1> e <pos2> vanno tra parentesi)
+Successfully reset light in the area ranging from @1 to @2.=Luce nell'area tra @1 e @2 reimpostata con successo.
+Failed to load one or more blocks in area.=Errore nel caricare uno o più blocchi mappa nell'area.
+List mods installed on the server=Elenca le mod installate nel server
+Cannot give an empty item.=Impossibile dare un oggetto vuoto.
+Cannot give an unknown item.=Impossibile dare un oggetto sconosciuto.
+Giving 'ignore' is not allowed.=Non è permesso dare 'ignore'.
+@1 is not a known player.=@1 non è un giocatore conosciuto.
+@1 partially added to inventory.=@1 parzialmente aggiunto all'inventario.
+@1 could not be added to inventory.=@1 non può essere aggiunto all'inventario.
+@1 added to inventory.=@1 aggiunto all'inventario.
+@1 partially added to inventory of @2.=@1 parzialmente aggiunto all'inventario di @2.
+@1 could not be added to inventory of @2.=Non è stato possibile aggiungere @1 all'inventario di @2.
+@1 added to inventory of @2.=@1 aggiunto all'inventario di @2.
+<name> <ItemString> [<count> [<wear>]]=<nome> <NomeOggetto> [<quantità> [<usura>]]
+Give item to player=Dà oggetti ai giocatori
+Name and ItemString required.=Richiesti nome e NomeOggetto.
+<ItemString> [<count> [<wear>]]=<NomeOggetto> [<quantità> [<usura>]]
+Give item to yourself=Dà oggetti a te stessǝ
+ItemString required.=Richiesto NomeOggetto.
+<EntityName> [<X>,<Y>,<Z>]=<NomeEntità> [<X>,<Y>,<Z>]
+Spawn entity at given (or your) position=Genera un'entità alla data coordinata (o la tua)
+EntityName required.=Richiesto NomeEntità
+Unable to spawn entity, player is nil.=Impossibile generare l'entità, il giocatore è nil.
+Cannot spawn an unknown entity.=Impossibile generare un'entità sconosciuta.
+Invalid parameters (@1).=Parametri non validi (@1).
+@1 spawned.=Generata entità @1.
+@1 failed to spawn.=Errore nel generare @1
+Destroy item in hand=Distrugge l'oggetto in mano
+Unable to pulverize, no player.=Impossibile polverizzare, nessun giocatore.
+Unable to pulverize, no item in hand.=Impossibile polverizzare, nessun oggetto in mano.
+An item was pulverized.=Un oggetto è stato polverizzato.
+[<range>] [<seconds>] [<limit>]=[<raggio>] [<secondi>] [<limite>]
+Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=Controlla chi è l'ultimo giocatore che ha toccato un nodo o un nodo nelle sue vicinanze, negli ultimi secondi indicati. Di base: raggio @= 0, secondi @= 86400 @= 24h, limite @= 5.
+Rollback functions are disabled.=Le funzioni di rollback sono disabilitate.
+That limit is too high!=Il limite è troppo alto!
+Checking @1 ...=Controllando @1 ...
+Nobody has touched the specified location in @1 seconds.=Nessuno ha toccato il punto specificato negli ultimi @1 secondi.
+@1 @2 @3 -> @4 @5 seconds ago.=@1 @2 @3 -> @4 @5 secondi fa.
+Punch a node (range@=@1, seconds@=@2, limit@=@3).=Colpisce un nodo (raggio@=@1, secondi@=@2, limite@=@3)
+(<name> [<seconds>]) | (:<actor> [<seconds>])=(<nome> [<secondi>]) | (:<attore> [<secondi>])
+Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=Riavvolge le azioni di un giocatore. Di base, <secondi> è 60. Imposta <secondi> a inf per nessun limite di tempo
+Invalid parameters. See /help rollback and /help rollback_check.=Parametri non validi. Vedi /help rollback e /help rollback_check.
+Reverting actions of player '@1' since @2 seconds.=Riavvolge le azioni del giocatore '@1' avvenute negli ultimi @2 secondi.
+Reverting actions of @1 since @2 seconds.=Riavvolge le azioni di @1 avvenute negli ultimi @2 secondi.
+(log is too long to show)=(il log è troppo lungo per essere mostrato)
+Reverting actions succeeded.=Riavvolgimento azioni avvenuto con successo.
+Reverting actions FAILED.=Errore nel riavvolgere le azioni.
+Show server status=Mostra lo stato del server
+This command was disabled by a mod or game.=Questo comando è stato disabilitato da una mod o dal gioco.
+[<0..23>:<0..59> | <0..24000>]=[<0..23>:<0..59> | <0..24000>]
+Show or set time of day=Mostra o imposta l'orario della giornata
+Current time is @1:@2.=Orario corrente: @1:@2.
+You don't have permission to run this command (missing privilege: @1).=Non hai il permesso di eseguire questo comando (privilegio mancante: @1)
+Invalid time.=Orario non valido.
+Time of day changed.=Orario della giornata cambiato.
+Invalid hour (must be between 0 and 23 inclusive).=Ora non valida (deve essere tra 0 e 23 inclusi)
+Invalid minute (must be between 0 and 59 inclusive).=Minuto non valido (deve essere tra 0 e 59 inclusi)
+Show day count since world creation=Mostra il conteggio dei giorni da quando il mondo è stato creato
+Current day is @1.=Giorno attuale: @1.
+[<delay_in_seconds> | -1] [reconnect] [<message>]=[<ritardo_in_secondi> | -1] [reconnect] [<messaggio>]
+Shutdown server (-1 cancels a delayed shutdown)=Arresta il server (-1 annulla un arresto programmato)
+Server shutting down (operator request).=Arresto del server in corso (per richiesta dell'operatore)
+Ban the IP of a player or show the ban list=Bandisce l'IP del giocatore o mostra la lista di quelli banditi
+The ban list is empty.=La lista banditi è vuota.
+Ban list: @1=Lista banditi: @1
+Player is not online.=Il giocatore non è connesso.
+Failed to ban player.=Errore nel bandire il giocatore.
+Banned @1.=@1 banditǝ.
+<name> | <IP_address>=<nome> | <indirizzo_IP>
+Remove IP ban belonging to a player/IP=Perdona l'IP appartenente a un giocatore/IP
+Failed to unban player/IP.=Errore nel perdonare il giocatore/IP
+Unbanned @1.=@1 perdonatǝ
+<name> [<reason>]=<nome> [<ragione>]
+Kick a player=Caccia un giocatore
+Failed to kick player @1.=Errore nel cacciare il giocatore @1.
+Kicked @1.=@1 cacciatǝ.
+[full | quick]=[full | quick]
+Clear all objects in world=Elimina tutti gli oggetti/entità nel mondo
+Invalid usage, see /help clearobjects.=Uso incorretto, vedi /help clearobjects.
+Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Eliminando tutti gli oggetti/entità. Questo potrebbe richiedere molto tempo e farti eventualmente crashare. (di @1)
+Cleared all objects.=Tutti gli oggetti sono stati eliminati.
+<name> <message>=<nome> <messaggio>
+Send a direct message to a player=Invia un messaggio privato al giocatore
+Invalid usage, see /help msg.=Uso incorretto, vedi /help msg
+The player @1 is not online.=Il giocatore @1 non è connesso.
+DM from @1: @2=Messaggio privato da @1: @2
+Message sent.=Messaggio inviato.
+Get the last login time of a player or yourself=Ritorna l'ultimo accesso di un giocatore o di te stessǝ
+@1's last login time was @2.=L'ultimo accesso di @1 è avvenuto il @2
+@1's last login time is unknown.=L'ultimo accesso di @1 non è conosciuto
+Clear the inventory of yourself or another player=Svuota l'inventario tuo o di un altro giocatore
+You don't have permission to clear another player's inventory (missing privilege: @1).=Non hai il permesso di svuotare l'inventario di un altro giocatore (privilegio mancante: @1).
+@1 cleared your inventory.=@1 ha svuotato il tuo inventario.
+Cleared @1's inventory.=L'inventario di @1 è stato svuotato.
+Player must be online to clear inventory!=Il giocatore deve essere connesso per svuotarne l'inventario!
+Players can't be killed, damage has been disabled.=I giocatori non possono essere uccisi, il danno è disabilitato.
+Player @1 is not online.=Il giocatore @1 non è connesso.
+You are already dead.=Sei già mortǝ.
+@1 is already dead.=@1 è già mortǝ.
+@1 has been killed.=@1 è stato uccisǝ.
+Kill player or yourself=Uccide un giocatore o te stessǝ
+Available commands: @1=Comandi disponibili: @1
+Use '/help <cmd>' to get more information, or '/help all' to list everything.=Usa '/help <comando>' per ottenere più informazioni, o '/help all' per elencare tutti i comandi.
+Available commands:=Comandi disponibili:
+Command not available: @1=Comando non disponibile: @1
+[all | privs | <cmd>]=[all | privs | <comando>]
+Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi
+Available privileges:=Privilegi disponibili:
+Command=Comando
+Parameters=Parametri
+For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco.
+Double-click to copy the entry to the chat history.=Doppio click per copiare la voce nella cronologia della chat.
+Command: @1 @2=Comando: @1 @2
+Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /help <comando>)
+Close=Chiudi
+Privilege=Privilegio
+Description=Descrizione
+print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset
+Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati
+Statistics written to action log.=Statistiche scritte nel log delle azioni.
+Statistics were reset.=Le statistiche sono state resettate.
+Usage: @1=Utilizzo: @1
+Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=I formati supportati sono txt, csv, lua, json e json_pretty (le strutture potrebbero essere soggetti a cambiamenti).
+(no description)=(nessuna descrizione)
+Can interact with things and modify the world=Si può interagire con le cose e modificare il mondo
+Can speak in chat=Si può parlare in chat
+Can modify 'shout' and 'interact' privileges=Si possono modificare i privilegi 'shout' e 'interact'
+Can modify privileges=Si possono modificare i privilegi
+Can teleport self=Si può teletrasportare se stessз
+Can teleport other players=Si possono teletrasportare gli altri giocatori
+Can set the time of day using /time=Si può impostate l'orario della giornata tramite /time
+Can do server maintenance stuff=Si possono eseguire operazioni di manutenzione del server
+Can bypass node protection in the world=Si può aggirare la protezione dei nodi nel mondo
+Can ban and unban players=Si possono bandire e perdonare i giocatori
+Can kick players=Si possono cacciare i giocatori
+Can use /give and /giveme=Si possono usare /give e /give me
+Can use /setpassword and /clearpassword=Si possono usare /setpassword e /clearpassword
+Can use fly mode=Si può usare la modalità volo
+Can use fast mode=Si può usare la modalità rapida
+Can fly through solid nodes using noclip mode=Si può volare attraverso i nodi solidi con la modalità incorporea
+Can use the rollback functionality=Si può usare la funzione di rollback
+Allows enabling various debug options that may affect gameplay=Permette di abilitare varie opzioni di debug che potrebbero influenzare l'esperienza di gioco
+Unknown Item=Oggetto sconosciuto
+Air=Aria
+Ignore=Ignora
+You can't place 'ignore' nodes!=Non puoi piazzare nodi 'ignore'!
diff --git a/builtin/locale/template.txt b/builtin/locale/template.txt
new file mode 100644
index 000000000..c5ace1a2f
--- /dev/null
+++ b/builtin/locale/template.txt
@@ -0,0 +1,224 @@
+# textdomain: __builtin
+Empty command.=
+Invalid command: @1=
+Invalid command usage.=
+You don't have permission to run this command (missing privileges: @1).=
+Unable to get position of player @1.=
+Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=
+<action>=
+Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=
+Show the name of the server owner=
+The administrator of this server is @1.=
+There's no administrator named in the config file.=
+[<name>]=
+Show privileges of yourself or another player=
+Player @1 does not exist.=
+Privileges of @1: @2=
+<privilege>=
+Return list of all online players with privilege=
+Invalid parameters (see /help haspriv).=
+Unknown privilege!=
+Players online with the "@1" privilege: @2=
+Your privileges are insufficient.=
+Unknown privilege: @1=
+@1 granted you privileges: @2=
+<name> (<privilege> | all)=
+Give privileges to player=
+Invalid parameters (see /help grant).=
+<privilege> | all=
+Grant privileges to yourself=
+Invalid parameters (see /help grantme).=
+@1 revoked privileges from you: @2=
+Remove privileges from player=
+Invalid parameters (see /help revoke).=
+Revoke privileges from yourself=
+Invalid parameters (see /help revokeme).=
+<name> <password>=
+Set player's password=
+Name field required.=
+Your password was cleared by @1.=
+Password of player "@1" cleared.=
+Your password was set by @1.=
+Password of player "@1" set.=
+<name>=
+Set empty password for a player=
+Reload authentication data=
+Done.=
+Failed.=
+Remove a player's data=
+Player "@1" removed.=
+No such player "@1" to remove.=
+Player "@1" is connected, cannot remove.=
+Unhandled remove_player return code @1.=
+Cannot teleport out of map bounds!=
+Cannot get player with name @1.=
+Cannot teleport, @1 is attached to an object!=
+Teleporting @1 to @2.=
+One does not teleport to oneself.=
+Cannot get teleportee with name @1.=
+Cannot get target player with name @1.=
+Teleporting @1 to @2 at @3.=
+<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=
+Teleport to position or player=
+You don't have permission to teleport other players (missing privilege: @1).=
+([-n] <name> <value>) | <name>=
+Set or read server configuration setting=
+Failed. Use '/set -n <name> <value>' to create a new setting.=
+@1 @= @2=
+<not set>=
+Invalid parameters (see /help set).=
+Finished emerging @1 blocks in @2ms.=
+emergeblocks update: @1/@2 blocks emerged (@3%)=
+(here [<radius>]) | (<pos1> <pos2>)=
+Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=
+Started emerge of area ranging from @1 to @2.=
+Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=
+Successfully cleared area ranging from @1 to @2.=
+Failed to clear one or more blocks in area.=
+Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=
+Successfully reset light in the area ranging from @1 to @2.=
+Failed to load one or more blocks in area.=
+List mods installed on the server=
+Cannot give an empty item.=
+Cannot give an unknown item.=
+Giving 'ignore' is not allowed.=
+@1 is not a known player.=
+@1 partially added to inventory.=
+@1 could not be added to inventory.=
+@1 added to inventory.=
+@1 partially added to inventory of @2.=
+@1 could not be added to inventory of @2.=
+@1 added to inventory of @2.=
+<name> <ItemString> [<count> [<wear>]]=
+Give item to player=
+Name and ItemString required.=
+<ItemString> [<count> [<wear>]]=
+Give item to yourself=
+ItemString required.=
+<EntityName> [<X>,<Y>,<Z>]=
+Spawn entity at given (or your) position=
+EntityName required.=
+Unable to spawn entity, player is nil.=
+Cannot spawn an unknown entity.=
+Invalid parameters (@1).=
+@1 spawned.=
+@1 failed to spawn.=
+Destroy item in hand=
+Unable to pulverize, no player.=
+Unable to pulverize, no item in hand.=
+An item was pulverized.=
+[<range>] [<seconds>] [<limit>]=
+Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=
+Rollback functions are disabled.=
+That limit is too high!=
+Checking @1 ...=
+Nobody has touched the specified location in @1 seconds.=
+@1 @2 @3 -> @4 @5 seconds ago.=
+Punch a node (range@=@1, seconds@=@2, limit@=@3).=
+(<name> [<seconds>]) | (:<actor> [<seconds>])=
+Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=
+Invalid parameters. See /help rollback and /help rollback_check.=
+Reverting actions of player '@1' since @2 seconds.=
+Reverting actions of @1 since @2 seconds.=
+(log is too long to show)=
+Reverting actions succeeded.=
+Reverting actions FAILED.=
+Show server status=
+This command was disabled by a mod or game.=
+[<0..23>:<0..59> | <0..24000>]=
+Show or set time of day=
+Current time is @1:@2.=
+You don't have permission to run this command (missing privilege: @1).=
+Invalid time.=
+Time of day changed.=
+Invalid hour (must be between 0 and 23 inclusive).=
+Invalid minute (must be between 0 and 59 inclusive).=
+Show day count since world creation=
+Current day is @1.=
+[<delay_in_seconds> | -1] [reconnect] [<message>]=
+Shutdown server (-1 cancels a delayed shutdown)=
+Server shutting down (operator request).=
+Ban the IP of a player or show the ban list=
+The ban list is empty.=
+Ban list: @1=
+Player is not online.=
+Failed to ban player.=
+Banned @1.=
+<name> | <IP_address>=
+Remove IP ban belonging to a player/IP=
+Failed to unban player/IP.=
+Unbanned @1.=
+<name> [<reason>]=
+Kick a player=
+Failed to kick player @1.=
+Kicked @1.=
+[full | quick]=
+Clear all objects in world=
+Invalid usage, see /help clearobjects.=
+Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=
+Cleared all objects.=
+<name> <message>=
+Send a direct message to a player=
+Invalid usage, see /help msg.=
+The player @1 is not online.=
+DM from @1: @2=
+Message sent.=
+Get the last login time of a player or yourself=
+@1's last login time was @2.=
+@1's last login time is unknown.=
+Clear the inventory of yourself or another player=
+You don't have permission to clear another player's inventory (missing privilege: @1).=
+@1 cleared your inventory.=
+Cleared @1's inventory.=
+Player must be online to clear inventory!=
+Players can't be killed, damage has been disabled.=
+Player @1 is not online.=
+You are already dead.=
+@1 is already dead.=
+@1 has been killed.=
+Kill player or yourself=
+Available commands: @1=
+Use '/help <cmd>' to get more information, or '/help all' to list everything.=
+Available commands:=
+Command not available: @1=
+[all | privs | <cmd>]=
+Get help for commands or list privileges=
+Available privileges:=
+Command=
+Parameters=
+For more information, click on any entry in the list.=
+Double-click to copy the entry to the chat history.=
+Command: @1 @2=
+Available commands: (see also: /help <cmd>)=
+Close=
+Privilege=
+Description=
+print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
+Handle the profiler and profiling data=
+Statistics written to action log.=
+Statistics were reset.=
+Usage: @1=
+Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
+(no description)=
+Can interact with things and modify the world=
+Can speak in chat=
+Can modify 'shout' and 'interact' privileges=
+Can modify privileges=
+Can teleport self=
+Can teleport other players=
+Can set the time of day using /time=
+Can do server maintenance stuff=
+Can bypass node protection in the world=
+Can ban and unban players=
+Can kick players=
+Can use /give and /giveme=
+Can use /setpassword and /clearpassword=
+Can use fly mode=
+Can use fast mode=
+Can fly through solid nodes using noclip mode=
+Can use the rollback functionality=
+Allows enabling various debug options that may affect gameplay=
+Unknown Item=
+Air=
+Ignore=
+You can't place 'ignore' nodes!=
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
index cd896f9ec..6db351048 100644
--- a/builtin/mainmenu/common.lua
+++ b/builtin/mainmenu/common.lua
@@ -14,14 +14,11 @@
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---------------------------------------------------------------------------------
+
-- Global menu data
---------------------------------------------------------------------------------
menudata = {}
---------------------------------------------------------------------------------
-- Local cached values
---------------------------------------------------------------------------------
local min_supp_proto, max_supp_proto
function common_update_cached_supp_proto()
@@ -29,14 +26,12 @@ function common_update_cached_supp_proto()
max_supp_proto = core.get_max_supp_proto()
end
common_update_cached_supp_proto()
---------------------------------------------------------------------------------
+
-- Menu helper functions
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
local function render_client_count(n)
- if n > 99 then return '99+'
- elseif n >= 0 then return tostring(n)
+ if n > 999 then return '99+'
+ elseif n >= 0 then return tostring(n)
else return '?' end
end
@@ -50,21 +45,7 @@ local function configure_selected_world_params(idx)
end
end
---------------------------------------------------------------------------------
-function image_column(tooltip, flagname)
- return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," ..
- "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
- "1=" .. core.formspec_escape(defaulttexturedir ..
- (flagname and "server_flags_" .. flagname .. ".png" or "blank.png")) .. "," ..
- "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," ..
- "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," ..
- "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," ..
- "5=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png")
-end
-
-
---------------------------------------------------------------------------------
-function render_serverlist_row(spec, is_favorite)
+function render_serverlist_row(spec)
local text = ""
if spec.name then
text = text .. core.formspec_escape(spec.name:trim())
@@ -75,31 +56,29 @@ function render_serverlist_row(spec, is_favorite)
end
end
- local grey_out = not is_server_protocol_compat(spec.proto_min, spec.proto_max)
+ local grey_out = not spec.is_compatible
- local details
- if is_favorite then
- details = "1,"
- else
- details = "0,"
- end
+ local details = {}
- if spec.ping then
- local ping = spec.ping * 1000
- if ping <= 50 then
- details = details .. "2,"
- elseif ping <= 100 then
- details = details .. "3,"
- elseif ping <= 250 then
- details = details .. "4,"
+ if spec.lag or spec.ping then
+ local lag = (spec.lag or 0) * 1000 + (spec.ping or 0) * 250
+ if lag <= 125 then
+ table.insert(details, "1")
+ elseif lag <= 175 then
+ table.insert(details, "2")
+ elseif lag <= 250 then
+ table.insert(details, "3")
else
- details = details .. "5,"
+ table.insert(details, "4")
end
else
- details = details .. "0,"
+ table.insert(details, "0")
end
- if spec.clients and spec.clients_max then
+ table.insert(details, ",")
+
+ local color = (grey_out and "#aaaaaa") or ((spec.is_favorite and "#ddddaa") or "#ffffff")
+ if spec.clients and (spec.clients_max or 0) > 0 then
local clients_percent = 100 * spec.clients / spec.clients_max
-- Choose a color depending on how many clients are connected
@@ -110,38 +89,35 @@ function render_serverlist_row(spec, is_favorite)
elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green
elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow
elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker)
- else clients_color = '#ffba97' -- 90-100%: orange
+ else clients_color = '#ffba97' -- 90-100%: orange
end
- details = details .. clients_color .. ',' ..
- render_client_count(spec.clients) .. ',/,' ..
- render_client_count(spec.clients_max) .. ','
-
- elseif grey_out then
- details = details .. '#aaaaaa,?,/,?,'
+ table.insert(details, clients_color)
+ table.insert(details, render_client_count(spec.clients) .. " / " ..
+ render_client_count(spec.clients_max))
else
- details = details .. ',?,/,?,'
+ table.insert(details, color)
+ table.insert(details, "?")
end
if spec.creative then
- details = details .. "1,"
- else
- details = details .. "0,"
- end
-
- if spec.damage then
- details = details .. "1,"
+ table.insert(details, "1") -- creative icon
else
- details = details .. "0,"
+ table.insert(details, "0")
end
if spec.pvp then
- details = details .. "1,"
+ table.insert(details, "2") -- pvp icon
+ elseif spec.damage then
+ table.insert(details, "1") -- heart icon
else
- details = details .. "0,"
+ table.insert(details, "0")
end
- return details .. (grey_out and '#aaaaaa,' or ',') .. text
+ table.insert(details, color)
+ table.insert(details, text)
+
+ return table.concat(details, ",")
end
--------------------------------------------------------------------------------
@@ -150,14 +126,13 @@ os.tempfolder = function()
return temp .. DIR_DELIM .. "MT_" .. math.random(0, 10000)
end
---------------------------------------------------------------------------------
os.tmpname = function()
local path = os.tempfolder()
io.open(path, "w"):close()
return path
end
-
--------------------------------------------------------------------------------
+
function menu_render_worldlist()
local retval = ""
local current_worldlist = menudata.worldlist:get_list()
@@ -171,7 +146,6 @@ function menu_render_worldlist()
return retval
end
---------------------------------------------------------------------------------
function menu_handle_key_up_down(fields, textlist, settingname)
local oldidx, newidx = core.get_textlist_index(textlist), 1
if fields.key_up or fields.key_down then
@@ -188,7 +162,6 @@ function menu_handle_key_up_down(fields, textlist, settingname)
return false
end
---------------------------------------------------------------------------------
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
local textlines = core.wrap_text(text, textlen, true)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
@@ -206,7 +179,6 @@ function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transp
return retval
end
---------------------------------------------------------------------------------
function is_server_protocol_compat(server_proto_min, server_proto_max)
if (not server_proto_min) or (not server_proto_max) then
-- There is no info. Assume the best and act as if we would be compatible.
@@ -214,7 +186,7 @@ function is_server_protocol_compat(server_proto_min, server_proto_max)
end
return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min
end
---------------------------------------------------------------------------------
+
function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
if not is_server_protocol_compat(server_proto_min, server_proto_max) then
local server_prot_ver_info, client_prot_ver_info
@@ -242,7 +214,7 @@ function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
return true
end
---------------------------------------------------------------------------------
+
function menu_worldmt(selected, setting, value)
local world = menudata.worldlist:get_list()[selected]
if world then
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
index 2cf70c9c9..9bdf92a74 100644
--- a/builtin/mainmenu/dlg_config_world.lua
+++ b/builtin/mainmenu/dlg_config_world.lua
@@ -74,7 +74,7 @@ local function get_formspec(data)
"label[1.75,0;" .. data.worldspec.name .. "]"
if mod.is_modpack or mod.type == "game" then
- local info = minetest.formspec_escape(
+ local info = core.formspec_escape(
core.get_content_info(mod.path).description)
if info == "" then
if mod.is_modpack then
diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
index 7328f3358..b0736a4fd 100644
--- a/builtin/mainmenu/dlg_contentstore.lua
+++ b/builtin/mainmenu/dlg_contentstore.lua
@@ -15,7 +15,7 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-if not minetest.get_http_api then
+if not core.get_http_api then
function create_store_dlg()
return messagebox("store",
fgettext("ContentDB is not available when Minetest was compiled without cURL"))
@@ -27,7 +27,7 @@ end
-- before the package list is ordered based on installed state.
local store = { packages = {}, packages_full = {}, packages_full_unordered = {} }
-local http = minetest.get_http_api()
+local http = core.get_http_api()
-- Screenshot
local screenshot_dir = core.get_cache_path() .. DIR_DELIM .. "cdb"
@@ -152,7 +152,7 @@ local function start_install(package)
end
local function queue_download(package)
- local max_concurrent_downloads = tonumber(minetest.settings:get("contentdb_max_concurrent_downloads"))
+ local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
if number_downloading < max_concurrent_downloads then
start_install(package)
else
@@ -320,7 +320,7 @@ function install_dialog.get_formspec()
selected_game_idx = i
end
- games[i] = minetest.formspec_escape(games[i].name)
+ games[i] = core.formspec_escape(games[i].name)
end
local selected_game = pkgmgr.games[selected_game_idx]
@@ -331,7 +331,7 @@ function install_dialog.get_formspec()
local formatted_deps = {}
for _, dep in pairs(install_dialog.dependencies) do
formatted_deps[#formatted_deps + 1] = "#fff"
- formatted_deps[#formatted_deps + 1] = minetest.formspec_escape(dep.name)
+ formatted_deps[#formatted_deps + 1] = core.formspec_escape(dep.name)
if dep.installed then
formatted_deps[#formatted_deps + 1] = "#ccf"
formatted_deps[#formatted_deps + 1] = fgettext("Already installed")
@@ -402,7 +402,7 @@ function install_dialog.handle_submit(this, fields)
end
if fields.will_install_deps ~= nil then
- install_dialog.will_install_deps = minetest.is_yes(fields.will_install_deps)
+ install_dialog.will_install_deps = core.is_yes(fields.will_install_deps)
return true
end
@@ -553,7 +553,7 @@ function store.load()
end
end
- local timeout = tonumber(minetest.settings:get("curl_file_download_timeout"))
+ local timeout = tonumber(core.settings:get("curl_file_download_timeout"))
local response = http.fetch_sync({ url = url, timeout = timeout })
if not response.succeeded then
return
@@ -793,8 +793,8 @@ function store.get_formspec(dlgdata)
-- title
formspec[#formspec + 1] = "label[1.875,0.1;"
formspec[#formspec + 1] = core.formspec_escape(
- minetest.colorize(mt_color_green, package.title) ..
- minetest.colorize("#BFBFBF", " by " .. package.author))
+ core.colorize(mt_color_green, package.title) ..
+ core.colorize("#BFBFBF", " by " .. package.author))
formspec[#formspec + 1] = "]"
-- buttons
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 5931496c1..1938747fe 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -443,7 +443,7 @@ local function create_world_buttonhandler(this, fields)
end
if fields["mgv6_biomes"] then
- local entry = minetest.formspec_escape(fields["mgv6_biomes"])
+ local entry = core.formspec_escape(fields["mgv6_biomes"])
for b=1, #mgv6_biomes do
if entry == mgv6_biomes[b][1] then
local ftable = core.settings:get_flags("mgv6_spflags")
diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
index bfb5d269a..787936e31 100644
--- a/builtin/mainmenu/pkgmgr.lua
+++ b/builtin/mainmenu/pkgmgr.lua
@@ -90,7 +90,7 @@ local function load_texture_packs(txtpath, retval)
retval[#retval + 1] = {
name = item,
author = conf:get("author"),
- release = tonumber(conf:get("release") or "0"),
+ release = tonumber(conf:get("release")) or 0,
list_name = name,
type = "txp",
path = path,
@@ -135,7 +135,7 @@ function get_mods(path,retval,modpack)
-- Read from config
toadd.name = name
toadd.author = mod_conf.author
- toadd.release = tonumber(mod_conf.release or "0")
+ toadd.release = tonumber(mod_conf.release) or 0
toadd.path = prefix
toadd.type = "mod"
@@ -413,18 +413,7 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
end
---------- toggles or en/disables a mod or modpack and its dependencies --------
-function pkgmgr.enable_mod(this, toset)
- local list = this.data.list:get_list()
- local mod = list[this.data.selected_mod]
-
- -- Game mods can't be enabled or disabled
- if mod.is_game_content then
- return
- end
-
- local toggled_mods = {}
-
- local enabled_mods = {}
+local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
if not mod.is_modpack then
-- Toggle or en/disable the mod
if toset == nil then
@@ -443,23 +432,29 @@ function pkgmgr.enable_mod(this, toset)
-- interleaved unsupported
for i = 1, #list do
if list[i].modpack == mod.name then
- if toset == nil then
- toset = not list[i].enabled
- end
- if list[i].enabled ~= toset then
- list[i].enabled = toset
- toggled_mods[#toggled_mods+1] = list[i].name
- end
- if toset then
- enabled_mods[list[i].name] = true
- end
+ toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, list[i])
end
end
end
+end
+
+function pkgmgr.enable_mod(this, toset)
+ local list = this.data.list:get_list()
+ local mod = list[this.data.selected_mod]
+
+ -- Game mods can't be enabled or disabled
+ if mod.is_game_content then
+ return
+ end
+
+ local toggled_mods = {}
+ local enabled_mods = {}
+ toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
+
if not toset then
-- Mod(s) were disabled, so no dependencies need to be enabled
table.sort(toggled_mods)
- minetest.log("info", "Following mods were disabled: " ..
+ core.log("info", "Following mods were disabled: " ..
table.concat(toggled_mods, ", "))
return
end
@@ -496,7 +491,7 @@ function pkgmgr.enable_mod(this, toset)
enabled_mods[name] = true
local mod_to_enable = list[mod_ids[name]]
if not mod_to_enable then
- minetest.log("warning", "Mod dependency \"" .. name ..
+ core.log("warning", "Mod dependency \"" .. name ..
"\" not found!")
else
if mod_to_enable.enabled == false then
@@ -517,7 +512,7 @@ function pkgmgr.enable_mod(this, toset)
-- Log the list of enabled mods
table.sort(toggled_mods)
- minetest.log("info", "Following mods were enabled: " ..
+ core.log("info", "Following mods were enabled: " ..
table.concat(toggled_mods, ", "))
end
diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua
index d98736e54..9876d8ac5 100644
--- a/builtin/mainmenu/serverlistmgr.lua
+++ b/builtin/mainmenu/serverlistmgr.lua
@@ -47,6 +47,15 @@ function serverlistmgr.sync()
}}
end
+ local serverlist_url = core.settings:get("serverlist_url") or ""
+ if not core.get_http_api or serverlist_url == "" then
+ serverlistmgr.servers = {{
+ name = fgettext("Public server list is disabled"),
+ description = ""
+ }}
+ return
+ end
+
if public_downloading then
return
end
diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua
index 336730bf4..fb7f121f8 100644
--- a/builtin/mainmenu/tab_content.lua
+++ b/builtin/mainmenu/tab_content.lua
@@ -146,10 +146,25 @@ local function get_formspec(tabview, name, tabdata)
end
--------------------------------------------------------------------------------
+local function handle_doubleclick(pkg)
+ if pkg.type == "txp" then
+ if core.settings:get("texture_path") == pkg.path then
+ core.settings:set("texture_path", "")
+ else
+ core.settings:set("texture_path", pkg.path)
+ end
+ packages = nil
+ end
+end
+
+--------------------------------------------------------------------------------
local function handle_buttons(tabview, fields, tabname, tabdata)
if fields["pkglist"] ~= nil then
local event = core.explode_table_event(fields["pkglist"])
tabdata.selected_pkg = event.row
+ if event.type == "DCL" then
+ handle_doubleclick(packages:get_list()[tabdata.selected_pkg])
+ end
return true
end
diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua
index 075274798..a34dd58bb 100644
--- a/builtin/mainmenu/tab_credits.lua
+++ b/builtin/mainmenu/tab_credits.lua
@@ -23,28 +23,37 @@ local core_developers = {
"Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>",
"Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
"paramat",
- "Auke Kok (sofar) <sofar@foo-projects.org>",
"Andrew Ward (rubenwardy) <rw@rubenwardy.com>",
"Krock/SmallJoker <mk939@ymail.com>",
"Lars Hofhansl <larsh@apache.org>",
+ "Pierre-Yves Rollo <dev@pyrollo.com>",
+ "v-rob <robinsonvincent89@gmail.com>",
}
+-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
+
local active_contributors = {
- "Hugues Ross [Formspecs]",
+ "Wuzzy [devtest game, visual corrections]",
+ "Zughy [Visual improvements, various fixes]",
"Maksim (MoNTE48) [Android]",
- "DS [Formspecs]",
- "pyrollo [Formspecs: Hypertext]",
- "v-rob [Formspecs]",
- "Jordach [set_sky]",
- "random-geek [Formspecs]",
- "Wuzzy [Pathfinder, builtin, translations]",
- "ANAND (ClobberXD) [Fixes, per-player FOV]",
- "Warr1024 [Fixes]",
- "Paul Ouellette (pauloue) [Fixes, Script API]",
- "Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com> [Audiovisuals]",
- "HybridDog [Script API]",
+ "numzero [Graphics and rendering]",
+ "appgurueu [Various internal fixes]",
+ "Desour [Formspec and vector API changes]",
+ "HybridDog [Rendering fixes and documentation]",
+ "Hugues Ross [Graphics-related improvements]",
+ "ANAND (ClobberXD) [Mouse buttons rebinding]",
+ "luk3yx [Fixes]",
+ "hecks [Audiovisuals, Lua API]",
+ "LoneWolfHT [Object crosshair, documentation fixes]",
+ "Lejo [Server-related improvements]",
+ "EvidenceB [Compass HUD element]",
+ "Paul Ouellette (pauloue) [Lua API, documentation]",
+ "TheTermos [Collision detection, physics]",
+ "David CARLIER [Unix & Haiku build fixes]",
"dcbrwn [Object shading]",
- "srifqi [Fixes]",
+ "Elias Fleckenstein [API features/fixes]",
+ "Jean-Patrick Guerrero (kilbith) [model element, visual fixes]",
+ "k.h.lai [Memory leak fixes, documentation]",
}
local previous_core_developers = {
@@ -60,30 +69,23 @@ local previous_core_developers = {
"sapier",
"Zeno",
"ShadowNinja <shadowninja@minetest.net>",
+ "Auke Kok (sofar) <sofar@foo-projects.org>",
}
local previous_contributors = {
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest Logo]",
- "Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"red-001 <red-001@outlook.ie>",
- "numberZero [Audiovisuals: meshgen]",
"Giuseppe Bilotta",
+ "Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"MirceaKitsune <mirceakitsune@gmail.com>",
"Constantin Wenger (SpeedProg)",
"Ciaran Gultnieks (CiaranG)",
"stujones11 [Android UX improvements]",
- "Jeija <jeija@mesecons.net> [HTTP, particles]",
- "Vincent Glize (Dumbeldor) [Cleanups, CSM APIs]",
- "Ben Deutsch [Rendering, Fixes, SQLite auth]",
- "TeTpaAka [Hand overriding, nametag colors]",
- "Rui [Sound Pitch]",
- "Duane Robertson <duane@duanerobertson.com> [MGValleys]",
- "Raymoo [Tool Capabilities]",
"Rogier <rogier777@gmail.com> [Fixes]",
"Gregory Currie (gregorycu) [optimisation]",
- "TriBlade9 <triblade9@mail.com> [Audiovisuals]",
- "T4im [Profiler]",
- "Jurgen Doser (doserj) <jurgen.doser@gmail.com>",
+ "srifqi [Fixes]",
+ "JacobF",
+ "Jeija <jeija@mesecons.net> [HTTP, particles]",
}
local function buildCreditList(source)
diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua
index e6748ed88..fb7409864 100644
--- a/builtin/mainmenu/tab_online.lua
+++ b/builtin/mainmenu/tab_online.lua
@@ -15,17 +15,50 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---------------------------------------------------------------------------------
+local function get_sorted_servers()
+ local servers = {
+ fav = {},
+ public = {},
+ incompatible = {}
+ }
+
+ local favs = serverlistmgr.get_favorites()
+ local taken_favs = {}
+ local result = menudata.search_result or serverlistmgr.servers
+ for _, server in ipairs(result) do
+ server.is_favorite = false
+ for index, fav in ipairs(favs) do
+ if server.address == fav.address and server.port == fav.port then
+ taken_favs[index] = true
+ server.is_favorite = true
+ break
+ end
+ end
+ server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max)
+ if server.is_favorite then
+ table.insert(servers.fav, server)
+ elseif server.is_compatible then
+ table.insert(servers.public, server)
+ else
+ table.insert(servers.incompatible, server)
+ end
+ end
+
+ if not menudata.search_result then
+ for index, fav in ipairs(favs) do
+ if not taken_favs[index] then
+ table.insert(servers.fav, fav)
+ end
+ end
+ end
+
+ return servers
+end
+
local function get_formspec(tabview, name, tabdata)
-- Update the cached supported proto info,
-- it may have changed after a change by the settings menu.
common_update_cached_supp_proto()
- local selected
- if menudata.search_result then
- selected = menudata.search_result[tabdata.selected]
- else
- selected = serverlistmgr.servers[tabdata.selected]
- end
if not tabdata.search_for then
tabdata.search_for = ""
@@ -33,128 +66,221 @@ local function get_formspec(tabview, name, tabdata)
local retval =
-- Search
- "field[0.15,0.075;5.91,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
- "image_button[5.63,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
- "image_button[6.3,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
- "image_button[6.97,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png")
- .. ";btn_mp_refresh;]" ..
+ "field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
+ "container[7.25,0.25]" ..
+ "image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
+ "image_button[0.75,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
+ "image_button[1.5,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") .. ";btn_mp_refresh;]" ..
+ "tooltip[btn_mp_clear;" .. fgettext("Clear") .. "]" ..
+ "tooltip[btn_mp_search;" .. fgettext("Search") .. "]" ..
+ "tooltip[btn_mp_refresh;" .. fgettext("Refresh") .. "]" ..
+ "container_end[]" ..
+
+ "container[9.75,0]" ..
+ "box[0,0;5.75,7;#666666]" ..
-- Address / Port
- "label[7.75,-0.25;" .. fgettext("Address / Port") .. "]" ..
- "field[8,0.65;3.25,0.5;te_address;;" ..
+ "label[0.25,0.35;" .. fgettext("Address") .. "]" ..
+ "label[4.25,0.35;" .. fgettext("Port") .. "]" ..
+ "field[0.25,0.5;4,0.75;te_address;;" ..
core.formspec_escape(core.settings:get("address")) .. "]" ..
- "field[11.1,0.65;1.4,0.5;te_port;;" ..
+ "field[4.25,0.5;1.25,0.75;te_port;;" ..
core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
-- Name / Password
- "label[7.75,0.95;" .. fgettext("Name / Password") .. "]" ..
- "field[8,1.85;2.9,0.5;te_name;;" ..
+ "label[0.25,1.55;" .. fgettext("Name") .. "]" ..
+ "label[3,1.55;" .. fgettext("Password") .. "]" ..
+ "field[0.25,1.75;2.75,0.75;te_name;;" ..
core.formspec_escape(core.settings:get("name")) .. "]" ..
- "pwdfield[10.73,1.85;1.77,0.5;te_pwd;]" ..
+ "pwdfield[3,1.75;2.5,0.75;te_pwd;]" ..
-- Description Background
- "box[7.73,2.25;4.25,2.6;#999999]"..
+ "label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
+ "box[0.25,3;5.25,2.75;#999999]"..
-- Connect
- "button[9.88,4.9;2.3,1;btn_mp_connect;" .. fgettext("Connect") .. "]"
+ "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
- if tabdata.selected and selected then
+ if tabdata.selected then
if gamedata.fav then
- retval = retval .. "button[7.73,4.9;2.3,1;btn_delete_favorite;" ..
+ retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
fgettext("Del. Favorite") .. "]"
end
- if selected.description then
- retval = retval .. "textarea[8.1,2.3;4.23,2.9;;;" ..
- core.formspec_escape((gamedata.serverdescription or ""), true) .. "]"
+ if gamedata.serverdescription then
+ retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
+ core.formspec_escape(gamedata.serverdescription) .. "]"
end
end
- --favorites
+ retval = retval .. "container_end[]"
+
+ -- Table
retval = retval .. "tablecolumns[" ..
- image_column(fgettext("Favorite"), "favorite") .. ";" ..
- image_column(fgettext("Ping")) .. ",padding=0.25;" ..
- "color,span=3;" ..
- "text,align=right;" .. -- clients
- "text,align=center,padding=0.25;" .. -- "/"
- "text,align=right,padding=0.25;" .. -- clients_max
- image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
- image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
- --~ PvP = Player versus Player
- image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
+ "image,tooltip=" .. fgettext("Ping") .. "," ..
+ "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
+ "1=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," ..
+ "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," ..
+ "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," ..
+ "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") .. "," ..
+ "5=" .. core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. "," ..
+ "6=" .. core.formspec_escape(defaulttexturedir .. "server_public.png") .. "," ..
+ "7=" .. core.formspec_escape(defaulttexturedir .. "server_incompatible.png") .. ";" ..
"color,span=1;" ..
- "text,padding=1]" ..
- "table[-0.15,0.6;7.75,5.15;favorites;"
-
- if menudata.search_result then
- local favs = serverlistmgr.get_favorites()
- for i = 1, #menudata.search_result do
- local server = menudata.search_result[i]
- for fav_id = 1, #favs do
- if server.address == favs[fav_id].address and
- server.port == favs[fav_id].port then
- server.is_favorite = true
- end
- end
-
- if i ~= 1 then
- retval = retval .. ","
- end
-
- retval = retval .. render_serverlist_row(server, server.is_favorite)
- end
- elseif #serverlistmgr.servers > 0 then
- local favs = serverlistmgr.get_favorites()
- if #favs > 0 then
- for i = 1, #favs do
- for j = 1, #serverlistmgr.servers do
- if serverlistmgr.servers[j].address == favs[i].address and
- serverlistmgr.servers[j].port == favs[i].port then
- table.insert(serverlistmgr.servers, i, table.remove(serverlistmgr.servers, j))
- end
- end
- if favs[i].address ~= serverlistmgr.servers[i].address then
- table.insert(serverlistmgr.servers, i, favs[i])
- end
+ "text,align=inline;"..
+ "color,span=1;" ..
+ "text,align=inline,width=4.25;" ..
+ "image,tooltip=" .. fgettext("Creative mode") .. "," ..
+ "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
+ "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_creative.png") .. "," ..
+ "align=inline,padding=0.25,width=1.5;" ..
+ --~ PvP = Player versus Player
+ "image,tooltip=" .. fgettext("Damage / PvP") .. "," ..
+ "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
+ "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_damage.png") .. "," ..
+ "2=" .. core.formspec_escape(defaulttexturedir .. "server_flags_pvp.png") .. "," ..
+ "align=inline,padding=0.25,width=1.5;" ..
+ "color,align=inline,span=1;" ..
+ "text,align=inline,padding=1]" ..
+ "table[0.25,1;9.25,5.75;servers;"
+
+ local servers = get_sorted_servers()
+
+ local dividers = {
+ fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,",
+ public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,",
+ incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,,"
+ }
+ local order = {"fav", "public", "incompatible"}
+
+ tabdata.lookup = {} -- maps row number to server
+ local rows = {}
+ for _, section in ipairs(order) do
+ local section_servers = servers[section]
+ if next(section_servers) ~= nil then
+ rows[#rows + 1] = dividers[section]
+ for _, server in ipairs(section_servers) do
+ tabdata.lookup[#rows + 1] = server
+ rows[#rows + 1] = render_serverlist_row(server)
end
end
-
- retval = retval .. render_serverlist_row(serverlistmgr.servers[1], (#favs > 0))
- for i = 2, #serverlistmgr.servers do
- retval = retval .. "," .. render_serverlist_row(serverlistmgr.servers[i], (i <= #favs))
- end
end
+ retval = retval .. table.concat(rows, ",")
+
if tabdata.selected then
retval = retval .. ";" .. tabdata.selected .. "]"
else
retval = retval .. ";0]"
end
- return retval
+ return retval, "size[15.5,7,false]real_coordinates[true]"
end
--------------------------------------------------------------------------------
-local function main_button_handler(tabview, fields, name, tabdata)
- local serverlist = menudata.search_result or serverlistmgr.servers
+local function search_server_list(input)
+ menudata.search_result = nil
+ if #serverlistmgr.servers < 2 then
+ return
+ end
+
+ -- setup the keyword list
+ local keywords = {}
+ for word in input:gmatch("%S+") do
+ word = word:gsub("(%W)", "%%%1")
+ table.insert(keywords, word)
+ end
+
+ if #keywords == 0 then
+ return
+ end
+
+ menudata.search_result = {}
+
+ -- Search the serverlist
+ local search_result = {}
+ for i = 1, #serverlistmgr.servers do
+ local server = serverlistmgr.servers[i]
+ local found = 0
+ for k = 1, #keywords do
+ local keyword = keywords[k]
+ if server.name then
+ local sername = server.name:lower()
+ local _, count = sername:gsub(keyword, keyword)
+ found = found + count * 4
+ end
+
+ if server.description then
+ local desc = server.description:lower()
+ local _, count = desc:gsub(keyword, keyword)
+ found = found + count * 2
+ end
+ end
+ if found > 0 then
+ local points = (#serverlistmgr.servers - i) / 5 + found
+ server.points = points
+ table.insert(search_result, server)
+ end
+ end
+
+ if #search_result == 0 then
+ return
+ end
+
+ table.sort(search_result, function(a, b)
+ return a.points > b.points
+ end)
+ menudata.search_result = search_result
+end
+
+local function set_selected_server(tabdata, idx, server)
+ -- reset selection
+ if idx == nil or server == nil then
+ tabdata.selected = nil
+
+ core.settings:set("address", "")
+ core.settings:set("remote_port", "30000")
+ return
+ end
+
+ local address = server.address
+ local port = server.port
+ gamedata.serverdescription = server.description
+
+ gamedata.fav = false
+ for _, fav in ipairs(serverlistmgr.get_favorites()) do
+ if address == fav.address and port == fav.port then
+ gamedata.fav = true
+ break
+ end
+ end
+
+ if address and port then
+ core.settings:set("address", address)
+ core.settings:set("remote_port", port)
+ end
+ tabdata.selected = idx
+end
+
+local function main_button_handler(tabview, fields, name, tabdata)
if fields.te_name then
gamedata.playername = fields.te_name
core.settings:set("name", fields.te_name)
end
- if fields.favorites then
- local event = core.explode_table_event(fields.favorites)
- local fav = serverlist[event.row]
+ if fields.servers then
+ local event = core.explode_table_event(fields.servers)
+ local server = tabdata.lookup[event.row]
- if event.type == "DCL" then
- if event.row <= #serverlist then
+ if server then
+ if event.type == "DCL" then
if not is_server_protocol_compat_or_error(
- fav.proto_min, fav.proto_max) then
+ server.proto_min, server.proto_max) then
return true
end
- gamedata.address = fav.address
- gamedata.port = fav.port
+ gamedata.address = server.address
+ gamedata.port = server.port
gamedata.playername = fields.te_name
gamedata.selected_world = 0
@@ -162,84 +288,32 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.password = fields.te_pwd
end
- gamedata.servername = fav.name
- gamedata.serverdescription = fav.description
+ gamedata.servername = server.name
+ gamedata.serverdescription = server.description
if gamedata.address and gamedata.port then
core.settings:set("address", gamedata.address)
core.settings:set("remote_port", gamedata.port)
core.start()
end
+ return true
end
- return true
- end
-
- if event.type == "CHG" then
- if event.row <= #serverlist then
- gamedata.fav = false
- local favs = serverlistmgr.get_favorites()
- local address = fav.address
- local port = fav.port
- gamedata.serverdescription = fav.description
-
- for i = 1, #favs do
- if fav.address == favs[i].address and
- fav.port == favs[i].port then
- gamedata.fav = true
- end
- end
-
- if address and port then
- core.settings:set("address", address)
- core.settings:set("remote_port", port)
- end
- tabdata.selected = event.row
- end
- return true
- end
- end
-
- if fields.key_up or fields.key_down then
- local fav_idx = core.get_table_index("favorites")
- local fav = serverlist[fav_idx]
-
- if fav_idx then
- if fields.key_up and fav_idx > 1 then
- fav_idx = fav_idx - 1
- elseif fields.key_down and fav_idx < #serverlistmgr.servers then
- fav_idx = fav_idx + 1
+ if event.type == "CHG" then
+ set_selected_server(tabdata, event.row, server)
+ return true
end
- else
- fav_idx = 1
- end
-
- if not serverlistmgr.servers or not fav then
- tabdata.selected = 0
- return true
- end
-
- local address = fav.address
- local port = fav.port
- gamedata.serverdescription = fav.description
- if address and port then
- core.settings:set("address", address)
- core.settings:set("remote_port", port)
end
-
- tabdata.selected = fav_idx
- return true
end
if fields.btn_delete_favorite then
- local current_favorite = core.get_table_index("favorites")
- if not current_favorite then return end
-
- serverlistmgr.delete_favorite(serverlistmgr.servers[current_favorite])
- serverlistmgr.sync()
- tabdata.selected = nil
-
- core.settings:set("address", "")
- core.settings:set("remote_port", "30000")
+ local idx = core.get_table_index("servers")
+ if not idx then return end
+ local server = tabdata.lookup[idx]
+ if not server then return end
+
+ serverlistmgr.delete_favorite(server)
+ -- the server at [idx+1] will be at idx once list is refreshed
+ set_selected_server(tabdata, idx, tabdata.lookup[idx+1])
return true
end
@@ -250,63 +324,13 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
- tabdata.selected = 1
- local input = fields.te_search:lower()
tabdata.search_for = fields.te_search
-
- if #serverlistmgr.servers < 2 then
- return true
- end
-
- menudata.search_result = {}
-
- -- setup the keyword list
- local keywords = {}
- for word in input:gmatch("%S+") do
- word = word:gsub("(%W)", "%%%1")
- table.insert(keywords, word)
+ search_server_list(fields.te_search:lower())
+ if menudata.search_result then
+ -- first server in row 2 due to header
+ set_selected_server(tabdata, 2, menudata.search_result[1])
end
- if #keywords == 0 then
- menudata.search_result = nil
- return true
- end
-
- -- Search the serverlist
- local search_result = {}
- for i = 1, #serverlistmgr.servers do
- local server = serverlistmgr.servers[i]
- local found = 0
- for k = 1, #keywords do
- local keyword = keywords[k]
- if server.name then
- local sername = server.name:lower()
- local _, count = sername:gsub(keyword, keyword)
- found = found + count * 4
- end
-
- if server.description then
- local desc = server.description:lower()
- local _, count = desc:gsub(keyword, keyword)
- found = found + count * 2
- end
- end
- if found > 0 then
- local points = (#serverlistmgr.servers - i) / 5 + found
- server.points = points
- table.insert(search_result, server)
- end
- end
- if #search_result > 0 then
- table.sort(search_result, function(a, b)
- return a.points > b.points
- end)
- menudata.search_result = search_result
- local first_server = search_result[1]
- core.settings:set("address", first_server.address)
- core.settings:set("remote_port", first_server.port)
- gamedata.serverdescription = first_server.description
- end
return true
end
@@ -322,20 +346,22 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.address = fields.te_address
gamedata.port = tonumber(fields.te_port)
gamedata.selected_world = 0
- local fav_idx = core.get_table_index("favorites")
- local fav = serverlist[fav_idx]
- if fav_idx and fav_idx <= #serverlist and
- fav.address == gamedata.address and
- fav.port == gamedata.port then
+ local idx = core.get_table_index("servers")
+ local server = idx and tabdata.lookup[idx]
+
+ set_selected_server(tabdata)
- serverlistmgr.add_favorite(fav)
+ if server and server.address == gamedata.address and
+ server.port == gamedata.port then
- gamedata.servername = fav.name
- gamedata.serverdescription = fav.description
+ serverlistmgr.add_favorite(server)
+
+ gamedata.servername = server.name
+ gamedata.serverdescription = server.description
if not is_server_protocol_compat_or_error(
- fav.proto_min, fav.proto_max) then
+ server.proto_min, server.proto_max) then
return true
end
else
@@ -354,6 +380,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
core.start()
return true
end
+
return false
end
@@ -362,7 +389,6 @@ local function on_change(type, old_tab, new_tab)
serverlistmgr.sync()
end
---------------------------------------------------------------------------------
return {
name = "online",
caption = fgettext("Join Game"),
diff --git a/builtin/profiler/init.lua b/builtin/profiler/init.lua
index a0033d752..7f63dfaea 100644
--- a/builtin/profiler/init.lua
+++ b/builtin/profiler/init.lua
@@ -15,6 +15,8 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+local S = core.get_translator("__builtin")
+
local function get_bool_default(name, default)
local val = core.settings:get_bool(name)
if val == nil then
@@ -40,9 +42,9 @@ function profiler.init_chatcommand()
instrumentation.init_chatcommand()
end
- local param_usage = "print [filter] | dump [filter] | save [format [filter]] | reset"
+ local param_usage = S("print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset")
core.register_chatcommand("profiler", {
- description = "handle the profiler and profiling data",
+ description = S("Handle the profiler and profiling data"),
params = param_usage,
privs = { server=true },
func = function(name, param)
@@ -51,21 +53,19 @@ function profiler.init_chatcommand()
if command == "dump" then
core.log("action", reporter.print(sampler.profile, arg0))
- return true, "Statistics written to action log"
+ return true, S("Statistics written to action log.")
elseif command == "print" then
return true, reporter.print(sampler.profile, arg0)
elseif command == "save" then
return reporter.save(sampler.profile, args[1] or "txt", args[2])
elseif command == "reset" then
sampler.reset()
- return true, "Statistics were reset"
+ return true, S("Statistics were reset.")
end
- return false, string.format(
- "Usage: %s\n" ..
- "Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).",
- param_usage
- )
+ return false,
+ S("Usage: @1", param_usage) .. "\n" ..
+ S("Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).")
end
})
diff --git a/builtin/profiler/reporter.lua b/builtin/profiler/reporter.lua
index fed47a36b..5928a3718 100644
--- a/builtin/profiler/reporter.lua
+++ b/builtin/profiler/reporter.lua
@@ -15,6 +15,10 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+local S = core.get_translator("__builtin")
+-- Note: In this file, only messages are translated
+-- but not the table itself, to keep it simple.
+
local DIR_DELIM, LINE_DELIM = DIR_DELIM, "\n"
local table, unpack, string, pairs, io, os = table, unpack, string, pairs, io, os
local rep, sprintf, tonumber = string.rep, string.format, tonumber
@@ -104,11 +108,11 @@ local TxtFormatter = Formatter:new {
end,
format = function(self, filter)
local profile = self.profile
- self:print("Values below show absolute/relative times spend per server step by the instrumented function.")
- self:print("A total of %d samples were taken", profile.stats_total.samples)
+ self:print(S("Values below show absolute/relative times spend per server step by the instrumented function."))
+ self:print(S("A total of @1 sample(s) were taken.", profile.stats_total.samples))
if filter then
- self:print("The output is limited to '%s'", filter)
+ self:print(S("The output is limited to '@1'.", filter))
end
self:print()
@@ -259,19 +263,18 @@ function reporter.save(profile, format, filter)
local output, io_err = io.open(path, "w")
if not output then
- return false, "Saving of profile failed with: " .. io_err
+ return false, S("Saving of profile failed: @1", io_err)
end
local content, err = serialize_profile(profile, format, filter)
if not content then
output:close()
- return false, "Saving of profile failed with: " .. err
+ return false, S("Saving of profile failed: @1", err)
end
output:write(content)
output:close()
- local logmessage = "Profile saved to " .. path
- core.log("action", logmessage)
- return true, logmessage
+ core.log("action", "Profile saved to " .. path)
+ return true, S("Profile saved to @1", path)
end
return reporter
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 8b6227b37..75efe64da 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -75,7 +75,7 @@ free_move (Flying) bool false
# If enabled, makes move directions relative to the player's pitch when flying or swimming.
pitch_move (Pitch move mode) bool false
-# Fast movement (via the "special" key).
+# Fast movement (via the "Aux1" key).
# This requires the "fast" privilege on the server.
fast_move (Fast movement) bool false
@@ -99,14 +99,14 @@ invert_mouse (Invert mouse) bool false
# Mouse sensitivity multiplier.
mouse_sensitivity (Mouse sensitivity) float 0.2
-# If enabled, "special" key instead of "sneak" key is used for climbing down and
+# If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and
# descending.
-aux1_descends (Special key for climbing/descending) bool false
+aux1_descends (Aux1 key for climbing/descending) bool false
# Double-tapping the jump key toggles fly mode.
doubletap_jump (Double tap jump for fly) bool false
-# If disabled, "special" key is used to fly fast if both fly and fast mode are
+# If disabled, "Aux1" key is used to fly fast if both fly and fast mode are
# enabled.
always_fly_fast (Always fly and fast) bool true
@@ -135,9 +135,9 @@ touchscreen_threshold (Touch screen threshold) int 20 0 100
# If disabled, virtual joystick will center to first-touch's position.
fixed_virtual_joystick (Fixed virtual joystick) bool false
-# (Android) Use virtual joystick to trigger "aux" button.
-# If enabled, virtual joystick will also tap "aux" button when out of main circle.
-virtual_joystick_triggers_aux (Virtual joystick triggers aux button) bool false
+# (Android) Use virtual joystick to trigger "Aux1" button.
+# If enabled, virtual joystick will also tap "Aux1" button when out of main circle.
+virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
# Enable joysticks
enable_joysticks (Enable joysticks) bool false
@@ -199,7 +199,7 @@ keymap_inventory (Inventory key) key KEY_KEY_I
# Key for moving fast in fast mode.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_special1 (Special key) key KEY_KEY_E
+keymap_aux1 (Aux1 key) key KEY_KEY_E
# Key for opening the chat window.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
@@ -451,6 +451,10 @@ keymap_decrease_viewing_range_min (View range decrease key) key -
[**Basic]
+# Whether nametag backgrounds should be shown by default.
+# Mods may still set a background.
+show_nametag_backgrounds (Show nametag backgrounds by default) bool true
+
# Enable vertex buffer objects.
# This should greatly improve graphics performance.
enable_vbo (VBO) bool true
@@ -1132,6 +1136,10 @@ enable_rollback_recording (Rollback recording) bool false
# @name, @message, @timestamp (optional)
chat_message_format (Chat message format) string <@name> @message
+# If the execution of a chat command takes longer than this specified time in
+# seconds, add the time information to the chat command message
+chatcommand_msg_time_threshold (Chat command time message threshold) float 0.1
+
# A message to be displayed to all clients when the server shuts down.
kick_msg_shutdown (Shutdown message) string Server shutting down.