summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/async/game.lua59
-rw-r--r--builtin/async/mainmenu.lua (renamed from builtin/async/init.lua)4
-rw-r--r--builtin/client/init.lua2
-rw-r--r--builtin/client/misc.lua7
-rw-r--r--builtin/common/information_formspecs.lua4
-rw-r--r--builtin/common/misc_helpers.lua161
-rw-r--r--builtin/common/mod_storage.lua19
-rw-r--r--builtin/common/serialize.lua353
-rw-r--r--builtin/common/strict.lua37
-rw-r--r--builtin/common/tests/misc_helpers_spec.lua99
-rw-r--r--builtin/common/tests/serialize_spec.lua158
-rw-r--r--builtin/common/tests/vector_spec.lua10
-rw-r--r--builtin/common/vector.lua14
-rw-r--r--builtin/game/async.lua22
-rw-r--r--builtin/game/chat.lua119
-rw-r--r--builtin/game/falling.lua12
-rw-r--r--builtin/game/features.lua2
-rw-r--r--builtin/game/init.lua4
-rw-r--r--builtin/game/item.lua178
-rw-r--r--builtin/game/item_entity.lua13
-rw-r--r--builtin/game/item_s.lua156
-rw-r--r--builtin/game/misc.lua101
-rw-r--r--builtin/game/misc_s.lua93
-rw-r--r--builtin/game/register.lua2
-rw-r--r--builtin/game/statbars.lua5
-rw-r--r--builtin/game/voxelarea.lua22
-rw-r--r--builtin/init.lua6
-rw-r--r--builtin/locale/__builtin.de.tr5
-rw-r--r--builtin/locale/__builtin.it.tr5
-rw-r--r--builtin/locale/template.txt5
-rw-r--r--builtin/mainmenu/common.lua18
-rw-r--r--builtin/mainmenu/dlg_config_world.lua117
-rw-r--r--builtin/mainmenu/dlg_contentstore.lua28
-rw-r--r--builtin/mainmenu/dlg_create_world.lua89
-rw-r--r--builtin/mainmenu/dlg_delete_content.lua13
-rw-r--r--builtin/mainmenu/dlg_delete_world.lua12
-rw-r--r--builtin/mainmenu/dlg_register.lua123
-rw-r--r--builtin/mainmenu/dlg_settings_advanced.lua105
-rw-r--r--builtin/mainmenu/dlg_version_info.lua172
-rw-r--r--builtin/mainmenu/generate_from_settingtypes.lua17
-rw-r--r--builtin/mainmenu/init.lua7
-rw-r--r--builtin/mainmenu/pkgmgr.lua165
-rw-r--r--builtin/mainmenu/tab_about.lua144
-rw-r--r--builtin/mainmenu/tab_content.lua35
-rw-r--r--builtin/mainmenu/tab_local.lua167
-rw-r--r--builtin/mainmenu/tab_online.lua57
-rw-r--r--builtin/mainmenu/tab_settings.lua49
-rw-r--r--builtin/mainmenu/tests/serverlistmgr_spec.lua1
-rw-r--r--builtin/settingtypes.txt2274
49 files changed, 3262 insertions, 2008 deletions
diff --git a/builtin/async/game.lua b/builtin/async/game.lua
new file mode 100644
index 000000000..6512f0706
--- /dev/null
+++ b/builtin/async/game.lua
@@ -0,0 +1,59 @@
+core.log("info", "Initializing asynchronous environment (game)")
+
+local function pack2(...)
+ return {n=select('#', ...), ...}
+end
+
+-- Entrypoint to run async jobs, called by C++
+function core.job_processor(func, params)
+ local retval = pack2(func(unpack(params, 1, params.n)))
+
+ return retval
+end
+
+-- Import a bunch of individual files from builtin/game/
+local gamepath = core.get_builtin_path() .. "game" .. DIR_DELIM
+
+dofile(gamepath .. "constants.lua")
+dofile(gamepath .. "item_s.lua")
+dofile(gamepath .. "misc_s.lua")
+dofile(gamepath .. "features.lua")
+dofile(gamepath .. "voxelarea.lua")
+
+-- Transfer of globals
+do
+ local all = assert(core.transferred_globals)
+ core.transferred_globals = nil
+
+ all.registered_nodes = {}
+ all.registered_craftitems = {}
+ all.registered_tools = {}
+ for k, v in pairs(all.registered_items) do
+ -- Disable further modification
+ setmetatable(v, {__newindex = {}})
+ -- Reassemble the other tables
+ if v.type == "node" then
+ all.registered_nodes[k] = v
+ elseif v.type == "craftitem" then
+ all.registered_craftitems[k] = v
+ elseif v.type == "tool" then
+ all.registered_tools[k] = v
+ end
+ end
+
+ for k, v in pairs(all) do
+ core[k] = v
+ end
+end
+
+-- For tables that are indexed by item name:
+-- If table[X] does not exist, default to table[core.registered_aliases[X]]
+local alias_metatable = {
+ __index = function(t, name)
+ return rawget(t, core.registered_aliases[name])
+ end
+}
+setmetatable(core.registered_items, alias_metatable)
+setmetatable(core.registered_nodes, alias_metatable)
+setmetatable(core.registered_craftitems, alias_metatable)
+setmetatable(core.registered_tools, alias_metatable)
diff --git a/builtin/async/init.lua b/builtin/async/mainmenu.lua
index 3803994d6..0e9c222d1 100644
--- a/builtin/async/init.lua
+++ b/builtin/async/mainmenu.lua
@@ -1,5 +1,4 @@
-
-core.log("info", "Initializing Asynchronous environment")
+core.log("info", "Initializing asynchronous environment")
function core.job_processor(func, serialized_param)
local param = core.deserialize(serialized_param)
@@ -8,4 +7,3 @@ function core.job_processor(func, serialized_param)
return retval or core.serialize(nil)
end
-
diff --git a/builtin/client/init.lua b/builtin/client/init.lua
index 589fe8f24..3719a90ee 100644
--- a/builtin/client/init.lua
+++ b/builtin/client/init.lua
@@ -5,6 +5,8 @@ local commonpath = scriptpath.."common"..DIR_DELIM
dofile(clientpath .. "register.lua")
dofile(commonpath .. "after.lua")
+dofile(commonpath .. "mod_storage.lua")
dofile(commonpath .. "chatcommands.lua")
dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "death_formspec.lua")
+dofile(clientpath .. "misc.lua")
diff --git a/builtin/client/misc.lua b/builtin/client/misc.lua
new file mode 100644
index 000000000..80e0f2904
--- /dev/null
+++ b/builtin/client/misc.lua
@@ -0,0 +1,7 @@
+function core.setting_get_pos(name)
+ local value = core.settings:get(name)
+ if not value then
+ return nil
+ end
+ return core.string_to_pos(value)
+end
diff --git a/builtin/common/information_formspecs.lua b/builtin/common/information_formspecs.lua
index 3405263bf..1445a017c 100644
--- a/builtin/common/information_formspecs.lua
+++ b/builtin/common/information_formspecs.lua
@@ -22,7 +22,6 @@ local LIST_FORMSPEC_DESCRIPTION = [[
local F = core.formspec_escape
local S = core.get_translator("__builtin")
-local check_player_privs = core.check_player_privs
-- CHAT COMMANDS FORMSPEC
@@ -58,10 +57,11 @@ local function build_chatcommands_formspec(name, sel, copy)
.. "any entry in the list.").. "\n" ..
S("Double-click to copy the entry to the chat history.")
+ local privs = core.get_player_privs(name)
for i, data in ipairs(mod_cmds) do
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)
+ local has_priv = privs[cmds[2].privs]
rows[#rows + 1] = ("%s,1,%s,%s"):format(
has_priv and COLOR_GREEN or COLOR_GRAY,
cmds[1], F(cmds[2].params))
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index f5f89acd7..467f18804 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -204,7 +204,7 @@ end
--------------------------------------------------------------------------------
function string:trim()
- return (self:gsub("^%s*(.-)%s*$", "%1"))
+ return self:match("^%s*(.-)%s*$")
end
--------------------------------------------------------------------------------
@@ -245,16 +245,16 @@ function math.round(x)
return math.ceil(x - 0.5)
end
-
+local formspec_escapes = {
+ ["\\"] = "\\\\",
+ ["["] = "\\[",
+ ["]"] = "\\]",
+ [";"] = "\\;",
+ [","] = "\\,"
+}
function core.formspec_escape(text)
- if text ~= nil then
- text = string.gsub(text,"\\","\\\\")
- text = string.gsub(text,"%]","\\]")
- text = string.gsub(text,"%[","\\[")
- text = string.gsub(text,";","\\;")
- text = string.gsub(text,",","\\,")
- end
- return text
+ -- Use explicit character set instead of dot here because it doubles the performance
+ return text and string.gsub(text, "[\\%[%];,]", formspec_escapes)
end
@@ -265,18 +265,21 @@ function core.wrap_text(text, max_length, as_table)
return as_table and {text} or text
end
- for word in text:gmatch('%S+') do
- local cur_length = #table.concat(line, ' ')
- if cur_length > 0 and cur_length + #word + 1 >= max_length then
+ local line_length = 0
+ for word in text:gmatch("%S+") do
+ if line_length > 0 and line_length + #word + 1 >= max_length then
-- word wouldn't fit on current line, move to next line
- table.insert(result, table.concat(line, ' '))
- line = {}
+ table.insert(result, table.concat(line, " "))
+ line = {word}
+ line_length = #word
+ else
+ table.insert(line, word)
+ line_length = line_length + 1 + #word
end
- table.insert(line, word)
end
- table.insert(result, table.concat(line, ' '))
- return as_table and result or table.concat(result, '\n')
+ table.insert(result, table.concat(line, " "))
+ return as_table and result or table.concat(result, "\n")
end
--------------------------------------------------------------------------------
@@ -425,54 +428,50 @@ function core.string_to_pos(value)
return nil
end
- local x, y, z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
- if x and y and z then
- x = tonumber(x)
- y = tonumber(y)
- z = tonumber(z)
- return vector.new(x, y, z)
- end
- x, y, z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
+ value = value:match("^%((.-)%)$") or value -- strip parentheses
+
+ local x, y, z = value:trim():match("^([%d.-]+)[,%s]%s*([%d.-]+)[,%s]%s*([%d.-]+)$")
if x and y and z then
x = tonumber(x)
y = tonumber(y)
z = tonumber(z)
return vector.new(x, y, z)
end
+
return nil
end
--------------------------------------------------------------------------------
-function core.string_to_area(value)
- local p1, p2 = unpack(value:split(") ("))
- if p1 == nil or p2 == nil then
- return nil
- end
- p1 = core.string_to_pos(p1 .. ")")
- p2 = core.string_to_pos("(" .. p2)
- if p1 == nil or p2 == nil then
- return nil
+do
+ local rel_num_cap = "(~?-?%d*%.?%d*)" -- may be overly permissive as this will be tonumber'ed anyways
+ local num_delim = "[,%s]%s*"
+ local pattern = "^" .. table.concat({rel_num_cap, rel_num_cap, rel_num_cap}, num_delim) .. "$"
+
+ local function parse_area_string(pos, relative_to)
+ local pp = {}
+ pp.x, pp.y, pp.z = pos:trim():match(pattern)
+ return core.parse_coordinates(pp.x, pp.y, pp.z, relative_to)
end
- return p1, p2
-end
+ function core.string_to_area(value, relative_to)
+ local p1, p2 = value:match("^%((.-)%)%s*%((.-)%)$")
+ if not p1 then
+ return
+ end
-local function test_string_to_area()
- local p1, p2 = core.string_to_area("(10.0, 5, -2) ( 30.2, 4, -12.53)")
- assert(p1.x == 10.0 and p1.y == 5 and p1.z == -2)
- assert(p2.x == 30.2 and p2.y == 4 and p2.z == -12.53)
+ p1 = parse_area_string(p1, relative_to)
+ p2 = parse_area_string(p2, relative_to)
- p1, p2 = core.string_to_area("(10.0, 5, -2 30.2, 4, -12.53")
- assert(p1 == nil and p2 == nil)
+ if p1 == nil or p2 == nil then
+ return
+ end
- p1, p2 = core.string_to_area("(10.0, 5,) -2 fgdf2, 4, -12.53")
- assert(p1 == nil and p2 == nil)
+ return p1, p2
+ end
end
-test_string_to_area()
-
--------------------------------------------------------------------------------
function table.copy(t, seen)
local n = {}
@@ -701,3 +700,71 @@ end
function core.is_nan(number)
return number ~= number
end
+
+--[[ Helper function for parsing an optionally relative number
+of a chat command parameter, using the chat command tilde notation.
+
+Parameters:
+* arg: String snippet containing the number; possible values:
+ * "<number>": return as number
+ * "~<number>": return relative_to + <number>
+ * "~": return relative_to
+ * Anything else will return `nil`
+* relative_to: Number to which the `arg` number might be relative to
+
+Returns:
+A number or `nil`, depending on `arg.
+
+Examples:
+* `core.parse_relative_number("5", 10)` returns 5
+* `core.parse_relative_number("~5", 10)` returns 15
+* `core.parse_relative_number("~", 10)` returns 10
+]]
+function core.parse_relative_number(arg, relative_to)
+ if not arg then
+ return nil
+ elseif arg == "~" then
+ return relative_to
+ elseif string.sub(arg, 1, 1) == "~" then
+ local number = tonumber(string.sub(arg, 2))
+ if not number then
+ return nil
+ end
+ if core.is_nan(number) or number == math.huge or number == -math.huge then
+ return nil
+ end
+ return relative_to + number
+ else
+ local number = tonumber(arg)
+ if core.is_nan(number) or number == math.huge or number == -math.huge then
+ return nil
+ end
+ return number
+ end
+end
+
+--[[ Helper function to parse coordinates that might be relative
+to another position; supports chat command tilde notation.
+Intended to be used in chat command parameter parsing.
+
+Parameters:
+* x, y, z: Parsed x, y, and z coordinates as strings
+* relative_to: Position to which to compare the position
+
+Syntax of x, y and z:
+* "<number>": return as number
+* "~<number>": return <number> + player position on this axis
+* "~": return player position on this axis
+
+Returns: a vector or nil for invalid input or if player does not exist
+]]
+function core.parse_coordinates(x, y, z, relative_to)
+ if not relative_to then
+ x, y, z = tonumber(x), tonumber(y), tonumber(z)
+ return x and y and z and { x = x, y = y, z = z }
+ end
+ local rx = core.parse_relative_number(x, relative_to.x)
+ local ry = core.parse_relative_number(y, relative_to.y)
+ local rz = core.parse_relative_number(z, relative_to.z)
+ return rx and ry and rz and { x = rx, y = ry, z = rz }
+end
diff --git a/builtin/common/mod_storage.lua b/builtin/common/mod_storage.lua
new file mode 100644
index 000000000..7ccf62900
--- /dev/null
+++ b/builtin/common/mod_storage.lua
@@ -0,0 +1,19 @@
+-- Modify core.get_mod_storage to return the storage for the current mod.
+
+local get_current_modname = core.get_current_modname
+
+local old_get_mod_storage = core.get_mod_storage
+
+local storages = setmetatable({}, {
+ __mode = "v", -- values are weak references (can be garbage-collected)
+ __index = function(self, modname)
+ local storage = old_get_mod_storage(modname)
+ self[modname] = storage
+ return storage
+ end,
+})
+
+function core.get_mod_storage()
+ local modname = get_current_modname()
+ return modname and storages[modname]
+end
diff --git a/builtin/common/serialize.lua b/builtin/common/serialize.lua
index 300b394c6..caf989e69 100644
--- a/builtin/common/serialize.lua
+++ b/builtin/common/serialize.lua
@@ -1,205 +1,224 @@
--- Lua module to serialize values as Lua code.
--- From: https://github.com/fab13n/metalua/blob/no-dll/src/lib/serialize.lua
+-- From: https://github.com/appgurueu/modlib/blob/master/luon.lua
-- License: MIT
--- @copyright 2006-2997 Fabien Fleutot <metalua@gmail.com>
--- @author Fabien Fleutot <metalua@gmail.com>
--- @author ShadowNinja <shadowninja@minetest.net>
---------------------------------------------------------------------------------
---- Serialize an object into a source code string. This string, when passed as
--- an argument to deserialize(), returns an object structurally identical to
--- the original one. The following are currently supported:
--- * Booleans, numbers, strings, and nil.
--- * Functions; uses interpreter-dependent (and sometimes platform-dependent) bytecode!
--- * Tables; they can cantain multiple references and can be recursive, but metatables aren't saved.
--- This works in two phases:
--- 1. Recursively find and record multiple references and recursion.
--- 2. Recursively dump the value into a string.
--- @param x Value to serialize (nil is allowed).
--- @return load()able string containing the value.
-function core.serialize(x)
- local local_index = 1 -- Top index of the "_" local table in the dump
- -- table->nil/1/2 set of tables seen.
- -- nil = not seen, 1 = seen once, 2 = seen multiple times.
- local seen = {}
+local next, rawget, pairs, pcall, error, type, setfenv, loadstring
+ = next, rawget, pairs, pcall, error, type, setfenv, loadstring
- -- nest_points are places where a table appears within itself, directly
- -- or not. For instance, all of these chunks create nest points in
- -- table x: "x = {}; x[x] = 1", "x = {}; x[1] = x",
- -- "x = {}; x[1] = {y = {x}}".
- -- To handle those, two tables are used by mark_nest_point:
- -- * nested - Transient set of tables being currently traversed.
- -- Used for detecting nested tables.
- -- * nest_points - parent->{key=value, ...} table cantaining the nested
- -- keys and values in the parent. They're all dumped after all the
- -- other table operations have been performed.
- --
- -- mark_nest_point(p, k, v) fills nest_points with information required
- -- to remember that key/value (k, v) creates a nest point in table
- -- parent. It also marks "parent" and the nested item(s) as occuring
- -- multiple times, since several references to it will be required in
- -- order to patch the nest points.
- local nest_points = {}
- local nested = {}
- local function mark_nest_point(parent, k, v)
- local nk, nv = nested[k], nested[v]
- local np = nest_points[parent]
- if not np then
- np = {}
- nest_points[parent] = np
- end
- np[k] = v
- seen[parent] = 2
- if nk then seen[k] = 2 end
- if nv then seen[v] = 2 end
- end
+local table_concat, string_dump, string_format, string_match, math_huge
+ = table.concat, string.dump, string.format, string.match, math.huge
- -- First phase, list the tables and functions which appear more than
- -- once in x.
- local function mark_multiple_occurences(x)
- local tp = type(x)
- if tp ~= "table" and tp ~= "function" then
- -- No identity (comparison is done by value, not by instance)
+-- Recursively counts occurences of objects (non-primitives including strings) in a table.
+local function count_objects(value)
+ local counts = {}
+ if value == nil then
+ -- Early return for nil; tables can't contain nil
+ return counts
+ end
+ local function count_values(val)
+ local type_ = type(val)
+ if type_ == "boolean" or type_ == "number" then
return
end
- if seen[x] == 1 then
- seen[x] = 2
- elseif seen[x] ~= 2 then
- seen[x] = 1
- end
-
- if tp == "table" then
- nested[x] = true
- for k, v in pairs(x) do
- if nested[k] or nested[v] then
- mark_nest_point(x, k, v)
- else
- mark_multiple_occurences(k)
- mark_multiple_occurences(v)
+ local count = counts[val]
+ counts[val] = (count or 0) + 1
+ if type_ == "table" then
+ if not count then
+ for k, v in pairs(val) do
+ count_values(k)
+ count_values(v)
end
end
- nested[x] = nil
+ elseif type_ ~= "string" and type_ ~= "function" then
+ error("unsupported type: " .. type_)
end
end
+ count_values(value)
+ return counts
+end
- local dumped = {} -- object->varname set
- local local_defs = {} -- Dumped local definitions as source code lines
+-- Build a "set" of Lua keywords. These can't be used as short key names.
+-- See https://www.lua.org/manual/5.1/manual.html#2.1
+local keywords = {}
+for _, keyword in pairs({
+ "and", "break", "do", "else", "elseif",
+ "end", "false", "for", "function", "if",
+ "in", "local", "nil", "not", "or",
+ "repeat", "return", "then", "true", "until", "while",
+ "goto" -- LuaJIT, Lua 5.2+
+}) do
+ keywords[keyword] = true
+end
- -- Mutually recursive local functions:
- local dump_val, dump_or_ref_val
+local function quote(string)
+ return string_format("%q", string)
+end
- -- If x occurs multiple times, dump the local variable rather than
- -- the value. If it's the first time it's dumped, also dump the
- -- content in local_defs.
- function dump_or_ref_val(x)
- if seen[x] ~= 2 then
- return dump_val(x)
- end
- local var = dumped[x]
- if var then -- Already referenced
- return var
+local function dump_func(func)
+ return string_format("loadstring(%q)", string_dump(func))
+end
+
+-- Serializes Lua nil, booleans, numbers, strings, tables and even functions
+-- Tables are referenced by reference, strings are referenced by value. Supports circular tables.
+local function serialize(value, write)
+ local reference, refnum = "r1", 1
+ -- [object] = reference string
+ local references = {}
+ -- Circular tables that must be filled using `table[key] = value` statements
+ local to_fill = {}
+ for object, count in pairs(count_objects(value)) do
+ local type_ = type(object)
+ -- Object must appear more than once. If it is a string, the reference has to be shorter than the string.
+ if count >= 2 and (type_ ~= "string" or #reference + 2 < #object) then
+ write(reference)
+ write("=")
+ if type_ == "table" then
+ write("{}")
+ elseif type_ == "function" then
+ write(dump_func(object))
+ elseif type_ == "string" then
+ write(quote(object))
+ end
+ write(";")
+ references[object] = reference
+ if type_ == "table" then
+ to_fill[object] = reference
+ end
+ refnum = refnum + 1
+ reference = ("r%X"):format(refnum)
end
- -- First occurence, create and register reference
- local val = dump_val(x)
- local i = local_index
- local_index = local_index + 1
- var = "_["..i.."]"
- local_defs[#local_defs + 1] = var.." = "..val
- dumped[x] = var
- return var
end
-
- -- Second phase. Dump the object; subparts occuring multiple times
- -- are dumped in local variables which can be referenced multiple
- -- times. Care is taken to dump local vars in a sensible order.
- function dump_val(x)
- local tp = type(x)
- if x == nil then return "nil"
- elseif tp == "string" then return string.format("%q", x)
- elseif tp == "boolean" then return x and "true" or "false"
- elseif tp == "function" then
- return string.format("loadstring(%q)", string.dump(x))
- elseif tp == "number" then
- -- Serialize numbers reversibly with string.format
- return string.format("%.17g", x)
- elseif tp == "table" then
- local vals = {}
- local idx_dumped = {}
- local np = nest_points[x]
- for i, v in ipairs(x) do
- if not np or not np[i] then
- vals[#vals + 1] = dump_or_ref_val(v)
- end
- idx_dumped[i] = true
+ -- Used to decide whether we should do "key=..."
+ local function use_short_key(key)
+ return not references[key] and type(key) == "string" and (not keywords[key]) and string_match(key, "^[%a_][%a%d_]*$")
+ end
+ local function dump(value)
+ -- Primitive types
+ if value == nil then
+ return write("nil")
+ end
+ if value == true then
+ return write("true")
+ end
+ if value == false then
+ return write("false")
+ end
+ local type_ = type(value)
+ if type_ == "number" then
+ return write(string_format("%.17g", value))
+ end
+ -- Reference types: table, function and string
+ local ref = references[value]
+ if ref then
+ return write(ref)
+ end
+ if type_ == "string" then
+ return write(quote(value))
+ end
+ if type_ == "function" then
+ return write(dump_func(value))
+ end
+ if type_ == "table" then
+ write("{")
+ -- First write list keys:
+ -- Don't use the table length #value here as it may horribly fail
+ -- for tables which use large integers as keys in the hash part;
+ -- stop at the first "hole" (nil value) instead
+ local len = 0
+ local first = true -- whether this is the first entry, which may not have a leading comma
+ while true do
+ local v = rawget(value, len + 1) -- use rawget to avoid metatables like the vector metatable
+ if v == nil then break end
+ if first then first = false else write(",") end
+ dump(v)
+ len = len + 1
end
- for k, v in pairs(x) do
- if (not np or not np[k]) and
- not idx_dumped[k] then
- vals[#vals + 1] = "["..dump_or_ref_val(k).."] = "
- ..dump_or_ref_val(v)
+ -- Now write map keys ([key] = value)
+ for k, v in next, value do
+ -- We have written all non-float keys in [1, len] already
+ if type(k) ~= "number" or k % 1 ~= 0 or k < 1 or k > len then
+ if first then first = false else write(",") end
+ if use_short_key(k) then
+ write(k)
+ else
+ write("[")
+ dump(k)
+ write("]")
+ end
+ write("=")
+ dump(v)
end
end
- return "{"..table.concat(vals, ", ").."}"
- else
- error("Can't serialize data of type "..tp)
+ write("}")
+ return
end
end
-
- local function dump_nest_points()
- for parent, vals in pairs(nest_points) do
- for k, v in pairs(vals) do
- local_defs[#local_defs + 1] = dump_or_ref_val(parent)
- .."["..dump_or_ref_val(k).."] = "
- ..dump_or_ref_val(v)
+ -- Write the statements to fill circular tables
+ for table, ref in pairs(to_fill) do
+ for k, v in pairs(table) do
+ write(ref)
+ if use_short_key(k) then
+ write(".")
+ write(k)
+ else
+ write("[")
+ dump(k)
+ write("]")
end
+ write("=")
+ dump(v)
+ write(";")
end
end
-
- mark_multiple_occurences(x)
- local top_level = dump_or_ref_val(x)
- dump_nest_points()
-
- if next(local_defs) then
- return "local _ = {}\n"
- ..table.concat(local_defs, "\n")
- .."\nreturn "..top_level
- else
- return "return "..top_level
- end
+ write("return ")
+ dump(value)
end
--- Deserialization
-
-local function safe_loadstring(...)
- local func, err = loadstring(...)
- if func then
- setfenv(func, {})
- return func
- end
- return nil, err
+function core.serialize(value)
+ local rope = {}
+ serialize(value, function(text)
+ -- Faster than table.insert(rope, text) on PUC Lua 5.1
+ rope[#rope + 1] = text
+ end)
+ return table_concat(rope)
end
local function dummy_func() end
+local nan = (0/0)^1 -- +nan
+
function core.deserialize(str, safe)
- if type(str) ~= "string" then
- return nil, "Cannot deserialize type '"..type(str)
- .."'. Argument must be a string."
+ -- Backwards compatibility
+ if str == nil then
+ core.log("deprecated", "minetest.deserialize called with nil (expected string).")
+ return nil, "Invalid type: Expected a string, got nil"
end
- if str:byte(1) == 0x1B then
- return nil, "Bytecode prohibited"
+ local t = type(str)
+ if t ~= "string" then
+ error(("minetest.deserialize called with %s (expected string)."):format(t))
end
- local f, err = loadstring(str)
- if not f then return nil, err end
- -- The environment is recreated every time so deseralized code cannot
- -- pollute it with permanent references.
- setfenv(f, {loadstring = safe and dummy_func or safe_loadstring})
+ local func, err = loadstring(str)
+ if not func then return nil, err end
- local good, data = pcall(f)
- if good then
- return data
+ -- math.huge is serialized to inf, NaNs are serialized to nan by Lua
+ local env = {inf = math_huge, nan = nan}
+ if safe then
+ env.loadstring = dummy_func
else
- return nil, data
+ env.loadstring = function(str, ...)
+ local func, err = loadstring(str, ...)
+ if func then
+ setfenv(func, env)
+ return func
+ end
+ return nil, err
+ end
+ end
+ setfenv(func, env)
+ local success, value_or_err = pcall(func)
+ if success then
+ return value_or_err
end
+ return nil, value_or_err
end
diff --git a/builtin/common/strict.lua b/builtin/common/strict.lua
index ccde9676b..936ebb37b 100644
--- a/builtin/common/strict.lua
+++ b/builtin/common/strict.lua
@@ -1,9 +1,4 @@
-
--- Always warn when creating a global variable, even outside of a function.
--- This ignores mod namespaces (variables with the same name as the current mod).
-local WARN_INIT = false
-
-local getinfo = debug.getinfo
+local getinfo, rawget, rawset = debug.getinfo, rawget, rawset
function core.global_exists(name)
if type(name) ~= "string" then
@@ -19,39 +14,33 @@ local declared = {}
local warned = {}
function meta:__newindex(name, value)
+ if declared[name] then
+ return
+ end
local info = getinfo(2, "Sl")
local desc = ("%s:%d"):format(info.short_src, info.currentline)
- if not declared[name] then
- local warn_key = ("%s\0%d\0%s"):format(info.source,
- info.currentline, name)
- if not warned[warn_key] and info.what ~= "main" and
- info.what ~= "C" then
- core.log("warning", ("Assignment to undeclared "..
- "global %q inside a function at %s.")
+ local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
+ if not warned[warn_key] and info.what ~= "main" and info.what ~= "C" then
+ core.log("warning", ("Assignment to undeclared global %q inside a function at %s.")
:format(name, desc))
- warned[warn_key] = true
- end
- declared[name] = true
- end
- -- Ignore mod namespaces
- if WARN_INIT and name ~= core.get_current_modname() then
- core.log("warning", ("Global variable %q created at %s.")
- :format(name, desc))
+ warned[warn_key] = true
end
rawset(self, name, value)
+ declared[name] = true
end
function meta:__index(name)
+ if declared[name] then
+ return
+ end
local info = getinfo(2, "Sl")
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
- if not declared[name] and not warned[warn_key] and info.what ~= "C" then
+ if not warned[warn_key] and info.what ~= "C" then
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
:format(name, info.short_src, info.currentline))
warned[warn_key] = true
end
- return rawget(self, name)
end
setmetatable(_G, meta)
-
diff --git a/builtin/common/tests/misc_helpers_spec.lua b/builtin/common/tests/misc_helpers_spec.lua
index b16987f0b..7d046d5b7 100644
--- a/builtin/common/tests/misc_helpers_spec.lua
+++ b/builtin/common/tests/misc_helpers_spec.lua
@@ -1,4 +1,5 @@
_G.core = {}
+_G.vector = {metatable = {}}
dofile("builtin/common/vector.lua")
dofile("builtin/common/misc_helpers.lua")
@@ -66,9 +67,107 @@ describe("pos", function()
end)
end)
+describe("area parsing", function()
+ describe("valid inputs", function()
+ it("accepts absolute numbers", function()
+ local p1, p2 = core.string_to_area("(10.0, 5, -2) ( 30.2 4 -12.53)")
+ assert(p1.x == 10 and p1.y == 5 and p1.z == -2)
+ assert(p2.x == 30.2 and p2.y == 4 and p2.z == -12.53)
+ end)
+
+ it("accepts relative numbers", function()
+ local p1, p2 = core.string_to_area("(1,2,3) (~5,~-5,~)", {x=10,y=10,z=10})
+ assert(type(p1) == "table" and type(p2) == "table")
+ assert(p1.x == 1 and p1.y == 2 and p1.z == 3)
+ assert(p2.x == 15 and p2.y == 5 and p2.z == 10)
+
+ p1, p2 = core.string_to_area("(1 2 3) (~5 ~-5 ~)", {x=10,y=10,z=10})
+ assert(type(p1) == "table" and type(p2) == "table")
+ assert(p1.x == 1 and p1.y == 2 and p1.z == 3)
+ assert(p2.x == 15 and p2.y == 5 and p2.z == 10)
+ end)
+ end)
+ describe("invalid inputs", function()
+ it("rejects too few numbers", function()
+ local p1, p2 = core.string_to_area("(1,1) (1,1,1,1)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+ end)
+
+ it("rejects too many numbers", function()
+ local p1, p2 = core.string_to_area("(1,1,1,1) (1,1,1,1)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+ end)
+
+ it("rejects nan & inf", function()
+ local p1, p2 = core.string_to_area("(1,1,1) (1,1,nan)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(1,1,1) (1,1,~nan)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(1,1,1) (1,~nan,1)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(1,1,1) (1,1,inf)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(1,1,1) (1,1,~inf)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(1,1,1) (1,~inf,1)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(nan,nan,nan) (nan,nan,nan)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(nan,nan,nan) (nan,nan,nan)")
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(inf,inf,inf) (-inf,-inf,-inf)", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(inf,inf,inf) (-inf,-inf,-inf)")
+ assert(p1 == nil and p2 == nil)
+ end)
+
+ it("rejects words", function()
+ local p1, p2 = core.string_to_area("bananas", {x=1,y=1,z=1})
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("bananas", "foobar")
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("bananas")
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(bananas,bananas,bananas)")
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(bananas,bananas,bananas) (bananas,bananas,bananas)")
+ assert(p1 == nil and p2 == nil)
+ end)
+
+ it("requires parenthesis & valid numbers", function()
+ local p1, p2 = core.string_to_area("(10.0, 5, -2 30.2, 4, -12.53")
+ assert(p1 == nil and p2 == nil)
+
+ p1, p2 = core.string_to_area("(10.0, 5,) -2 fgdf2, 4, -12.53")
+ assert(p1 == nil and p2 == nil)
+ end)
+ end)
+end)
+
describe("table", function()
it("indexof()", function()
assert.equal(1, table.indexof({"foo", "bar"}, "foo"))
assert.equal(-1, table.indexof({"foo", "bar"}, "baz"))
end)
end)
+
+describe("formspec_escape", function()
+ it("escapes", function()
+ assert.equal(nil, core.formspec_escape(nil))
+ assert.equal("", core.formspec_escape(""))
+ assert.equal("\\[Hello\\\\\\[", core.formspec_escape("[Hello\\["))
+ end)
+end)
diff --git a/builtin/common/tests/serialize_spec.lua b/builtin/common/tests/serialize_spec.lua
index e46b7dcc5..340e226ee 100644
--- a/builtin/common/tests/serialize_spec.lua
+++ b/builtin/common/tests/serialize_spec.lua
@@ -1,42 +1,97 @@
_G.core = {}
+_G.vector = {metatable = {}}
_G.setfenv = require 'busted.compatibility'.setfenv
dofile("builtin/common/serialize.lua")
dofile("builtin/common/vector.lua")
+-- Supports circular tables; does not support table keys
+-- Correctly checks whether a mapping of references ("same") exists
+-- Is significantly more efficient than assert.same
+local function assert_same(a, b, same)
+ same = same or {}
+ if same[a] or same[b] then
+ assert(same[a] == b and same[b] == a)
+ return
+ end
+ if a == b then
+ return
+ end
+ if type(a) ~= "table" or type(b) ~= "table" then
+ assert(a == b)
+ return
+ end
+ same[a] = b
+ same[b] = a
+ local count = 0
+ for k, v in pairs(a) do
+ count = count + 1
+ assert(type(k) ~= "table")
+ assert_same(v, b[k], same)
+ end
+ for _ in pairs(b) do
+ count = count - 1
+ end
+ assert(count == 0)
+end
+
+local x, y = {}, {}
+local t1, t2 = {x, x, y, y}, {x, y, x, y}
+assert.same(t1, t2) -- will succeed because it only checks whether the depths match
+assert(not pcall(assert_same, t1, t2)) -- will correctly fail because it checks whether the refs match
+
describe("serialize", function()
+ local function assert_preserves(value)
+ local preserved_value = core.deserialize(core.serialize(value))
+ assert_same(value, preserved_value)
+ end
it("works", function()
- local test_in = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
- local test_out = core.deserialize(core.serialize(test_in))
-
- assert.same(test_in, test_out)
+ assert_preserves({cat={sound="nyan", speed=400}, dog={sound="woof"}})
end)
it("handles characters", function()
- local test_in = {escape_chars="\n\r\t\v\\\"\'", non_european="θשׁ٩∂"}
- local test_out = core.deserialize(core.serialize(test_in))
- assert.same(test_in, test_out)
+ assert_preserves({escape_chars="\n\r\t\v\\\"\'", non_european="θשׁ٩∂"})
+ end)
+
+ it("handles NaN & infinities", function()
+ local nan = core.deserialize(core.serialize(0/0))
+ assert(nan ~= nan)
+ assert_preserves(math.huge)
+ assert_preserves(-math.huge)
end)
it("handles precise numbers", function()
- local test_in = 0.2695949158945771
- local test_out = core.deserialize(core.serialize(test_in))
- assert.same(test_in, test_out)
+ assert_preserves(0.2695949158945771)
end)
it("handles big integers", function()
- local test_in = 269594915894577
- local test_out = core.deserialize(core.serialize(test_in))
- assert.same(test_in, test_out)
+ assert_preserves(269594915894577)
end)
it("handles recursive structures", function()
local test_in = { hello = "world" }
test_in.foo = test_in
+ assert_preserves(test_in)
+ end)
+
+ it("handles cross-referencing structures", function()
+ local test_in = {
+ foo = {
+ baz = {
+ {}
+ },
+ },
+ bar = {
+ baz = {},
+ },
+ }
- local test_out = core.deserialize(core.serialize(test_in))
- assert.same(test_in, test_out)
+ test_in.foo.baz[1].foo = test_in.foo
+ test_in.foo.baz[1].bar = test_in.bar
+ test_in.bar.baz[1] = test_in.foo.baz[1]
+
+ assert_preserves(test_in)
end)
it("strips functions in safe mode", function()
@@ -46,6 +101,7 @@ describe("serialize", function()
end,
foo = "bar"
}
+ setfenv(test_in.func, _G)
local str = core.serialize(test_in)
assert.not_nil(str:find("loadstring"))
@@ -57,13 +113,77 @@ describe("serialize", function()
it("vectors work", function()
local v = vector.new(1, 2, 3)
- assert.same({{x = 1, y = 2, z = 3}}, core.deserialize(core.serialize({v})))
- assert.same({x = 1, y = 2, z = 3}, core.deserialize(core.serialize(v)))
+ assert_preserves({v})
+ assert_preserves(v)
-- abuse
v = vector.new(1, 2, 3)
v.a = "bla"
- assert.same({x = 1, y = 2, z = 3, a = "bla"},
- core.deserialize(core.serialize(v)))
+ assert_preserves(v)
+ end)
+
+ it("handles keywords as keys", function()
+ assert_preserves({["and"] = "keyword", ["for"] = "keyword"})
+ end)
+
+ describe("fuzzing", function()
+ local atomics = {true, false, math.huge, -math.huge} -- no NaN or nil
+ local function atomic()
+ return atomics[math.random(1, #atomics)]
+ end
+ local function num()
+ local sign = math.random() < 0.5 and -1 or 1
+ -- HACK math.random(a, b) requires a, b & b - a to fit within a 32-bit int
+ -- Use two random calls to generate a random number from 0 - 2^50 as lower & upper 25 bits
+ local val = math.random(0, 2^25) * 2^25 + math.random(0, 2^25 - 1)
+ local exp = math.random() < 0.5 and 1 or 2^(math.random(-120, 120))
+ return sign * val * exp
+ end
+ local function charcodes(count)
+ if count == 0 then return end
+ return math.random(0, 0xFF), charcodes(count - 1)
+ end
+ local function str()
+ return string.char(charcodes(math.random(0, 100)))
+ end
+ local primitives = {atomic, num, str}
+ local function primitive()
+ return primitives[math.random(1, #primitives)]()
+ end
+ local function tab(max_actions)
+ local root = {}
+ local tables = {root}
+ local function random_table()
+ return tables[math.random(1, #tables)]
+ end
+ for _ = 1, math.random(1, max_actions) do
+ local tab = random_table()
+ local value
+ if math.random() < 0.5 then
+ if math.random() < 0.5 then
+ value = random_table()
+ else
+ value = {}
+ table.insert(tables, value)
+ end
+ else
+ value = primitive()
+ end
+ tab[math.random() < 0.5 and (#tab + 1) or primitive()] = value
+ end
+ return root
+ end
+ it("primitives work", function()
+ for _ = 1, 1e3 do
+ assert_preserves(primitive())
+ end
+ end)
+ it("tables work", function()
+ for _ = 1, 100 do
+ local fuzzed_table = tab(1e3)
+ assert_same(fuzzed_table, table.copy(fuzzed_table))
+ assert_preserves(fuzzed_table)
+ end
+ end)
end)
end)
diff --git a/builtin/common/tests/vector_spec.lua b/builtin/common/tests/vector_spec.lua
index 2f72f3383..6a0b81a89 100644
--- a/builtin/common/tests/vector_spec.lua
+++ b/builtin/common/tests/vector_spec.lua
@@ -1,4 +1,4 @@
-_G.vector = {}
+_G.vector = {metatable = {}}
dofile("builtin/common/vector.lua")
describe("vector", function()
@@ -128,6 +128,14 @@ describe("vector", function()
assert.equal(vector.new(4.1, 5.9, 5.5), a:apply(f))
end)
+ it("combine()", function()
+ local a = vector.new(1, 2, 3)
+ local b = vector.new(3, 2, 1)
+ assert.equal(vector.add(a, b), vector.combine(a, b, function(x, y) return x + y end))
+ assert.equal(vector.new(3, 2, 3), vector.combine(a, b, math.max))
+ assert.equal(vector.new(1, 2, 1), vector.combine(a, b, math.min))
+ end)
+
it("equals()", function()
local function assertE(a, b)
assert.is_true(vector.equals(a, b))
diff --git a/builtin/common/vector.lua b/builtin/common/vector.lua
index 581d014e0..a08472e32 100644
--- a/builtin/common/vector.lua
+++ b/builtin/common/vector.lua
@@ -6,10 +6,8 @@ Note: The vector.*-functions must be able to accept old vectors that had no meta
-- localize functions
local setmetatable = setmetatable
-vector = {}
-
-local metatable = {}
-vector.metatable = metatable
+-- vector.metatable is set by C++.
+local metatable = vector.metatable
local xyz = {"x", "y", "z"}
@@ -112,6 +110,14 @@ function vector.apply(v, func)
)
end
+function vector.combine(a, b, func)
+ return fast_new(
+ func(a.x, b.x),
+ func(a.y, b.y),
+ func(a.z, b.z)
+ )
+end
+
function vector.distance(a, b)
local x = a.x - b.x
local y = a.y - b.y
diff --git a/builtin/game/async.lua b/builtin/game/async.lua
new file mode 100644
index 000000000..469f179d7
--- /dev/null
+++ b/builtin/game/async.lua
@@ -0,0 +1,22 @@
+
+core.async_jobs = {}
+
+function core.async_event_handler(jobid, retval)
+ local callback = core.async_jobs[jobid]
+ assert(type(callback) == "function")
+ callback(unpack(retval, 1, retval.n))
+ core.async_jobs[jobid] = nil
+end
+
+function core.handle_async(func, callback, ...)
+ assert(type(func) == "function" and type(callback) == "function",
+ "Invalid minetest.handle_async invocation")
+ local args = {n = select("#", ...), ...}
+ local mod_origin = core.get_last_run_mod()
+
+ local jobid = core.do_async_callback(func, args, mod_origin)
+ core.async_jobs[jobid] = callback
+
+ return true
+end
+
diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua
index 493bb92c0..bbcdcf2d0 100644
--- a/builtin/game/chat.lua
+++ b/builtin/game/chat.lua
@@ -130,8 +130,13 @@ local function parse_range_str(player_name, str)
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
+ local player = core.get_player_by_name(player_name)
+ local relpos
+ if player then
+ relpos = player:get_pos()
+ end
+ p1, p2 = core.string_to_area(str, relpos)
+ if p1 == nil or p2 == nil then
return false, S("Incorrect area format. "
.. "Expected: (x1,y1,z1) (x2,y2,z2)")
end
@@ -310,12 +315,7 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
and revokename == core.settings:get("name")
and revokename ~= ""
if revokeprivstr == "all" then
- revokeprivs = privs
- privs = {}
- else
- for priv, _ in pairs(revokeprivs) do
- privs[priv] = nil
- end
+ revokeprivs = table.copy(privs)
end
local privs_unknown = ""
@@ -332,7 +332,10 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
end
local def = core.registered_privileges[priv]
if not def then
- privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n"
+ -- Old/removed privileges might still be granted to certain players
+ if not privs[priv] then
+ privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n"
+ end
elseif is_singleplayer and def.give_to_singleplayer then
irrevokable[priv] = true
elseif is_admin and def.give_to_admin then
@@ -359,19 +362,22 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
end
local revokecount = 0
-
- core.set_player_privs(revokename, privs)
for priv, _ in pairs(revokeprivs) do
- -- call the on_revoke callbacks
- core.run_priv_callbacks(revokename, priv, caller, "revoke")
+ privs[priv] = nil
revokecount = revokecount + 1
end
- local new_privs = core.get_player_privs(revokename)
if revokecount == 0 then
return false, S("No privileges were revoked.")
end
+ core.set_player_privs(revokename, privs)
+ for priv, _ in pairs(revokeprivs) do
+ -- call the on_revoke callbacks
+ core.run_priv_callbacks(revokename, priv, caller, "revoke")
+ end
+ local new_privs = core.get_player_privs(revokename)
+
core.log("action", caller..' revoked ('
..core.privs_to_string(revokeprivs, ', ')
..') privileges from '..revokename)
@@ -569,10 +575,15 @@ core.register_chatcommand("teleport", {
description = S("Teleport to position or player"),
privs = {teleport=true},
func = function(name, param)
+ local player = core.get_player_by_name(name)
+ local relpos
+ if player then
+ relpos = player:get_pos()
+ end
local p = {}
- 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
+ p.x, p.y, p.z = string.match(param, "^([%d.~-]+)[, ] *([%d.~-]+)[, ] *([%d.~-]+)$")
+ p = core.parse_coordinates(p.x, p.y, p.z, relpos)
+ if p and p.x and p.y and p.z then
return teleport_to_pos(name, p)
end
@@ -586,9 +597,19 @@ core.register_chatcommand("teleport", {
"other players (missing privilege: @1).", "bring")
local teleportee_name
+ p = {}
teleportee_name, p.x, p.y, p.z = param:match(
- "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
+ "^([^ ]+) +([%d.~-]+)[, ] *([%d.~-]+)[, ] *([%d.~-]+)$")
+ if teleportee_name then
+ local teleportee = core.get_player_by_name(teleportee_name)
+ if not teleportee then
+ return
+ end
+ relpos = teleportee:get_pos()
+ p = core.parse_coordinates(p.x, p.y, p.z, relpos)
+ end
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
@@ -621,6 +642,10 @@ core.register_chatcommand("set", {
setname, setvalue = string.match(param, "([^ ]+) (.+)")
if setname and setvalue then
+ if setname:sub(1, 7) == "secure." then
+ return false, S("Failed. Cannot modify secure settings. "
+ .. "Edit the settings file manually.")
+ end
if not core.settings:get(setname) then
return false, S("Failed. Use '/set -n <name> <value>' "
.. "to create a new setting.")
@@ -837,7 +862,7 @@ core.register_chatcommand("spawnentity", {
description = S("Spawn entity at given (or your) position"),
privs = {give=true, interact=true},
func = function(name, param)
- local entityname, p = string.match(param, "^([^ ]+) *(.*)$")
+ local entityname, pstr = string.match(param, "^([^ ]+) *(.*)$")
if not entityname then
return false, S("EntityName required.")
end
@@ -851,11 +876,15 @@ core.register_chatcommand("spawnentity", {
if not core.registered_entities[entityname] then
return false, S("Cannot spawn an unknown entity.")
end
- if p == "" then
+ local p
+ if pstr == "" then
p = player:get_pos()
else
- p = core.string_to_pos(p)
- if p == nil then
+ p = {}
+ p.x, p.y, p.z = string.match(pstr, "^([%d.~-]+)[, ] *([%d.~-]+)[, ] *([%d.~-]+)$")
+ local relpos = player:get_pos()
+ p = core.parse_coordinates(p.x, p.y, p.z, relpos)
+ if not (p and p.x and p.y and p.z) then
return false, S("Invalid parameters (@1).", param)
end
end
@@ -1014,6 +1043,13 @@ core.register_chatcommand("status", {
end,
})
+local function get_time(timeofday)
+ local time = math.floor(timeofday * 1440)
+ local minute = time % 60
+ local hour = (time - minute) / 60
+ return time, hour, minute
+end
+
core.register_chatcommand("time", {
params = S("[<0..23>:<0..59> | <0..24000>]"),
description = S("Show or set time of day"),
@@ -1032,9 +1068,14 @@ core.register_chatcommand("time", {
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
+ local relative, negative, hour, minute = param:match("^(~?)(%-?)(%d+):(%d+)$")
+ if not relative then -- checking the first capture against nil suffices
+ local new_time = core.parse_relative_number(param, core.get_timeofday() * 24000)
+ if not new_time then
+ new_time = tonumber(param) or -1
+ else
+ new_time = new_time % 24000
+ end
if new_time ~= new_time or new_time < 0 or new_time > 24000 then
return false, S("Invalid time (must be between 0 and 24000).")
end
@@ -1042,14 +1083,29 @@ core.register_chatcommand("time", {
core.log("action", name .. " sets time to " .. new_time)
return true, S("Time of day changed.")
end
+ local new_time
hour = tonumber(hour)
minute = tonumber(minute)
- if hour < 0 or hour > 23 then
- return false, S("Invalid hour (must be between 0 and 23 inclusive).")
- elseif minute < 0 or minute > 59 then
- return false, S("Invalid minute (must be between 0 and 59 inclusive).")
+ if relative == "" then
+ if hour < 0 or hour > 23 then
+ return false, S("Invalid hour (must be between 0 and 23 inclusive).")
+ elseif minute < 0 or minute > 59 then
+ return false, S("Invalid minute (must be between 0 and 59 inclusive).")
+ end
+ new_time = (hour * 60 + minute) / 1440
+ else
+ if minute < 0 or minute > 59 then
+ return false, S("Invalid minute (must be between 0 and 59 inclusive).")
+ end
+ local current_time = core.get_timeofday()
+ if negative == "-" then -- negative time
+ hour, minute = -hour, -minute
+ end
+ new_time = (current_time + (hour * 60 + minute) / 1440) % 1
+ local _
+ _, hour, minute = get_time(new_time)
end
- core.set_timeofday((hour * 60 + minute) / 1440)
+ core.set_timeofday(new_time)
core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute))
return true, S("Time of day changed.")
end,
@@ -1131,6 +1187,9 @@ core.register_chatcommand("ban", {
return true, S("Ban list: @1", ban_list)
end
end
+ if core.is_singleplayer() then
+ return false, S("You cannot ban players in singleplayer!")
+ end
if not core.get_player_by_name(param) then
return false, S("Player is not online.")
end
diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua
index 29cb56aae..d5727f2a7 100644
--- a/builtin/game/falling.lua
+++ b/builtin/game/falling.lua
@@ -158,12 +158,10 @@ core.register_entity(":__builtin:falling_node", {
or def.drawtype == "normal"
or def.drawtype == "nodebox" then
if (def.paramtype2 == "facedir" or def.paramtype2 == "colorfacedir") then
- local fdir = node.param2 % 32
+ local fdir = node.param2 % 32 % 24
-- Get rotation from a precalculated lookup table
local euler = facedir_to_euler[fdir + 1]
- if euler then
- self.object:set_rotation(euler)
- end
+ self.object:set_rotation(euler)
elseif (def.drawtype ~= "plantlike" and def.drawtype ~= "plantlike_rooted" and
(def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike")) then
local rot = node.param2 % 8
@@ -264,7 +262,7 @@ core.register_entity(":__builtin:falling_node", {
end
-- Decide if we're replacing the node or placing on top
- local np = vector.new(bcp)
+ local np = vector.copy(bcp)
if bcd and bcd.buildable_to and
(not self.floats or bcd.liquidtype == "none") then
core.remove_node(bcp)
@@ -436,7 +434,7 @@ local function drop_attached_node(p)
if def and def.preserve_metadata then
local oldmeta = core.get_meta(p):to_table().fields
-- Copy pos and node because the callback can modify them.
- local pos_copy = vector.new(p)
+ local pos_copy = vector.copy(p)
local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
local drop_stacks = {}
for k, v in pairs(drops) do
@@ -461,7 +459,7 @@ end
function builtin_shared.check_attached_node(p, n)
local def = core.registered_nodes[n.name]
- local d = vector.new()
+ local d = vector.zero()
if def.paramtype2 == "wallmounted" or
def.paramtype2 == "colorwallmounted" then
-- The fallback vector here is in case 'wallmounted to dir' is nil due
diff --git a/builtin/game/features.lua b/builtin/game/features.lua
index 583ef5092..73b16361e 100644
--- a/builtin/game/features.lua
+++ b/builtin/game/features.lua
@@ -21,7 +21,9 @@ core.features = {
use_texture_alpha_string_modes = true,
degrotate_240_steps = true,
abm_min_max_y = true,
+ particlespawner_tweenable = true,
dynamic_add_media_table = true,
+ get_sky_as_table = true,
}
function core.has_feature(arg)
diff --git a/builtin/game/init.lua b/builtin/game/init.lua
index bb007fabd..d7606f357 100644
--- a/builtin/game/init.lua
+++ b/builtin/game/init.lua
@@ -8,6 +8,7 @@ local gamepath = scriptpath .. "game".. DIR_DELIM
local builtin_shared = {}
dofile(gamepath .. "constants.lua")
+dofile(gamepath .. "item_s.lua")
assert(loadfile(gamepath .. "item.lua"))(builtin_shared)
dofile(gamepath .. "register.lua")
@@ -16,8 +17,10 @@ if core.settings:get_bool("profiler.load") then
end
dofile(commonpath .. "after.lua")
+dofile(commonpath .. "mod_storage.lua")
dofile(gamepath .. "item_entity.lua")
dofile(gamepath .. "deprecated.lua")
+dofile(gamepath .. "misc_s.lua")
dofile(gamepath .. "misc.lua")
dofile(gamepath .. "privileges.lua")
dofile(gamepath .. "auth.lua")
@@ -32,5 +35,6 @@ dofile(gamepath .. "voxelarea.lua")
dofile(gamepath .. "forceloading.lua")
dofile(gamepath .. "statbars.lua")
dofile(gamepath .. "knockback.lua")
+dofile(gamepath .. "async.lua")
profiler = nil
diff --git a/builtin/game/item.lua b/builtin/game/item.lua
index 2a4b4e38f..b49787987 100644
--- a/builtin/game/item.lua
+++ b/builtin/game/item.lua
@@ -5,8 +5,8 @@ local builtin_shared = ...
local function copy_pointed_thing(pointed_thing)
return {
type = pointed_thing.type,
- above = vector.new(pointed_thing.above),
- under = vector.new(pointed_thing.under),
+ above = pointed_thing.above and vector.copy(pointed_thing.above),
+ under = pointed_thing.under and vector.copy(pointed_thing.under),
ref = pointed_thing.ref,
}
end
@@ -15,15 +15,6 @@ end
-- Item definition helpers
--
-function core.inventorycube(img1, img2, img3)
- img2 = img2 or img1
- img3 = img3 or img1
- return "[inventorycube"
- .. "{" .. img1:gsub("%^", "&")
- .. "{" .. img2:gsub("%^", "&")
- .. "{" .. img3:gsub("%^", "&")
-end
-
function core.get_pointed_thing_position(pointed_thing, above)
if pointed_thing.type == "node" then
if above then
@@ -37,144 +28,6 @@ function core.get_pointed_thing_position(pointed_thing, above)
end
end
-function core.dir_to_facedir(dir, is6d)
- --account for y if requested
- if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
-
- --from above
- if dir.y < 0 then
- if math.abs(dir.x) > math.abs(dir.z) then
- if dir.x < 0 then
- return 19
- else
- return 13
- end
- else
- if dir.z < 0 then
- return 10
- else
- return 4
- end
- end
-
- --from below
- else
- if math.abs(dir.x) > math.abs(dir.z) then
- if dir.x < 0 then
- return 15
- else
- return 17
- end
- else
- if dir.z < 0 then
- return 6
- else
- return 8
- end
- end
- end
-
- --otherwise, place horizontally
- elseif math.abs(dir.x) > math.abs(dir.z) then
- if dir.x < 0 then
- return 3
- else
- return 1
- end
- else
- if dir.z < 0 then
- return 2
- else
- return 0
- end
- end
-end
-
--- Table of possible dirs
-local facedir_to_dir = {
- vector.new( 0, 0, 1),
- vector.new( 1, 0, 0),
- vector.new( 0, 0, -1),
- vector.new(-1, 0, 0),
- vector.new( 0, -1, 0),
- vector.new( 0, 1, 0),
-}
--- Mapping from facedir value to index in facedir_to_dir.
-local facedir_to_dir_map = {
- [0]=1, 2, 3, 4,
- 5, 2, 6, 4,
- 6, 2, 5, 4,
- 1, 5, 3, 6,
- 1, 6, 3, 5,
- 1, 4, 3, 2,
-}
-function core.facedir_to_dir(facedir)
- return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
-end
-
-function core.dir_to_wallmounted(dir)
- if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
- if dir.y < 0 then
- return 1
- else
- return 0
- end
- elseif math.abs(dir.x) > math.abs(dir.z) then
- if dir.x < 0 then
- return 3
- else
- return 2
- end
- else
- if dir.z < 0 then
- return 5
- else
- return 4
- end
- end
-end
-
--- table of dirs in wallmounted order
-local wallmounted_to_dir = {
- [0] = vector.new( 0, 1, 0),
- vector.new( 0, -1, 0),
- vector.new( 1, 0, 0),
- vector.new(-1, 0, 0),
- vector.new( 0, 0, 1),
- vector.new( 0, 0, -1),
-}
-function core.wallmounted_to_dir(wallmounted)
- return wallmounted_to_dir[wallmounted % 8]
-end
-
-function core.dir_to_yaw(dir)
- return -math.atan2(dir.x, dir.z)
-end
-
-function core.yaw_to_dir(yaw)
- return vector.new(-math.sin(yaw), 0, math.cos(yaw))
-end
-
-function core.is_colored_paramtype(ptype)
- return (ptype == "color") or (ptype == "colorfacedir") or
- (ptype == "colorwallmounted") or (ptype == "colordegrotate")
-end
-
-function core.strip_param2_color(param2, paramtype2)
- if not core.is_colored_paramtype(paramtype2) then
- return nil
- end
- if paramtype2 == "colorfacedir" then
- param2 = math.floor(param2 / 32) * 32
- elseif paramtype2 == "colorwallmounted" then
- param2 = math.floor(param2 / 8) * 8
- elseif paramtype2 == "colordegrotate" then
- param2 = math.floor(param2 / 32) * 32
- end
- -- paramtype2 == "color" requires no modification.
- return param2
-end
-
local function has_all_groups(tbl, required_groups)
if type(required_groups) == "string" then
return (tbl[required_groups] or 0) ~= 0
@@ -323,12 +176,12 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
end
-- Place above pointed node
- local place_to = vector.new(above)
+ local place_to = vector.copy(above)
-- If node under is buildable_to, place into it instead (eg. snow)
if olddef_under.buildable_to then
log("info", "node under is buildable to")
- place_to = vector.new(under)
+ place_to = vector.copy(under)
end
if core.is_protected(place_to, playername) then
@@ -409,7 +262,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
-- Run callback
if def.after_place_node and not prevent_after_place then
-- Deepcopy place_to and pointed_thing because callback can modify it
- local place_to_copy = vector.new(place_to)
+ local place_to_copy = vector.copy(place_to)
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
if def.after_place_node(place_to_copy, placer, itemstack,
pointed_thing_copy) then
@@ -420,7 +273,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
-- Run script hook
for _, callback in ipairs(core.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
- local place_to_copy = vector.new(place_to)
+ local place_to_copy = vector.copy(place_to)
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
@@ -548,7 +401,7 @@ function core.node_punch(pos, node, puncher, pointed_thing)
-- Run script hook
for _, callback in ipairs(core.registered_on_punchnodes) do
-- Copy pos and node because callback can modify them
- local pos_copy = vector.new(pos)
+ local pos_copy = vector.copy(pos)
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
local pointed_thing_copy = pointed_thing and copy_pointed_thing(pointed_thing) or nil
callback(pos_copy, node_copy, puncher, pointed_thing_copy)
@@ -589,7 +442,7 @@ function core.node_dig(pos, node, digger)
local def = core.registered_nodes[node.name]
-- Copy pos because the callback could modify it
if def and (not def.diggable or
- (def.can_dig and not def.can_dig(vector.new(pos), digger))) then
+ (def.can_dig and not def.can_dig(vector.copy(pos), digger))) then
log("info", diggername .. " tried to dig "
.. node.name .. " which is not diggable "
.. core.pos_to_string(pos))
@@ -636,7 +489,7 @@ function core.node_dig(pos, node, digger)
if def and def.preserve_metadata then
local oldmeta = core.get_meta(pos):to_table().fields
-- Copy pos and node because the callback can modify them.
- local pos_copy = vector.new(pos)
+ local pos_copy = vector.copy(pos)
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
local drop_stacks = {}
for k, v in pairs(drops) do
@@ -668,7 +521,7 @@ function core.node_dig(pos, node, digger)
-- Run callback
if def and def.after_dig_node then
-- Copy pos and node because callback can modify them
- local pos_copy = vector.new(pos)
+ local pos_copy = vector.copy(pos)
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
end
@@ -679,7 +532,7 @@ function core.node_dig(pos, node, digger)
core.set_last_run_mod(origin.mod)
-- Copy pos and node because callback can modify them
- local pos_copy = vector.new(pos)
+ local pos_copy = vector.copy(pos)
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
callback(pos_copy, node_copy, digger)
end
@@ -744,13 +597,8 @@ core.nodedef_default = {
-- Node properties
drawtype = "normal",
visual_scale = 1.0,
- -- Don't define these because otherwise the old tile_images and
- -- special_materials wouldn't be read
- --tiles ={""},
- --special_tiles = {
- -- {name="", backface_culling=true},
- -- {name="", backface_culling=true},
- --},
+ tiles = {},
+ special_tiles = {},
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
paramtype2 = "none",
diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua
index 9b1b23bfd..53f98a7c7 100644
--- a/builtin/game/item_entity.lua
+++ b/builtin/game/item_entity.lua
@@ -58,17 +58,21 @@ core.register_entity(":__builtin:item", {
local glow = def and def.light_source and
math.floor(def.light_source / 2 + 0.5)
+ local size_bias = 1e-3 * math.random() -- small random bias to counter Z-fighting
+ local c = {-size, -size, -size, size, size, size}
self.object:set_properties({
is_visible = true,
visual = "wielditem",
textures = {itemname},
- visual_size = {x = size, y = size},
- collisionbox = {-size, -size, -size, size, size, size},
+ visual_size = {x = size + size_bias, y = size + size_bias},
+ collisionbox = c,
automatic_rotate = math.pi * 0.5 * 0.2 / size,
wield_item = self.itemstring,
glow = glow,
})
+ -- cache for usage in on_step
+ self._collisionbox = c
end,
get_staticdata = function(self)
@@ -93,6 +97,7 @@ core.register_entity(":__builtin:item", {
self.object:set_armor_groups({immortal = 1})
self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration({x = 0, y = -gravity, z = 0})
+ self._collisionbox = self.initial_properties.collisionbox
self:set_item()
end,
@@ -163,7 +168,7 @@ core.register_entity(":__builtin:item", {
local pos = self.object:get_pos()
local node = core.get_node_or_nil({
x = pos.x,
- y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
+ y = pos.y + self._collisionbox[2] - 0.05,
z = pos.z
})
-- Delete in 'ignore' nodes
@@ -176,7 +181,7 @@ core.register_entity(":__builtin:item", {
if self.force_out then
-- This code runs after the entity got a push from the is_stuck code.
-- It makes sure the entity is entirely outside the solid node
- local c = self.object:get_properties().collisionbox
+ local c = self._collisionbox
local s = self.force_out_start
local f = self.force_out
local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
diff --git a/builtin/game/item_s.lua b/builtin/game/item_s.lua
new file mode 100644
index 000000000..a51cd0a1c
--- /dev/null
+++ b/builtin/game/item_s.lua
@@ -0,0 +1,156 @@
+-- Minetest: builtin/item_s.lua
+-- The distinction of what goes here is a bit tricky, basically it's everything
+-- that does not (directly or indirectly) need access to ServerEnvironment,
+-- Server or writable access to IGameDef on the engine side.
+-- (The '_s' stands for standalone.)
+
+--
+-- Item definition helpers
+--
+
+function core.inventorycube(img1, img2, img3)
+ img2 = img2 or img1
+ img3 = img3 or img1
+ return "[inventorycube"
+ .. "{" .. img1:gsub("%^", "&")
+ .. "{" .. img2:gsub("%^", "&")
+ .. "{" .. img3:gsub("%^", "&")
+end
+
+function core.dir_to_facedir(dir, is6d)
+ --account for y if requested
+ if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
+
+ --from above
+ if dir.y < 0 then
+ if math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 19
+ else
+ return 13
+ end
+ else
+ if dir.z < 0 then
+ return 10
+ else
+ return 4
+ end
+ end
+
+ --from below
+ else
+ if math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 15
+ else
+ return 17
+ end
+ else
+ if dir.z < 0 then
+ return 6
+ else
+ return 8
+ end
+ end
+ end
+
+ --otherwise, place horizontally
+ elseif math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 1
+ end
+ else
+ if dir.z < 0 then
+ return 2
+ else
+ return 0
+ end
+ end
+end
+
+-- Table of possible dirs
+local facedir_to_dir = {
+ vector.new( 0, 0, 1),
+ vector.new( 1, 0, 0),
+ vector.new( 0, 0, -1),
+ vector.new(-1, 0, 0),
+ vector.new( 0, -1, 0),
+ vector.new( 0, 1, 0),
+}
+-- Mapping from facedir value to index in facedir_to_dir.
+local facedir_to_dir_map = {
+ [0]=1, 2, 3, 4,
+ 5, 2, 6, 4,
+ 6, 2, 5, 4,
+ 1, 5, 3, 6,
+ 1, 6, 3, 5,
+ 1, 4, 3, 2,
+}
+function core.facedir_to_dir(facedir)
+ return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
+end
+
+function core.dir_to_wallmounted(dir)
+ if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
+ if dir.y < 0 then
+ return 1
+ else
+ return 0
+ end
+ elseif math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 2
+ end
+ else
+ if dir.z < 0 then
+ return 5
+ else
+ return 4
+ end
+ end
+end
+
+-- table of dirs in wallmounted order
+local wallmounted_to_dir = {
+ [0] = vector.new( 0, 1, 0),
+ vector.new( 0, -1, 0),
+ vector.new( 1, 0, 0),
+ vector.new(-1, 0, 0),
+ vector.new( 0, 0, 1),
+ vector.new( 0, 0, -1),
+}
+function core.wallmounted_to_dir(wallmounted)
+ return wallmounted_to_dir[wallmounted % 8]
+end
+
+function core.dir_to_yaw(dir)
+ return -math.atan2(dir.x, dir.z)
+end
+
+function core.yaw_to_dir(yaw)
+ return vector.new(-math.sin(yaw), 0, math.cos(yaw))
+end
+
+function core.is_colored_paramtype(ptype)
+ return (ptype == "color") or (ptype == "colorfacedir") or
+ (ptype == "colorwallmounted") or (ptype == "colordegrotate")
+end
+
+function core.strip_param2_color(param2, paramtype2)
+ if not core.is_colored_paramtype(paramtype2) then
+ return nil
+ end
+ if paramtype2 == "colorfacedir" then
+ param2 = math.floor(param2 / 32) * 32
+ elseif paramtype2 == "colorwallmounted" then
+ param2 = math.floor(param2 / 8) * 8
+ elseif paramtype2 == "colordegrotate" then
+ param2 = math.floor(param2 / 32) * 32
+ end
+ -- paramtype2 == "color" requires no modification.
+ return param2
+end
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index e86efc50c..997b1894a 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -121,53 +121,6 @@ function core.get_player_radius_area(player_name, radius)
end
-function core.hash_node_position(pos)
- return (pos.z + 32768) * 65536 * 65536
- + (pos.y + 32768) * 65536
- + pos.x + 32768
-end
-
-
-function core.get_position_from_hash(hash)
- local x = (hash % 65536) - 32768
- hash = math.floor(hash / 65536)
- local y = (hash % 65536) - 32768
- hash = math.floor(hash / 65536)
- local z = (hash % 65536) - 32768
- return vector.new(x, y, z)
-end
-
-
-function core.get_item_group(name, group)
- if not core.registered_items[name] or not
- core.registered_items[name].groups[group] then
- return 0
- end
- return core.registered_items[name].groups[group]
-end
-
-
-function core.get_node_group(name, group)
- core.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
- return core.get_item_group(name, group)
-end
-
-
-function core.setting_get_pos(name)
- local value = core.settings:get(name)
- if not value then
- return nil
- end
- return core.string_to_pos(value)
-end
-
-
--- See l_env.cpp for the other functions
-function core.get_artificial_light(param1)
- return math.floor(param1 / 16)
-end
-
-
-- To be overriden by protection mods
function core.is_protected(pos, name)
@@ -284,40 +237,30 @@ end
core.dynamic_media_callbacks = {}
--- PNG encoder safety wrapper
+-- Transfer of certain globals into async environment
+-- see builtin/async/game.lua for the other side
-local o_encode_png = core.encode_png
-function core.encode_png(width, height, data, compression)
- if type(width) ~= "number" then
- error("Incorrect type for 'width', expected number, got " .. type(width))
- end
- if type(height) ~= "number" then
- error("Incorrect type for 'height', expected number, got " .. type(height))
+local function copy_filtering(t, seen)
+ if type(t) == "userdata" or type(t) == "function" then
+ return true -- don't use nil so presence can still be detected
+ elseif type(t) ~= "table" then
+ return t
end
-
- local expected_byte_count = width * height * 4
-
- if type(data) ~= "table" and type(data) ~= "string" then
- error("Incorrect type for 'data', expected table or string, got " .. type(data))
- end
-
- local data_length = type(data) == "table" and #data * 4 or string.len(data)
-
- if data_length ~= expected_byte_count then
- error(string.format(
- "Incorrect length of 'data', width and height imply %d bytes but %d were provided",
- expected_byte_count,
- data_length
- ))
- end
-
- if type(data) == "table" then
- local dataBuf = {}
- for i = 1, #data do
- dataBuf[i] = core.colorspec_to_bytes(data[i])
- end
- data = table.concat(dataBuf)
+ local n = {}
+ seen = seen or {}
+ seen[t] = n
+ for k, v in pairs(t) do
+ local k_ = seen[k] or copy_filtering(k, seen)
+ local v_ = seen[v] or copy_filtering(v, seen)
+ n[k_] = v_
end
+ return n
+end
- return o_encode_png(width, height, data, compression or 6)
+function core.get_globals_to_transfer()
+ local all = {
+ registered_items = copy_filtering(core.registered_items),
+ registered_aliases = core.registered_aliases,
+ }
+ return all
end
diff --git a/builtin/game/misc_s.lua b/builtin/game/misc_s.lua
new file mode 100644
index 000000000..67a0ec684
--- /dev/null
+++ b/builtin/game/misc_s.lua
@@ -0,0 +1,93 @@
+-- Minetest: builtin/misc_s.lua
+-- The distinction of what goes here is a bit tricky, basically it's everything
+-- that does not (directly or indirectly) need access to ServerEnvironment,
+-- Server or writable access to IGameDef on the engine side.
+-- (The '_s' stands for standalone.)
+
+--
+-- Misc. API functions
+--
+
+function core.hash_node_position(pos)
+ return (pos.z + 32768) * 65536 * 65536
+ + (pos.y + 32768) * 65536
+ + pos.x + 32768
+end
+
+
+function core.get_position_from_hash(hash)
+ local x = (hash % 65536) - 32768
+ hash = math.floor(hash / 65536)
+ local y = (hash % 65536) - 32768
+ hash = math.floor(hash / 65536)
+ local z = (hash % 65536) - 32768
+ return vector.new(x, y, z)
+end
+
+
+function core.get_item_group(name, group)
+ if not core.registered_items[name] or not
+ core.registered_items[name].groups[group] then
+ return 0
+ end
+ return core.registered_items[name].groups[group]
+end
+
+
+function core.get_node_group(name, group)
+ core.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
+ return core.get_item_group(name, group)
+end
+
+
+function core.setting_get_pos(name)
+ local value = core.settings:get(name)
+ if not value then
+ return nil
+ end
+ return core.string_to_pos(value)
+end
+
+
+-- See l_env.cpp for the other functions
+function core.get_artificial_light(param1)
+ return math.floor(param1 / 16)
+end
+
+-- PNG encoder safety wrapper
+
+local o_encode_png = core.encode_png
+function core.encode_png(width, height, data, compression)
+ if type(width) ~= "number" then
+ error("Incorrect type for 'width', expected number, got " .. type(width))
+ end
+ if type(height) ~= "number" then
+ error("Incorrect type for 'height', expected number, got " .. type(height))
+ end
+
+ local expected_byte_count = width * height * 4
+
+ if type(data) ~= "table" and type(data) ~= "string" then
+ error("Incorrect type for 'data', expected table or string, got " .. type(data))
+ end
+
+ local data_length = type(data) == "table" and #data * 4 or string.len(data)
+
+ if data_length ~= expected_byte_count then
+ error(string.format(
+ "Incorrect length of 'data', width and height imply %d bytes but %d were provided",
+ expected_byte_count,
+ data_length
+ ))
+ end
+
+ if type(data) == "table" then
+ local dataBuf = {}
+ for i = 1, #data do
+ dataBuf[i] = core.colorspec_to_bytes(data[i])
+ end
+ data = table.concat(dataBuf)
+ end
+
+ return o_encode_png(width, height, data, compression or 6)
+end
diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index 0be107c36..ee4edabbf 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -1,4 +1,4 @@
--- Minetest: builtin/misc_register.lua
+-- Minetest: builtin/register.lua
local S = core.get_translator("__builtin")
diff --git a/builtin/game/statbars.lua b/builtin/game/statbars.lua
index cb7ff7b76..78d1d2728 100644
--- a/builtin/game/statbars.lua
+++ b/builtin/game/statbars.lua
@@ -138,13 +138,15 @@ local function player_event_handler(player,eventname)
end
function core.hud_replace_builtin(hud_name, definition)
-
if type(definition) ~= "table" or
definition.hud_elem_type ~= "statbar" then
return false
end
+ definition = table.copy(definition)
+
if hud_name == "health" then
+ definition.item = definition.item or definition.number or core.PLAYER_MAX_HP_DEFAULT
bar_definitions.hp = definition
for name, ids in pairs(hud_ids) do
@@ -159,6 +161,7 @@ function core.hud_replace_builtin(hud_name, definition)
end
if hud_name == "breath" then
+ definition.item = definition.item or definition.number or core.PLAYER_MAX_BREATH_DEFAULT
bar_definitions.breath = definition
for name, ids in pairs(hud_ids) do
diff --git a/builtin/game/voxelarea.lua b/builtin/game/voxelarea.lua
index 64436bf1a..62f07d928 100644
--- a/builtin/game/voxelarea.lua
+++ b/builtin/game/voxelarea.lua
@@ -1,6 +1,9 @@
+local math_floor = math.floor
+local vector_new = vector.new
+
VoxelArea = {
- MinEdge = vector.new(1, 1, 1),
- MaxEdge = vector.new(0, 0, 0),
+ MinEdge = vector_new(1, 1, 1),
+ MaxEdge = vector_new(0, 0, 0),
ystride = 0,
zstride = 0,
}
@@ -19,7 +22,7 @@ end
function VoxelArea:getExtent()
local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
- return vector.new(
+ return vector_new(
MaxEdge.x - MinEdge.x + 1,
MaxEdge.y - MinEdge.y + 1,
MaxEdge.z - MinEdge.z + 1
@@ -36,7 +39,7 @@ function VoxelArea:index(x, y, z)
local i = (z - MinEdge.z) * self.zstride +
(y - MinEdge.y) * self.ystride +
(x - MinEdge.x) + 1
- return math.floor(i)
+ return math_floor(i)
end
function VoxelArea:indexp(p)
@@ -44,24 +47,23 @@ function VoxelArea:indexp(p)
local i = (p.z - MinEdge.z) * self.zstride +
(p.y - MinEdge.y) * self.ystride +
(p.x - MinEdge.x) + 1
- return math.floor(i)
+ return math_floor(i)
end
function VoxelArea:position(i)
- local p = {}
local MinEdge = self.MinEdge
i = i - 1
- p.z = math.floor(i / self.zstride) + MinEdge.z
+ local z = math_floor(i / self.zstride) + MinEdge.z
i = i % self.zstride
- p.y = math.floor(i / self.ystride) + MinEdge.y
+ local y = math_floor(i / self.ystride) + MinEdge.y
i = i % self.ystride
- p.x = math.floor(i) + MinEdge.x
+ local x = math_floor(i) + MinEdge.x
- return p
+ return vector_new(x, y, z)
end
function VoxelArea:contains(x, y, z)
diff --git a/builtin/init.lua b/builtin/init.lua
index 7a9b5c427..869136016 100644
--- a/builtin/init.lua
+++ b/builtin/init.lua
@@ -56,8 +56,10 @@ elseif INIT == "mainmenu" then
if not custom_loaded then
dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
end
-elseif INIT == "async" then
- dofile(asyncpath .. "init.lua")
+elseif INIT == "async" then
+ dofile(asyncpath .. "mainmenu.lua")
+elseif INIT == "async_game" then
+ dofile(asyncpath .. "game.lua")
elseif INIT == "client" then
dofile(clientpath .. "init.lua")
else
diff --git a/builtin/locale/__builtin.de.tr b/builtin/locale/__builtin.de.tr
index 1b29f81e7..4a17f7a4b 100644
--- a/builtin/locale/__builtin.de.tr
+++ b/builtin/locale/__builtin.de.tr
@@ -72,6 +72,7 @@ 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. Cannot modify secure settings. Edit the settings file manually.=Fehlgeschlagen. Sicherheitseinstellungen können nicht modifiziert werden. Bearbeiten Sie die Einstellungsdatei manuell.
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>
@@ -151,6 +152,7 @@ Server shutting down (operator request).=Server wird heruntergefahren (Betreiber
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
+You cannot ban players in singleplayer!=Im Einzelspielermodus können Sie keine Spieler verbannen!
Player is not online.=Spieler ist nicht online.
Failed to ban player.=Konnte Spieler nicht verbannen.
Banned @1.=@1 verbannt.
@@ -195,7 +197,6 @@ Available commands:=Verfügbare Befehle:
Command not available: @1=Befehl nicht verfügbar: @1
[all | privs | <cmd>] [-t]=[all | privs | <Befehl>] [-t]
Get help for commands or list privileges (-t: output in chat)=Hilfe für Befehle erhalten oder Privilegien auflisten (-t: Ausgabe im Chat)
-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.
@@ -205,6 +206,7 @@ Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /h
Close=Schließen
Privilege=Privileg
Description=Beschreibung
+Available privileges:=Verfügbare Privilegien:
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.
@@ -232,7 +234,6 @@ 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
-Can view more debug info that might give a gameplay advantage=Kann zusätzliche Debuginformationen betrachten, welche einen spielerischen Vorteil geben könnten
Can enable wireframe=Kann Drahtmodell aktivieren
Unknown Item=Unbekannter Gegenstand
Air=Luft
diff --git a/builtin/locale/__builtin.it.tr b/builtin/locale/__builtin.it.tr
index 77f85c766..b04b48926 100644
--- a/builtin/locale/__builtin.it.tr
+++ b/builtin/locale/__builtin.it.tr
@@ -72,6 +72,7 @@ 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. Cannot modify secure settings. Edit the settings file manually.=
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>
@@ -151,6 +152,7 @@ Server shutting down (operator request).=Arresto del server in corso (per richie
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
+You cannot ban players in singleplayer!=
Player is not online.=Il giocatore non è connesso.
Failed to ban player.=Errore nel bandire il giocatore.
Banned @1.=@1 banditǝ.
@@ -195,7 +197,6 @@ Available commands:=Comandi disponibili:
Command not available: @1=Comando non disponibile: @1
[all | privs | <cmd>] [-t]=
Get help for commands or list privileges (-t: output in chat)=
-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.
@@ -205,6 +206,7 @@ Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /he
Close=Chiudi
Privilege=Privilegio
Description=Descrizione
+Available privileges:=Privilegi disponibili:
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.
@@ -232,7 +234,6 @@ 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
-Can view more debug info that might give a gameplay advantage=
Can enable wireframe=
Unknown Item=Oggetto sconosciuto
Air=Aria
diff --git a/builtin/locale/template.txt b/builtin/locale/template.txt
index 308d17f37..fa7352317 100644
--- a/builtin/locale/template.txt
+++ b/builtin/locale/template.txt
@@ -72,6 +72,7 @@ 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. Cannot modify secure settings. Edit the settings file manually.=
Failed. Use '/set -n <name> <value>' to create a new setting.=
@1 @= @2=
<not set>=
@@ -151,6 +152,7 @@ Server shutting down (operator request).=
Ban the IP of a player or show the ban list=
The ban list is empty.=
Ban list: @1=
+You cannot ban players in singleplayer!=
Player is not online.=
Failed to ban player.=
Banned @1.=
@@ -195,7 +197,6 @@ Available commands:=
Command not available: @1=
[all | privs | <cmd>] [-t]=
Get help for commands or list privileges (-t: output in chat)=
-Available privileges:=
Command=
Parameters=
For more information, click on any entry in the list.=
@@ -205,6 +206,7 @@ Available commands: (see also: /help <cmd>)=
Close=
Privilege=
Description=
+Available privileges:=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data=
Statistics written to action log.=
@@ -232,7 +234,6 @@ Can use fly mode=
Can use fast mode=
Can fly through solid nodes using noclip mode=
Can use the rollback functionality=
-Can view more debug info that might give a gameplay advantage=
Can enable wireframe=
Unknown Item=
Air=
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
index 8db8bb8d1..81e28f2bb 100644
--- a/builtin/mainmenu/common.lua
+++ b/builtin/mainmenu/common.lua
@@ -125,18 +125,12 @@ os.tmpname = function()
end
--------------------------------------------------------------------------------
-function menu_render_worldlist(show_gameid)
+function menu_render_worldlist()
local retval = {}
local current_worldlist = menudata.worldlist:get_list()
- local row
for i, v in ipairs(current_worldlist) do
- row = v.name
- if show_gameid == nil or show_gameid == true then
- row = row .. " [" .. v.gameid .. "]"
- end
- retval[#retval+1] = core.formspec_escape(row)
-
+ retval[#retval+1] = core.formspec_escape(v.name)
end
return table.concat(retval, ",")
@@ -242,3 +236,11 @@ function menu_worldmt_legacy(selected)
end
end
end
+
+function confirmation_formspec(message, confirm_id, confirm_label, cancel_id, cancel_label)
+ return "size[10,2.5,true]" ..
+ "label[0.5,0.5;" .. message .. "]" ..
+ "style[" .. confirm_id .. ";bgcolor=red]" ..
+ "button[0.5,1.5;2.5,0.5;" .. confirm_id .. ";" .. confirm_label .. "]" ..
+ "button[7.0,1.5;2.5,0.5;" .. cancel_id .. ";" .. cancel_label .. "]"
+end
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
index 9bdf92a74..e76e10ef7 100644
--- a/builtin/mainmenu/dlg_config_world.lua
+++ b/builtin/mainmenu/dlg_config_world.lua
@@ -61,12 +61,68 @@ local function init_data(data)
data.list:set_sortmode("alphabetic")
end
+
+-- Returns errors errors and a list of all enabled mods (inc. game and world mods)
+--
+-- `with_errors` is a table from mod virtual path to `{ type = "error" | "warning" }`.
+-- `enabled_mods_by_name` is a table from mod virtual path to `true`.
+--
+-- @param world_path Path to the world
+-- @param all_mods List of mods, with `enabled` property.
+-- @returns with_errors, enabled_mods_by_name
+local function check_mod_configuration(world_path, all_mods)
+ -- Build up lookup tables for enabled mods and all mods by vpath
+ local enabled_mod_paths = {}
+ local all_mods_by_vpath = {}
+ for _, mod in ipairs(all_mods) do
+ if mod.type == "mod" then
+ all_mods_by_vpath[mod.virtual_path] = mod
+ end
+ if mod.enabled then
+ enabled_mod_paths[mod.virtual_path] = mod.path
+ end
+ end
+
+ -- Use the engine's mod configuration code to resolve dependencies and return any errors
+ local config_status = core.check_mod_configuration(world_path, enabled_mod_paths)
+
+ -- Build the list of enabled mod virtual paths
+ local enabled_mods_by_name = {}
+ for _, mod in ipairs(config_status.satisfied_mods) do
+ assert(mod.virtual_path ~= "")
+ enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
+ end
+ for _, mod in ipairs(config_status.unsatisfied_mods) do
+ assert(mod.virtual_path ~= "")
+ enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
+ end
+
+ -- Build the table of errors
+ local with_error = {}
+ for _, mod in ipairs(config_status.unsatisfied_mods) do
+ local error = { type = "warning" }
+ with_error[mod.virtual_path] = error
+
+ for _, depname in ipairs(mod.unsatisfied_depends) do
+ if not enabled_mods_by_name[depname] then
+ error.type = "error"
+ break
+ end
+ end
+ end
+
+ return with_error, enabled_mods_by_name
+end
+
local function get_formspec(data)
if not data.list then
init_data(data)
end
- local mod = data.list:get_list()[data.selected_mod] or {name = ""}
+ local all_mods = data.list:get_list()
+ local with_error, enabled_mods_by_name = check_mod_configuration(data.worldspec.path, all_mods)
+
+ local mod = all_mods[data.selected_mod] or {name = ""}
local retval =
"size[11.5,7.5,true]" ..
@@ -87,6 +143,29 @@ local function get_formspec(data)
"textarea[0.25,0.7;5.75,7.2;;" .. info .. ";]"
else
local hard_deps, soft_deps = pkgmgr.get_dependencies(mod.path)
+
+ -- Add error messages to dep lists
+ if mod.enabled or mod.is_game_content then
+ for i, dep_name in ipairs(hard_deps) do
+ local dep = enabled_mods_by_name[dep_name]
+ if not dep then
+ hard_deps[i] = mt_color_red .. dep_name .. " " .. fgettext("(Unsatisfied)")
+ elseif with_error[dep.virtual_path] then
+ hard_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
+ else
+ hard_deps[i] = mt_color_green .. dep_name
+ end
+ end
+ for i, dep_name in ipairs(soft_deps) do
+ local dep = enabled_mods_by_name[dep_name]
+ if dep and with_error[dep.virtual_path] then
+ soft_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
+ elseif dep then
+ soft_deps[i] = mt_color_green .. dep_name
+ end
+ end
+ end
+
local hard_deps_str = table.concat(hard_deps, ",")
local soft_deps_str = table.concat(soft_deps, ",")
@@ -138,7 +217,6 @@ local function get_formspec(data)
if mod.name ~= "" and not mod.is_game_content then
if mod.is_modpack then
-
if pkgmgr.is_modpack_entirely_enabled(data, mod.name) then
retval = retval ..
"button[5.5,0.125;3,0.5;btn_mp_disable;" ..
@@ -163,10 +241,16 @@ local function get_formspec(data)
"button[8.95,0.125;2.5,0.5;btn_enable_all_mods;" ..
fgettext("Enable all") .. "]"
end
+
+ local use_technical_names = core.settings:get_bool("show_technical_names")
+
return retval ..
- "tablecolumns[color;tree;text]" ..
+ "tablecolumns[color;tree;image,align=inline,width=1.5,0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") ..
+ ",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16_white.png") ..
+ ",2=" .. core.formspec_escape(defaulttexturedir .. "error_icon_orange.png") ..
+ ",3=" .. core.formspec_escape(defaulttexturedir .. "error_icon_red.png") .. ";text]" ..
"table[5.5,0.75;5.75,6;world_config_modlist;" ..
- pkgmgr.render_packagelist(data.list) .. ";" .. data.selected_mod .."]"
+ pkgmgr.render_packagelist(data.list, use_technical_names, with_error) .. ";" .. data.selected_mod .."]"
end
local function handle_buttons(this, fields)
@@ -205,14 +289,19 @@ local function handle_buttons(this, fields)
local mods = worldfile:to_table()
local rawlist = this.data.list:get_raw_list()
+ local was_set = {}
for i = 1, #rawlist do
local mod = rawlist[i]
if not mod.is_modpack and
not mod.is_game_content then
if modname_valid(mod.name) then
- worldfile:set("load_mod_" .. mod.name,
- mod.enabled and "true" or "false")
+ if mod.enabled then
+ worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
+ was_set[mod.name] = true
+ elseif not was_set[mod.name] then
+ worldfile:set("load_mod_" .. mod.name, "false")
+ end
elseif mod.enabled then
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
"d \"$1\" as it contains disallowed characters. " ..
@@ -256,12 +345,26 @@ local function handle_buttons(this, fields)
if fields.btn_enable_all_mods then
local list = this.data.list:get_raw_list()
+ -- When multiple copies of a mod are installed, we need to avoid enabling multiple of them
+ -- at a time. So lets first collect all the enabled mods, and then use this to exclude
+ -- multiple enables.
+
+ local was_enabled = {}
for i = 1, #list do
if not list[i].is_game_content
- and not list[i].is_modpack then
+ and not list[i].is_modpack and list[i].enabled then
+ was_enabled[list[i].name] = true
+ end
+ end
+
+ for i = 1, #list do
+ if not list[i].is_game_content and not list[i].is_modpack and
+ not was_enabled[list[i].name] then
list[i].enabled = true
+ was_enabled[list[i].name] = true
end
end
+
enabled_all = true
return true
end
diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
index 276a7b096..2152b8a39 100644
--- a/builtin/mainmenu/dlg_contentstore.lua
+++ b/builtin/mainmenu/dlg_contentstore.lua
@@ -151,11 +151,9 @@ local function start_install(package, reason)
if conf_path then
local conf = Settings(conf_path)
- if name_is_title then
- conf:set("name", package.title)
- else
- conf:set("title", package.title)
- conf:set("name", package.name)
+ conf:set("title", package.title)
+ if not name_is_title then
+ conf:set("name", package.name)
end
if not conf:get("description") then
conf:set("description", package.short_description)
@@ -193,7 +191,7 @@ end
local function queue_download(package, reason)
local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
- if number_downloading < max_concurrent_downloads then
+ if number_downloading < math.max(max_concurrent_downloads, 1) then
start_install(package, reason)
else
table.insert(download_queue, { package = package, reason = reason })
@@ -360,7 +358,7 @@ function install_dialog.get_formspec()
selected_game_idx = i
end
- games[i] = core.formspec_escape(games[i].name)
+ games[i] = core.formspec_escape(games[i].title)
end
local selected_game = pkgmgr.games[selected_game_idx]
@@ -410,7 +408,7 @@ function install_dialog.get_formspec()
"container[0.375,0.70]",
"label[0,0.25;", fgettext("Base Game:"), "]",
- "dropdown[2,0;4.25,0.5;gameid;", table.concat(games, ","), ";", selected_game_idx, "]",
+ "dropdown[2,0;4.25,0.5;selected_game;", table.concat(games, ","), ";", selected_game_idx, "]",
"label[0,0.8;", fgettext("Dependencies:"), "]",
@@ -461,9 +459,9 @@ function install_dialog.handle_submit(this, fields)
return true
end
- if fields.gameid then
+ if fields.selected_game then
for _, game in pairs(pkgmgr.games) do
- if game.name == fields.gameid then
+ if game.title == fields.selected_game then
core.settings:set("menu_last_game", game.id)
break
end
@@ -490,12 +488,10 @@ local confirm_overwrite = {}
function confirm_overwrite.get_formspec()
local package = confirm_overwrite.package
- return "size[11.5,4.5,true]" ..
- "label[2,2;" ..
- fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name) .. "]"..
- "style[install;bgcolor=red]" ..
- "button[3.25,3.5;2.5,0.5;install;" .. fgettext("Overwrite") .. "]" ..
- "button[5.75,3.5;2.5,0.5;cancel;" .. fgettext("Cancel") .. "]"
+ return confirmation_formspec(
+ fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name),
+ 'install', fgettext("Overwrite"),
+ 'cancel', fgettext("Cancel"))
end
function confirm_overwrite.handle_submit(this, fields)
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 8d1509f33..806e019a9 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -15,9 +15,6 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--- cf. tab_local, the gamebar already provides game selection so we hide the list from here
-local hide_gamelist = PLATFORM ~= "Android"
-
local function table_to_flags(ftable)
-- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
local str = {}
@@ -94,14 +91,14 @@ local mgv6_biomes = {
local function create_world_formspec(dialogdata)
- -- Error out when no games found
+ -- Point the player to ContentDB when no games are found
if #pkgmgr.games == 0 then
- return "size[12.25,3,true]" ..
- "box[0,0;12,2;" .. mt_color_orange .. "]" ..
- "textarea[0.3,0;11.7,2;;;"..
- fgettext("You have no games installed.") .. "\n" ..
- fgettext("Download one from minetest.net") .. "]" ..
- "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+ return "size[8,2.5,true]" ..
+ "style[label_button;border=false]" ..
+ "button[0.5,0.5;7,0.5;label_button;" ..
+ fgettext("You have no games installed.") .. "]" ..
+ "button[0.5,1.5;2.5,0.5;world_create_open_cdb;" .. fgettext("Install a game") .. "]" ..
+ "button[5.0,1.5;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
end
local current_mg = dialogdata.mg
@@ -111,14 +108,11 @@ local function create_world_formspec(dialogdata)
local flags = dialogdata.flags
- local game, gameidx = pkgmgr.find_by_gameid(gameid)
- if game == nil and hide_gamelist then
+ local game = pkgmgr.find_by_gameid(gameid)
+ if game == nil then
-- should never happen but just pick the first game
game = pkgmgr.get_game(1)
- gameidx = 1
core.settings:set("menu_last_game", game.id)
- elseif game == nil then
- gameidx = 0
end
local disallowed_mapgen_settings = {}
@@ -296,17 +290,6 @@ local function create_world_formspec(dialogdata)
label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
end
- -- Warning if only devtest is installed
- local devtest_only = ""
- local gamelist_height = 2.3
- if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
- devtest_only = "box[0,0;5.8,1.7;#ff8800]" ..
- "textarea[0.3,0;6,1.8;;;"..
- fgettext("Warning: The Development Test is meant for developers.") .. "\n" ..
- fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
- gamelist_height = 0.5
- end
-
local retval =
"size[12.25,7,true]" ..
@@ -315,22 +298,28 @@ local function create_world_formspec(dialogdata)
"field[0.3,0.6;6,0.5;te_world_name;" ..
fgettext("World name") ..
";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
- "set_focus[te_world_name;false]" ..
+ "set_focus[te_world_name;false]"
- "field[0.3,1.7;6,0.5;te_seed;" ..
- fgettext("Seed") ..
- ";".. core.formspec_escape(dialogdata.seed) .. "]" ..
+ if not disallowed_mapgen_settings["seed"] then
+ retval = retval .. "field[0.3,1.7;6,0.5;te_seed;" ..
+ fgettext("Seed") ..
+ ";".. core.formspec_escape(dialogdata.seed) .. "]"
+
+ end
+
+ retval = retval ..
"label[0,2;" .. fgettext("Mapgen") .. "]"..
"dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
- if not hide_gamelist or devtest_only ~= "" then
+ -- Warning if only devtest is installed
+ if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
retval = retval ..
- "label[0,3.35;" .. fgettext("Game") .. "]"..
- "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
- pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
- "container[0,4.5]" ..
- devtest_only ..
+ "container[0,3.5]" ..
+ "box[0,0;5.8,1.7;#ff8800]" ..
+ "textarea[0.4,0.1;6,1.8;;;"..
+ fgettext("Development Test is meant for developers.") .. "]" ..
+ "button[1,1;4,0.5;world_create_open_cdb;" .. fgettext("Install another game") .. "]" ..
"container_end[]"
end
@@ -353,17 +342,20 @@ end
local function create_world_buttonhandler(this, fields)
+ if fields["world_create_open_cdb"] then
+ local dlg = create_store_dlg("game")
+ dlg:set_parent(this.parent)
+ this:delete()
+ this.parent:hide()
+ dlg:show()
+ return true
+ end
+
if fields["world_create_confirm"] or
fields["key_enter"] then
local worldname = fields["te_world_name"]
- local game, gameindex
- if hide_gamelist then
- game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
- else
- gameindex = core.get_textlist_index("games")
- game = pkgmgr.get_game(gameindex)
- end
+ local game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
local message
if game == nil then
@@ -391,7 +383,7 @@ local function create_world_buttonhandler(this, fields)
end
if message == nil then
- this.data.seed = fields["te_seed"]
+ this.data.seed = fields["te_seed"] or ""
this.data.mg = fields["dd_mapgen"]
-- actual names as used by engine
@@ -412,9 +404,7 @@ local function create_world_buttonhandler(this, fields)
if message == nil then
core.settings:set("menu_last_game", game.id)
- if this.data.update_worldlist_filter then
- menudata.worldlist:set_filtercriteria(game.id)
- end
+ menudata.worldlist:set_filtercriteria(game.id)
menudata.worldlist:refresh()
core.settings:set("mainmenu_last_selected_world",
menudata.worldlist:raw_index_by_uid(worldname))
@@ -426,7 +416,7 @@ local function create_world_buttonhandler(this, fields)
end
this.data.worldname = fields["te_world_name"]
- this.data.seed = fields["te_seed"]
+ this.data.seed = fields["te_seed"] or ""
if fields["games"] then
local gameindex = core.get_textlist_index("games")
@@ -472,13 +462,12 @@ local function create_world_buttonhandler(this, fields)
end
-function create_create_world_dlg(update_worldlistfilter)
+function create_create_world_dlg()
local retval = dialog_create("sp_create_world",
create_world_formspec,
create_world_buttonhandler,
nil)
retval.data = {
- update_worldlist_filter = update_worldlistfilter,
worldname = "",
-- settings the world is created with:
seed = core.settings:get("fixed_map_seed") or "",
diff --git a/builtin/mainmenu/dlg_delete_content.lua b/builtin/mainmenu/dlg_delete_content.lua
index a24171541..4463825f7 100644
--- a/builtin/mainmenu/dlg_delete_content.lua
+++ b/builtin/mainmenu/dlg_delete_content.lua
@@ -18,15 +18,10 @@
--------------------------------------------------------------------------------
local function delete_content_formspec(dialogdata)
- local retval =
- "size[11.5,4.5,true]" ..
- "label[2,2;" ..
- fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name) .. "]"..
- "style[dlg_delete_content_confirm;bgcolor=red]" ..
- "button[3.25,3.5;2.5,0.5;dlg_delete_content_confirm;" .. fgettext("Delete") .. "]" ..
- "button[5.75,3.5;2.5,0.5;dlg_delete_content_cancel;" .. fgettext("Cancel") .. "]"
-
- return retval
+ return confirmation_formspec(
+ fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name),
+ 'dlg_delete_content_confirm', fgettext("Delete"),
+ 'dlg_delete_content_cancel', fgettext("Cancel"))
end
--------------------------------------------------------------------------------
diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua
index 33e7bc945..67c0612bd 100644
--- a/builtin/mainmenu/dlg_delete_world.lua
+++ b/builtin/mainmenu/dlg_delete_world.lua
@@ -17,14 +17,10 @@
local function delete_world_formspec(dialogdata)
- local retval =
- "size[10,2.5,true]" ..
- "label[0.5,0.5;" ..
- fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
- "style[world_delete_confirm;bgcolor=red]" ..
- "button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
- "button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
- return retval
+ return confirmation_formspec(
+ fgettext("Delete World \"$1\"?", dialogdata.delete_name),
+ 'world_delete_confirm', fgettext("Delete"),
+ 'world_delete_cancel', fgettext("Cancel"))
end
local function delete_world_buttonhandler(this, fields)
diff --git a/builtin/mainmenu/dlg_register.lua b/builtin/mainmenu/dlg_register.lua
new file mode 100644
index 000000000..a7658249c
--- /dev/null
+++ b/builtin/mainmenu/dlg_register.lua
@@ -0,0 +1,123 @@
+--Minetest
+--Copyright (C) 2022 rubenwardy
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--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.
+
+--------------------------------------------------------------------------------
+
+local function register_formspec(dialogdata)
+ local title = fgettext("Joining $1", dialogdata.server and dialogdata.server.name or dialogdata.address)
+ local buttons_y = 4 + 1.3
+ if dialogdata.error then
+ buttons_y = buttons_y + 0.8
+ end
+
+ local retval = {
+ "formspec_version[4]",
+ "size[8,", tostring(buttons_y + 1.175), "]",
+ "set_focus[", (dialogdata.name ~= "" and "password" or "name"), "]",
+ "label[0.375,0.8;", title, "]",
+ "field[0.375,1.575;7.25,0.8;name;", core.formspec_escape(fgettext("Name")), ";",
+ core.formspec_escape(dialogdata.name), "]",
+ "pwdfield[0.375,2.875;7.25,0.8;password;", core.formspec_escape(fgettext("Password")), "]",
+ "pwdfield[0.375,4.175;7.25,0.8;password_2;", core.formspec_escape(fgettext("Confirm Password")), "]"
+ }
+
+ if dialogdata.error then
+ table.insert_all(retval, {
+ "box[0.375,", tostring(buttons_y - 0.9), ";7.25,0.6;darkred]",
+ "label[0.625,", tostring(buttons_y - 0.6), ";", core.formspec_escape(dialogdata.error), "]",
+ })
+ end
+
+ table.insert_all(retval, {
+ "container[0.375,", tostring(buttons_y), "]",
+ "button[0,0;2.5,0.8;dlg_register_confirm;", fgettext("Register"), "]",
+ "button[4.75,0;2.5,0.8;dlg_register_cancel;", fgettext("Cancel"), "]",
+ "container_end[]",
+ })
+
+ return table.concat(retval, "")
+end
+
+--------------------------------------------------------------------------------
+local function register_buttonhandler(this, fields)
+ this.data.name = fields.name
+ this.data.error = nil
+
+ if fields.dlg_register_confirm or fields.key_enter then
+ if fields.name == "" then
+ this.data.error = fgettext("Missing name")
+ return true
+ end
+ if fields.password ~= fields.password_2 then
+ this.data.error = fgettext("Passwords do not match")
+ return true
+ end
+
+ gamedata.playername = fields.name
+ gamedata.password = fields.password
+ gamedata.address = this.data.address
+ gamedata.port = this.data.port
+ gamedata.allow_login_or_register = "register"
+ gamedata.selected_world = 0
+
+ assert(gamedata.address and gamedata.port)
+
+ local server = this.data.server
+ if server then
+ serverlistmgr.add_favorite(server)
+ gamedata.servername = server.name
+ gamedata.serverdescription = server.description
+ else
+ gamedata.servername = ""
+ gamedata.serverdescription = ""
+
+ serverlistmgr.add_favorite({
+ address = gamedata.address,
+ port = gamedata.port,
+ })
+ end
+
+ core.settings:set("name", fields.name)
+ core.settings:set("address", gamedata.address)
+ core.settings:set("remote_port", gamedata.port)
+
+ core.start()
+ end
+
+ if fields["dlg_register_cancel"] then
+ this:delete()
+ return true
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function create_register_dialog(address, port, server)
+ assert(address)
+ assert(type(port) == "number")
+
+ local retval = dialog_create("dlg_register",
+ register_formspec,
+ register_buttonhandler,
+ nil)
+ retval.data.address = address
+ retval.data.port = port
+ retval.data.server = server
+ retval.data.name = core.settings:get("name") or ""
+ return retval
+end
diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua
index 06fd32d84..69562e6a5 100644
--- a/builtin/mainmenu/dlg_settings_advanced.lua
+++ b/builtin/mainmenu/dlg_settings_advanced.lua
@@ -351,9 +351,9 @@ local function parse_config_file(read_all, parse_mods)
local file = io.open(path, "r")
if file then
if not games_category_initialized then
- fgettext_ne("Games") -- not used, but needed for xgettext
+ fgettext_ne("Content: Games") -- not used, but needed for xgettext
table.insert(settings, {
- name = "Games",
+ name = "Content: Games",
level = 0,
type = "category",
})
@@ -378,15 +378,15 @@ local function parse_config_file(read_all, parse_mods)
-- Parse mods
local mods_category_initialized = false
local mods = {}
- get_mods(core.get_modpath(), mods)
+ get_mods(core.get_modpath(), "mods", mods)
for _, mod in ipairs(mods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not mods_category_initialized then
- fgettext_ne("Mods") -- not used, but needed for xgettext
+ fgettext_ne("Content: Mods") -- not used, but needed for xgettext
table.insert(settings, {
- name = "Mods",
+ name = "Content: Mods",
level = 0,
type = "category",
})
@@ -395,6 +395,37 @@ local function parse_config_file(read_all, parse_mods)
table.insert(settings, {
name = mod.name,
+ readable_name = mod.title,
+ level = 1,
+ type = "category",
+ })
+
+ parse_single_file(file, path, read_all, settings, 2, false)
+
+ file:close()
+ end
+ end
+
+ -- Parse client mods
+ local clientmods_category_initialized = false
+ local clientmods = {}
+ get_mods(core.get_clientmodpath(), "clientmods", clientmods)
+ for _, mod in ipairs(clientmods) do
+ local path = mod.path .. DIR_DELIM .. FILENAME
+ local file = io.open(path, "r")
+ if file then
+ if not clientmods_category_initialized then
+ fgettext_ne("Client Mods") -- not used, but needed for xgettext
+ table.insert(settings, {
+ name = "Client Mods",
+ level = 0,
+ type = "category",
+ })
+ clientmods_category_initialized = true
+ end
+
+ table.insert(settings, {
+ name = mod.name,
level = 1,
type = "category",
})
@@ -497,44 +528,40 @@ end
local function get_current_np_group(setting)
local value = core.settings:get_np_group(setting.name)
- local t = {}
if value == nil then
- t = setting.values
- else
- table.insert(t, value.offset)
- table.insert(t, value.scale)
- table.insert(t, value.spread.x)
- table.insert(t, value.spread.y)
- table.insert(t, value.spread.z)
- table.insert(t, value.seed)
- table.insert(t, value.octaves)
- table.insert(t, value.persistence)
- table.insert(t, value.lacunarity)
- table.insert(t, value.flags)
+ return setting.values
end
- return t
+ local p = "%g"
+ return {
+ p:format(value.offset),
+ p:format(value.scale),
+ p:format(value.spread.x),
+ p:format(value.spread.y),
+ p:format(value.spread.z),
+ p:format(value.seed),
+ p:format(value.octaves),
+ p:format(value.persistence),
+ p:format(value.lacunarity),
+ value.flags
+ }
end
local function get_current_np_group_as_string(setting)
local value = core.settings:get_np_group(setting.name)
- local t
if value == nil then
- t = setting.default
- else
- t = value.offset .. ", " ..
- value.scale .. ", (" ..
- value.spread.x .. ", " ..
- value.spread.y .. ", " ..
- value.spread.z .. "), " ..
- value.seed .. ", " ..
- value.octaves .. ", " ..
- value.persistence .. ", " ..
- value.lacunarity
- if value.flags ~= "" then
- t = t .. ", " .. value.flags
- end
+ return setting.default
end
- return t
+ return ("%g, %g, (%g, %g, %g), %g, %g, %g, %g"):format(
+ value.offset,
+ value.scale,
+ value.spread.x,
+ value.spread.y,
+ value.spread.z,
+ value.seed,
+ value.octaves,
+ value.persistence,
+ value.lacunarity
+ ) .. (value.flags ~= "" and (", " .. value.flags) or "")
end
local checkboxes = {} -- handle checkboxes events
@@ -667,7 +694,7 @@ local function create_change_setting_formspec(dialogdata)
elseif setting.type == "v3f" then
local val = get_current_value(setting)
local v3f = {}
- for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
+ for line in val:gmatch("[+-]?[%d.+-eE]+") do -- All numeric characters
table.insert(v3f, line)
end
@@ -960,7 +987,7 @@ local function create_settings_formspec(tabview, _, tabdata)
local current_level = 0
for _, entry in ipairs(settings) do
local name
- if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
+ if not core.settings:get_bool("show_technical_names") and entry.readable_name then
name = fgettext_ne(entry.readable_name)
else
name = entry.name
@@ -1001,7 +1028,7 @@ local function create_settings_formspec(tabview, _, tabdata)
"button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
"button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
"checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
- .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
+ .. dump(core.settings:get_bool("show_technical_names")) .. "]"
return formspec
end
@@ -1084,7 +1111,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
if fields["cb_tech_settings"] then
- core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
+ core.settings:set("show_technical_names", fields["cb_tech_settings"])
core.settings:write()
core.update_formspec(this:get_formspec())
return true
diff --git a/builtin/mainmenu/dlg_version_info.lua b/builtin/mainmenu/dlg_version_info.lua
new file mode 100644
index 000000000..568fca3f4
--- /dev/null
+++ b/builtin/mainmenu/dlg_version_info.lua
@@ -0,0 +1,172 @@
+--[[
+Minetest
+Copyright (C) 2018-2020 SmallJoker, 2022 rubenwardy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+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.
+]]
+
+if not core.get_http_api then
+ function check_new_version()
+ end
+ return
+end
+
+local function version_info_formspec(data)
+ local cur_ver = core.get_version()
+ local title = fgettext("A new $1 version is available", cur_ver.project)
+ local message =
+ fgettext("Installed version: $1\nNew version: $2\n" ..
+ "Visit $3 to find out how to get the newest version and stay up to date" ..
+ " with features and bugfixes.",
+ cur_ver.string, data.new_version or "", data.url or "")
+
+ local fs = {
+ "formspec_version[3]",
+ "size[12.8,7]",
+ "style_type[label;textcolor=#0E0]",
+ "label[0.5,0.8;", core.formspec_escape(title), "]",
+ "textarea[0.4,1.6;12,3.4;;;",
+ core.formspec_escape(message), "]",
+ "container[0.4,5.8]",
+ "button[0.0,0;4.0,0.8;version_check_visit;", fgettext("Visit website"), "]",
+ "button[4.5,0;3.5,0.8;version_check_remind;", fgettext("Later"), "]",
+ "button[8.5.5,0;3.5,0.8;version_check_never;", fgettext("Never"), "]",
+ "container_end[]",
+ }
+
+ return table.concat(fs, "")
+end
+
+local function version_info_buttonhandler(this, fields)
+ if fields.version_check_remind then
+ -- Erase last known, user will be reminded again at next check
+ core.settings:set("update_last_known", "")
+ this:delete()
+ return true
+ end
+ if fields.version_check_never then
+ core.settings:set("update_last_checked", "disabled")
+ this:delete()
+ return true
+ end
+ if fields.version_check_visit then
+ if type(this.data.url) == "string" then
+ core.open_url(this.data.url)
+ end
+ this:delete()
+ return true
+ end
+
+ return false
+end
+
+local function create_version_info_dlg(new_version, url)
+ assert(type(new_version) == "string")
+ assert(type(url) == "string")
+
+ local retval = dialog_create("version_info",
+ version_info_formspec,
+ version_info_buttonhandler,
+ nil)
+
+ retval.data.new_version = new_version
+ retval.data.url = url
+
+ return retval
+end
+
+local function get_current_version_code()
+ -- Format: Major.Minor.Patch
+ -- Convert to MMMNNNPPP
+ local cur_string = core.get_version().string
+ local cur_major, cur_minor, cur_patch = cur_string:match("^(%d+).(%d+).(%d+)")
+
+ if not cur_patch then
+ core.log("error", "Failed to parse version numbers (invalid tag format?)")
+ return
+ end
+
+ return (cur_major * 1000 + cur_minor) * 1000 + cur_patch
+end
+
+local function on_version_info_received(json)
+ local maintab = ui.find_by_name("maintab")
+ if maintab.hidden then
+ -- Another dialog is open, abort.
+ return
+ end
+
+ local known_update = tonumber(core.settings:get("update_last_known")) or 0
+
+ -- Format: MMNNPPP (Major, Minor, Patch)
+ local new_number = type(json.latest) == "table" and json.latest.version_code
+ if type(new_number) ~= "number" then
+ core.log("error", "Failed to read version number (invalid response?)")
+ return
+ end
+
+ local cur_number = get_current_version_code()
+ if new_number <= known_update or new_number < cur_number then
+ return
+ end
+
+ -- Also consider updating from 1.2.3-dev to 1.2.3
+ if new_number == cur_number and not core.get_version().is_dev then
+ return
+ end
+
+ core.settings:set("update_last_known", tostring(new_number))
+
+ -- Show version info dialog (once)
+ maintab:hide()
+
+ local version_info_dlg = create_version_info_dlg(json.latest.version, json.latest.url)
+ version_info_dlg:set_parent(maintab)
+ version_info_dlg:show()
+
+ ui.update()
+end
+
+function check_new_version()
+ local url = core.settings:get("update_information_url")
+ if core.settings:get("update_last_checked") == "disabled" or
+ url == "" then
+ -- Never show any updates
+ return
+ end
+
+ local time_now = os.time()
+ local time_checked = tonumber(core.settings:get("update_last_checked")) or 0
+ if time_now - time_checked < 2 * 24 * 3600 then
+ -- Check interval of 2 entire days
+ return
+ end
+
+ core.settings:set("update_last_checked", tostring(time_now))
+
+ core.handle_async(function(params)
+ local http = core.get_http_api()
+ return http.fetch_sync(params)
+ end, { url = url }, function(result)
+ local json = result.succeeded and core.parse_json(result.data)
+ if type(json) ~= "table" or not json.latest then
+ core.log("error", "Failed to read JSON output from " .. url ..
+ ", status code = " .. result.code)
+ return
+ end
+
+ on_version_info_received(json)
+ end)
+end
diff --git a/builtin/mainmenu/generate_from_settingtypes.lua b/builtin/mainmenu/generate_from_settingtypes.lua
index 43fc57bb9..0f551fbb1 100644
--- a/builtin/mainmenu/generate_from_settingtypes.lua
+++ b/builtin/mainmenu/generate_from_settingtypes.lua
@@ -31,7 +31,7 @@ local group_format_template = [[
# octaves = %s,
# persistence = %s,
# lacunarity = %s,
-# flags = %s
+# flags =%s
# }
]]
@@ -55,7 +55,11 @@ local function create_minetest_conf_example()
end
if entry.comment ~= "" then
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
- insert(result, "# " .. comment_line .. "\n")
+ if comment_line == "" then
+ insert(result, "#\n")
+ else
+ insert(result, "# " .. comment_line .. "\n")
+ end
end
end
insert(result, "# type: " .. entry.type)
@@ -73,10 +77,14 @@ local function create_minetest_conf_example()
end
insert(result, "\n")
if group_format == true then
+ local flags = entry.values[10]
+ if flags ~= "" then
+ flags = " "..flags
+ end
insert(result, sprintf(group_format_template, entry.name, entry.values[1],
entry.values[2], entry.values[3], entry.values[4], entry.values[5],
entry.values[6], entry.values[7], entry.values[8], entry.values[9],
- entry.values[10]))
+ flags))
else
local append
if entry.default ~= "" then
@@ -91,7 +99,7 @@ end
local translation_file_header = [[
// This file is automatically generated
-// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files
+// It contains a bunch of fake gettext calls, to tell xgettext about the strings in config files
// To update it, refer to the bottom of builtin/mainmenu/dlg_settings_advanced.lua
fake_function() {]]
@@ -126,4 +134,3 @@ file = assert(io.open("src/settings_translation_file.cpp", "w"))
--file = assert(io.open("settings_translation_file.cpp", "w"))
file:write(create_translation_file())
file:close()
-
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index 8e716c2eb..c3a28a570 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -17,9 +17,11 @@
mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF"
+mt_color_lightblue = "#99CCFF"
mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
+mt_color_red = "#FF3300"
local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path()
@@ -43,7 +45,9 @@ dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
local tabs = {}
@@ -91,6 +95,7 @@ local function init_globals()
-- Create main tabview
local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0})
+ -- note: size would be 15.5,7.1 in real coordinates mode
tv_main:set_autosave_tab(true)
tv_main:add(tabs.local_game)
@@ -118,8 +123,8 @@ local function init_globals()
end
ui.set_default("maintab")
+ check_new_version()
tv_main:show()
-
ui.update()
end
diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
index 23f24d617..32a65fd08 100644
--- a/builtin/mainmenu/pkgmgr.lua
+++ b/builtin/mainmenu/pkgmgr.lua
@@ -78,34 +78,35 @@ local function load_texture_packs(txtpath, retval)
for _, item in ipairs(list) do
if item ~= "base" then
- local name = item
-
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
- if path == current_texture_path then
- name = fgettext("$1 (Enabled)", name)
- end
-
local conf = Settings(path .. "texture_pack.conf")
+ local enabled = path == current_texture_path
+ local title = conf:get("title") or item
+
+ -- list_* is only used if non-nil, else the regular versions are used.
retval[#retval + 1] = {
name = item,
+ title = title,
+ list_name = enabled and fgettext("$1 (Enabled)", item) or nil,
+ list_title = enabled and fgettext("$1 (Enabled)", title) or nil,
author = conf:get("author"),
release = tonumber(conf:get("release")) or 0,
- list_name = name,
type = "txp",
path = path,
- enabled = path == current_texture_path,
+ enabled = enabled,
}
end
end
end
-function get_mods(path,retval,modpack)
+function get_mods(path, virtual_path, retval, modpack)
local mods = core.get_dir_list(path, true)
for _, name in ipairs(mods) do
if name:sub(1, 1) ~= "." then
- local prefix = path .. DIR_DELIM .. name
+ local mod_path = path .. DIR_DELIM .. name
+ local mod_virtual_path = virtual_path .. "/" .. name
local toadd = {
dir_name = name,
parent_dir = path,
@@ -114,18 +115,18 @@ function get_mods(path,retval,modpack)
-- Get config file
local mod_conf
- local modpack_conf = io.open(prefix .. DIR_DELIM .. "modpack.conf")
+ local modpack_conf = io.open(mod_path .. DIR_DELIM .. "modpack.conf")
if modpack_conf then
toadd.is_modpack = true
modpack_conf:close()
- mod_conf = Settings(prefix .. DIR_DELIM .. "modpack.conf"):to_table()
+ mod_conf = Settings(mod_path .. DIR_DELIM .. "modpack.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
toadd.is_name_explicit = true
end
else
- mod_conf = Settings(prefix .. DIR_DELIM .. "mod.conf"):to_table()
+ mod_conf = Settings(mod_path .. DIR_DELIM .. "mod.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
toadd.is_name_explicit = true
@@ -134,14 +135,16 @@ function get_mods(path,retval,modpack)
-- Read from config
toadd.name = name
+ toadd.title = mod_conf.title
toadd.author = mod_conf.author
toadd.release = tonumber(mod_conf.release) or 0
- toadd.path = prefix
+ toadd.path = mod_path
+ toadd.virtual_path = mod_virtual_path
toadd.type = "mod"
-- Check modpack.txt
-- Note: modpack.conf is already checked above
- local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt")
+ local modpackfile = io.open(mod_path .. DIR_DELIM .. "modpack.txt")
if modpackfile then
modpackfile:close()
toadd.is_modpack = true
@@ -153,7 +156,7 @@ function get_mods(path,retval,modpack)
elseif toadd.is_modpack then
toadd.type = "modpack"
toadd.is_modpack = true
- get_mods(prefix, retval, name)
+ get_mods(mod_path, mod_virtual_path, retval, name)
end
end
end
@@ -334,7 +337,7 @@ function pkgmgr.identify_modname(modpath,filename)
return nil
end
--------------------------------------------------------------------------------
-function pkgmgr.render_packagelist(render_list)
+function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
@@ -346,31 +349,75 @@ function pkgmgr.render_packagelist(render_list)
local retval = {}
for i, v in ipairs(list) do
local color = ""
+ local icon = 0
+ local error = with_error and with_error[v.virtual_path]
+ local function update_error(val)
+ if val and (not error or (error.type == "warning" and val.type == "error")) then
+ error = val
+ end
+ end
+
if v.is_modpack then
local rawlist = render_list:get_raw_list()
color = mt_color_dark_green
- for j = 1, #rawlist, 1 do
- if rawlist[j].modpack == list[i].name and
- not rawlist[j].enabled then
- -- Modpack not entirely enabled so showing as grey
- color = mt_color_grey
- break
+ for j = 1, #rawlist do
+ if rawlist[j].modpack == list[i].name then
+ if with_error then
+ update_error(with_error[rawlist[j].virtual_path])
+ end
+
+ if rawlist[j].enabled then
+ icon = 1
+ else
+ -- Modpack not entirely enabled so showing as grey
+ color = mt_color_grey
+ end
end
end
elseif v.is_game_content or v.type == "game" then
+ icon = 1
color = mt_color_blue
+
+ local rawlist = render_list:get_raw_list()
+ if v.type == "game" and with_error then
+ for j = 1, #rawlist do
+ if rawlist[j].is_game_content then
+ update_error(with_error[rawlist[j].virtual_path])
+ end
+ end
+ end
elseif v.enabled or v.type == "txp" then
+ icon = 1
color = mt_color_green
end
+ if error then
+ if error.type == "warning" then
+ color = mt_color_orange
+ icon = 2
+ else
+ color = mt_color_red
+ icon = 3
+ end
+ end
+
retval[#retval + 1] = color
if v.modpack ~= nil or v.loc == "game" then
retval[#retval + 1] = "1"
else
retval[#retval + 1] = "0"
end
- retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
+
+ if with_error then
+ retval[#retval + 1] = icon
+ end
+
+ if use_technical_names then
+ retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
+ else
+ retval[#retval + 1] = core.formspec_escape(v.list_title or v.list_name or v.title or v.name)
+ end
end
return table.concat(retval, ",")
@@ -397,6 +444,14 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
return true
end
+local function disable_all_by_name(list, name, except)
+ for i=1, #list do
+ if list[i].name == name and list[i] ~= except then
+ list[i].enabled = false
+ end
+ end
+end
+
---------- toggles or en/disables a mod or modpack and its dependencies --------
local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
if not mod.is_modpack then
@@ -405,13 +460,16 @@ local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mo
toset = not mod.enabled
end
if mod.enabled ~= toset then
- mod.enabled = toset
toggled_mods[#toggled_mods+1] = mod.name
end
if toset then
-- Mark this mod for recursive dependency traversal
enabled_mods[mod.name] = true
+
+ -- Disable other mods with the same name
+ disable_all_by_name(list, mod.name, mod)
end
+ mod.enabled = toset
else
-- Toggle or en/disable every mod in the modpack,
-- interleaved unsupported
@@ -472,6 +530,7 @@ function pkgmgr.enable_mod(this, toset)
end
end
end
+
-- If sp is 0, every dependency is already activated
while sp > 0 do
local name = to_enable[sp]
@@ -483,8 +542,8 @@ function pkgmgr.enable_mod(this, toset)
if not mod_to_enable then
core.log("warning", "Mod dependency \"" .. name ..
"\" not found!")
- else
- if not mod_to_enable.enabled then
+ elseif not mod_to_enable.is_game_content then
+ if not mod_to_enable.enabled then
mod_to_enable.enabled = true
toggled_mods[#toggled_mods+1] = mod_to_enable.name
end
@@ -626,6 +685,8 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
else
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
end
+ else
+ error("basefolder didn't return a recognised type, this shouldn't happen")
end
-- Copy it
@@ -652,13 +713,14 @@ function pkgmgr.preparemodlist(data)
--read global mods
local modpaths = core.get_modpaths()
- for _, modpath in ipairs(modpaths) do
- get_mods(modpath, global_mods)
+ for key, modpath in pairs(modpaths) do
+ get_mods(modpath, key, global_mods)
end
for i=1,#global_mods,1 do
global_mods[i].type = "mod"
global_mods[i].loc = "global"
+ global_mods[i].enabled = false
retval[#retval + 1] = global_mods[i]
end
@@ -671,7 +733,7 @@ function pkgmgr.preparemodlist(data)
retval[#retval + 1] = {
type = "game",
is_game_content = true,
- name = fgettext("$1 mods", gamespec.name),
+ name = fgettext("$1 mods", gamespec.title),
path = gamespec.path
}
end
@@ -692,22 +754,37 @@ function pkgmgr.preparemodlist(data)
DIR_DELIM .. "world.mt"
local worldfile = Settings(filename)
-
- for key,value in pairs(worldfile:to_table()) do
+ for key, value in pairs(worldfile:to_table()) do
if key:sub(1, 9) == "load_mod_" then
key = key:sub(10)
- local element = nil
- for i=1,#retval,1 do
+ local mod_found = false
+
+ local fallback_found = false
+ local fallback_mod = nil
+
+ for i=1, #retval do
if retval[i].name == key and
- not retval[i].is_modpack then
- element = retval[i]
- break
+ not retval[i].is_modpack then
+ if core.is_yes(value) or retval[i].virtual_path == value then
+ retval[i].enabled = true
+ mod_found = true
+ break
+ elseif fallback_found then
+ -- Only allow fallback if only one mod matches
+ fallback_mod = nil
+ else
+ fallback_found = true
+ fallback_mod = retval[i]
+ end
end
end
- if element ~= nil then
- element.enabled = value ~= "false" and value ~= "nil" and value
- else
- core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+
+ if not mod_found then
+ if fallback_mod and value:find("/") then
+ fallback_mod.enabled = true
+ else
+ core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+ end
end
end
end
@@ -801,7 +878,7 @@ function pkgmgr.get_game_mods(gamespec, retval)
if gamespec ~= nil and
gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
- get_mods(gamespec.gamemods_path, retval)
+ get_mods(gamespec.gamemods_path, ("games/%s/mods"):format(gamespec.id), retval)
end
end
@@ -837,10 +914,10 @@ end
function pkgmgr.gamelist()
local retval = ""
if #pkgmgr.games > 0 then
- retval = retval .. core.formspec_escape(pkgmgr.games[1].name)
+ retval = retval .. core.formspec_escape(pkgmgr.games[1].title)
for i=2,#pkgmgr.games,1 do
- retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].name)
+ retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title)
end
end
return retval
diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua
index ba258fd2d..a84ebce3f 100644
--- a/builtin/mainmenu/tab_about.lua
+++ b/builtin/mainmenu/tab_about.lua
@@ -15,48 +15,46 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---------------------------------------------------------------------------------
+-- https://github.com/orgs/minetest/teams/engine/members
local core_developers = {
- "Perttu Ahola (celeron55) <celeron55@gmail.com>",
+ "Perttu Ahola (celeron55) <celeron55@gmail.com> [Project founder]",
"sfan5 <sfan5@live.de>",
- "Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>",
+ "ShadowNinja <shadowninja@minetest.net>",
+ "Nathanaëlle Courant (Nore/Ekdohibs) <nore@mesecons.net>",
"Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
- "paramat",
"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>",
"hecks",
"Hugues Ross <hugues.ross@gmail.com>",
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
}
+local core_team = {
+ "Zughy [Issue triager]",
+}
+
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
local active_contributors = {
- "Wuzzy [I18n for builtin, liquid features, fixes]",
- "Zughy [Various features and fixes]",
- "numzero [Graphics and rendering]",
- "Desour [Internal fixes, Clipboard on X11]",
- "Lars Müller [Various internal fixes]",
- "JosiahWI [CMake, cleanups and fixes]",
- "HybridDog [builtin, documentation]",
- "Jude Melton-Houghton [Database implementation]",
- "savilli [Fixes]",
+ "Wuzzy [Features, translations, devtest]",
+ "Lars Müller [Lua optimizations and fixes]",
+ "Jude Melton-Houghton [Optimizations, bugfixes]",
+ "paradust7 [Performance, fixes, Irrlicht refactoring]",
+ "Desour [Fixes]",
+ "ROllerozxa [Main menu]",
+ "savilli [Bugfixes]",
+ "Lexi Hale [Particlespawner animation]",
"Liso [Shadow Mapping]",
- "MoNTE48 [Build fix]",
- "Jean-Patrick Guerrero (kilbith) [Fixes]",
- "ROllerozxa [Code cleanups]",
- "Lejo [bitop library integration]",
- "LoneWolfHT [Build fixes]",
+ "JosiahWI [Fixes, build system]",
+ "numzero [Graphics and rendering]",
+ "HybridDog [Fixes]",
"NeroBurner [Joystick]",
- "Elias Fleckenstein [Internal fixes]",
- "David CARLIER [Unix & Haiku build fixes]",
"pecksin [Clickable web links]",
- "srfqi [Android & rendering fixes]",
- "EvidenceB [Formspec]",
+ "Daroc Alden [Fixes]",
+ "Jean-Patrick Guerrero (kilbith) [Fixes]",
}
local previous_core_developers = {
@@ -71,33 +69,50 @@ local previous_core_developers = {
"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
"sapier",
"Zeno",
- "ShadowNinja <shadowninja@minetest.net>",
"Auke Kok (sofar) <sofar@foo-projects.org>",
"Aaron Suen <warr1024@gmail.com>",
+ "paramat",
+ "Pierre-Yves Rollo <dev@pyrollo.com>",
}
local previous_contributors = {
- "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest Logo]",
+ "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest logo]",
"red-001 <red-001@outlook.ie>",
"Giuseppe Bilotta",
+ "ClobberXD",
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"MirceaKitsune <mirceakitsune@gmail.com>",
+ "MoNTE48",
"Constantin Wenger (SpeedProg)",
"Ciaran Gultnieks (CiaranG)",
"Paul Ouellette (pauloue)",
"stujones11",
+ "srifqi",
"Rogier <rogier777@gmail.com>",
"Gregory Currie (gregorycu)",
"JacobF",
- "Jeija <jeija@mesecons.net> [HTTP, particles]",
+ "Jeija <jeija@mesecons.net>",
}
-local function buildCreditList(source)
+local function prepare_credits(dest, source)
+ for _, s in ipairs(source) do
+ -- if there's text inside brackets make it gray-ish
+ s = s:gsub("%[.-%]", core.colorize("#aaa", "%1"))
+ dest[#dest+1] = s
+ end
+end
+
+local function build_hacky_list(items, spacing)
+ spacing = spacing or 0.5
+ local y = spacing / 2
local ret = {}
- for i = 1, #source do
- ret[i] = core.formspec_escape(source[i])
+ for _, item in ipairs(items) do
+ if item ~= "" then
+ ret[#ret+1] = ("label[0,%f;%s]"):format(y, core.formspec_escape(item))
+ end
+ y = y + spacing
end
- return table.concat(ret, ",,")
+ return table.concat(ret, ""), y
end
return {
@@ -106,42 +121,73 @@ return {
cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version()
- local fs = "image[0.75,0.5;2.2,2.2;" .. core.formspec_escape(logofile) .. "]" ..
+
+ local credit_list = {}
+ table.insert_all(credit_list, {
+ core.colorize("#ff0", fgettext("Core Developers"))
+ })
+ prepare_credits(credit_list, core_developers)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Core Team"))
+ })
+ prepare_credits(credit_list, core_team)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Active Contributors"))
+ })
+ prepare_credits(credit_list, active_contributors)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Previous Core Developers"))
+ })
+ prepare_credits(credit_list, previous_core_developers)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Previous Contributors"))
+ })
+ prepare_credits(credit_list, previous_contributors)
+ local credit_fs, scroll_height = build_hacky_list(credit_list)
+ -- account for the visible portion
+ scroll_height = math.max(0, scroll_height - 6.9)
+
+ local fs = "image[1.5,0.6;2.5,2.5;" .. core.formspec_escape(logofile) .. "]" ..
"style[label_button;border=false]" ..
- "button[0.5,2;2.5,2;label_button;" .. version.project .. " " .. version.string .. "]" ..
- "button[0.75,2.75;2,2;homepage;minetest.net]" ..
- "tablecolumns[color;text]" ..
- "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
- "table[3.5,-0.25;8.5,6.05;list_credits;" ..
- "#FFFF00," .. fgettext("Core Developers") .. ",," ..
- buildCreditList(core_developers) .. ",,," ..
- "#FFFF00," .. fgettext("Active Contributors") .. ",," ..
- buildCreditList(active_contributors) .. ",,," ..
- "#FFFF00," .. fgettext("Previous Core Developers") ..",," ..
- buildCreditList(previous_core_developers) .. ",,," ..
- "#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
- buildCreditList(previous_contributors) .. "," ..
- ";1]"
+ "button[0.1,3.4;5.3,0.5;label_button;" ..
+ core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
+ "button[1.5,4.1;2.5,0.8;homepage;minetest.net]" ..
+ "scroll_container[5.5,0.1;9.5,6.9;scroll_credits;vertical;" ..
+ tostring(scroll_height / 1000) .. "]" .. credit_fs ..
+ "scroll_container_end[]"..
+ "scrollbar[15,0.1;0.4,6.9;vertical;scroll_credits;0]"
-- Render information
- fs = fs .. "label[0.75,4.9;" ..
+ fs = fs .. "style[label_button2;border=false]" ..
+ "button[0.1,6;5.3,1;label_button2;" ..
fgettext("Active renderer:") .. "\n" ..
core.formspec_escape(core.get_screen_info().render_info) .. "]"
- if PLATFORM ~= "Android" then
+ if PLATFORM == "Android" then
+ fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
+ else
fs = fs .. "tooltip[userdata;" ..
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
"and texture packs in a file manager / explorer.") .. "]"
- fs = fs .. "button[0,4;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]"
+ fs = fs .. "button[0.5,5.1;4.5,0.8;userdata;" .. fgettext("Open User Data Directory") .. "]"
end
- return fs
+ return fs, "size[15.5,7.1,false]real_coordinates[true]"
end,
cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then
core.open_url("https://www.minetest.net")
end
+ if fields.share_debug then
+ local path = core.get_user_path() .. DIR_DELIM .. "debug.txt"
+ core.share_file(path)
+ end
+
if fields.userdata then
core.open_dir(core.get_user_path())
end
diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua
index fb7f121f8..5e14d1902 100644
--- a/builtin/mainmenu/tab_content.lua
+++ b/builtin/mainmenu/tab_content.lua
@@ -51,12 +51,14 @@ local function get_formspec(tabview, name, tabdata)
tabdata.selected_pkg = 1
end
+ local use_technical_names = core.settings:get_bool("show_technical_names")
+
local retval =
"label[0.05,-0.25;".. fgettext("Installed Packages:") .. "]" ..
"tablecolumns[color;tree;text]" ..
"table[0,0.25;5.1,4.3;pkglist;" ..
- pkgmgr.render_packagelist(packages) ..
+ pkgmgr.render_packagelist(packages, use_technical_names) ..
";" .. tabdata.selected_pkg .. "]" ..
"button[0,4.85;5.25,0.5;btn_contentdb;".. fgettext("Browse online content") .. "]"
@@ -87,9 +89,17 @@ local function get_formspec(tabview, name, tabdata)
desc = info.description
end
+ local title_and_name
+ if selected_pkg.type == "game" then
+ title_and_name = selected_pkg.name
+ else
+ title_and_name = (selected_pkg.title or selected_pkg.name) .. "\n" ..
+ core.colorize("#BFBFBF", selected_pkg.name)
+ end
+
retval = retval ..
"image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]" ..
- "label[8.25,0.6;" .. core.formspec_escape(selected_pkg.name) .. "]" ..
+ "label[8.25,0.6;" .. core.formspec_escape(title_and_name) .. "]" ..
"box[5.5,2.2;6.15,2.35;#000]"
if selected_pkg.type == "mod" then
@@ -154,6 +164,9 @@ local function handle_doubleclick(pkg)
core.settings:set("texture_path", pkg.path)
end
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
end
end
@@ -197,17 +210,17 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
- if fields.btn_mod_mgr_use_txp then
- local txp = packages:get_list()[tabdata.selected_pkg]
- core.settings:set("texture_path", txp.path)
- packages = nil
- return true
- end
-
+ if fields.btn_mod_mgr_use_txp or fields.btn_mod_mgr_disable_txp then
+ local txp_path = ""
+ if fields.btn_mod_mgr_use_txp then
+ txp_path = packages:get_list()[tabdata.selected_pkg].path
+ end
- if fields.btn_mod_mgr_disable_txp then
- core.settings:set("texture_path", "")
+ core.settings:set("texture_path", txp_path)
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
return true
end
diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua
index e77c6f04d..f8de10db6 100644
--- a/builtin/mainmenu/tab_local.lua
+++ b/builtin/mainmenu/tab_local.lua
@@ -16,7 +16,6 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-local enable_gamebar = PLATFORM ~= "Android"
local current_game, singleplayer_refresh_gamebar
local valid_disabled_settings = {
["enable_damage"]=true,
@@ -24,95 +23,88 @@ local valid_disabled_settings = {
["enable_server"]=true,
}
-if enable_gamebar then
- -- Currently chosen game in gamebar for theming and filtering
- function current_game()
- local last_game_id = core.settings:get("menu_last_game")
- local game = pkgmgr.find_by_gameid(last_game_id)
+-- Currently chosen game in gamebar for theming and filtering
+function current_game()
+ local last_game_id = core.settings:get("menu_last_game")
+ local game = pkgmgr.find_by_gameid(last_game_id)
- return game
- end
+ return game
+end
- -- Apply menu changes from given game
- function apply_game(game)
- core.set_topleft_text(game.name)
- core.settings:set("menu_last_game", game.id)
- menudata.worldlist:set_filtercriteria(game.id)
+-- Apply menu changes from given game
+function apply_game(game)
+ core.set_topleft_text(game.name)
+ core.settings:set("menu_last_game", game.id)
+ menudata.worldlist:set_filtercriteria(game.id)
- mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
+ mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
- local index = filterlist.get_current_index(menudata.worldlist,
- tonumber(core.settings:get("mainmenu_last_selected_world")))
- if not index or index < 1 then
- local selected = core.get_textlist_index("sp_worlds")
- if selected ~= nil and selected < #menudata.worldlist:get_list() then
- index = selected
- else
- index = #menudata.worldlist:get_list()
- end
+ local index = filterlist.get_current_index(menudata.worldlist,
+ tonumber(core.settings:get("mainmenu_last_selected_world")))
+ if not index or index < 1 then
+ local selected = core.get_textlist_index("sp_worlds")
+ if selected ~= nil and selected < #menudata.worldlist:get_list() then
+ index = selected
+ else
+ index = #menudata.worldlist:get_list()
end
- menu_worldmt_legacy(index)
end
+ menu_worldmt_legacy(index)
+end
- function singleplayer_refresh_gamebar()
+function singleplayer_refresh_gamebar()
- local old_bar = ui.find_by_name("game_button_bar")
- if old_bar ~= nil then
- old_bar:delete()
+ local old_bar = ui.find_by_name("game_button_bar")
+ if old_bar ~= nil then
+ old_bar:delete()
+ end
+
+ local function game_buttonbar_button_handler(fields)
+ if fields.game_open_cdb then
+ local maintab = ui.find_by_name("maintab")
+ local dlg = create_store_dlg("game")
+ dlg:set_parent(maintab)
+ maintab:hide()
+ dlg:show()
+ return true
end
- local function game_buttonbar_button_handler(fields)
- if fields.game_open_cdb then
- local maintab = ui.find_by_name("maintab")
- local dlg = create_store_dlg("game")
- dlg:set_parent(maintab)
- maintab:hide()
- dlg:show()
+ for _, game in ipairs(pkgmgr.games) do
+ if fields["game_btnbar_" .. game.id] then
+ apply_game(game)
return true
end
-
- for _, game in ipairs(pkgmgr.games) do
- if fields["game_btnbar_" .. game.id] then
- apply_game(game)
- return true
- end
- end
end
+ end
- local btnbar = buttonbar_create("game_button_bar",
- game_buttonbar_button_handler,
- {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
+ local btnbar = buttonbar_create("game_button_bar",
+ game_buttonbar_button_handler,
+ {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
- for _, game in ipairs(pkgmgr.games) do
- local btn_name = "game_btnbar_" .. game.id
+ for _, game in ipairs(pkgmgr.games) do
+ local btn_name = "game_btnbar_" .. game.id
- local image = nil
- local text = nil
- local tooltip = core.formspec_escape(game.name)
+ local image = nil
+ local text = nil
+ local tooltip = core.formspec_escape(game.title)
- if (game.menuicon_path or "") ~= "" then
- image = core.formspec_escape(game.menuicon_path)
- else
- local part1 = game.id:sub(1,5)
- local part2 = game.id:sub(6,10)
- local part3 = game.id:sub(11)
+ if (game.menuicon_path or "") ~= "" then
+ image = core.formspec_escape(game.menuicon_path)
+ else
+ local part1 = game.id:sub(1,5)
+ local part2 = game.id:sub(6,10)
+ local part3 = game.id:sub(11)
- text = part1 .. "\n" .. part2
- if part3 ~= "" then
- text = text .. "\n" .. part3
- end
+ text = part1 .. "\n" .. part2
+ if part3 ~= "" then
+ text = text .. "\n" .. part3
end
- btnbar:add_button(btn_name, text, image, tooltip)
end
-
- local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
- btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
- end
-else
- -- Currently chosen game in gamebar: no gamebar -> no "current" game
- function current_game()
- return nil
+ btnbar:add_button(btn_name, text, image, tooltip)
end
+
+ local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
+ btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
end
local function get_disabled_settings(game)
@@ -187,7 +179,7 @@ local function get_formspec(tabview, name, tabdata)
damage ..
host ..
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
- menu_render_worldlist(not enable_gamebar) ..
+ menu_render_worldlist() ..
";" .. index .. "]"
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
@@ -324,7 +316,7 @@ local function main_button_handler(this, fields, name, tabdata)
end
if fields["world_create"] ~= nil then
- local create_world_dlg = create_create_world_dlg(enable_gamebar)
+ local create_world_dlg = create_create_world_dlg()
create_world_dlg:set_parent(this)
this:hide()
create_world_dlg:show()
@@ -371,26 +363,23 @@ local function main_button_handler(this, fields, name, tabdata)
end
end
-local on_change
-if enable_gamebar then
- function on_change(type, old_tab, new_tab)
- if (type == "ENTER") then
- local game = current_game()
- if game then
- apply_game(game)
- end
+local function on_change(type, old_tab, new_tab)
+ if (type == "ENTER") then
+ local game = current_game()
+ if game then
+ apply_game(game)
+ end
- singleplayer_refresh_gamebar()
- ui.find_by_name("game_button_bar"):show()
- else
- menudata.worldlist:set_filtercriteria(nil)
- local gamebar = ui.find_by_name("game_button_bar")
- if gamebar then
- gamebar:hide()
- end
- core.set_topleft_text("")
- mm_game_theme.update(new_tab,nil)
+ singleplayer_refresh_gamebar()
+ ui.find_by_name("game_button_bar"):show()
+ else
+ menudata.worldlist:set_filtercriteria(nil)
+ local gamebar = ui.find_by_name("game_button_bar")
+ if gamebar then
+ gamebar:hide()
end
+ core.set_topleft_text("")
+ mm_game_theme.update(new_tab,nil)
end
end
diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua
index fb7409864..899f30bd1 100644
--- a/builtin/mainmenu/tab_online.lua
+++ b/builtin/mainmenu/tab_online.lua
@@ -87,27 +87,34 @@ local function get_formspec(tabview, name, tabdata)
"field[4.25,0.5;1.25,0.75;te_port;;" ..
core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
- -- Name / Password
- "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[3,1.75;2.5,0.75;te_pwd;]" ..
-
-- Description Background
- "label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
- "box[0.25,3;5.25,2.75;#999999]"..
+ "label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
+ "box[0.25,1.85;5.25,2.7;#999999]"..
+
+ -- Name / Password
+ "container[0,4.8]" ..
+ "label[0.25,0;" .. fgettext("Name") .. "]" ..
+ "label[3,0;" .. fgettext("Password") .. "]" ..
+ "field[0.25,0.2;2.625,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
+ "pwdfield[2.875,0.2;2.625,0.75;te_pwd;]" ..
+ "container_end[]" ..
-- Connect
- "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
+ "button[3,6;2.5,0.75;btn_mp_login;" .. fgettext("Login") .. "]"
+
+ if core.settings:get_bool("enable_split_login_register") then
+ retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
+ end
if tabdata.selected then
if gamedata.fav then
- retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
- fgettext("Del. Favorite") .. "]"
+ retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
+ retval = retval .. "style[btn_delete_favorite;padding=6]"
+ retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
+ "server_favorite_delete.png") .. ";btn_delete_favorite;]"
end
if gamedata.serverdescription then
- retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
+ retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
core.formspec_escape(gamedata.serverdescription) .. "]"
end
end
@@ -339,12 +346,15 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
- if (fields.btn_mp_connect or fields.key_enter)
+ if (fields.btn_mp_login or fields.key_enter)
and fields.te_address ~= "" and fields.te_port then
gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd
gamedata.address = fields.te_address
gamedata.port = tonumber(fields.te_port)
+
+ local enable_split_login_register = core.settings:get_bool("enable_split_login_register")
+ gamedata.allow_login_or_register = enable_split_login_register and "login" or "any"
gamedata.selected_world = 0
local idx = core.get_table_index("servers")
@@ -381,6 +391,25 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
+ if fields.btn_mp_register and fields.te_address ~= "" and fields.te_port then
+ local idx = core.get_table_index("servers")
+ local server = idx and tabdata.lookup[idx]
+ if server and (server.address ~= fields.te_address or server.port ~= tonumber(fields.te_port)) then
+ server = nil
+ end
+
+ if server and not is_server_protocol_compat_or_error(
+ server.proto_min, server.proto_max) then
+ return true
+ end
+
+ local dlg = create_register_dialog(fields.te_address, tonumber(fields.te_port), server)
+ dlg:set_parent(tabview)
+ tabview:hide()
+ dlg:show()
+ return true
+ end
+
return false
end
diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
index 700b7390f..21c77aa8e 100644
--- a/builtin/mainmenu/tab_settings.lua
+++ b/builtin/mainmenu/tab_settings.lua
@@ -50,7 +50,7 @@ local labels = {
fgettext("Low"),
fgettext("Medium"),
fgettext("High"),
- fgettext("Ultra High")
+ fgettext("Very High")
}
}
@@ -160,7 +160,7 @@ local function formspec(tabview, name, tabdata)
.. getSettingIndex.NodeHighlighting() .. "]" ..
"dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
.. getSettingIndex.Leaves() .. "]" ..
- "box[4,0;3.75,4.5;#999999]" ..
+ "box[4,0;3.75,4.9;#999999]" ..
"label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
"dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
.. getSettingIndex.Filter() .. "]" ..
@@ -169,9 +169,6 @@ local function formspec(tabview, name, tabdata)
"label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
"dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
.. getSettingIndex.Antialiasing() .. "]" ..
- "label[4.25,3.45;" .. fgettext("Screen:") .. "]" ..
- "checkbox[4.25,3.6;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
- .. dump(core.settings:get_bool("autosave_screensize")) .. "]" ..
"box[8,0;3.75,4.5;#999999]"
local video_driver = core.settings:get("video_driver")
@@ -203,10 +200,15 @@ local function formspec(tabview, name, tabdata)
if core.settings:get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
- "label[4.3,4.2;" .. fgettext("Touchthreshold: (px)") .. "]" ..
- "dropdown[4.25,4.65;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
+ "label[4.25,3.5;" .. fgettext("Touch threshold (px):") .. "]" ..
+ "dropdown[4.25,3.95;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.settings:get("touchscreen_threshold")) / 10) + 1) ..
- "]box[4.0,4.5;3.75,1.0;#999999]"
+ "]"
+ else
+ tab_string = tab_string ..
+ "label[4.25,3.65;" .. fgettext("Screen:") .. "]" ..
+ "checkbox[4.25,3.9;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
+ .. dump(core.settings:get_bool("autosave_screensize")) .. "]"
end
if shaders_enabled then
@@ -219,9 +221,18 @@ local function formspec(tabview, name, tabdata)
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
"checkbox[8.25,2;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
- --"label[8.25,3.0;" .. fgettext("Dynamic shadows: ") .. "]" ..
- --"dropdown[8.25,3.5;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
- -- .. getSettingIndex.ShadowMapping() .. "]"
+
+ if video_driver == "opengl" then
+ tab_string = tab_string ..
+ "label[8.25,2.8;" .. fgettext("Dynamic shadows:") .. "]" ..
+ "label[8.25,3.2;" .. fgettext("(game support required)") .. "]" ..
+ "dropdown[8.25,3.7;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
+ .. getSettingIndex.ShadowMapping() .. "]"
+ else
+ tab_string = tab_string ..
+ "label[8.38,2.7;" .. core.colorize("#888888",
+ fgettext("Dynamic shadows")) .. "]"
+ end
else
tab_string = tab_string ..
"label[8.38,0.7;" .. core.colorize("#888888",
@@ -231,9 +242,9 @@ local function formspec(tabview, name, tabdata)
"label[8.38,1.7;" .. core.colorize("#888888",
fgettext("Waving Leaves")) .. "]" ..
"label[8.38,2.2;" .. core.colorize("#888888",
- fgettext("Waving Plants")) .. "]"
- --"label[8.38,2.7;" .. core.colorize("#888888",
- -- fgettext("Dynamic shadows")) .. "]"
+ fgettext("Waving Plants")) .. "]"..
+ "label[8.38,2.7;" .. core.colorize("#888888",
+ fgettext("Dynamic shadows")) .. "]"
end
return tab_string
@@ -364,11 +375,11 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.settings:set("enable_dynamic_shadows", "false")
else
local shadow_presets = {
- [2] = { 80, 512, "true", 0, "false" },
- [3] = { 120, 1024, "true", 1, "false" },
- [4] = { 350, 2048, "true", 1, "false" },
- [5] = { 350, 2048, "true", 2, "true" },
- [6] = { 450, 4096, "true", 2, "true" },
+ [2] = { 62, 512, "true", 0, "false" },
+ [3] = { 93, 1024, "true", 0, "false" },
+ [4] = { 140, 2048, "true", 1, "false" },
+ [5] = { 210, 4096, "true", 2, "true" },
+ [6] = { 300, 8192, "true", 2, "true" },
}
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
if s then
diff --git a/builtin/mainmenu/tests/serverlistmgr_spec.lua b/builtin/mainmenu/tests/serverlistmgr_spec.lua
index a091959fb..ab7a6c60c 100644
--- a/builtin/mainmenu/tests/serverlistmgr_spec.lua
+++ b/builtin/mainmenu/tests/serverlistmgr_spec.lua
@@ -1,4 +1,5 @@
_G.core = {}
+_G.vector = {metatable = {}}
_G.unpack = table.unpack
_G.serverlistmgr = {}
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 01bebe4cc..52b4b4d9d 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -63,26 +63,15 @@
# There shouldn't be too much settings per category; settings that shouldn't be
# modified by the "average user" should be in (sub-)categories called "Advanced".
+
[Controls]
+
+[*General]
+
# If enabled, you can place blocks at the position (feet + eye level) where you stand.
# This is helpful when working with nodeboxes in small areas.
enable_build_where_you_stand (Build inside player) bool false
-# Player is able to fly without being affected by gravity.
-# This requires the "fly" privilege on the server.
-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 "Aux1" key).
-# This requires the "fast" privilege on the server.
-fast_move (Fast movement) bool false
-
-# If enabled together with fly mode, player is able to fly through solid nodes.
-# This requires the "noclip" privilege on the server.
-noclip (Noclip) bool false
-
# Smooths camera when looking around. Also called look or mouse smoothing.
# Useful for recording videos.
cinematic (Cinematic mode) bool false
@@ -93,12 +82,6 @@ camera_smoothing (Camera smoothing) float 0.0 0.0 0.99
# Smooths rotation of camera in cinematic mode. 0 to disable.
cinematic_camera_smoothing (Camera smoothing in cinematic mode) float 0.7 0.0 0.99
-# Invert vertical mouse movement.
-invert_mouse (Invert mouse) bool false
-
-# Mouse sensitivity multiplier.
-mouse_sensitivity (Mouse sensitivity) float 0.2
-
# If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and
# descending.
aux1_descends (Aux1 key for climbing/descending) bool false
@@ -108,11 +91,11 @@ doubletap_jump (Double tap jump for fly) bool false
# 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
+always_fly_fast (Always fly fast) bool true
# The time in seconds it takes between repeated node placements when holding
# the place button.
-repeat_place_time (Place repetition interval) float 0.25 0.001
+repeat_place_time (Place repetition interval) float 0.25 0.25 2
# Automatically jump up single-node obstacles.
autojump (Automatic jumping) bool false
@@ -121,12 +104,15 @@ autojump (Automatic jumping) bool false
# Enable this when you dig or place too often by accident.
safe_dig_and_place (Safe digging and placing) bool false
-# Enable random user input (only used for testing).
-random_input (Random input) bool false
+[*Keyboard and Mouse]
-# Continuous forward movement, toggled by autoforward key.
-# Press the autoforward key again or the backwards movement to disable.
-continuous_forward (Continuous forward) bool false
+# Invert vertical mouse movement.
+invert_mouse (Invert mouse) bool false
+
+# Mouse sensitivity multiplier.
+mouse_sensitivity (Mouse sensitivity) float 0.2 0.001 10.0
+
+[*Touchscreen]
# The length in pixels it takes for touch screen interaction to start.
touchscreen_threshold (Touch screen threshold) int 20 0 100
@@ -139,345 +125,179 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
# 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
-
-# The identifier of the joystick to use
-joystick_id (Joystick ID) int 0
-
-# The type of joystick
-joystick_type (Joystick type) enum auto auto,generic,xbox,dragonrise_gamecube
-
-# The time in seconds it takes between repeated events
-# when holding down a joystick button combination.
-repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001
-
-# The dead zone of the joystick
-joystick_deadzone (Joystick dead zone) int 2048
-
-# The sensitivity of the joystick axes for moving the
-# in-game view frustum around.
-joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
-
-# Key for moving the player forward.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_forward (Forward key) key KEY_KEY_W
-
-# Key for moving the player backward.
-# Will also disable autoforward, when active.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_backward (Backward key) key KEY_KEY_S
-
-# Key for moving the player left.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_left (Left key) key KEY_KEY_A
-
-# Key for moving the player right.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_right (Right key) key KEY_KEY_D
-
-# Key for jumping.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_jump (Jump key) key KEY_SPACE
-
-# Key for sneaking.
-# Also used for climbing down and descending in water if aux1_descends is disabled.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_sneak (Sneak key) key KEY_LSHIFT
-
-# Key for digging.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_dig (Dig key) key KEY_LBUTTON
-
-# Key for placing.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_place (Place key) key KEY_RBUTTON
-
-# Key for opening the inventory.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-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_aux1 (Aux1 key) key KEY_KEY_E
-
-# Key for opening the chat window.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_chat (Chat key) key KEY_KEY_T
-
-# Key for opening the chat window to type commands.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_cmd (Command key) key /
-
-# Key for opening the chat window to type local commands.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_cmd_local (Command key) key .
-
-# Key for toggling unlimited view range.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_rangeselect (Range select key) key KEY_KEY_R
-
-# Key for toggling flying.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_freemove (Fly key) key KEY_KEY_K
-
-# Key for toggling pitch move mode.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_pitchmove (Pitch move key) key KEY_KEY_P
-
-# Key for toggling fast mode.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_fastmove (Fast key) key KEY_KEY_J
-
-# Key for toggling noclip mode.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_noclip (Noclip key) key KEY_KEY_H
-
-# Key for selecting the next item in the hotbar.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_hotbar_next (Hotbar next key) key KEY_KEY_N
-
-# Key for selecting the previous item in the hotbar.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_hotbar_previous (Hotbar previous key) key KEY_KEY_B
-
-# Key for muting the game.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_mute (Mute key) key KEY_KEY_M
-
-# Key for increasing the volume.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_increase_volume (Inc. volume key) key
-# Key for decreasing the volume.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_decrease_volume (Dec. volume key) key
+[Graphics and Audio]
-# Key for toggling autoforward.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_autoforward (Automatic forward key) key
+[*Graphics]
-# Key for toggling cinematic mode.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_cinematic (Cinematic mode key) key
+[**Screen]
-# Key for toggling display of minimap.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_minimap (Minimap key) key KEY_KEY_V
-
-# Key for taking screenshots.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_screenshot (Screenshot) key KEY_F12
-
-# Key for dropping the currently selected item.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_drop (Drop item key) key KEY_KEY_Q
-
-# Key to use view zoom when possible.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_zoom (View zoom key) key KEY_KEY_Z
-
-# Key for selecting the first hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot1 (Hotbar slot 1 key) key KEY_KEY_1
-
-# Key for selecting the second hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot2 (Hotbar slot 2 key) key KEY_KEY_2
-
-# Key for selecting the third hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot3 (Hotbar slot 3 key) key KEY_KEY_3
-
-# Key for selecting the fourth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot4 (Hotbar slot 4 key) key KEY_KEY_4
-
-# Key for selecting the fifth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot5 (Hotbar slot 5 key) key KEY_KEY_5
-
-# Key for selecting the sixth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot6 (Hotbar slot 6 key) key KEY_KEY_6
+# Width component of the initial window size. Ignored in fullscreen mode.
+screen_w (Screen width) int 1024 1 65535
-# Key for selecting the seventh hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot7 (Hotbar slot 7 key) key KEY_KEY_7
+# Height component of the initial window size. Ignored in fullscreen mode.
+screen_h (Screen height) int 600 1 65535
-# Key for selecting the eighth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot8 (Hotbar slot 8 key) key KEY_KEY_8
+# Save window size automatically when modified.
+autosave_screensize (Autosave screen size) bool true
-# Key for selecting the ninth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot9 (Hotbar slot 9 key) key KEY_KEY_9
+# Fullscreen mode.
+fullscreen (Full screen) bool false
-# Key for selecting the tenth hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot10 (Hotbar slot 10 key) key KEY_KEY_0
+# Open the pause menu when the window's focus is lost. Does not pause if a formspec is
+# open.
+pause_on_lost_focus (Pause on lost window focus) bool false
-# Key for selecting the 11th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot11 (Hotbar slot 11 key) key
+[**FPS]
-# Key for selecting the 12th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot12 (Hotbar slot 12 key) key
+# If FPS would go higher than this, limit it by sleeping
+# to not waste CPU power for no benefit.
+fps_max (Maximum FPS) int 60 1 4294967295
-# Key for selecting the 13th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot13 (Hotbar slot 13 key) key
+# Vertical screen synchronization.
+vsync (VSync) bool false
-# Key for selecting the 14th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot14 (Hotbar slot 14 key) key
+# Maximum FPS when the window is not focused, or when the game is paused.
+fps_max_unfocused (FPS when unfocused or paused) int 20 1 4294967295
-# Key for selecting the 15th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot15 (Hotbar slot 15 key) key
+# View distance in nodes.
+viewing_range (Viewing range) int 190 20 4000
-# Key for selecting the 16th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot16 (Hotbar slot 16 key) key
+# Undersampling is similar to using a lower screen resolution, but it applies
+# to the game world only, keeping the GUI intact.
+# It should give a significant performance boost at the cost of less detailed image.
+# Higher values result in a less detailed image.
+undersampling (Undersampling) int 1 1 8
-# Key for selecting the 17th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot17 (Hotbar slot 17 key) key
+[**Graphics Effects]
-# Key for selecting the 18th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot18 (Hotbar slot 18 key) key
+# Makes all liquids opaque
+opaque_water (Opaque liquids) bool false
-# Key for selecting the 19th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot19 (Hotbar slot 19 key) key
+# Leaves style:
+# - Fancy: all faces visible
+# - Simple: only outer faces, if defined special_tiles are used
+# - Opaque: disable transparency
+leaves_style (Leaves style) enum fancy fancy,simple,opaque
-# Key for selecting the 20th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot20 (Hotbar slot 20 key) key
+# Connects glass if supported by node.
+connected_glass (Connect glass) bool false
-# Key for selecting the 21st hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot21 (Hotbar slot 21 key) key
+# Enable smooth lighting with simple ambient occlusion.
+# Disable for speed or for different looks.
+smooth_lighting (Smooth lighting) bool true
-# Key for selecting the 22nd hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot22 (Hotbar slot 22 key) key
+# Enables tradeoffs that reduce CPU load or increase rendering performance
+# at the expense of minor visual glitches that do not impact game playability.
+performance_tradeoffs (Tradeoffs for performance) bool false
-# Key for selecting the 23rd hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot23 (Hotbar slot 23 key) key
+# Adds particles when digging a node.
+enable_particles (Digging particles) bool true
-# Key for selecting the 24th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot24 (Hotbar slot 24 key) key
+[**3d]
-# Key for selecting the 25th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot25 (Hotbar slot 25 key) key
+# 3D support.
+# Currently supported:
+# - none: no 3d output.
+# - anaglyph: cyan/magenta color 3d.
+# - interlaced: odd/even line based polarisation screen support.
+# - topbottom: split screen top/bottom.
+# - sidebyside: split screen side by side.
+# - crossview: Cross-eyed 3d
+# - pageflip: quadbuffer based 3d.
+# Note that the interlaced mode requires shaders to be enabled.
+3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,crossview,pageflip
-# Key for selecting the 26th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot26 (Hotbar slot 26 key) key
+# Strength of 3D mode parallax.
+3d_paralax_strength (3D mode parallax strength) float 0.025 -0.087 0.087
-# Key for selecting the 27th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot27 (Hotbar slot 27 key) key
+[**Bobbing]
-# Key for selecting the 28th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot28 (Hotbar slot 28 key) key
+# Arm inertia, gives a more realistic movement of
+# the arm when the camera moves.
+arm_inertia (Arm inertia) bool true
-# Key for selecting the 29th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot29 (Hotbar slot 29 key) key
+# Enable view bobbing and amount of view bobbing.
+# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
+view_bobbing_amount (View bobbing factor) float 1.0 0.0 7.9
-# Key for selecting the 30th hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot30 (Hotbar slot 30 key) key
+# Multiplier for fall bobbing.
+# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
+fall_bobbing_amount (Fall bobbing factor) float 0.03 0.0 100.0
-# Key for selecting the 31st hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot31 (Hotbar slot 31 key) key
+[**Camera]
-# Key for selecting the 32nd hotbar slot.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_slot32 (Hotbar slot 32 key) key
+# Camera 'near clipping plane' distance in nodes, between 0 and 0.25
+# Only works on GLES platforms. Most users will not need to change this.
+# Increasing can reduce artifacting on weaker GPUs.
+# 0.1 = Default, 0.25 = Good value for weaker tablets.
+near_plane (Near plane) float 0.1 0 0.25
-# Key for toggling the display of the HUD.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_hud (HUD toggle key) key KEY_F1
+# Field of view in degrees.
+fov (Field of view) int 72 45 160
-# Key for toggling the display of chat.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_chat (Chat toggle key) key KEY_F2
+# Alters the light curve by applying 'gamma correction' to it.
+# Higher values make middle and lower light levels brighter.
+# Value '1.0' leaves the light curve unaltered.
+# This only has significant effect on daylight and artificial
+# light, it has very little effect on natural night light.
+display_gamma (Light curve gamma) float 1.0 0.33 3.0
-# Key for toggling the display of the large chat console.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_console (Large chat console key) key KEY_F10
+# The strength (darkness) of node ambient-occlusion shading.
+# Lower is darker, Higher is lighter. The valid range of values for this
+# setting is 0.25 to 4.0 inclusive. If the value is out of range it will be
+# set to the nearest valid value.
+ambient_occlusion_gamma (Ambient occlusion gamma) float 2.2 0.25 4.0
-# Key for toggling the display of fog.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_force_fog_off (Fog toggle key) key KEY_F3
+[**Screenshots]
-# Key for toggling the camera update. Only used for development
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_update_camera (Camera update toggle key) key
+# Path to save screenshots at. Can be an absolute or relative path.
+# The folder will be created if it doesn't already exist.
+screenshot_path (Screenshot folder) path screenshots
-# Key for toggling the display of debug info.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_debug (Debug info toggle key) key KEY_F5
+# Format of screenshots.
+screenshot_format (Screenshot format) enum png png,jpg
-# Key for toggling the display of the profiler. Used for development.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_toggle_profiler (Profiler toggle key) key KEY_F6
+# Screenshot quality. Only used for JPEG format.
+# 1 means worst quality; 100 means best quality.
+# Use 0 for default quality.
+screenshot_quality (Screenshot quality) int 0 0 100
-# Key for switching between first- and third-person camera.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_camera_mode (Toggle camera mode key) key KEY_KEY_C
+[**Node and Entity Highlighting]
-# Key for increasing the viewing range.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_increase_viewing_range_min (View range increase key) key +
+# Method used to highlight selected object.
+node_highlighting (Node highlighting) enum box box,halo,none
-# Key for decreasing the viewing range.
-# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
-keymap_decrease_viewing_range_min (View range decrease key) key -
+# Show entity selection boxes
+# A restart is required after changing this.
+show_entity_selectionbox (Show entity selection boxes) bool false
-[Graphics]
+# Selection box border color (R,G,B).
+selectionbox_color (Selection box color) string (0,0,0)
-[*In-Game]
+# Width of the selection box lines around nodes.
+selectionbox_width (Selection box width) int 2 1 5
-[**Basic]
+# Crosshair color (R,G,B).
+# Also controls the object crosshair color
+crosshair_color (Crosshair color) string (255,255,255)
-# Whether name tag backgrounds should be shown by default.
-# Mods may still set a background.
-show_nametag_backgrounds (Show name tag backgrounds by default) bool true
+# Crosshair alpha (opaqueness, between 0 and 255).
+# This also applies to the object crosshair.
+crosshair_alpha (Crosshair alpha) int 255 0 255
-# Enable vertex buffer objects.
-# This should greatly improve graphics performance.
-enable_vbo (VBO) bool true
+[**Fog]
# Whether to fog out the end of the visible area.
enable_fog (Fog) bool true
-# Leaves style:
-# - Fancy: all faces visible
-# - Simple: only outer faces, if defined special_tiles are used
-# - Opaque: disable transparency
-leaves_style (Leaves style) enum fancy fancy,simple,opaque
-
-# Connects glass if supported by node.
-connected_glass (Connect glass) bool false
+# Make fog and sky colors depend on daytime (dawn/sunset) and view direction.
+directional_colored_fog (Colored fog) bool true
-# Enable smooth lighting with simple ambient occlusion.
-# Disable for speed or for different looks.
-smooth_lighting (Smooth lighting) bool true
+# Fraction of the visible distance at which fog starts to be rendered
+fog_start (Fog start) float 0.4 0.0 0.99
-# Enables tradeoffs that reduce CPU load or increase rendering performance
-# at the expense of minor visual glitches that do not impact game playability.
-performance_tradeoffs (Tradeoffs for performance) bool false
+[**Clouds]
# Clouds are a client side effect.
enable_clouds (Clouds) bool true
@@ -485,13 +305,7 @@ enable_clouds (Clouds) bool true
# Use 3D cloud look instead of flat.
enable_3d_clouds (3D clouds) bool true
-# Method used to highlight selected object.
-node_highlighting (Node highlighting) enum box box,halo,none
-
-# Adds particles when digging a node.
-enable_particles (Digging particles) bool true
-
-[**Filtering]
+[**Filtering and Antialiasing]
# Use mipmapping to scale textures. May slightly increase performance,
# especially when using a high resolution texture pack.
@@ -521,7 +335,7 @@ texture_clean_transparent (Clean transparent textures) bool false
# bilinear/trilinear/anisotropic filtering is enabled.
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
-texture_min_size (Minimum texture size) int 64
+texture_min_size (Minimum texture size) int 64 1 32768
# Use multi-sample antialiasing (MSAA) to smooth out block edges.
# This algorithm smooths out the 3D viewport while keeping the image sharp,
@@ -532,23 +346,15 @@ texture_min_size (Minimum texture size) int 64
# A restart is required after changing this option.
fsaa (FSAA) enum 0 0,1,2,4,8,16
-# Undersampling is similar to using a lower screen resolution, but it applies
-# to the game world only, keeping the GUI intact.
-# It should give a significant performance boost at the cost of less detailed image.
-# Higher values result in a less detailed image.
-undersampling (Undersampling) int 1 1 8
-[**Shaders]
+[*Shaders]
# Shaders allow advanced visual effects and may increase performance on some video
# cards.
# This only works with the OpenGL video backend.
enable_shaders (Shaders) bool true
-# Path to shader directory. If no path is defined, default location will be used.
-shader_path (Shader path) path
-
-[***Tone Mapping]
+[**Tone Mapping]
# Enables Hable's 'Uncharted 2' filmic tone mapping.
# Simulates the tone curve of photographic film and how this approximates the
@@ -556,7 +362,15 @@ shader_path (Shader path) path
# enhanced, highlights and shadows are gradually compressed.
tone_mapping (Filmic tone mapping) bool false
-[***Waving Nodes]
+[**Waving Nodes]
+
+# Set to true to enable waving leaves.
+# Requires shaders to be enabled.
+enable_waving_leaves (Waving leaves) bool false
+
+# Set to true to enable waving plants.
+# Requires shaders to be enabled.
+enable_waving_plants (Waving plants) bool false
# Set to true to enable waving liquids (like water).
# Requires shaders to be enabled.
@@ -578,132 +392,88 @@ water_wave_length (Waving liquids wavelength) float 20.0 0.1
# Requires waving liquids to be enabled.
water_wave_speed (Waving liquids wave speed) float 5.0
-# Set to true to enable waving leaves.
-# Requires shaders to be enabled.
-enable_waving_leaves (Waving leaves) bool false
+[**Dynamic shadows]
-# Set to true to enable waving plants.
+# Set to true to enable Shadow Mapping.
# Requires shaders to be enabled.
-enable_waving_plants (Waving plants) bool false
+enable_dynamic_shadows (Dynamic shadows) bool false
-[**Advanced]
-
-# Arm inertia, gives a more realistic movement of
-# the arm when the camera moves.
-arm_inertia (Arm inertia) bool true
-
-# If FPS would go higher than this, limit it by sleeping
-# to not waste CPU power for no benefit.
-fps_max (Maximum FPS) int 60 1
-
-# Maximum FPS when the window is not focused, or when the game is paused.
-fps_max_unfocused (FPS when unfocused or paused) int 20 1
+# Set the shadow strength gamma.
+# Adjusts the intensity of in-game dynamic shadows.
+# Lower value means lighter shadows, higher value means darker shadows.
+shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0
-# Open the pause menu when the window's focus is lost. Does not pause if a formspec is
-# open.
-pause_on_lost_focus (Pause on lost window focus) bool false
-
-# View distance in nodes.
-viewing_range (Viewing range) int 190 20 4000
-
-# Camera 'near clipping plane' distance in nodes, between 0 and 0.25
-# Only works on GLES platforms. Most users will not need to change this.
-# Increasing can reduce artifacting on weaker GPUs.
-# 0.1 = Default, 0.25 = Good value for weaker tablets.
-near_plane (Near plane) float 0.1 0 0.25
-
-# Width component of the initial window size. Ignored in fullscreen mode.
-screen_w (Screen width) int 1024 1
+# Maximum distance to render shadows.
+shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 120.0 10.0 1000.0
-# Height component of the initial window size. Ignored in fullscreen mode.
-screen_h (Screen height) int 600 1
+# Texture size to render the shadow map on.
+# This must be a power of two.
+# Bigger numbers create better shadows but it is also more expensive.
+shadow_map_texture_size (Shadow map texture size) int 1024 128 8192
-# Save window size automatically when modified.
-autosave_screensize (Autosave screen size) bool true
+# Sets shadow texture quality to 32 bits.
+# On false, 16 bits texture will be used.
+# This can cause much more artifacts in the shadow.
+shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
-# Fullscreen mode.
-fullscreen (Full screen) bool false
+# Enable Poisson disk filtering.
+# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
+shadow_poisson_filter (Poisson filtering) bool true
-# Vertical screen synchronization.
-vsync (VSync) bool false
+# Define shadow filtering quality.
+# This simulates the soft shadows effect by applying a PCF or Poisson disk
+# but also uses more resources.
+shadow_filters (Shadow filter quality) enum 1 0,1,2
-# Field of view in degrees.
-fov (Field of view) int 72 45 160
+# Enable colored shadows.
+# On true translucent nodes cast colored shadows. This is expensive.
+shadow_map_color (Colored shadows) bool false
-# Alters the light curve by applying 'gamma correction' to it.
-# Higher values make middle and lower light levels brighter.
-# Value '1.0' leaves the light curve unaltered.
-# This only has significant effect on daylight and artificial
-# light, it has very little effect on natural night light.
-display_gamma (Light curve gamma) float 1.0 0.33 3.0
+# Spread a complete update of shadow map over given amount of frames.
+# Higher values might make shadows laggy, lower values
+# will consume more resources.
+# Minimum value: 1; maximum value: 16
+shadow_update_frames (Map shadows update frames) int 8 1 16
-# Gradient of light curve at minimum light level.
-# Controls the contrast of the lowest light levels.
-lighting_alpha (Light curve low gradient) float 0.0 0.0 3.0
+# Set the soft shadow radius size.
+# Lower values mean sharper shadows, bigger values mean softer shadows.
+# Minimum value: 1.0; maximum value: 15.0
+shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0
-# Gradient of light curve at maximum light level.
-# Controls the contrast of the highest light levels.
-lighting_beta (Light curve high gradient) float 1.5 0.0 3.0
+# Set the tilt of Sun/Moon orbit in degrees.
+# Value of 0 means no tilt / vertical orbit.
+# Minimum value: 0.0; maximum value: 60.0
+shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 0.0 60.0
-# Strength of light curve boost.
-# The 3 'boost' parameters define a range of the light
-# curve that is boosted in brightness.
-lighting_boost (Light curve boost) float 0.2 0.0 0.4
+[*Audio]
-# Center of light curve boost range.
-# Where 0.0 is minimum light level, 1.0 is maximum light level.
-lighting_boost_center (Light curve boost center) float 0.5 0.0 1.0
+# Volume of all sounds.
+# Requires the sound system to be enabled.
+sound_volume (Volume) float 0.7 0.0 1.0
-# Spread of light curve boost range.
-# Controls the width of the range to be boosted.
-# Standard deviation of the light curve boost Gaussian.
-lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
+# Whether to mute sounds. You can unmute sounds at any time, unless the
+# sound system is disabled (enable_sound=false).
+# In-game, you can toggle the mute state with the mute key or by using the
+# pause menu.
+mute_sound (Mute sound) bool false
-# Path to texture directory. All textures are first searched from here.
-texture_path (Texture path) path
+[*User Interfaces]
-# The rendering back-end.
+# Set the language. Leave empty to use the system language.
# A restart is required after changing this.
-# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
-# On other platforms, OpenGL is recommended.
-# Shaders are supported by OpenGL (desktop only) and OGLES2 (experimental)
-video_driver (Video driver) enum opengl opengl,ogles1,ogles2
-
-# Radius of cloud area stated in number of 64 node cloud squares.
-# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
-cloud_radius (Cloud radius) int 12
-
-# Enable view bobbing and amount of view bobbing.
-# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
-view_bobbing_amount (View bobbing factor) float 1.0
-
-# Multiplier for fall bobbing.
-# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
-fall_bobbing_amount (Fall bobbing factor) float 0.03
-
-# 3D support.
-# Currently supported:
-# - none: no 3d output.
-# - anaglyph: cyan/magenta color 3d.
-# - interlaced: odd/even line based polarisation screen support.
-# - topbottom: split screen top/bottom.
-# - sidebyside: split screen side by side.
-# - crossview: Cross-eyed 3d
-# - pageflip: quadbuffer based 3d.
-# Note that the interlaced mode requires shaders to be enabled.
-3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,crossview,pageflip
-
-# Strength of 3D mode parallax.
-3d_paralax_strength (3D mode parallax strength) float 0.025
+language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW
-# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
-console_height (Console height) float 0.6 0.1 1.0
+[**GUIs]
-# In-game chat console background color (R,G,B).
-console_color (Console color) string (0,0,0)
+# Scale GUI by a user specified value.
+# Use a nearest-neighbor-anti-alias filter to scale the GUI.
+# This will smooth over some of the rough edges, and blend
+# pixels when scaling down, at the cost of blurring some
+# edge pixels when images are scaled by non-integer sizes.
+gui_scaling (GUI scaling) float 1.0 0.5 20
-# In-game chat console background alpha (opaqueness, between 0 and 255).
-console_alpha (Console alpha) int 200 0 255
+# Enables animation of inventory items.
+inventory_items_animations (Inventory items animations) bool false
# Formspec full-screen background opacity (between 0 and 255).
formspec_fullscreen_bg_opacity (Formspec Full-Screen Background Opacity) int 140 0 255
@@ -711,112 +481,6 @@ formspec_fullscreen_bg_opacity (Formspec Full-Screen Background Opacity) int 140
# Formspec full-screen background color (R,G,B).
formspec_fullscreen_bg_color (Formspec Full-Screen Background Color) string (0,0,0)
-# Formspec default background opacity (between 0 and 255).
-formspec_default_bg_opacity (Formspec Default Background Opacity) int 140 0 255
-
-# Formspec default background color (R,G,B).
-formspec_default_bg_color (Formspec Default Background Color) string (0,0,0)
-
-# Selection box border color (R,G,B).
-selectionbox_color (Selection box color) string (0,0,0)
-
-# Width of the selection box lines around nodes.
-selectionbox_width (Selection box width) int 2 1 5
-
-# Crosshair color (R,G,B).
-# Also controls the object crosshair color
-crosshair_color (Crosshair color) string (255,255,255)
-
-# Crosshair alpha (opaqueness, between 0 and 255).
-# This also applies to the object crosshair.
-crosshair_alpha (Crosshair alpha) int 255 0 255
-
-# Maximum number of recent chat messages to show
-recent_chat_messages (Recent Chat Messages) int 6 2 20
-
-# Whether node texture animations should be desynchronized per mapblock.
-desynchronize_mapblock_texture_animation (Desynchronize block animation) bool true
-
-# Maximum proportion of current window to be used for hotbar.
-# Useful if there's something to be displayed right or left of hotbar.
-hud_hotbar_max_width (Maximum hotbar width) float 1.0
-
-# Modifies the size of the HUD elements.
-hud_scaling (HUD scale factor) float 1.0
-
-# Enables caching of facedir rotated meshes.
-enable_mesh_cache (Mesh cache) bool false
-
-# Delay between mesh updates on the client in ms. Increasing this will slow
-# down the rate of mesh updates, thus reducing jitter on slower clients.
-mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
-
-# Size of the MapBlock cache of the mesh generator. Increasing this will
-# increase the cache hit %, reducing the data being copied from the main
-# thread, thus reducing jitter.
-meshgen_block_cache_size (Mapblock mesh generator's MapBlock cache size in MB) int 20 0 1000
-
-# Enables minimap.
-enable_minimap (Minimap) bool true
-
-# Shape of the minimap. Enabled = round, disabled = square.
-minimap_shape_round (Round minimap) bool true
-
-# True = 256
-# False = 128
-# Usable to make minimap smoother on slower machines.
-minimap_double_scan_height (Minimap scan height) bool true
-
-# Make fog and sky colors depend on daytime (dawn/sunset) and view direction.
-directional_colored_fog (Colored fog) bool true
-
-# The strength (darkness) of node ambient-occlusion shading.
-# Lower is darker, Higher is lighter. The valid range of values for this
-# setting is 0.25 to 4.0 inclusive. If the value is out of range it will be
-# set to the nearest valid value.
-ambient_occlusion_gamma (Ambient occlusion gamma) float 2.2 0.25 4.0
-
-# Enables animation of inventory items.
-inventory_items_animations (Inventory items animations) bool false
-
-# Fraction of the visible distance at which fog starts to be rendered
-fog_start (Fog start) float 0.4 0.0 0.99
-
-# Makes all liquids opaque
-opaque_water (Opaque liquids) bool false
-
-# Textures on a node may be aligned either to the node or to the world.
-# The former mode suits better things like machines, furniture, etc., while
-# the latter makes stairs and microblocks fit surroundings better.
-# However, as this possibility is new, thus may not be used by older servers,
-# this option allows enforcing it for certain node types. Note though that
-# that is considered EXPERIMENTAL and may not work properly.
-world_aligned_mode (World-aligned textures mode) enum enable disable,enable,force_solid,force_nodebox
-
-# World-aligned textures may be scaled to span several nodes. However,
-# the server may not send the scale you want, especially if you use
-# a specially-designed texture pack; with this option, the client tries
-# to determine the scale automatically basing on the texture size.
-# See also texture_min_size.
-# Warning: This option is EXPERIMENTAL!
-autoscale_mode (Autoscaling mode) enum disable disable,enable,force
-
-# Show entity selection boxes
-# A restart is required after changing this.
-show_entity_selectionbox (Show entity selection boxes) bool false
-
-[*Menus]
-
-# Use a cloud animation for the main menu background.
-menu_clouds (Clouds in menu) bool true
-
-# Scale GUI by a user specified value.
-# Use a nearest-neighbor-anti-alias filter to scale the GUI.
-# This will smooth over some of the rough edges, and blend
-# pixels when scaling down, at the cost of blurring some
-# edge pixels when images are scaled by non-integer sizes.
-gui_scaling (GUI scaling) float 1.0 0.001
-
# When gui_scaling_filter is true, all GUI images need to be
# filtered in software, but some images are generated directly
# to hardware (e.g. render-to-texture for nodes in inventory).
@@ -829,170 +493,105 @@ gui_scaling_filter (GUI scaling filter) bool false
gui_scaling_filter_txr2img (GUI scaling filter txr2img) bool true
# Delay showing tooltips, stated in milliseconds.
-tooltip_show_delay (Tooltip delay) int 400
+tooltip_show_delay (Tooltip delay) int 400 0 18446744073709551615
# Append item name to tooltip.
tooltip_append_itemname (Append item name) bool false
-font_bold (Font bold by default) bool false
-
-font_italic (Font italic by default) bool false
+# Use a cloud animation for the main menu background.
+menu_clouds (Clouds in menu) bool true
-# Shadow offset (in pixels) of the default font. If 0, then shadow will not be drawn.
-font_shadow (Font shadow) int 1
+[**HUD]
-# Opaqueness (alpha) of the shadow behind the default font, between 0 and 255.
-font_shadow_alpha (Font shadow alpha) int 127 0 255
+# Modifies the size of the HUD elements.
+hud_scaling (HUD scaling) float 1.0 0.5 20
-# Font size of the default font where 1 unit = 1 pixel at 96 DPI
-font_size (Font size) int 16 1
+# Whether name tag backgrounds should be shown by default.
+# Mods may still set a background.
+show_nametag_backgrounds (Show name tag backgrounds by default) bool true
-# For pixel-style fonts that do not scale well, this ensures that font sizes used
-# with this font will always be divisible by this value, in pixels. For instance,
-# a pixel font 16 pixels tall should have this set to 16, so it will only ever be
-# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32.
-font_size_divisible_by (Font size divisible by) int 1 1
+[**Chat]
-# Path to the default font. Must be a TrueType font.
-# The fallback font will be used if the font cannot be loaded.
-font_path (Regular font path) filepath fonts/Arimo-Regular.ttf
+# Maximum number of recent chat messages to show
+recent_chat_messages (Recent Chat Messages) int 6 2 20
-font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf
-font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf
-font_path_bold_italic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf
+# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
+console_height (Console height) float 0.6 0.1 1.0
-# Font size of the monospace font where 1 unit = 1 pixel at 96 DPI
-mono_font_size (Monospace font size) int 16 1
+# In-game chat console background color (R,G,B).
+console_color (Console color) string (0,0,0)
-# For pixel-style fonts that do not scale well, this ensures that font sizes used
-# with this font will always be divisible by this value, in pixels. For instance,
-# a pixel font 16 pixels tall should have this set to 16, so it will only ever be
-# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32.
-mono_font_size_divisible_by (Monospace font size divisible by) int 1 1
+# In-game chat console background alpha (opaqueness, between 0 and 255).
+console_alpha (Console alpha) int 200 0 255
-# Path to the monospace font. Must be a TrueType font.
-# This font is used for e.g. the console and profiler screen.
-mono_font_path (Monospace font path) filepath fonts/Cousine-Regular.ttf
+# Maximum proportion of current window to be used for hotbar.
+# Useful if there's something to be displayed right or left of hotbar.
+hud_hotbar_max_width (Maximum hotbar width) float 1.0 0.001 1.0
-mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf
-mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf
-mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf
+# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
+clickable_chat_weblinks (Chat weblinks) bool true
-# Path of the fallback font. Must be a TrueType font.
-# This font will be used for certain languages or if the default font is unavailable.
-fallback_font_path (Fallback font path) filepath fonts/DroidSansFallbackFull.ttf
+# Optional override for chat weblink color.
+chat_weblink_color (Weblink color) string
# Font size of the recent chat text and chat prompt in point (pt).
# Value 0 will use the default font size.
-chat_font_size (Chat font size) int 0
-
-# Path to save screenshots at. Can be an absolute or relative path.
-# The folder will be created if it doesn't already exist.
-screenshot_path (Screenshot folder) path screenshots
-
-# Format of screenshots.
-screenshot_format (Screenshot format) enum png png,jpg
-
-# Screenshot quality. Only used for JPEG format.
-# 1 means worst quality; 100 means best quality.
-# Use 0 for default quality.
-screenshot_quality (Screenshot quality) int 0 0 100
-
-[*Advanced]
+chat_font_size (Chat font size) int 0 0 72
-# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
-screen_dpi (DPI) int 72 1
-# Adjust the detected display density, used for scaling UI elements.
-display_density_factor (Display Density Scaling Factor) float 1
+[**Content Repository]
-# Windows systems only: Start Minetest with the command line window in the background.
-# Contains the same information as the file debug.txt (default name).
-enable_console (Enable console window) bool false
-
-[Sound]
-
-# Enables the sound system.
-# If disabled, this completely disables all sounds everywhere and the in-game
-# sound controls will be non-functional.
-# Changing this setting requires a restart.
-enable_sound (Sound) bool true
-
-# Volume of all sounds.
-# Requires the sound system to be enabled.
-sound_volume (Volume) float 0.7 0.0 1.0
-
-# Whether to mute sounds. You can unmute sounds at any time, unless the
-# sound system is disabled (enable_sound=false).
-# In-game, you can toggle the mute state with the mute key or by using the
-# pause menu.
-mute_sound (Mute sound) bool false
-
-[Client]
+# The URL for the content repository
+contentdb_url (ContentDB URL) string https://content.minetest.net
-# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
-clickable_chat_weblinks (Chat weblinks) bool false
+# Comma-separated list of flags to hide in the content repository.
+# "nonfree" can be used to hide packages which do not qualify as 'free software',
+# as defined by the Free Software Foundation.
+# You can also specify content ratings.
+# These flags are independent from Minetest versions,
+# so see a full list at https://content.minetest.net/help/content_flags/
+contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
-# Optional override for chat weblink color.
-chat_weblink_color (Weblink color) string
+# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
+# This should be lower than curl_parallel_limit.
+contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1
-[*Network]
-# Address to connect to.
-# Leave this blank to start a local server.
-# Note that the address field in the main menu overrides this setting.
-address (Server address) string
+[Client and Server]
-# Port to connect to (UDP).
-# Note that the port field in the main menu overrides this setting.
-remote_port (Remote port) int 30000 1 65535
-
-# Prometheus listener address.
-# If Minetest is compiled with ENABLE_PROMETHEUS option enabled,
-# enable metrics listener for Prometheus on that address.
-# Metrics can be fetched on http://127.0.0.1:30000/metrics
-prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
+[*Client]
# Save the map received by the client on disk.
enable_local_map_saving (Saving map received from server) bool false
-# Enable usage of remote media server (if provided by server).
-# Remote servers offer a significantly faster way to download media (e.g. textures)
-# when connecting to the server.
-enable_remote_media_server (Connect to external media server) bool true
-
-# Enable Lua modding support on client.
-# This support is experimental and API can change.
-enable_client_modding (Client modding) bool false
-
# URL to the server list displayed in the Multiplayer Tab.
serverlist_url (Serverlist URL) string servers.minetest.net
-# File in client/serverlist/ that contains your favorite servers displayed in the
-# Multiplayer Tab.
-serverlist_file (Serverlist file) string favoriteservers.json
-
-# Maximum size of the out chat queue.
-# 0 to disable queueing and -1 to make the queue size unlimited.
-max_out_chat_queue_size (Maximum size of the out chat queue) int 20
+# If enabled, account registration is separate from login in the UI.
+# If disabled, new accounts will be registered automatically when logging in.
+enable_split_login_register (Enable split login/register) bool true
-# Enable register confirmation when connecting to server.
-# If disabled, new account will be registered automatically.
-enable_register_confirmation (Enable register confirmation) bool true
+# URL to JSON file which provides information about the newest Minetest release
+update_information_url (Update information URL) string https://www.minetest.net/release_info.json
-[*Advanced]
+# Unix timestamp (integer) of when the client last checked for an update
+# Set this value to "disabled" to never check for updates.
+update_last_checked (Last update check) string
-# Timeout for client to remove unused map data from memory.
-client_unload_unused_data_timeout (Mapblock unload timeout) int 600
+# Version number which was last seen during an update check.
+#
+# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch
+# Ex: 5.5.0 is 005005000
+update_last_known (Last known version update) int 0
-# Maximum number of mapblocks for client to be kept in memory.
-# Set to -1 for unlimited amount.
-client_mapblock_limit (Mapblock limit) int 7500
+[*Server]
-# Whether to show the client debug info (has the same effect as hitting F5).
-show_debug (Show debug info) bool false
+# Name of the player.
+# When running a server, clients connecting with this name are admins.
+# When starting from the main menu, this is overridden.
+name (Admin name) string
-[Server / Singleplayer]
+[**Serverlist and MOTD]
# Name of the server, to be displayed when players join and in the serverlist.
server_name (Server name) string Minetest server
@@ -1012,15 +611,20 @@ server_announce (Announce server) bool false
# Announce to this serverlist.
serverlist_url (Serverlist URL) string servers.minetest.net
-# Remove color codes from incoming chat messages
-# Use this to stop players from being able to use color in their messages
-strip_color_codes (Strip color codes) bool false
+# Message of the day displayed to players connecting.
+motd (Message of the day) string
-[*Network]
+# Maximum number of players that can be connected simultaneously.
+max_users (Maximum users) int 15 0 65535
+
+# If this is set, players will always (re)spawn at the given position.
+static_spawnpoint (Static spawnpoint) string
+
+[**Networking]
# Network port to listen (UDP).
# This value will be overridden when starting from the main menu.
-port (Server port) int 30000
+port (Server port) int 30000 1 65535
# The network interface that the server listens on.
bind_address (Bind address) string
@@ -1041,65 +645,14 @@ remote_media (Remote media) string
# Needs enable_ipv6 to be enabled.
ipv6_server (IPv6 server) bool false
-[**Advanced]
-
-# Maximum number of blocks that are simultaneously sent per client.
-# The maximum total count is calculated dynamically:
-# max_total = ceil((#clients + max_users) * per_client / 4)
-max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 40
-
-# To reduce lag, block transfers are slowed down when a player is building something.
-# This determines how long they are slowed down after placing or removing a node.
-full_block_send_enable_min_time_from_building (Delay in sending blocks after building) float 2.0
-
-# Maximum number of packets sent per send step, if you have a slow connection
-# try reducing it, but don't reduce it to a number below double of targeted
-# client number.
-max_packets_per_iteration (Max. packets per iteration) int 1024
-
-# Compression level to use when sending mapblocks to the client.
-# -1 - use default compression level
-# 0 - least compression, fastest
-# 9 - best compression, slowest
-map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
-
-[*Game]
-
-# Default game when creating a new world.
-# This will be overridden when creating a world from the main menu.
-default_game (Default game) string minetest
-
-# Message of the day displayed to players connecting.
-motd (Message of the day) string
-
-# Maximum number of players that can be connected simultaneously.
-max_users (Maximum users) int 15
-
-# World directory (everything in the world is stored here).
-# Not needed if starting from the main menu.
-map-dir (Map directory) path
-
-# Time in seconds for item entity (dropped items) to live.
-# Setting it to -1 disables the feature.
-item_entity_ttl (Item entity TTL) int 900
-
-# Specifies the default stack size of nodes, items and tools.
-# Note that mods or games may explicitly set a stack for certain (or all) items.
-default_stack_max (Default stack size) int 99
-
-# Enable players getting damage and dying.
-enable_damage (Damage) bool false
-
-# Enable creative mode for all players
-creative_mode (Creative) bool false
-
-# A chosen map seed for a new map, leave empty for random.
-# Will be overridden when creating a new world in the main menu.
-fixed_map_seed (Fixed map seed) string
+[*Server Security]
# New users need to input this password.
default_password (Default password) string
+# If enabled, players cannot join without a password or change theirs to an empty password.
+disallow_empty_password (Disallow empty passwords) bool false
+
# The privileges that new users automatically get.
# See /privs in game for a full list on your server and mod configuration.
default_privs (Default privileges) string interact, shout
@@ -1107,25 +660,6 @@ default_privs (Default privileges) string interact, shout
# Privileges that players with basic_privs can grant
basic_privs (Basic privileges) string interact, shout
-# Whether players are shown to clients without any range limit.
-# Deprecated, use the setting player_transfer_distance instead.
-unlimited_player_transfer_distance (Unlimited player transfer distance) bool true
-
-# Defines the maximal player transfer distance in blocks (0 = unlimited).
-player_transfer_distance (Player transfer distance) int 0
-
-# Whether to allow players to damage and kill each other.
-enable_pvp (Player versus player) bool true
-
-# Enable mod channels support.
-enable_mod_channels (Mod channels) bool false
-
-# If this is set, players will always (re)spawn at the given position.
-static_spawnpoint (Static spawnpoint) string
-
-# If enabled, players cannot join without a password or change theirs to an empty password.
-disallow_empty_password (Disallow empty passwords) bool false
-
# If enabled, disable cheat prevention in multiplayer.
disable_anticheat (Disable anticheat) bool false
@@ -1133,317 +667,108 @@ disable_anticheat (Disable anticheat) bool false
# This option is only read when server starts.
enable_rollback_recording (Rollback recording) bool false
-# Format of player chat messages. The following strings are valid placeholders:
-# @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
+[**Client-side Modding]
-# A message to be displayed to all clients when the server shuts down.
-kick_msg_shutdown (Shutdown message) string Server shutting down.
+# Restricts the access of certain client-side functions on servers.
+# Combine the byteflags below to restrict client-side features, or set to 0
+# for no restrictions:
+# LOAD_CLIENT_MODS: 1 (disable loading client-provided mods)
+# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
+# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
+# READ_NODEDEFS: 8 (disable get_node_def call client-side)
+# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to
+# csm_restriction_noderange)
+# READ_PLAYERINFO: 32 (disable get_player_names call client-side)
+csm_restriction_flags (Client side modding restrictions) int 62 0 63
-# A message to be displayed to all clients when the server crashes.
-kick_msg_crash (Crash message) string This server has experienced an internal error. You will now be disconnected.
+# If the CSM restriction for node range is enabled, get_node calls are limited
+# to this distance from the player to the node.
+csm_restriction_noderange (Client side node lookup range restriction) int 0 0 4294967295
-# Whether to ask clients to reconnect after a (Lua) crash.
-# Set this to true if your server is set up to restart automatically.
-ask_reconnect_on_crash (Ask to reconnect after crash) bool false
+[**Chat]
-# From how far clients know about objects, stated in mapblocks (16 nodes).
-#
-# Setting this larger than active_block_range will also cause the server
-# to maintain active objects up to this distance in the direction the
-# player is looking. (This can avoid mobs suddenly disappearing from view)
-active_object_send_range_blocks (Active object send range) int 8
+# Remove color codes from incoming chat messages
+# Use this to stop players from being able to use color in their messages
+strip_color_codes (Strip color codes) bool false
-# The radius of the volume of blocks around every player that is subject to the
-# active block stuff, stated in mapblocks (16 nodes).
-# In active blocks objects are loaded and ABMs run.
-# This is also the minimum range in which active objects (mobs) are maintained.
-# This should be configured together with active_object_send_range_blocks.
-active_block_range (Active block range) int 4
+# Set the maximum length of a chat message (in characters) sent by clients.
+chat_message_max_size (Chat message max length) int 500 10 65535
-# From how far blocks are sent to clients, stated in mapblocks (16 nodes).
-max_block_send_distance (Max block send distance) int 12
+# Amount of messages a player may send per 10 seconds.
+chat_message_limit_per_10sec (Chat message count limit) float 10.0 1.0
-# Maximum number of forceloaded mapblocks.
-max_forceloaded_blocks (Maximum forceloaded blocks) int 16
+# Kick players who sent more than X messages per 10 seconds.
+chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
-# Interval of sending time of day to clients.
-time_send_interval (Time send interval) int 5
+[*Server Gameplay]
# Controls length of day/night cycle.
# Examples:
# 72 = 20min, 360 = 4min, 1 = 24hour, 0 = day/night/whatever stays unchanged.
-time_speed (Time speed) int 72
+time_speed (Time speed) int 72 0
# Time of day when a new world is started, in millihours (0-23999).
world_start_time (World start time) int 6125 0 23999
-# Interval of saving important changes in the world, stated in seconds.
-server_map_save_interval (Map save interval) float 5.3
-
-# Set the maximum character length of a chat message sent by clients.
-chat_message_max_size (Chat message max length) int 500
-
-# Amount of messages a player may send per 10 seconds.
-chat_message_limit_per_10sec (Chat message count limit) float 10.0
+# Time in seconds for item entity (dropped items) to live.
+# Setting it to -1 disables the feature.
+item_entity_ttl (Item entity TTL) int 900 -1
-# Kick players who sent more than X messages per 10 seconds.
-chat_message_limit_trigger_kick (Chat message kick threshold) int 50
+# Specifies the default stack size of nodes, items and tools.
+# Note that mods or games may explicitly set a stack for certain (or all) items.
+default_stack_max (Default stack size) int 99 1 65535
[**Physics]
# Horizontal and vertical acceleration on ground or when climbing,
# in nodes per second per second.
-movement_acceleration_default (Default acceleration) float 3
+movement_acceleration_default (Default acceleration) float 3.0 0.0
# Horizontal acceleration in air when jumping or falling,
# in nodes per second per second.
-movement_acceleration_air (Acceleration in air) float 2
+movement_acceleration_air (Acceleration in air) float 2.0 0.0
# Horizontal and vertical acceleration in fast mode,
# in nodes per second per second.
-movement_acceleration_fast (Fast mode acceleration) float 10
+movement_acceleration_fast (Fast mode acceleration) float 10.0 0.0
# Walking and flying speed, in nodes per second.
-movement_speed_walk (Walking speed) float 4
+movement_speed_walk (Walking speed) float 4.0 0.0
# Sneaking speed, in nodes per second.
-movement_speed_crouch (Sneaking speed) float 1.35
+movement_speed_crouch (Sneaking speed) float 1.35 0.0
# Walking, flying and climbing speed in fast mode, in nodes per second.
-movement_speed_fast (Fast mode speed) float 20
+movement_speed_fast (Fast mode speed) float 20.0 0.0
# Vertical climbing speed, in nodes per second.
-movement_speed_climb (Climbing speed) float 3
+movement_speed_climb (Climbing speed) float 3.0 0.0
# Initial vertical speed when jumping, in nodes per second.
-movement_speed_jump (Jumping speed) float 6.5
+movement_speed_jump (Jumping speed) float 6.5 0.0
+# How much you are slowed down when moving inside a liquid.
# Decrease this to increase liquid resistance to movement.
-movement_liquid_fluidity (Liquid fluidity) float 1
+movement_liquid_fluidity (Liquid fluidity) float 1.0 0.001
# Maximum liquid resistance. Controls deceleration when entering liquid at
# high speed.
movement_liquid_fluidity_smooth (Liquid fluidity smoothing) float 0.5
-# Controls sinking speed in liquid.
-movement_liquid_sink (Liquid sinking) float 10
+# Controls sinking speed in liquid when idling. Negative values will cause
+# you to rise instead.
+movement_liquid_sink (Liquid sinking) float 10.0
# Acceleration of gravity, in nodes per second per second.
movement_gravity (Gravity) float 9.81
-[**Advanced]
-
-# Handling for deprecated Lua API calls:
-# - none: Do not log deprecated calls
-# - log: mimic and log backtrace of deprecated call (default).
-# - error: abort on usage of deprecated call (suggested for mod developers).
-deprecated_lua_api_handling (Deprecated Lua API handling) enum log none,log,error
-
-# Number of extra blocks that can be loaded by /clearobjects at once.
-# This is a trade-off between SQLite transaction overhead and
-# memory consumption (4096=100MB, as a rule of thumb).
-max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) int 4096
-
-# How much the server will wait before unloading unused mapblocks.
-# Higher value is smoother, but will use more RAM.
-server_unload_unused_data_timeout (Unload unused server data) int 29
-
-# Maximum number of statically stored objects in a block.
-max_objects_per_block (Maximum objects per block) int 64
-
-# See https://www.sqlite.org/pragma.html#pragma_synchronous
-sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
-
-# Compression level to use when saving mapblocks to disk.
-# -1 - use default compression level
-# 0 - least compression, fastest
-# 9 - best compression, slowest
-map_compression_level_disk (Map Compression Level for Disk Storage) int -1 -1 9
-
-# Length of a server tick and the interval at which objects are generally updated over
-# network.
-dedicated_server_step (Dedicated server step) float 0.09
-
-# Length of time between active block management cycles
-active_block_mgmt_interval (Active block management interval) float 2.0
-
-# Length of time between Active Block Modifier (ABM) execution cycles
-abm_interval (ABM interval) float 1.0
-
-# The time budget allowed for ABMs to execute on each step
-# (as a fraction of the ABM Interval)
-abm_time_budget (ABM time budget) float 0.2 0.1 0.9
-
-# Length of time between NodeTimer execution cycles
-nodetimer_interval (NodeTimer interval) float 0.2
-
-# If enabled, invalid world data won't cause the server to shut down.
-# Only enable this if you know what you are doing.
-ignore_world_load_errors (Ignore world errors) bool false
-
-# Max liquids processed per step.
-liquid_loop_max (Liquid loop max) int 100000
-
-# The time (in seconds) that the liquids queue may grow beyond processing
-# capacity until an attempt is made to decrease its size by dumping old queue
-# items. A value of 0 disables the functionality.
-liquid_queue_purge_time (Liquid queue purge time) int 0
-
-# Liquid update interval in seconds.
-liquid_update (Liquid update tick) float 1.0
-
-# At this distance the server will aggressively optimize which blocks are sent to
-# clients.
-# Small values potentially improve performance a lot, at the expense of visible
-# rendering glitches (some blocks will not be rendered under water and in caves,
-# as well as sometimes on land).
-# Setting this to a value greater than max_block_send_distance disables this
-# optimization.
-# Stated in mapblocks (16 nodes).
-block_send_optimize_distance (Block send optimize distance) int 4 2
-
-# If enabled the server will perform map block occlusion culling based on
-# on the eye position of the player. This can reduce the number of blocks
-# sent to the client 50-80%. The client will not longer receive most invisible
-# so that the utility of noclip mode is reduced.
-server_side_occlusion_culling (Server side occlusion culling) bool true
-
-# Restricts the access of certain client-side functions on servers.
-# Combine the byteflags below to restrict client-side features, or set to 0
-# for no restrictions:
-# LOAD_CLIENT_MODS: 1 (disable loading client-provided mods)
-# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
-# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
-# READ_NODEDEFS: 8 (disable get_node_def call client-side)
-# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to
-# csm_restriction_noderange)
-# READ_PLAYERINFO: 32 (disable get_player_names call client-side)
-csm_restriction_flags (Client side modding restrictions) int 62
-
-# If the CSM restriction for node range is enabled, get_node calls are limited
-# to this distance from the player to the node.
-csm_restriction_noderange (Client side node lookup range restriction) int 0
-
-[*Security]
-
-# Prevent mods from doing insecure things like running shell commands.
-secure.enable_security (Enable mod security) bool true
-
-# Comma-separated list of trusted mods that are allowed to access insecure
-# functions even when mod security is on (via request_insecure_environment()).
-secure.trusted_mods (Trusted mods) string
-
-# Comma-separated list of mods that are allowed to access HTTP APIs, which
-# allow them to upload and download data to/from the internet.
-secure.http_mods (HTTP mods) string
-
-[*Advanced]
-
-[**Profiling]
-# Load the game profiler to collect game profiling data.
-# Provides a /profiler command to access the compiled profile.
-# Useful for mod developers and server operators.
-profiler.load (Load the game profiler) bool false
-
-# The default format in which profiles are being saved,
-# when calling `/profiler save [format]` without format.
-profiler.default_report_format (Default report format) enum txt txt,csv,lua,json,json_pretty
-
-# The file path relative to your worldpath in which profiles will be saved to.
-profiler.report_path (Report path) string ""
-
-[***Instrumentation]
-
-# Instrument the methods of entities on registration.
-instrument.entity (Entity methods) bool true
-
-# Instrument the action function of Active Block Modifiers on registration.
-instrument.abm (Active Block Modifiers) bool true
-
-# Instrument the action function of Loading Block Modifiers on registration.
-instrument.lbm (Loading Block Modifiers) bool true
-
-# Instrument chat commands on registration.
-instrument.chatcommand (Chat commands) bool true
-
-# Instrument global callback functions on registration.
-# (anything you pass to a minetest.register_*() function)
-instrument.global_callback (Global callbacks) bool true
-
-[****Advanced]
-# Instrument builtin.
-# This is usually only needed by core/builtin contributors
-instrument.builtin (Builtin) bool false
-
-# Have the profiler instrument itself:
-# * Instrument an empty function.
-# This estimates the overhead, that instrumentation is adding (+1 function call).
-# * Instrument the sampler being used to update the statistics.
-instrument.profiler (Profiler) bool false
-
-[Client and Server]
-
-# Name of the player.
-# When running a server, clients connecting with this name are admins.
-# When starting from the main menu, this is overridden.
-name (Player name) string
-
-# Set the language. Leave empty to use the system language.
-# A restart is required after changing this.
-language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW
-
-# Level of logging to be written to debug.txt:
-# - <nothing> (no logging)
-# - none (messages with no level)
-# - error
-# - warning
-# - action
-# - info
-# - verbose
-debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose
-
-# If the file size of debug.txt exceeds the number of megabytes specified in
-# this setting when it is opened, the file is moved to debug.txt.1,
-# deleting an older debug.txt.1 if it exists.
-# debug.txt is only moved if this setting is positive.
-debug_log_size_max (Debug log file size threshold) int 50
-
-# Minimal level of logging to be written to chat.
-chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose
-
-# Enable IPv6 support (for both client and server).
-# Required for IPv6 connections to work at all.
-enable_ipv6 (IPv6) bool true
-
-[*Advanced]
-
-# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
-curl_timeout (cURL interactive timeout) int 20000
-
-# Limits number of parallel HTTP requests. Affects:
-# - Media fetch if server uses remote_media setting.
-# - Serverlist download and server announcement.
-# - Downloads performed by main menu (e.g. mod manager).
-# Only has an effect if compiled with cURL.
-curl_parallel_limit (cURL parallel limit) int 8
-
-# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
-curl_file_download_timeout (cURL file download timeout) int 300000
-
-# Replaces the default main menu with a custom one.
-main_menu_script (Main menu script) string
-
-# Print the engine's profiling data in regular intervals (in seconds).
-# 0 = disable. Useful for developers.
-profiler_print_interval (Engine profiling data print interval) int 0
[Mapgen]
+# A chosen map seed for a new map, leave empty for random.
+# Will be overridden when creating a new world in the main menu.
+fixed_map_seed (Fixed map seed) string
+
# Name of map generator to be used when creating a new world.
# Creating a world in the main menu will override this.
# Current mapgens in a highly unstable state:
@@ -1451,10 +776,10 @@ profiler_print_interval (Engine profiling data print interval) int 0
mg_name (Mapgen name) enum v7 v7,valleys,carpathian,v5,flat,fractal,singlenode,v6
# Water surface level of the world.
-water_level (Water level) int 1
+water_level (Water level) int 1 -31000 31000
# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
-max_block_generate_distance (Max block generate distance) int 10
+max_block_generate_distance (Max block generate distance) int 10 1 32767
# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).
# Only mapchunks completely within the mapgen limit are generated.
@@ -1466,7 +791,7 @@ mapgen_limit (Map generation limit) int 31007 0 31007
# and jungle grass, in all other mapgens this flag controls all decorations.
mg_flags (Mapgen flags) flags caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores,nocaves,nodungeons,nolight,nodecorations,nobiomes,noores
-[*Biome API temperature and humidity noise parameters]
+[*Biome API noise parameters]
# Temperature variation for biomes.
mg_biome_np_heat (Heat noise) noise_params_2d 50, 50, (1000, 1000, 1000), 5349, 3, 0.5, 2.0, eased
@@ -1491,7 +816,7 @@ mgv5_spflags (Mapgen V5 specific flags) flags caverns caverns,nocaverns
mgv5_cave_width (Cave width) float 0.09
# Y of upper limit of large caves.
-mgv5_large_cave_depth (Large cave depth) int -256
+mgv5_large_cave_depth (Large cave depth) int -256 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgv5_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -1509,19 +834,19 @@ mgv5_large_cave_num_max (Large cave maximum number) int 2 0 64
mgv5_large_cave_flooded (Large cave proportion flooded) float 0.5 0.0 1.0
# Y-level of cavern upper limit.
-mgv5_cavern_limit (Cavern limit) int -256
+mgv5_cavern_limit (Cavern limit) int -256 -31000 31000
# Y-distance over which caverns expand to full size.
-mgv5_cavern_taper (Cavern taper) int 256
+mgv5_cavern_taper (Cavern taper) int 256 0 32767
# Defines full size of caverns, smaller values create larger caverns.
mgv5_cavern_threshold (Cavern threshold) float 0.7
# Lower Y limit of dungeons.
-mgv5_dungeon_ymin (Dungeon minimum Y) int -31000
+mgv5_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgv5_dungeon_ymax (Dungeon maximum Y) int 31000
+mgv5_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
[**Noises]
@@ -1566,10 +891,10 @@ mgv6_freq_desert (Desert noise threshold) float 0.45
mgv6_freq_beach (Beach noise threshold) float 0.15
# Lower Y limit of dungeons.
-mgv6_dungeon_ymin (Dungeon minimum Y) int -31000
+mgv6_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgv6_dungeon_ymax (Dungeon maximum Y) int 31000
+mgv6_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
[**Noises]
@@ -1615,19 +940,19 @@ mgv6_np_apple_trees (Apple trees noise) noise_params_2d 0, 1, (100, 100, 100), 3
mgv7_spflags (Mapgen V7 specific flags) flags mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns,nomountains,noridges,nofloatlands,nocaverns
# Y of mountain density gradient zero level. Used to shift mountains vertically.
-mgv7_mount_zero_level (Mountain zero level) int 0
+mgv7_mount_zero_level (Mountain zero level) int 0 -31000 31000
# Lower Y limit of floatlands.
-mgv7_floatland_ymin (Floatland minimum Y) int 1024
+mgv7_floatland_ymin (Floatland minimum Y) int 1024 -31000 31000
# Upper Y limit of floatlands.
-mgv7_floatland_ymax (Floatland maximum Y) int 4096
+mgv7_floatland_ymax (Floatland maximum Y) int 4096 -31000 31000
# Y-distance over which floatlands taper from full density to nothing.
# Tapering starts at this distance from the Y limit.
# For a solid floatland layer, this controls the height of hills/mountains.
# Must be less than or equal to half the distance between the Y limits.
-mgv7_floatland_taper (Floatland tapering distance) int 256
+mgv7_floatland_taper (Floatland tapering distance) int 256 0 32767
# Exponent of the floatland tapering. Alters the tapering behaviour.
# Value = 1.0 creates a uniform, linear tapering.
@@ -1654,7 +979,7 @@ mgv7_floatland_density (Floatland density) float -0.6
# required value depending on 'mgv7_np_floatland'), to avoid
# server-intensive extreme water flow and to avoid vast flooding of the
# world surface below.
-mgv7_floatland_ywater (Floatland water level) int -31000
+mgv7_floatland_ywater (Floatland water level) int -31000 -31000 31000
# Controls width of tunnels, a smaller value creates wider tunnels.
# Value >= 10.0 completely disables generation of tunnels and avoids the
@@ -1662,7 +987,7 @@ mgv7_floatland_ywater (Floatland water level) int -31000
mgv7_cave_width (Cave width) float 0.09
# Y of upper limit of large caves.
-mgv7_large_cave_depth (Large cave depth) int -33
+mgv7_large_cave_depth (Large cave depth) int -33 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgv7_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -1680,19 +1005,19 @@ mgv7_large_cave_num_max (Large cave maximum number) int 2 0 64
mgv7_large_cave_flooded (Large cave proportion flooded) float 0.5 0.0 1.0
# Y-level of cavern upper limit.
-mgv7_cavern_limit (Cavern limit) int -256
+mgv7_cavern_limit (Cavern limit) int -256 -31000 31000
# Y-distance over which caverns expand to full size.
-mgv7_cavern_taper (Cavern taper) int 256
+mgv7_cavern_taper (Cavern taper) int 256 0 32767
# Defines full size of caverns, smaller values create larger caverns.
mgv7_cavern_threshold (Cavern threshold) float 0.7
# Lower Y limit of dungeons.
-mgv7_dungeon_ymin (Dungeon minimum Y) int -31000
+mgv7_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgv7_dungeon_ymax (Dungeon maximum Y) int 31000
+mgv7_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
[**Noises]
@@ -1766,7 +1091,7 @@ mgcarpathian_valley_width (River valley width) float 0.25
mgcarpathian_cave_width (Cave width) float 0.09
# Y of upper limit of large caves.
-mgcarpathian_large_cave_depth (Large cave depth) int -33
+mgcarpathian_large_cave_depth (Large cave depth) int -33 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgcarpathian_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -1784,19 +1109,19 @@ mgcarpathian_large_cave_num_max (Large cave maximum number) int 2 0 64
mgcarpathian_large_cave_flooded (Large cave proportion flooded) float 0.5 0.0 1.0
# Y-level of cavern upper limit.
-mgcarpathian_cavern_limit (Cavern limit) int -256
+mgcarpathian_cavern_limit (Cavern limit) int -256 -31000 31000
# Y-distance over which caverns expand to full size.
-mgcarpathian_cavern_taper (Cavern taper) int 256
+mgcarpathian_cavern_taper (Cavern taper) int 256 0 32767
# Defines full size of caverns, smaller values create larger caverns.
mgcarpathian_cavern_threshold (Cavern threshold) float 0.7
# Lower Y limit of dungeons.
-mgcarpathian_dungeon_ymin (Dungeon minimum Y) int -31000
+mgcarpathian_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgcarpathian_dungeon_ymax (Dungeon maximum Y) int 31000
+mgcarpathian_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
[**Noises]
@@ -1858,10 +1183,10 @@ mgcarpathian_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 50
mgflat_spflags (Mapgen Flat specific flags) flags nolakes,nohills,nocaverns lakes,hills,caverns,nolakes,nohills,nocaverns
# Y of flat ground.
-mgflat_ground_level (Ground level) int 8
+mgflat_ground_level (Ground level) int 8 -31000 31000
# Y of upper limit of large caves.
-mgflat_large_cave_depth (Large cave depth) int -33
+mgflat_large_cave_depth (Large cave depth) int -33 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgflat_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -1900,19 +1225,19 @@ mgflat_hill_threshold (Hill threshold) float 0.45
mgflat_hill_steepness (Hill steepness) float 64.0
# Y-level of cavern upper limit.
-mgflat_cavern_limit (Cavern limit) int -256
+mgflat_cavern_limit (Cavern limit) int -256 -31000 31000
# Y-distance over which caverns expand to full size.
-mgflat_cavern_taper (Cavern taper) int 256
+mgflat_cavern_taper (Cavern taper) int 256 0 32767
# Defines full size of caverns, smaller values create larger caverns.
mgflat_cavern_threshold (Cavern threshold) float 0.7
# Lower Y limit of dungeons.
-mgflat_dungeon_ymin (Dungeon minimum Y) int -31000
+mgflat_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgflat_dungeon_ymax (Dungeon maximum Y) int 31000
+mgflat_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
[**Noises]
@@ -1947,7 +1272,7 @@ mgfractal_spflags (Mapgen Fractal specific flags) flags terrain terrain,noterrai
mgfractal_cave_width (Cave width) float 0.09
# Y of upper limit of large caves.
-mgfractal_large_cave_depth (Large cave depth) int -33
+mgfractal_large_cave_depth (Large cave depth) int -33 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgfractal_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -1965,10 +1290,10 @@ mgfractal_large_cave_num_max (Large cave maximum number) int 2 0 64
mgfractal_large_cave_flooded (Large cave proportion flooded) float 0.5 0.0 1.0
# Lower Y limit of dungeons.
-mgfractal_dungeon_ymin (Dungeon minimum Y) int -31000
+mgfractal_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgfractal_dungeon_ymax (Dungeon maximum Y) int 31000
+mgfractal_dungeon_ymax (Dungeon maximum Y) int 31000 -31000 31000
# Selects one of 18 fractal types.
# 1 = 4D "Roundy" Mandelbrot set.
@@ -1995,7 +1320,7 @@ mgfractal_fractal (Fractal type) int 1 1 18
# Increasing this increases the amount of fine detail, but also
# increases processing load.
# At iterations = 20 this mapgen has a similar load to mapgen V7.
-mgfractal_iterations (Iterations) int 11
+mgfractal_iterations (Iterations) int 11 1 65535
# (X,Y,Z) scale of fractal in nodes.
# Actual fractal size will be 2 to 3 times larger.
@@ -2078,10 +1403,10 @@ mgvalleys_spflags (Mapgen Valleys specific flags) flags altitude_chill,humid_riv
# The vertical distance over which heat drops by 20 if 'altitude_chill' is
# enabled. Also the vertical distance over which humidity drops by 10 if
# 'altitude_dry' is enabled.
-mgvalleys_altitude_chill (Altitude chill) int 90
+mgvalleys_altitude_chill (Altitude chill) int 90 0 65535
# Depth below which you'll find large caves.
-mgvalleys_large_cave_depth (Large cave depth) int -33
+mgvalleys_large_cave_depth (Large cave depth) int -33 -31000 31000
# Minimum limit of random number of small caves per mapchunk.
mgvalleys_small_cave_num_min (Small cave minimum number) int 0 0 256
@@ -2099,19 +1424,19 @@ mgvalleys_large_cave_num_max (Large cave maximum number) int 2 0 64
mgvalleys_large_cave_flooded (Large cave proportion flooded) float 0.5 0.0 1.0
# Depth below which you'll find giant caverns.
-mgvalleys_cavern_limit (Cavern upper limit) int -256
+mgvalleys_cavern_limit (Cavern upper limit) int -256 -31000 31000
# Y-distance over which caverns expand to full size.
-mgvalleys_cavern_taper (Cavern taper) int 192
+mgvalleys_cavern_taper (Cavern taper) int 192 0 32767
# Defines full size of caverns, smaller values create larger caverns.
mgvalleys_cavern_threshold (Cavern threshold) float 0.6
# How deep to make rivers.
-mgvalleys_river_depth (River depth) int 4
+mgvalleys_river_depth (River depth) int 4 0 65535
# How wide to make rivers.
-mgvalleys_river_size (River size) int 5
+mgvalleys_river_size (River size) int 5 0 65535
# Controls width of tunnels, a smaller value creates wider tunnels.
# Value >= 10.0 completely disables generation of tunnels and avoids the
@@ -2119,10 +1444,10 @@ mgvalleys_river_size (River size) int 5
mgvalleys_cave_width (Cave width) float 0.09
# Lower Y limit of dungeons.
-mgvalleys_dungeon_ymin (Dungeon minimum Y) int -31000
+mgvalleys_dungeon_ymin (Dungeon minimum Y) int -31000 -31000 31000
# Upper Y limit of dungeons.
-mgvalleys_dungeon_ymax (Dungeon maximum Y) int 63
+mgvalleys_dungeon_ymax (Dungeon maximum Y) int 63 -31000 31000
[**Noises]
@@ -2159,15 +1484,413 @@ mgvalleys_np_inter_valley_slope (Valley slope) noise_params_2d 0.5, 0.5, (128, 1
# 3D noise that determines number of dungeons per mapchunk.
mgvalleys_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0
+
+[Advanced]
+
+[*Developer Options]
+
+# Enable Lua modding support on client.
+# This support is experimental and API can change.
+enable_client_modding (Client modding) bool false
+
+# Replaces the default main menu with a custom one.
+main_menu_script (Main menu script) string
+
+[**Mod Security]
+
+# Prevent mods from doing insecure things like running shell commands.
+secure.enable_security (Enable mod security) bool true
+
+# Comma-separated list of trusted mods that are allowed to access insecure
+# functions even when mod security is on (via request_insecure_environment()).
+secure.trusted_mods (Trusted mods) string
+
+# Comma-separated list of mods that are allowed to access HTTP APIs, which
+# allow them to upload and download data to/from the internet.
+secure.http_mods (HTTP mods) string
+
+[**Debugging]
+
+# Level of logging to be written to debug.txt:
+# - <nothing> (no logging)
+# - none (messages with no level)
+# - error
+# - warning
+# - action
+# - info
+# - verbose
+# - trace
+debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose,trace
+
+# If the file size of debug.txt exceeds the number of megabytes specified in
+# this setting when it is opened, the file is moved to debug.txt.1,
+# deleting an older debug.txt.1 if it exists.
+# debug.txt is only moved if this setting is positive.
+debug_log_size_max (Debug log file size threshold) int 50 1
+
+# Minimal level of logging to be written to chat.
+chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose,trace
+
+# Handling for deprecated Lua API calls:
+# - none: Do not log deprecated calls
+# - log: mimic and log backtrace of deprecated call (default).
+# - error: abort on usage of deprecated call (suggested for mod developers).
+deprecated_lua_api_handling (Deprecated Lua API handling) enum log none,log,error
+
+# Enable random user input (only used for testing).
+random_input (Random input) bool false
+
+# Enable mod channels support.
+enable_mod_channels (Mod channels) bool false
+
+[**Mod Profiler]
+
+# Load the game profiler to collect game profiling data.
+# Provides a /profiler command to access the compiled profile.
+# Useful for mod developers and server operators.
+profiler.load (Load the game profiler) bool false
+
+# The default format in which profiles are being saved,
+# when calling `/profiler save [format]` without format.
+profiler.default_report_format (Default report format) enum txt txt,csv,lua,json,json_pretty
+
+# The file path relative to your worldpath in which profiles will be saved to.
+profiler.report_path (Report path) string ""
+
+# Instrument the methods of entities on registration.
+instrument.entity (Entity methods) bool true
+
+# Instrument the action function of Active Block Modifiers on registration.
+instrument.abm (Active Block Modifiers) bool true
+
+# Instrument the action function of Loading Block Modifiers on registration.
+instrument.lbm (Loading Block Modifiers) bool true
+
+# Instrument chat commands on registration.
+instrument.chatcommand (Chat commands) bool true
+
+# Instrument global callback functions on registration.
+# (anything you pass to a minetest.register_*() function)
+instrument.global_callback (Global callbacks) bool true
+
+# Instrument builtin.
+# This is usually only needed by core/builtin contributors
+instrument.builtin (Builtin) bool false
+
+# Have the profiler instrument itself:
+# * Instrument an empty function.
+# This estimates the overhead, that instrumentation is adding (+1 function call).
+# * Instrument the sampler being used to update the statistics.
+instrument.profiler (Profiler) bool false
+
+[**Engine profiler]
+
+# Print the engine's profiling data in regular intervals (in seconds).
+# 0 = disable. Useful for developers.
+profiler_print_interval (Engine profiling data print interval) int 0 0
+
+
[*Advanced]
+# Enable IPv6 support (for both client and server).
+# Required for IPv6 connections to work at all.
+enable_ipv6 (IPv6) bool true
+
+# If enabled, invalid world data won't cause the server to shut down.
+# Only enable this if you know what you are doing.
+ignore_world_load_errors (Ignore world errors) bool false
+
+[**Graphics]
+
+# Path to shader directory. If no path is defined, default location will be used.
+shader_path (Shader path) path
+
+# The rendering back-end.
+# A restart is required after changing this.
+# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
+# On other platforms, OpenGL is recommended.
+# Shaders are supported by OpenGL (desktop only) and OGLES2 (experimental)
+video_driver (Video driver) enum opengl opengl,ogles1,ogles2
+
+# Distance in nodes at which transparency depth sorting is enabled
+# Use this to limit the performance impact of transparency depth sorting
+transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128
+
+# Enable vertex buffer objects.
+# This should greatly improve graphics performance.
+enable_vbo (VBO) bool true
+
+# Radius of cloud area stated in number of 64 node cloud squares.
+# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
+cloud_radius (Cloud radius) int 12 1 62
+
+# Whether node texture animations should be desynchronized per mapblock.
+desynchronize_mapblock_texture_animation (Desynchronize block animation) bool true
+
+# Enables caching of facedir rotated meshes.
+enable_mesh_cache (Mesh cache) bool false
+
+# Delay between mesh updates on the client in ms. Increasing this will slow
+# down the rate of mesh updates, thus reducing jitter on slower clients.
+mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
+
+# Size of the MapBlock cache of the mesh generator. Increasing this will
+# increase the cache hit %, reducing the data being copied from the main
+# thread, thus reducing jitter.
+meshgen_block_cache_size (Mapblock mesh generator's MapBlock cache size in MB) int 20 0 1000
+
+# True = 256
+# False = 128
+# Usable to make minimap smoother on slower machines.
+minimap_double_scan_height (Minimap scan height) bool true
+
+# Textures on a node may be aligned either to the node or to the world.
+# The former mode suits better things like machines, furniture, etc., while
+# the latter makes stairs and microblocks fit surroundings better.
+# However, as this possibility is new, thus may not be used by older servers,
+# this option allows enforcing it for certain node types. Note though that
+# that is considered EXPERIMENTAL and may not work properly.
+world_aligned_mode (World-aligned textures mode) enum enable disable,enable,force_solid,force_nodebox
+
+# World-aligned textures may be scaled to span several nodes. However,
+# the server may not send the scale you want, especially if you use
+# a specially-designed texture pack; with this option, the client tries
+# to determine the scale automatically basing on the texture size.
+# See also texture_min_size.
+# Warning: This option is EXPERIMENTAL!
+autoscale_mode (Autoscaling mode) enum disable disable,enable,force
+
+[**Font]
+
+font_bold (Font bold by default) bool false
+
+font_italic (Font italic by default) bool false
+
+# Shadow offset (in pixels) of the default font. If 0, then shadow will not be drawn.
+font_shadow (Font shadow) int 1 0 65535
+
+# Opaqueness (alpha) of the shadow behind the default font, between 0 and 255.
+font_shadow_alpha (Font shadow alpha) int 127 0 255
+
+# Font size of the default font where 1 unit = 1 pixel at 96 DPI
+font_size (Font size) int 16 5 72
+
+# For pixel-style fonts that do not scale well, this ensures that font sizes used
+# with this font will always be divisible by this value, in pixels. For instance,
+# a pixel font 16 pixels tall should have this set to 16, so it will only ever be
+# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32.
+font_size_divisible_by (Font size divisible by) int 1 1
+
+# Path to the default font. Must be a TrueType font.
+# The fallback font will be used if the font cannot be loaded.
+font_path (Regular font path) filepath fonts/Arimo-Regular.ttf
+
+font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf
+font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf
+font_path_bold_italic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf
+
+# Font size of the monospace font where 1 unit = 1 pixel at 96 DPI
+mono_font_size (Monospace font size) int 16 5 72
+
+# For pixel-style fonts that do not scale well, this ensures that font sizes used
+# with this font will always be divisible by this value, in pixels. For instance,
+# a pixel font 16 pixels tall should have this set to 16, so it will only ever be
+# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32.
+mono_font_size_divisible_by (Monospace font size divisible by) int 1 1
+
+# Path to the monospace font. Must be a TrueType font.
+# This font is used for e.g. the console and profiler screen.
+mono_font_path (Monospace font path) filepath fonts/Cousine-Regular.ttf
+
+mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf
+mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf
+mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf
+
+# Path of the fallback font. Must be a TrueType font.
+# This font will be used for certain languages or if the default font is unavailable.
+fallback_font_path (Fallback font path) filepath fonts/DroidSansFallbackFull.ttf
+
+[**Lighting]
+
+# Gradient of light curve at minimum light level.
+# Controls the contrast of the lowest light levels.
+lighting_alpha (Light curve low gradient) float 0.0 0.0 3.0
+
+# Gradient of light curve at maximum light level.
+# Controls the contrast of the highest light levels.
+lighting_beta (Light curve high gradient) float 1.5 0.0 3.0
+
+# Strength of light curve boost.
+# The 3 'boost' parameters define a range of the light
+# curve that is boosted in brightness.
+lighting_boost (Light curve boost) float 0.2 0.0 0.4
+
+# Center of light curve boost range.
+# Where 0.0 is minimum light level, 1.0 is maximum light level.
+lighting_boost_center (Light curve boost center) float 0.5 0.0 1.0
+
+# Spread of light curve boost range.
+# Controls the width of the range to be boosted.
+# Standard deviation of the light curve boost Gaussian.
+lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
+
+[**Networking]
+
+# Prometheus listener address.
+# If Minetest is compiled with ENABLE_PROMETHEUS option enabled,
+# enable metrics listener for Prometheus on that address.
+# Metrics can be fetched on http://127.0.0.1:30000/metrics
+prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
+
+# Maximum size of the out chat queue.
+# 0 to disable queueing and -1 to make the queue size unlimited.
+max_out_chat_queue_size (Maximum size of the out chat queue) int 20 -1 32767
+
+# Timeout for client to remove unused map data from memory, in seconds.
+client_unload_unused_data_timeout (Mapblock unload timeout) float 600.0 0.0
+
+# Maximum number of mapblocks for client to be kept in memory.
+# Set to -1 for unlimited amount.
+client_mapblock_limit (Mapblock limit) int 7500 -1 2147483647
+
+# Whether to show the client debug info (has the same effect as hitting F5).
+show_debug (Show debug info) bool false
+
+# Maximum number of blocks that are simultaneously sent per client.
+# The maximum total count is calculated dynamically:
+# max_total = ceil((#clients + max_users) * per_client / 4)
+max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 40 1 4294967295
+
+# To reduce lag, block transfers are slowed down when a player is building something.
+# This determines how long they are slowed down after placing or removing a node.
+full_block_send_enable_min_time_from_building (Delay in sending blocks after building) float 2.0 0.0
+
+# Maximum number of packets sent per send step, if you have a slow connection
+# try reducing it, but don't reduce it to a number below double of targeted
+# client number.
+max_packets_per_iteration (Max. packets per iteration) int 1024 1 65535
+
+# Compression level to use when sending mapblocks to the client.
+# -1 - use default compression level
+# 0 - least compression, fastest
+# 9 - best compression, slowest
+map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
+
+[**Server]
+
+# Format of player chat messages. The following strings are valid placeholders:
+# @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 0.0
+
+# A message to be displayed to all clients when the server shuts down.
+kick_msg_shutdown (Shutdown message) string Server shutting down.
+
+# A message to be displayed to all clients when the server crashes.
+kick_msg_crash (Crash message) string This server has experienced an internal error. You will now be disconnected.
+
+# Whether to ask clients to reconnect after a (Lua) crash.
+# Set this to true if your server is set up to restart automatically.
+ask_reconnect_on_crash (Ask to reconnect after crash) bool false
+
+[**Server/Env Performance]
+
+# Length of a server tick and the interval at which objects are generally updated over
+# network, stated in seconds.
+dedicated_server_step (Dedicated server step) float 0.09 0.0
+
+# Whether players are shown to clients without any range limit.
+# Deprecated, use the setting player_transfer_distance instead.
+unlimited_player_transfer_distance (Unlimited player transfer distance) bool true
+
+# Defines the maximal player transfer distance in blocks (0 = unlimited).
+player_transfer_distance (Player transfer distance) int 0 0 65535
+
+# From how far clients know about objects, stated in mapblocks (16 nodes).
+#
+# Setting this larger than active_block_range will also cause the server
+# to maintain active objects up to this distance in the direction the
+# player is looking. (This can avoid mobs suddenly disappearing from view)
+active_object_send_range_blocks (Active object send range) int 8 1 65535
+
+# The radius of the volume of blocks around every player that is subject to the
+# active block stuff, stated in mapblocks (16 nodes).
+# In active blocks objects are loaded and ABMs run.
+# This is also the minimum range in which active objects (mobs) are maintained.
+# This should be configured together with active_object_send_range_blocks.
+active_block_range (Active block range) int 4 1 65535
+
+# From how far blocks are sent to clients, stated in mapblocks (16 nodes).
+max_block_send_distance (Max block send distance) int 12 1 65535
+
+# Maximum number of forceloaded mapblocks.
+max_forceloaded_blocks (Maximum forceloaded blocks) int 16 0
+
+# Interval of sending time of day to clients, stated in seconds.
+time_send_interval (Time send interval) float 5.0 0.001
+
+# Interval of saving important changes in the world, stated in seconds.
+server_map_save_interval (Map save interval) float 5.3 0.001
+
+# How long the server will wait before unloading unused mapblocks, stated in seconds.
+# Higher value is smoother, but will use more RAM.
+server_unload_unused_data_timeout (Unload unused server data) int 29 0 4294967295
+
+# Maximum number of statically stored objects in a block.
+max_objects_per_block (Maximum objects per block) int 256 1 65535
+
+# Length of time between active block management cycles, stated in seconds.
+active_block_mgmt_interval (Active block management interval) float 2.0 0.0
+
+# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds.
+abm_interval (ABM interval) float 1.0 0.0
+
+# The time budget allowed for ABMs to execute on each step
+# (as a fraction of the ABM Interval)
+abm_time_budget (ABM time budget) float 0.2 0.1 0.9
+
+# Length of time between NodeTimer execution cycles, stated in seconds.
+nodetimer_interval (NodeTimer interval) float 0.2 0.0
+
+# Max liquids processed per step.
+liquid_loop_max (Liquid loop max) int 100000 1 4294967295
+
+# The time (in seconds) that the liquids queue may grow beyond processing
+# capacity until an attempt is made to decrease its size by dumping old queue
+# items. A value of 0 disables the functionality.
+liquid_queue_purge_time (Liquid queue purge time) int 0 0 65535
+
+# Liquid update interval in seconds.
+liquid_update (Liquid update tick) float 1.0 0.001
+
+# At this distance the server will aggressively optimize which blocks are sent to
+# clients.
+# Small values potentially improve performance a lot, at the expense of visible
+# rendering glitches (some blocks will not be rendered under water and in caves,
+# as well as sometimes on land).
+# Setting this to a value greater than max_block_send_distance disables this
+# optimization.
+# Stated in mapblocks (16 nodes).
+block_send_optimize_distance (Block send optimize distance) int 4 2 32767
+
+# If enabled the server will perform map block occlusion culling based on
+# on the eye position of the player. This can reduce the number of blocks
+# sent to the client 50-80%. The client will not longer receive most invisible
+# so that the utility of noclip mode is reduced.
+server_side_occlusion_culling (Server side occlusion culling) bool true
+
+[**Mapgen]
+
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
# WARNING!: There is no benefit, and there are several dangers, in
# increasing this value above 5.
# Reducing this value increases cave and dungeon density.
# Altering this value is for special usage, leaving it unchanged is
# recommended.
-chunksize (Chunk size) int 5
+chunksize (Chunk size) int 5 1 10
# Dump the mapgen debug information.
enable_mapgen_debug_info (Mapgen debug) bool false
@@ -2193,21 +1916,438 @@ emergequeue_limit_generate (Per-player limit of queued blocks to generate) int 1
# speed, but this may harm game performance by interfering with other
# processes, especially in singleplayer and/or when running Lua code in
# 'on_generated'. For many users the optimum setting may be '1'.
-num_emerge_threads (Number of emerge threads) int 1
+num_emerge_threads (Number of emerge threads) int 1 0 32767
-[Online Content Repository]
+[**cURL]
-# The URL for the content repository
-contentdb_url (ContentDB URL) string https://content.minetest.net
+# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
+curl_timeout (cURL interactive timeout) int 20000 100 2147483647
-# Comma-separated list of flags to hide in the content repository.
-# "nonfree" can be used to hide packages which do not qualify as 'free software',
-# as defined by the Free Software Foundation.
-# You can also specify content ratings.
-# These flags are independent from Minetest versions,
-# so see a full list at https://content.minetest.net/help/content_flags/
-contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
+# Limits number of parallel HTTP requests. Affects:
+# - Media fetch if server uses remote_media setting.
+# - Serverlist download and server announcement.
+# - Downloads performed by main menu (e.g. mod manager).
+# Only has an effect if compiled with cURL.
+curl_parallel_limit (cURL parallel limit) int 8 1 2147483647
-# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
-# This should be lower than curl_parallel_limit.
-contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3
+# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
+curl_file_download_timeout (cURL file download timeout) int 300000 100 2147483647
+
+[**Misc]
+
+# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
+screen_dpi (DPI) int 72 1
+
+# Adjust the detected display density, used for scaling UI elements.
+display_density_factor (Display Density Scaling Factor) float 1 0.5 5.0
+
+# Windows systems only: Start Minetest with the command line window in the background.
+# Contains the same information as the file debug.txt (default name).
+enable_console (Enable console window) bool false
+
+# Number of extra blocks that can be loaded by /clearobjects at once.
+# This is a trade-off between SQLite transaction overhead and
+# memory consumption (4096=100MB, as a rule of thumb).
+max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) int 4096 0 4294967295
+
+# World directory (everything in the world is stored here).
+# Not needed if starting from the main menu.
+map-dir (Map directory) path
+
+# See https://www.sqlite.org/pragma.html#pragma_synchronous
+sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
+
+# Compression level to use when saving mapblocks to disk.
+# -1 - use default compression level
+# 0 - least compression, fastest
+# 9 - best compression, slowest
+map_compression_level_disk (Map Compression Level for Disk Storage) int -1 -1 9
+
+# Enable usage of remote media server (if provided by server).
+# Remote servers offer a significantly faster way to download media (e.g. textures)
+# when connecting to the server.
+enable_remote_media_server (Connect to external media server) bool true
+
+# File in client/serverlist/ that contains your favorite servers displayed in the
+# Multiplayer Tab.
+serverlist_file (Serverlist file) string favoriteservers.json
+
+
+[*Gamepads]
+
+# Enable joysticks. Requires a restart to take effect
+enable_joysticks (Enable joysticks) bool false
+
+# The identifier of the joystick to use
+joystick_id (Joystick ID) int 0 0 255
+
+# The type of joystick
+joystick_type (Joystick type) enum auto auto,generic,xbox,dragonrise_gamecube
+
+# The time in seconds it takes between repeated events
+# when holding down a joystick button combination.
+repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001
+
+# The dead zone of the joystick
+joystick_deadzone (Joystick dead zone) int 2048 0 65535
+
+# The sensitivity of the joystick axes for moving the
+# in-game view frustum around.
+joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170.0 0.001
+
+
+[*Temporary Settings]
+
+# Path to texture directory. All textures are first searched from here.
+texture_path (Texture path) path
+
+# Enables minimap.
+enable_minimap (Minimap) bool true
+
+# Shape of the minimap. Enabled = round, disabled = square.
+minimap_shape_round (Round minimap) bool true
+
+# Address to connect to.
+# Leave this blank to start a local server.
+# Note that the address field in the main menu overrides this setting.
+address (Server address) string
+
+# Port to connect to (UDP).
+# Note that the port field in the main menu overrides this setting.
+remote_port (Remote port) int 30000 1 65535
+
+# Default game when creating a new world.
+# This will be overridden when creating a world from the main menu.
+default_game (Default game) string minetest
+
+# Enable players getting damage and dying.
+enable_damage (Damage) bool false
+
+# Enable creative mode for all players
+creative_mode (Creative) bool false
+
+# Whether to allow players to damage and kill each other.
+enable_pvp (Player versus player) bool true
+
+# Player is able to fly without being affected by gravity.
+# This requires the "fly" privilege on the server.
+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 "Aux1" key).
+# This requires the "fast" privilege on the server.
+fast_move (Fast movement) bool false
+
+# If enabled together with fly mode, player is able to fly through solid nodes.
+# This requires the "noclip" privilege on the server.
+noclip (Noclip) bool false
+
+# Continuous forward movement, toggled by autoforward key.
+# Press the autoforward key again or the backwards movement to disable.
+continuous_forward (Continuous forward) bool false
+
+# Formspec default background opacity (between 0 and 255).
+formspec_default_bg_opacity (Formspec Default Background Opacity) int 140 0 255
+
+# Formspec default background color (R,G,B).
+formspec_default_bg_color (Formspec Default Background Color) string (0,0,0)
+
+# Whether to show technical names.
+# Affects mods and texture packs in the Content and Select Mods menus, as well as
+# setting names in All Settings.
+# Controlled by the checkbox in the "All settings" menu.
+show_technical_names (Show technical names) bool false
+
+# Enables the sound system.
+# If disabled, this completely disables all sounds everywhere and the in-game
+# sound controls will be non-functional.
+# Changing this setting requires a restart.
+enable_sound (Sound) bool true
+
+# Key for moving the player forward.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_forward (Forward key) key KEY_KEY_W
+
+# Key for moving the player backward.
+# Will also disable autoforward, when active.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_backward (Backward key) key KEY_KEY_S
+
+# Key for moving the player left.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_left (Left key) key KEY_KEY_A
+
+# Key for moving the player right.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_right (Right key) key KEY_KEY_D
+
+# Key for jumping.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_jump (Jump key) key KEY_SPACE
+
+# Key for sneaking.
+# Also used for climbing down and descending in water if aux1_descends is disabled.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_sneak (Sneak key) key KEY_LSHIFT
+
+# Key for digging.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_dig (Dig key) key KEY_LBUTTON
+
+# Key for placing.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_place (Place key) key KEY_RBUTTON
+
+# Key for opening the inventory.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+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_aux1 (Aux1 key) key KEY_KEY_E
+
+# Key for opening the chat window.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_chat (Chat key) key KEY_KEY_T
+
+# Key for opening the chat window to type commands.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_cmd (Command key) key /
+
+# Key for opening the chat window to type local commands.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_cmd_local (Command key) key .
+
+# Key for toggling unlimited view range.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_rangeselect (Range select key) key KEY_KEY_R
+
+# Key for toggling flying.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_freemove (Fly key) key KEY_KEY_K
+
+# Key for toggling pitch move mode.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_pitchmove (Pitch move key) key KEY_KEY_P
+
+# Key for toggling fast mode.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_fastmove (Fast key) key KEY_KEY_J
+
+# Key for toggling noclip mode.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_noclip (Noclip key) key KEY_KEY_H
+
+# Key for selecting the next item in the hotbar.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_hotbar_next (Hotbar next key) key KEY_KEY_N
+
+# Key for selecting the previous item in the hotbar.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_hotbar_previous (Hotbar previous key) key KEY_KEY_B
+
+# Key for muting the game.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_mute (Mute key) key KEY_KEY_M
+
+# Key for increasing the volume.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_increase_volume (Inc. volume key) key
+
+# Key for decreasing the volume.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_decrease_volume (Dec. volume key) key
+
+# Key for toggling autoforward.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_autoforward (Automatic forward key) key
+
+# Key for toggling cinematic mode.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_cinematic (Cinematic mode key) key
+
+# Key for toggling display of minimap.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_minimap (Minimap key) key KEY_KEY_V
+
+# Key for taking screenshots.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_screenshot (Screenshot) key KEY_F12
+
+# Key for dropping the currently selected item.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_drop (Drop item key) key KEY_KEY_Q
+
+# Key to use view zoom when possible.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_zoom (View zoom key) key KEY_KEY_Z
+
+# Key for selecting the first hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot1 (Hotbar slot 1 key) key KEY_KEY_1
+
+# Key for selecting the second hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot2 (Hotbar slot 2 key) key KEY_KEY_2
+
+# Key for selecting the third hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot3 (Hotbar slot 3 key) key KEY_KEY_3
+
+# Key for selecting the fourth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot4 (Hotbar slot 4 key) key KEY_KEY_4
+
+# Key for selecting the fifth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot5 (Hotbar slot 5 key) key KEY_KEY_5
+
+# Key for selecting the sixth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot6 (Hotbar slot 6 key) key KEY_KEY_6
+
+# Key for selecting the seventh hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot7 (Hotbar slot 7 key) key KEY_KEY_7
+
+# Key for selecting the eighth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot8 (Hotbar slot 8 key) key KEY_KEY_8
+
+# Key for selecting the ninth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot9 (Hotbar slot 9 key) key KEY_KEY_9
+
+# Key for selecting the tenth hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot10 (Hotbar slot 10 key) key KEY_KEY_0
+
+# Key for selecting the 11th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot11 (Hotbar slot 11 key) key
+
+# Key for selecting the 12th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot12 (Hotbar slot 12 key) key
+
+# Key for selecting the 13th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot13 (Hotbar slot 13 key) key
+
+# Key for selecting the 14th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot14 (Hotbar slot 14 key) key
+
+# Key for selecting the 15th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot15 (Hotbar slot 15 key) key
+
+# Key for selecting the 16th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot16 (Hotbar slot 16 key) key
+
+# Key for selecting the 17th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot17 (Hotbar slot 17 key) key
+
+# Key for selecting the 18th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot18 (Hotbar slot 18 key) key
+
+# Key for selecting the 19th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot19 (Hotbar slot 19 key) key
+
+# Key for selecting the 20th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot20 (Hotbar slot 20 key) key
+
+# Key for selecting the 21st hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot21 (Hotbar slot 21 key) key
+
+# Key for selecting the 22nd hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot22 (Hotbar slot 22 key) key
+
+# Key for selecting the 23rd hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot23 (Hotbar slot 23 key) key
+
+# Key for selecting the 24th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot24 (Hotbar slot 24 key) key
+
+# Key for selecting the 25th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot25 (Hotbar slot 25 key) key
+
+# Key for selecting the 26th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot26 (Hotbar slot 26 key) key
+
+# Key for selecting the 27th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot27 (Hotbar slot 27 key) key
+
+# Key for selecting the 28th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot28 (Hotbar slot 28 key) key
+
+# Key for selecting the 29th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot29 (Hotbar slot 29 key) key
+
+# Key for selecting the 30th hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot30 (Hotbar slot 30 key) key
+
+# Key for selecting the 31st hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot31 (Hotbar slot 31 key) key
+
+# Key for selecting the 32nd hotbar slot.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_slot32 (Hotbar slot 32 key) key
+
+# Key for toggling the display of the HUD.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_hud (HUD toggle key) key KEY_F1
+
+# Key for toggling the display of chat.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_chat (Chat toggle key) key KEY_F2
+
+# Key for toggling the display of the large chat console.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_console (Large chat console key) key KEY_F10
+
+# Key for toggling the display of fog.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_force_fog_off (Fog toggle key) key KEY_F3
+
+# Key for toggling the camera update. Only used for development
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_update_camera (Camera update toggle key) key
+
+# Key for toggling the display of debug info.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_debug (Debug info toggle key) key KEY_F5
+
+# Key for toggling the display of the profiler. Used for development.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_profiler (Profiler toggle key) key KEY_F6
+
+# Key for switching between first- and third-person camera.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_camera_mode (Toggle camera mode key) key KEY_KEY_C
+
+# Key for increasing the viewing range.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_increase_viewing_range_min (View range increase key) key +
+
+# Key for decreasing the viewing range.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_decrease_viewing_range_min (View range decrease key) key -