diff --git a/.github/workflows/cpp_lint.yml b/.github/workflows/cpp_lint.yml
index 1f97d105a..2bd884c7a 100644
--- a/.github/workflows/cpp_lint.yml
+++ b/.github/workflows/cpp_lint.yml
@@ -24,20 +24,21 @@ on:
- '.github/workflows/**.yml'
jobs:
- clang_format:
- runs-on: ubuntu-18.04
- steps:
- - uses: actions/checkout@v2
- - name: Install clang-format
- run: |
- sudo apt-get install clang-format-9 -qyy
- - name: Run clang-format
- run: |
- source ./util/ci/lint.sh
- perform_lint
- env:
- CLANG_FORMAT: clang-format-9
+# clang_format:
+# runs-on: ubuntu-18.04
+# steps:
+# - uses: actions/checkout@v2
+# - name: Install clang-format
+# run: |
+# sudo apt-get install clang-format-9 -qyy
+#
+# - name: Run clang-format
+# run: |
+# source ./util/ci/clang-format.sh
+# check_format
+# env:
+# CLANG_FORMAT: clang-format-9
clang_tidy:
runs-on: ubuntu-18.04
diff --git a/.gitignore b/.gitignore
index 1cfca5fc2..3949bb44c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -89,8 +89,7 @@ src/test_config.h
src/cmake_config.h
src/cmake_config_githash.h
src/unittest/test_world/world.mt
-src/lua/build/
-locale/
+/locale/
.directory
*.cbp
*.layout
diff --git a/README.md b/README.md
index cdeb0b417..235c7374d 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ Some can be changed in the key config dialog in the settings tab.
| P | Enable/disable pitch move mode |
| J | Enable/disable fast mode (needs fast privilege) |
| H | Enable/disable noclip mode (needs noclip privilege) |
-| E | Move fast in fast mode |
+| E | Aux1 (Move fast in fast mode. Games may add special features) |
| C | Cycle through camera modes |
| V | Cycle through minimap modes |
| Shift + V | Change minimap orientation |
diff --git a/build/android/icons/aux1_btn.svg b/build/android/icons/aux1_btn.svg
new file mode 100644
index 000000000..e0ee97c0c
--- /dev/null
+++ b/build/android/icons/aux1_btn.svg
@@ -0,0 +1,143 @@
+
+
diff --git a/build/android/icons/aux_btn.svg b/build/android/icons/aux_btn.svg
deleted file mode 100644
index 6bbefff67..000000000
--- a/build/android/icons/aux_btn.svg
+++ /dev/null
@@ -1,411 +0,0 @@
-
-
-
-
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 387b4ba6c..04e8e69ea 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(fgettext("You died"))
+ core.display_chat_message(core.gettext("You died."))
local formspec = "size[8,5]bgcolor[#320000b4;true]" ..
"background9[0,0;0,0;bg_common.png;true;40]" ..
"style[you_died;font_size=+4;content_offset=0]" ..
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 ' 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 ' to get more "
+ .. "information, or '/help all' to list "
+ .. "everything.")
+ else
+ msg = core.gettext("Available commands: ")
+ .. table.concat(cmds, " ") .. "\n"
+ .. core.gettext("Use '.help ' 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 | ]"),
- description = gettext("Get help for commands"),
+ params = core.gettext("[all | ]"),
+ 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 | ]",
- description = "Get help for commands or list privileges",
+ params = S("[all | privs | ]"),
+ 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 0994f2793..d83f32f82 100644
--- a/builtin/common/information_formspecs.lua
+++ b/builtin/common/information_formspecs.lua
@@ -22,7 +22,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
@@ -53,16 +54,17 @@ 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
for _, cmds in ipairs(data[2]) do
local has_priv = check_player_privs(name, cmds[2].privs)
if has_priv then
- rows[#rows + 1] = COLOR_BLUE .. ",0," .. formspec_escape(data[1]) .. ","
+ rows[#rows + 1] = COLOR_BLUE .. ",0," .. F(data[1]) .. ","
break
end
end
@@ -72,11 +74,11 @@ local function build_chatcommands_formspec(name, sel, copy)
rows[#rows + 1] = ("%s,1,%s,%s"):format(
-- has_priv and COLOR_GREEN or COLOR_GRAY,
COLOR_GREEN,
- 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
@@ -85,9 +87,9 @@ local function build_chatcommands_formspec(name, sel, copy)
end
return LIST_FORMSPEC_DESCRIPTION:format(
- "Available commands: (see also: /help )",
+ F(S("Available commands: (see also: /help )")),
table.concat(rows, ","), sel or 0,
- description, "Close"
+ F(description), F(S("Close"))
)
end
@@ -102,19 +104,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
diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua
index befdd47f9..340122bf2 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)
@@ -52,7 +54,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,7 +67,7 @@ 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)
@@ -73,7 +75,7 @@ core.register_on_chat_message(function(name, message)
core.set_last_run_mod(cmd_def.mod_origin)
local success, result = cmd_def.func(name, param)
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)
@@ -85,9 +87,10 @@ core.register_on_chat_message(function(name, message)
core.chat_send_player(name, result)
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 +110,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
@@ -132,9 +136,9 @@ core.register_chatcommand_alias = register_chatcommand_alias
-- Chat commands
--
core.register_chatcommand("me", {
- params = "",
- description = "Show chat action (e.g., '/me orders a pizza' displays"
- .. " ' orders a pizza')",
+ params = S(""),
+ description = S("Show chat action (e.g., '/me orders a pizza' "
+ .. "displays ' orders a pizza')"),
privs = {shout=true},
func = function(name, param)
core.chat_send_all("* " .. name .. " " .. param)
@@ -143,43 +147,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 = "[]",
- description = "Show privileges of yourself or another player",
+ params = S("[]"),
+ 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 = "",
- description = "Return list of all online players with privilege.",
+ params = S(""),
+ 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 = {}
@@ -189,19 +194,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
@@ -213,10 +219,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
@@ -230,33 +236,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 = " ( | all)",
- description = "Give privileges to player",
+ params = S(" ( | 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 = " | all",
- description = "Grant privileges to yourself",
+ params = S(" | 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,
@@ -265,11 +271,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)
@@ -278,7 +284,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
@@ -301,43 +307,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 = " ( | all)",
- description = "Remove privileges from player",
+ params = S(" ( | 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 = " | all",
- description = "Revoke privileges from yourself",
+ params = S(" | 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 = "",
- description = "Set player's password",
+ params = S(""),
+ description = S("Set player's password"),
privs = {password=true},
func = function(name, param)
local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
@@ -347,83 +353,83 @@ 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 = "",
- description = "Set empty password for a player",
+ params = S(""),
+ 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 = "",
- description = "Remove a player's data",
+ params = S(""),
+ 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,
})
@@ -454,46 +460,46 @@ 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, "Cannot teleport out of map bounds!"
+ return false, S("Cannot teleport out of map bounds!")
end
local teleportee = core.get_player_by_name(name)
if not teleportee then
- return false, "Cannot get player with name " .. name
+ return false, S("Cannot get player with name @1.", name)
end
if teleportee:get_attach() then
- return false, "Cannot teleport, " .. name ..
- " is attached to an object!"
+ return false, S("Cannot teleport, @1 " ..
+ "is attached to an object!", name)
end
teleportee:set_pos(p)
- return true, "Teleporting " .. name .. " to " .. core.pos_to_string(p, 1)
+ return true, S("Teleporting @1 to @2.", name, core.pos_to_string(p, 1))
end
-- Teleports player next to player if possible
local function teleport_to_player(name, target_name)
if name == target_name then
- return false, "One does not teleport to oneself."
+ return false, S("One does not teleport to oneself.")
end
local teleportee = core.get_player_by_name(name)
if not teleportee then
- return false, "Cannot get teleportee with name " .. name
+ return false, S("Cannot get teleportee with name @1.", name)
end
if teleportee:get_attach() then
- return false, "Cannot teleport, " .. name ..
- " is attached to an object!"
+ 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, "Cannot get target player with name " .. target_name
+ 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, "Teleporting " .. name .. " to " .. target_name .. " at " ..
- core.pos_to_string(p, 1)
+ return true, S("Teleporting @1 to @2 at @3.", name, target_name,
+ core.pos_to_string(p, 1))
end
core.register_chatcommand("teleport", {
- params = ",, | | ,, | ",
- description = "Teleport to position or player",
+ params = S(",, | | ,, | "),
+ description = S("Teleport to position or player"),
privs = {teleport=true},
func = function(name, param)
local p = {}
@@ -509,8 +515,8 @@ core.register_chatcommand("teleport", {
end
local has_bring_priv = core.check_player_privs(name, {bring=true})
- local missing_bring_msg = "You don't have permission to teleport " ..
- "other players (missing bring privilege)"
+ local missing_bring_msg = S("You don't have permission to teleport " ..
+ "other players (missing privilege: @1).", "bring")
local teleportee_name
teleportee_name, p.x, p.y, p.z = param:match(
@@ -537,8 +543,8 @@ core.register_chatcommand("teleport", {
register_chatcommand_alias("tp", "teleport")
core.register_chatcommand("set", {
- params = "([-n] ) | ",
- description = "Set or read server configuration setting",
+ params = S("([-n] ) | "),
+ description = S("Set or read server configuration setting"),
privs = {server=true},
func = function(name, param)
local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
@@ -551,23 +557,24 @@ 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 ' to create a new setting."
+ return false, S("Failed. Use '/set -n ' "
+ .. "to create a new setting.")
end
core.settings:set(setname, setvalue)
core.settings:write()
- 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 = ""
+ setvalue = S("")
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,
})
@@ -580,26 +587,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 []) | ()",
- description = "Load (or, if nonexistent, generate) map blocks "
- .. "contained in area pos1 to pos2 ( and must be in parentheses)",
+ params = S("(here []) | ()"),
+ description = S("Load (or, if nonexistent, generate) map blocks contained in "
+ .. "area pos1 to pos2 ( and must be in parentheses)"),
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -617,15 +625,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 []) | ()",
- description = "Delete map blocks contained in area pos1 to pos2 "
- .. "( and must be in parentheses)",
+ params = S("(here []) | ()"),
+ description = S("Delete map blocks contained in area pos1 to pos2 "
+ .. "( and must be in parentheses)"),
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -634,18 +642,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 []) | ()",
- description = "Resets lighting in the area between pos1 and pos2 "
- .. "( and must be in parentheses)",
+ params = S("(here []) | ()"),
+ description = S("Resets lighting in the area between pos1 and pos2 "
+ .. "( and must be in parentheses)"),
privs = {server = true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
@@ -654,17 +664,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 = {server = true},
func = function(name, param)
return true, table.concat(core.get_modnames(), ", ")
@@ -688,117 +699,136 @@ local function handle_give_command(cmd, giver, receiver, stackstring)
end
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()
- if giver == receiver then
- local msg = "%q %sadded to inventory."
- return true, msg:format(stackstring, partiality)
+ 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
- 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)
+ msg = S("@1 added to inventory.", stackstring)
+ end
+ if giver == receiver then
+ return true, msg
+ else
+ 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 = " [ []]",
- description = "Give item to player",
+ params = S(" [ []]"),
+ 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 = " [ []]",
- description = "Give item to yourself",
+ params = S(" [ []]"),
+ 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 = " [,,]",
- description = "Spawn entity at given (or your) position",
+ params = S(" [,,]"),
+ 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,
})
@@ -814,14 +844,15 @@ core.register_on_punchnode(function(pos, node, puncher)
end)
core.register_chatcommand("rollback_check", {
- params = "[] [] []",
- description = "Check who last touched a node or a node near it"
- .. " within the time specified by . Default: range = 0,"
- .. " seconds = 86400 = 24h, limit = 5. Set to inf for no time limit",
+ params = S("[] [] []"),
+ description = S("Check who last touched a node or a node near it "
+ .. "within the time specified by . "
+ .. "Default: range = 0, seconds = 86400 = 24h, limit = 5. "
+ .. "Set 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*)")
@@ -829,30 +860,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,
@@ -861,110 +892,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 = "( []) | (: [])",
- description = "Revert actions of a player. Default for is 60. Set to inf for no time limit",
+ params = S("( []) | (: [])"),
+ description = S("Revert actions of a player. "
+ .. "Default for is 60. "
+ .. "Set 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) or -1
if new_time ~= new_time or new_time < 0 or new_time > 24000 then
- return false, "Invalid time (must be between 0 and 24000)."
+ return false, S("Invalid time (must be between 0 and 24000).")
end
core.set_timeofday(new_time / 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,
})
register_chatcommand_alias("settime", "time")
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 = "[ | -1] [reconnect] []",
- description = "Shutdown server (-1 cancels a delayed shutdown)",
+ params = S("[ | -1] [reconnect] []"),
+ description = S("Shutdown server (-1 cancels a delayed shutdown)"),
privs = {server=true},
func = function(name, param)
local delay, reconnect, message
@@ -977,7 +1021,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
@@ -985,65 +1029,65 @@ core.register_chatcommand("shutdown", {
})
core.register_chatcommand("ban", {
- params = "[]",
- description = "Ban the IP of a player or show the ban list",
+ params = S("[]"),
+ 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 = " | ",
- description = "Remove IP ban belonging to a player/IP",
+ params = S(" | "),
+ 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 = " []",
- description = "Kick a player",
+ params = S(" []"),
+ 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 = {}
@@ -1052,46 +1096,45 @@ 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 ("
.. options.mode .. " mode).")
- core.chat_send_all("Clearing all objects. This may take a long time."
- .. " You may experience a timeout.")
+ core.chat_send_all(S("Clearing all objects. This may take a long time."
+ .. " You may experience a timeout."))
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 = "",
- description = "Send a private message to a player",
+ params = S(""),
+ description = S("Send a private 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", "PM from " .. name .. " to " .. sendto
.. ": " .. message)
core.chat_send_player(sendto, core.colorize("green",
- "PM from " .. name .. ": " .. message))
- return true, "Message sent."
+ S("PM from @1: @2", name, message)))
+ return true, S("Message sent.")
end,
})
register_chatcommand_alias("m", "msg")
register_chatcommand_alias("pm", "msg")
core.register_chatcommand("last-login", {
- params = "[]",
- description = "Get the last login time of a player or yourself",
+ params = S("[]"),
+ description = S("Get the last login time of a player or yourself"),
func = function(name, param)
if param == "" then
param = name
@@ -1099,25 +1142,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 = "[]",
- description = "Clear the inventory of yourself or another player",
+ params = S("[]"),
+ 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
@@ -1127,25 +1172,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 killer ~= victim then
@@ -1153,12 +1198,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 = "[]",
- description = "Kill player or yourself",
+ params = S("[]"),
+ description = S("Kill player or yourself"),
privs = {server=true},
func = function(name, param)
return handle_kill_command(name, param == "" and name or param)
@@ -1184,7 +1229,7 @@ core.register_chatcommand("spawn", {
})
core.register_chatcommand("setspawn", {
- description = "Sets the spawn point to your current position",
+ description = S("Sets the spawn point to your current position"),
privs = {server = true},
func = function(name)
local player = core.get_player_by_name(name)
@@ -1205,6 +1250,7 @@ core.register_chatcommand("setspawn", {
core.set_world_spawnpoint(pos)
- return true, "The spawn point has been set to " .. core.pos_to_string(pos)
+ return true, S("The spawn point has been set to @1",
+ core.pos_to_string(pos))
end
})
diff --git a/builtin/game/privileges.lua b/builtin/game/privileges.lua
index 5aa1544ea..7e3684a85 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
@@ -33,69 +35,69 @@ if core.settings:get_bool("creative_mode") then
creative = true
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 = creative,
})
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 = creative,
})
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 = creative,
})
core.register_privilege("fast", {
- description = "Can use fast mode",
+ description = S("Can use fast mode"),
give_to_singleplayer = creative,
})
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 418dc06ec..0fa0e3015 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
--
@@ -329,7 +331,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,
@@ -339,7 +341,7 @@ core.register_item(":unknown", {
})
core.register_node(":air", {
- description = "Air",
+ description = S("Air"),
inventory_image = "blank.png",
wield_image = "blank.png",
drawtype = "airlike",
@@ -357,7 +359,7 @@ core.register_node(":air", {
})
core.register_node(":ignore", {
- description = "Ignore",
+ description = S("Ignore"),
inventory_image = "ignore.png",
wield_image = "ignore.png",
drawtype = "airlike",
@@ -375,7 +377,7 @@ core.register_node(":ignore", {
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/locale/template.txt b/builtin/locale/template.txt
new file mode 100644
index 000000000..d85c53b68
--- /dev/null
+++ b/builtin/locale/template.txt
@@ -0,0 +1,226 @@
+# 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)=
+=
+Show chat action (e.g., '/me orders a pizza' displays ' 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.=
+[]=
+Show privileges of yourself or another player=
+Player @1 does not exist.=
+Privileges of @1: @2=
+=
+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=
+ ( | all)=
+Give privileges to player=
+Invalid parameters (see /help grant).=
+ | 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).=
+=
+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.=
+=
+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.=
+,, | | ,, | =
+Teleport to position or player=
+You don't have permission to teleport other players (missing privilege: @1).=
+([-n] ) | =
+Set or read server configuration setting=
+Failed. Use '/set -n ' to create a new setting.=
+@1 @= @2=
+=
+Invalid parameters (see /help set).=
+Finished emerging @1 blocks in @2ms.=
+emergeblocks update: @1/@2 blocks emerged (@3%)=
+(here []) | ()=
+Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 ( and must be in parentheses)=
+Started emerge of area ranging from @1 to @2.=
+Delete map blocks contained in area pos1 to pos2 ( and 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 ( and 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.=
+ [ []]=
+Give item to player=
+Name and ItemString required.=
+ [ []]=
+Give item to yourself=
+ItemString required.=
+ [,,]=
+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.=
+[] [] []=
+Check who last touched a node or a node near it within the time specified by . Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set 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).=
+( []) | (: [])=
+Revert actions of a player. Default for is 60. Set 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.=
+[ | -1] [reconnect] []=
+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.=
+ | =
+Remove IP ban belonging to a player/IP=
+Failed to unban player/IP.=
+Unbanned @1.=
+ []=
+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.=
+Cleared all objects.=
+=
+Send a private message to a player=
+Invalid usage, see /help msg.=
+The player @1 is not online.=
+PM 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 ' to get more information, or '/help all' to list everything.=
+Available commands:=
+Command not available: @1=
+[all | privs | ]=
+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 )=
+Close=
+Privilege=
+Description=
+print [] | dump [] | save [ []] | 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!=
+Sets the spawn point to your current position=
+The spawn point has been set to @1=
diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua
index a6c83de7a..c89777c90 100644
--- a/builtin/mainmenu/tab_content.lua
+++ b/builtin/mainmenu/tab_content.lua
@@ -158,11 +158,26 @@ local function get_formspec(tabview, name, tabdata)
return retval
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/profiler/init.lua b/builtin/profiler/init.lua
index cefb4c6ad..e41f57cde 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 [] | dump [] | save [ []] | 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/settingtypes.txt b/builtin/settingtypes.txt
index 89727a39d..2ed783442 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
diff --git a/client/shaders/3d_interlaced_merge/opengl_fragment.glsl b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl
index 7cba61b39..6d3ae5093 100644
--- a/client/shaders/3d_interlaced_merge/opengl_fragment.glsl
+++ b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl
@@ -6,7 +6,7 @@ uniform sampler2D textureFlags;
#define rightImage normalTexture
#define maskImage textureFlags
-varying mediump vec2 varTexCoord;
+varying mediump vec4 varTexCoord;
void main(void)
{
diff --git a/client/shaders/3d_interlaced_merge/opengl_vertex.glsl b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl
index 860049481..224b7d183 100644
--- a/client/shaders/3d_interlaced_merge/opengl_vertex.glsl
+++ b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl
@@ -1,4 +1,4 @@
-varying mediump vec2 varTexCoord;
+varying mediump vec4 varTexCoord;
void main(void)
{
diff --git a/clientmods/preview/mod.conf b/clientmods/preview/mod.conf
new file mode 100644
index 000000000..4e56ec293
--- /dev/null
+++ b/clientmods/preview/mod.conf
@@ -0,0 +1 @@
+name = preview
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index bc8a823a6..90066124e 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -166,6 +166,15 @@ void ClientMap::updateDrawList()
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
+ // Read the vision range, unless unlimited range is enabled.
+#if !defined(__ANDROID__) && !defined(__IOS__)
+ float range = m_control.range_all ? 1e7 : m_control.wanted_range;
+#else
+ // On mobile, "unlimited" range is only four times the regular range to
+ // prevent large FPS drops.
+ float range = m_control.range_all ? m_control.wanted_range * 4 : m_control.wanted_range;
+#endif
+
// Number of blocks currently loaded by the client
u32 blocks_loaded = 0;
// Number of blocks with mesh in rendering range
@@ -183,6 +192,7 @@ void ClientMap::updateDrawList()
occlusion_culling_enabled = false;
}
+
// Uncomment to debug occluded blocks in the wireframe mode
// TODO: Include this as a flag for an extended debugging setting
//if (occlusion_culling_enabled && m_control.show_wireframe)
@@ -219,33 +229,31 @@ void ClientMap::updateDrawList()
continue;
}
-#if !defined(__ANDROID__) && !defined(__IOS__)
- float range = 100000 * BS;
-#else
- float range = m_control.wanted_range * BS * 4;
-#endif
- if (!m_control.range_all)
- range = m_control.wanted_range * BS;
+ v3s16 block_coord = block->getPos();
+ v3s16 block_position = block->getPosRelative() + MAP_BLOCKSIZE / 2;
- float d = 0.0;
- if (!isBlockInSight(block->getPos(), camera_position,
- camera_direction, camera_fov, range, &d))
- continue;
+ // First, perform a simple distance check, with a padding of one extra block.
+ if (!m_control.range_all &&
+ block_position.getDistanceFrom(cam_pos_nodes) > range + MAP_BLOCKSIZE)
+ continue; // Out of range, skip.
+ // Keep the block alive as long as it is in range.
+ block->resetUsageTimer();
blocks_in_range_with_mesh++;
- /*
- Occlusion culling
- */
+ // Frustum culling
+ float d = 0.0;
+ if (!isBlockInSight(block_coord, camera_position,
+ camera_direction, camera_fov, range * BS, &d))
+ continue;
+
+ // Occlusion culling
if ((!m_control.range_all && d > m_control.wanted_range * BS) ||
(occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) {
blocks_occlusion_culled++;
continue;
}
- // This block is in range. Reset usage timer.
- block->resetUsageTimer();
-
// Add to set
block->refGrab();
m_drawlist.push_back({block, d});
@@ -293,8 +301,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
const v3f camera_position = m_camera_position;
- const v3f camera_direction = m_camera_direction;
- const f32 camera_fov = m_camera_fov;
/*
Get all blocks and draw all visible ones
@@ -316,15 +322,15 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
for (auto &item : m_drawlist) {
MapBlock *block = item.block;
v3s16 block_pos = block->getPos();
- float d;
- if (!isBlockInSight(block_pos, camera_position,
- camera_direction, camera_fov, 100000 * BS, &d))
- continue;
MapBlockMesh *mapBlockMesh = block->mesh;
if (!mapBlockMesh)
continue;
+ v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
+ float d = camera_position.getDistanceFrom(block_pos_r);
+ d = MYMAX(0,d - BLOCK_MAX_RADIUS);
+
// Mesh animation
if (pass == scene::ESNRP_SOLID) {
// Pretty random but this should work somewhat nicely
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 4b767b0ec..179685fcc 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -2526,7 +2526,7 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
input->isKeyDown(KeyType::LEFT),
input->isKeyDown(KeyType::RIGHT),
isKeyDown(KeyType::JUMP),
- isKeyDown(KeyType::SPECIAL1),
+ isKeyDown(KeyType::AUX1),
isKeyDown(KeyType::SNEAK),
isKeyDown(KeyType::ZOOM),
isKeyDown(KeyType::DIG),
@@ -2543,7 +2543,7 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
( (u32)(isKeyDown(KeyType::LEFT) & 0x1) << 2) |
( (u32)(isKeyDown(KeyType::RIGHT) & 0x1) << 3) |
( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) |
- ( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) |
+ ( (u32)(isKeyDown(KeyType::AUX1) & 0x1) << 5) |
( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) |
( (u32)(isKeyDown(KeyType::DIG) & 0x1) << 7) |
( (u32)(isKeyDown(KeyType::PLACE) & 0x1) << 8) |
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index ec618b00e..e3caa81e2 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -40,7 +40,7 @@ void KeyCache::populate()
key[KeyType::LEFT] = getKeySetting("keymap_left");
key[KeyType::RIGHT] = getKeySetting("keymap_right");
key[KeyType::JUMP] = getKeySetting("keymap_jump");
- key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
+ key[KeyType::AUX1] = getKeySetting("keymap_aux1");
key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
key[KeyType::DIG] = getKeySetting("keymap_dig");
key[KeyType::PLACE] = getKeySetting("keymap_place");
@@ -238,7 +238,7 @@ void RandomInputHandler::step(float dtime)
{
static RandomInputHandlerSimData rnd_data[] = {
{ "keymap_jump", 0.0f, 40 },
- { "keymap_special1", 0.0f, 40 },
+ { "keymap_aux1", 0.0f, 40 },
{ "keymap_forward", 0.0f, 40 },
{ "keymap_left", 0.0f, 40 },
{ "keymap_dig", 0.0f, 30 },
diff --git a/src/client/joystick_controller.cpp b/src/client/joystick_controller.cpp
index f4668b249..026671e00 100644
--- a/src/client/joystick_controller.cpp
+++ b/src/client/joystick_controller.cpp
@@ -79,7 +79,7 @@ JoystickLayout create_default_layout()
// Accessible without any modifier pressed
JLO_B_PB(KeyType::JUMP, bm | 1 << 0, 1 << 0);
- JLO_B_PB(KeyType::SPECIAL1, bm | 1 << 1, 1 << 1);
+ JLO_B_PB(KeyType::AUX1, bm | 1 << 1, 1 << 1);
// Accessible with start button not pressed, but four pressed
// TODO find usage for button 0
@@ -126,11 +126,11 @@ JoystickLayout create_xbox_layout()
// 4 Buttons
JLO_B_PB(KeyType::JUMP, 1 << 0, 1 << 0); // A/green
JLO_B_PB(KeyType::ESC, 1 << 1, 1 << 1); // B/red
- JLO_B_PB(KeyType::SPECIAL1, 1 << 2, 1 << 2); // X/blue
+ JLO_B_PB(KeyType::AUX1, 1 << 2, 1 << 2); // X/blue
JLO_B_PB(KeyType::INVENTORY, 1 << 3, 1 << 3); // Y/yellow
// Analog Sticks
- JLO_B_PB(KeyType::SPECIAL1, 1 << 11, 1 << 11); // left
+ JLO_B_PB(KeyType::AUX1, 1 << 11, 1 << 11); // left
JLO_B_PB(KeyType::SNEAK, 1 << 12, 1 << 12); // right
// Triggers
diff --git a/src/client/keys.h b/src/client/keys.h
index d4924a9d4..c8475b61c 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -32,7 +32,7 @@ public:
LEFT,
RIGHT,
JUMP,
- SPECIAL1,
+ AUX1,
SNEAK,
AUTOFORWARD,
DIG,
diff --git a/src/content/mods.cpp b/src/content/mods.cpp
index fd1d405d2..1c7fd4b4a 100644
--- a/src/content/mods.cpp
+++ b/src/content/mods.cpp
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "porting.h"
#include "convert_json.h"
+#include "script/common/c_internal.h"
bool parseDependsString(std::string &dep, std::unordered_set &symbols)
{
@@ -44,20 +45,24 @@ bool parseDependsString(std::string &dep, std::unordered_set &symbols)
return !dep.empty();
}
+static void log_mod_deprecation(const ModSpec &spec, const std::string &warning)
+{
+ auto handling_mode = get_deprecated_handling_mode();
+ if (handling_mode != DeprecatedHandlingMode::Ignore) {
+ std::ostringstream os;
+ os << warning << " (" << spec.name << " at " << spec.path << ")" << std::endl;
+
+ if (handling_mode == DeprecatedHandlingMode::Error) {
+ throw ModError(os.str());
+ } else {
+ warningstream << os.str();
+ }
+ }
+}
+
void parseModContents(ModSpec &spec)
{
// NOTE: this function works in mutual recursion with getModsInPath
- Settings info;
- info.readConfigFile((spec.path + DIR_DELIM + "mod.conf").c_str());
-
- if (info.exists("name"))
- spec.name = info.get("name");
-
- if (info.exists("author"))
- spec.author = info.get("author");
-
- if (info.exists("release"))
- spec.release = info.getS32("release");
spec.depends.clear();
spec.optdepends.clear();
@@ -78,6 +83,20 @@ void parseModContents(ModSpec &spec)
spec.modpack_content = getModsInPath(spec.path, true);
} else {
+ Settings info;
+ info.readConfigFile((spec.path + DIR_DELIM + "mod.conf").c_str());
+
+ if (info.exists("name"))
+ spec.name = info.get("name");
+ else
+ log_mod_deprecation(spec, "Mods not having a mod.conf file with the name is deprecated.");
+
+ if (info.exists("author"))
+ spec.author = info.get("author");
+
+ if (info.exists("release"))
+ spec.release = info.getS32("release");
+
// Attempt to load dependencies from mod.conf
bool mod_conf_has_depends = false;
if (info.exists("depends")) {
@@ -109,6 +128,10 @@ void parseModContents(ModSpec &spec)
std::vector dependencies;
std::ifstream is((spec.path + DIR_DELIM + "depends.txt").c_str());
+
+ if (is.good())
+ log_mod_deprecation(spec, "depends.txt is deprecated, please use mod.conf instead.");
+
while (is.good()) {
std::string dep;
std::getline(is, dep);
@@ -127,14 +150,10 @@ void parseModContents(ModSpec &spec)
}
}
- if (info.exists("description")) {
+ if (info.exists("description"))
spec.desc = info.get("description");
- } else {
- std::ifstream is((spec.path + DIR_DELIM + "description.txt")
- .c_str());
- spec.desc = std::string((std::istreambuf_iterator(is)),
- std::istreambuf_iterator());
- }
+ else if (fs::ReadFile(spec.path + DIR_DELIM + "description.txt", spec.desc))
+ log_mod_deprecation(spec, "description.txt is deprecated, please use mod.conf instead.");
}
}
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 96d197b4a..0453e1e02 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -93,7 +93,7 @@ void set_default_settings()
settings->setDefault("keymap_drop", "KEY_KEY_Q");
settings->setDefault("keymap_zoom", "KEY_KEY_Z");
settings->setDefault("keymap_inventory", "KEY_KEY_I");
- settings->setDefault("keymap_special1", "KEY_KEY_E");
+ settings->setDefault("keymap_aux1", "KEY_KEY_E");
settings->setDefault("keymap_chat", "KEY_KEY_T");
settings->setDefault("keymap_cmd", "/");
settings->setDefault("keymap_cmd_local", ".");
@@ -529,7 +529,7 @@ void set_default_settings()
settings->setDefault("touchtarget", "true");
settings->setDefault("touchscreen_threshold", "20");
settings->setDefault("fixed_virtual_joystick", "true");
- settings->setDefault("virtual_joystick_triggers_aux", "false");
+ settings->setDefault("virtual_joystick_triggers_aux1", "false");
#endif
// Mobile Platform
diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp
index a4038950d..798b8e210 100644
--- a/src/gui/guiKeyChangeMenu.cpp
+++ b/src/gui/guiKeyChangeMenu.cpp
@@ -47,7 +47,7 @@ enum
GUI_ID_KEY_BACKWARD_BUTTON,
GUI_ID_KEY_LEFT_BUTTON,
GUI_ID_KEY_RIGHT_BUTTON,
- GUI_ID_KEY_USE_BUTTON,
+ GUI_ID_KEY_AUX1_BUTTON,
GUI_ID_KEY_FLY_BUTTON,
GUI_ID_KEY_FAST_BUTTON,
GUI_ID_KEY_JUMP_BUTTON,
@@ -184,7 +184,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
core::rect rect(0, 0, option_w, 30 * s);
rect += topleft + v2s32(option_x, option_y);
- const wchar_t *text = wgettext("\"Special\" = climb down");
+ const wchar_t *text = wgettext("\"Aux1\" = climb down");
Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
GUI_ID_CB_AUX1_DESCENDS, text);
delete[] text;
@@ -423,7 +423,7 @@ void GUIKeyChangeMenu::init_keys()
this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
- this->add_key(GUI_ID_KEY_USE_BUTTON, wgettext("Special"), "keymap_special1");
+ this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp
index 68ffec70f..3ba88445b 100644
--- a/src/gui/touchscreengui.cpp
+++ b/src/gui/touchscreengui.cpp
@@ -43,7 +43,7 @@ const char **button_imagenames = (const char *[]) {
"drop_btn.png",
"down_btn.png",
//"zoom.png",
- //"aux_btn.png",
+ //"aux1_btn.png",
"inventory_btn.png",
"escape_btn.png",
"minimap_btn.png",
@@ -89,8 +89,8 @@ static irr::EKEY_CODE id2keycode(touch_gui_button_id id)
/*case zoom_id:
key = "zoom";
break;
- case special1_id:
- key = "special1";
+ case aux1_id:
+ key = "aux1";
break;*/
case fly_id:
key = "freemove";
@@ -437,7 +437,7 @@ TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, IEventReceiver *receiver)
m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
m_mouse_sensitivity = rangelim(g_settings->getFloat("mouse_sensitivity"), 0.1, 1.0);
m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
- m_joystick_triggers_special1 = g_settings->getBool("virtual_joystick_triggers_aux");
+ m_joystick_triggers_aux1 = g_settings->getBool("virtual_joystick_triggers_aux1");
m_screensize = m_device->getVideoDriver()->getScreenSize();
button_size = std::min(m_screensize.Y / 4.5f,
RenderingEngine::getDisplayDensity() *
@@ -549,9 +549,9 @@ void TouchScreenGUI::init(ISimpleTextureSource *tsrc)
m_screensize.Y - (3 * button_size)),
L"z", false);
- // init special1/aux button
- if (!m_joystick_triggers_special1)
- initButton(special1_id,
+ // init aux1 button
+ if (!m_joystick_triggers_aux1)
+ initButton(aux1_id,
rect(m_screensize.X - (1.25 * button_size),
m_screensize.Y - (2.5 * button_size),
m_screensize.X - (0.25 * button_size),
@@ -845,7 +845,7 @@ void TouchScreenGUI::moveJoystick(const SEvent &event, float dx, float dy) {
}
if (distance > button_size * 1.5) {
- m_joystick_status[j_special1] = true;
+ m_joystick_status[j_aux1] = true;
// move joystick "button"
s32 ndx = button_size * dx / distance * 1.5f - button_size / 2.0f * 1.5f;
s32 ndy = button_size * dy / distance * 1.5f - button_size / 2.0f * 1.5f;
@@ -1124,7 +1124,7 @@ bool TouchScreenGUI::quickTapDetection()
void TouchScreenGUI::applyJoystickStatus()
{
for (u32 i = 0; i < 5; i++) {
- if (i == 4 && !m_joystick_triggers_special1)
+ if (i == 4 && !m_joystick_triggers_aux1)
continue;
SEvent translated{};
diff --git a/src/gui/touchscreengui.h b/src/gui/touchscreengui.h
index 742c55a33..4242065c9 100644
--- a/src/gui/touchscreengui.h
+++ b/src/gui/touchscreengui.h
@@ -42,7 +42,7 @@ typedef enum
crunch_id,
inventory_id,
// zoom_id,
- // special1_id,
+ // aux1_id,
escape_id,
minimap_id,
range_id,
@@ -71,7 +71,7 @@ typedef enum
j_backward,
j_left,
j_right,
- j_special1
+ j_aux1
} touch_gui_joystick_move_id;
typedef enum
@@ -224,7 +224,7 @@ private:
// forward, backward, left, right
touch_gui_button_id m_joystick_names[5] = {
- forward_id, backward_id, left_id, right_id, /*special1_id*/};
+ forward_id, backward_id, left_id, right_id, /*aux1_id*/};
bool m_joystick_status[5] = {false, false, false, false, false};
/*
@@ -246,7 +246,7 @@ private:
size_t m_joystick_id;
bool m_joystick_has_really_moved = false;
bool m_fixed_joystick = false;
- bool m_joystick_triggers_special1 = false;
+ bool m_joystick_triggers_aux1 = false;
button_info *m_joystick_btn_off = nullptr;
button_info *m_joystick_btn_bg = nullptr;
button_info *m_joystick_btn_center = nullptr;
diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp
index 55eab522a..50deacb24 100644
--- a/src/script/lua_api/l_settings.cpp
+++ b/src/script/lua_api/l_settings.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_settings.h"
#include "lua_api/l_internal.h"
#include "cpp_api/s_security.h"
+#include "threading/mutex_auto_lock.h"
#include "util/string.h" // FlagDesc
#include "settings.h"
#include "noise.h"
@@ -291,20 +292,36 @@ int LuaSettings::l_write(lua_State* L)
return 1;
}
+static void push_settings_table(lua_State *L, const Settings *settings)
+{
+ std::vector keys = settings->getNames();
+ lua_newtable(L);
+ for (const std::string &key : keys) {
+ std::string value;
+ Settings *group = nullptr;
+
+ if (settings->getNoEx(key, value)) {
+ lua_pushstring(L, value.c_str());
+ } else if (settings->getGroupNoEx(key, group)) {
+ // Recursively push tables
+ push_settings_table(L, group);
+ } else {
+ // Impossible case (multithreading) due to MutexAutoLock
+ continue;
+ }
+
+ lua_setfield(L, -2, key.c_str());
+ }
+}
+
// to_table(self) -> {[key1]=value1,...}
int LuaSettings::l_to_table(lua_State* L)
{
NO_MAP_LOCK_REQUIRED;
LuaSettings* o = checkobject(L, 1);
- std::vector keys = o->m_settings->getNames();
-
- lua_newtable(L);
- for (const std::string &key : keys) {
- lua_pushstring(L, o->m_settings->get(key).c_str());
- lua_setfield(L, -2, key.c_str());
- }
-
+ MutexAutoLock(o->m_settings->m_mutex);
+ push_settings_table(L, o->m_settings);
return 1;
}
diff --git a/src/server.cpp b/src/server.cpp
index 8977861b5..c4bcd9dae 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2660,7 +2660,9 @@ void Server::fillMediaCache()
// Collect all media file paths
std::vector