aboutsummaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/common/filterlist.lua2
-rw-r--r--builtin/common/misc_helpers.lua59
-rw-r--r--builtin/common/serialize.lua13
-rw-r--r--builtin/common/strict.lua14
-rw-r--r--builtin/fstk/buttonbar.lua61
-rw-r--r--builtin/fstk/dialog.lua8
-rw-r--r--builtin/fstk/tabview.lua36
-rw-r--r--builtin/fstk/ui.lua12
-rw-r--r--builtin/game/auth.lua2
-rw-r--r--builtin/game/chatcommands.lua166
-rw-r--r--builtin/game/constants.lua17
-rw-r--r--builtin/game/deprecated.lua16
-rw-r--r--builtin/game/falling.lua176
-rw-r--r--builtin/game/features.lua7
-rw-r--r--builtin/game/init.lua4
-rw-r--r--builtin/game/item.lua89
-rw-r--r--builtin/game/item_entity.lua24
-rw-r--r--builtin/game/misc.lua157
-rw-r--r--builtin/game/privileges.lua1
-rw-r--r--builtin/game/register.lua34
-rw-r--r--builtin/game/static_spawn.lua22
-rw-r--r--builtin/init.lua35
-rw-r--r--builtin/mainmenu/common.lua224
-rw-r--r--builtin/mainmenu/dlg_config_world.lua38
-rw-r--r--builtin/mainmenu/dlg_create_world.lua6
-rw-r--r--builtin/mainmenu/dlg_delete_mod.lua9
-rw-r--r--builtin/mainmenu/dlg_delete_world.lua8
-rw-r--r--builtin/mainmenu/dlg_rename_modpack.lua12
-rw-r--r--builtin/mainmenu/dlg_settings_advanced.lua760
-rw-r--r--builtin/mainmenu/init.lua116
-rw-r--r--builtin/mainmenu/init_simple.lua2
-rw-r--r--builtin/mainmenu/modmgr.lua40
-rw-r--r--builtin/mainmenu/tab_credits.lua138
-rw-r--r--builtin/mainmenu/tab_mods.lua6
-rw-r--r--builtin/mainmenu/tab_multiplayer.lua284
-rw-r--r--builtin/mainmenu/tab_server.lua4
-rw-r--r--builtin/mainmenu/tab_settings.lua440
-rw-r--r--builtin/mainmenu/tab_simple_main.lua214
-rw-r--r--builtin/mainmenu/tab_singleplayer.lua4
-rw-r--r--builtin/mainmenu/tab_texturepacks.lua50
-rw-r--r--builtin/mainmenu/textures.lua4
-rw-r--r--builtin/settingtypes.txt1214
42 files changed, 3365 insertions, 1163 deletions
diff --git a/builtin/common/filterlist.lua b/builtin/common/filterlist.lua
index 210681133..2a62362e3 100644
--- a/builtin/common/filterlist.lua
+++ b/builtin/common/filterlist.lua
@@ -189,7 +189,7 @@ function filterlist.process(self)
for k,v in pairs(self.m_raw_list) do
if self.m_filtercriteria == nil or
self.m_filter_fct(v,self.m_filtercriteria) then
- table.insert(self.m_processed_list,v)
+ self.m_processed_list[#self.m_processed_list + 1] = v
end
end
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index bf672e6da..e4653d41d 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -2,7 +2,6 @@
--------------------------------------------------------------------------------
-- Localize functions to avoid table lookups (better performance).
-local table_insert = table.insert
local string_sub, string_find = string.sub, string.find
--------------------------------------------------------------------------------
@@ -94,13 +93,13 @@ function dump2(o, name, dumped)
-- the form _G["table: 0xFFFFFFF"]
keyStr = string.format("_G[%q]", tostring(k))
-- Dump key table
- table_insert(t, dump2(k, keyStr, dumped))
+ t[#t + 1] = dump2(k, keyStr, dumped)
end
else
keyStr = basic_dump(k)
end
local vname = string.format("%s[%s]", name, keyStr)
- table_insert(t, dump2(v, vname, dumped))
+ t[#t + 1] = dump2(v, vname, dumped)
end
return string.format("%s = {}\n%s", name, table.concat(t))
end
@@ -135,7 +134,7 @@ function dump(o, indent, nested, level)
local t = {}
local dumped_indexes = {}
for i, v in ipairs(o) do
- table_insert(t, dump(v, indent, nested, level + 1))
+ t[#t + 1] = dump(v, indent, nested, level + 1)
dumped_indexes[i] = true
end
for k, v in pairs(o) do
@@ -144,7 +143,7 @@ function dump(o, indent, nested, level)
k = "["..dump(k, indent, nested, level + 1).."]"
end
v = dump(v, indent, nested, level + 1)
- table_insert(t, k.." = "..v)
+ t[#t + 1] = k.." = "..v
end
end
nested[o] = nil
@@ -177,7 +176,7 @@ function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
local s = string_sub(str, pos, np - 1)
if include_empty or (s ~= "") then
max_splits = max_splits - 1
- table_insert(items, s)
+ items[#items + 1] = s
end
pos = npe + 1
until (max_splits == 0) or (pos > (len + 1))
@@ -186,8 +185,8 @@ end
--------------------------------------------------------------------------------
function table.indexof(list, val)
- for i = 1, #list do
- if list[i] == val then
+ for i, v in ipairs(list) do
+ if v == val then
return i
end
end
@@ -324,7 +323,7 @@ function core.splittext(text,charlimit)
local last_line = ""
while start ~= nil do
if string.len(last_line) + (stop-start) > charlimit then
- table_insert(retval, last_line)
+ retval[#retval + 1] = last_line
last_line = ""
end
@@ -335,7 +334,7 @@ function core.splittext(text,charlimit)
last_line = last_line .. string_sub(text, current_idx, stop - 1)
if gotnewline then
- table_insert(retval, last_line)
+ retval[#retval + 1] = last_line
last_line = ""
gotnewline = false
end
@@ -353,11 +352,11 @@ function core.splittext(text,charlimit)
--add last part of text
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
- table_insert(retval, last_line)
- table_insert(retval, string_sub(text, current_idx))
+ retval[#retval + 1] = last_line
+ retval[#retval + 1] = string_sub(text, current_idx)
else
last_line = last_line .. " " .. string_sub(text, current_idx)
- table_insert(retval, last_line)
+ retval[#retval + 1] = last_line
end
return retval
@@ -430,14 +429,14 @@ if INIT == "game" then
if iswall then
core.set_node(pos, {name = wield_name,
- param2 = dirs1[fdir+1]})
+ param2 = dirs1[fdir + 1]})
elseif isceiling then
if orient_flags.force_facedir then
core.set_node(pos, {name = wield_name,
param2 = 20})
else
core.set_node(pos, {name = wield_name,
- param2 = dirs2[fdir+1]})
+ param2 = dirs2[fdir + 1]})
end
else -- place right side up
if orient_flags.force_facedir then
@@ -555,6 +554,36 @@ assert(core.string_to_pos("( 10.0, 5, -2)").z == -2)
assert(core.string_to_pos("asd, 5, -2)") == nil)
--------------------------------------------------------------------------------
+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
+ end
+
+ return p1, p2
+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, 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
+
+test_string_to_area()
+
+--------------------------------------------------------------------------------
function table.copy(t, seen)
local n = {}
seen = seen or {}
diff --git a/builtin/common/serialize.lua b/builtin/common/serialize.lua
index 90b8b2ad6..b2165648e 100644
--- a/builtin/common/serialize.lua
+++ b/builtin/common/serialize.lua
@@ -104,7 +104,7 @@ function core.serialize(x)
local i = local_index
local_index = local_index + 1
var = "_["..i.."]"
- table.insert(local_defs, var.." = "..val)
+ local_defs[#local_defs + 1] = var.." = "..val
dumped[x] = var
return var
end
@@ -135,16 +135,15 @@ function core.serialize(x)
local np = nest_points[x]
for i, v in ipairs(x) do
if not np or not np[i] then
- table.insert(vals, dump_or_ref_val(v))
+ vals[#vals + 1] = dump_or_ref_val(v)
end
idx_dumped[i] = true
end
for k, v in pairs(x) do
if (not np or not np[k]) and
not idx_dumped[k] then
- table.insert(vals,
- "["..dump_or_ref_val(k).."] = "
- ..dump_or_ref_val(v))
+ vals[#vals + 1] = "["..dump_or_ref_val(k).."] = "
+ ..dump_or_ref_val(v)
end
end
return "{"..table.concat(vals, ", ").."}"
@@ -156,9 +155,9 @@ function core.serialize(x)
local function dump_nest_points()
for parent, vals in pairs(nest_points) do
for k, v in pairs(vals) do
- table.insert(local_defs, dump_or_ref_val(parent)
+ local_defs[#local_defs + 1] = dump_or_ref_val(parent)
.."["..dump_or_ref_val(k).."] = "
- ..dump_or_ref_val(v))
+ ..dump_or_ref_val(v)
end
end
end
diff --git a/builtin/common/strict.lua b/builtin/common/strict.lua
index c7b86461f..05ceadf7a 100644
--- a/builtin/common/strict.lua
+++ b/builtin/common/strict.lua
@@ -9,11 +9,6 @@ function core.global_exists(name)
end
-local function warn(message)
- print(os.date("%H:%M:%S: WARNING: ")..message)
-end
-
-
local meta = {}
local declared = {}
-- Key is source file, line, and variable name; seperated by NULs
@@ -27,7 +22,7 @@ function meta:__newindex(name, value)
info.currentline, name)
if not warned[warn_key] and info.what ~= "main" and
info.what ~= "C" then
- warn(("Assignment to undeclared "..
+ core.log("warning", ("Assignment to undeclared "..
"global %q inside a function at %s.")
:format(name, desc))
warned[warn_key] = true
@@ -35,9 +30,8 @@ function meta:__newindex(name, value)
declared[name] = true
end
-- Ignore mod namespaces
- if WARN_INIT and (not core.get_current_modname or
- name ~= core.get_current_modname()) then
- warn(("Global variable %q created at %s.")
+ if WARN_INIT and name ~= core.get_current_modname() then
+ core.log("warning", ("Global variable %q created at %s.")
:format(name, desc))
end
rawset(self, name, value)
@@ -48,7 +42,7 @@ function meta:__index(name)
local info = debug.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
- warn(("Undeclared global variable %q accessed at %s:%s")
+ core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
:format(name, info.short_src, info.currentline))
warned[warn_key] = true
end
diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua
index 9a9ec999b..465588324 100644
--- a/builtin/fstk/buttonbar.lua
+++ b/builtin/fstk/buttonbar.lua
@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
---self program is free software; you can redistribute it and/or modify
+--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.
--
---self program is distributed in the hope that it will be useful,
+--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 self program; if not, write to the Free Software Foundation, Inc.,
+--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -24,11 +24,11 @@ local function buttonbar_formspec(self)
local formspec = string.format("box[%f,%f;%f,%f;%s]",
self.pos.x,self.pos.y ,self.size.x,self.size.y,self.bgcolor)
-
+
for i=self.startbutton,#self.buttons,1 do
local btn_name = self.buttons[i].name
local btn_pos = {}
-
+
if self.orientation == "horizontal" then
btn_pos.x = self.pos.x + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@@ -36,7 +36,7 @@ local function buttonbar_formspec(self)
else
btn_pos.x = self.pos.x + (self.btn_size * 0.05)
end
-
+
if self.orientation == "vertical" then
btn_pos.y = self.pos.y + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@@ -44,18 +44,18 @@ local function buttonbar_formspec(self)
else
btn_pos.y = self.pos.y + (self.btn_size * 0.05)
end
-
+
if (self.orientation == "vertical" and
(btn_pos.y + self.btn_size <= self.pos.y + self.size.y)) or
(self.orientation == "horizontal" and
(btn_pos.x + self.btn_size <= self.pos.x + self.size.x)) then
-
+
local borders="true"
-
+
if self.buttons[i].image ~= nil then
borders="false"
end
-
+
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]tooltip[%s;%s]",
btn_pos.x, btn_pos.y, self.btn_size, self.btn_size,
@@ -75,7 +75,7 @@ local function buttonbar_formspec(self)
btn_dec_pos.y = self.pos.y + (self.btn_size * 0.05)
local btn_inc_pos = {}
local btn_size = {}
-
+
if self.orientation == "horizontal" then
btn_size.x = 0.5
btn_size.y = self.btn_size
@@ -87,25 +87,25 @@ local function buttonbar_formspec(self)
btn_inc_pos.x = self.pos.x + (self.btn_size * 0.05)
btn_inc_pos.y = self.pos.y + self.size.y - 0.5
end
-
+
local text_dec = "<"
local text_inc = ">"
if self.orientation == "vertical" then
text_dec = "^"
text_inc = "v"
end
-
+
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
btn_dec_pos.x, btn_dec_pos.y, btn_size.x, btn_size.y,
self.name, text_dec)
-
+
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_inc_%s;%s;true;true]",
btn_inc_pos.x, btn_inc_pos.y, btn_size.x, btn_size.y,
self.name, text_inc)
end
-
+
return formspec
end
@@ -113,16 +113,16 @@ local function buttonbar_buttonhandler(self, fields)
if fields["btnbar_inc_" .. self.name] ~= nil and
self.startbutton < #self.buttons then
-
+
self.startbutton = self.startbutton + 1
return true
end
-
+
if fields["btnbar_dec_" .. self.name] ~= nil and self.startbutton > 1 then
self.startbutton = self.startbutton - 1
return true
end
-
+
for i=1,#self.buttons,1 do
if fields[self.buttons[i].name] ~= nil then
return self.userbuttonhandler(fields)
@@ -134,35 +134,40 @@ local buttonbar_metatable = {
handle_buttons = buttonbar_buttonhandler,
handle_events = function(self, event) end,
get_formspec = buttonbar_formspec,
-
+
hide = function(self) self.hidden = true end,
show = function(self) self.hidden = false end,
delete = function(self) ui.delete(self) end,
-
+
add_button = function(self, name, caption, image, tooltip)
if caption == nil then caption = "" end
if image == nil then image = "" end
if tooltip == nil then tooltip = "" end
-
- table.insert(self.buttons,{ name=name, caption=caption, image=image, tooltip=tooltip})
+
+ self.buttons[#self.buttons + 1] = {
+ name = name,
+ caption = caption,
+ image = image,
+ tooltip = tooltip
+ }
if self.orientation == "horizontal" then
if ( (self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.x ) then
-
+
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
else
if ((self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.y ) then
-
+
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
end
end,
-
+
set_bgparams = function(self, bgcolor)
if (type(bgcolor) == "string") then
self.bgcolor = bgcolor
@@ -189,20 +194,20 @@ function buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
self.startbutton = 1
self.have_move_buttons = false
self.hidden = false
-
+
if self.orientation == "horizontal" then
self.btn_size = self.size.y
else
self.btn_size = self.size.x
end
-
+
if (self.btn_initial_offset == nil) then
self.btn_initial_offset = self.btn_size * 0.05
end
self.userbuttonhandler = cbf_buttonhandler
self.buttons = {}
-
+
setmetatable(self,buttonbar_metatable)
ui.add(self)
diff --git a/builtin/fstk/dialog.lua b/builtin/fstk/dialog.lua
index 214b0388f..df887f413 100644
--- a/builtin/fstk/dialog.lua
+++ b/builtin/fstk/dialog.lua
@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
---self program is free software; you can redistribute it and/or modify
+--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.
--
---self program is distributed in the hope that it will be useful,
+--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 self program; if not, write to the Free Software Foundation, Inc.,
+--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function dialog_event_handler(self,event)
@@ -61,7 +61,7 @@ function dialog_create(name,get_formspec,buttonhandler,eventhandler)
self.formspec = get_formspec
self.buttonhandler = buttonhandler
self.user_eventhandler = eventhandler
-
+
setmetatable(self,dialog_metatable)
ui.add(self)
diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua
index 47603fb1b..72551afd7 100644
--- a/builtin/fstk/tabview.lua
+++ b/builtin/fstk/tabview.lua
@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
---self program is free software; you can redistribute it and/or modify
+--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.
--
---self program is distributed in the hope that it will be useful,
+--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 self program; if not, write to the Free Software Foundation, Inc.,
+--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -46,7 +46,7 @@ local function add_tab(self,tab)
tabdata = {},
}
- table.insert(self.tablist,newtab)
+ self.tablist[#self.tablist + 1] = newtab
if self.last_tab_index == #self.tablist then
self.current_tab = tab.name
@@ -61,7 +61,7 @@ local function get_formspec(self)
local formspec = ""
if not self.hidden and (self.parent == nil or not self.parent.hidden) then
-
+
if self.parent == nil then
local tsize = self.tablist[self.last_tab_index].tabsize or
{width=self.width, height=self.height}
@@ -87,11 +87,11 @@ local function handle_buttons(self,fields)
if self.hidden then
return false
end
-
+
if self:handle_tab_buttons(fields) then
return true
end
-
+
if self.glb_btn_handler ~= nil and
self.glb_btn_handler(self,fields) then
return true
@@ -112,16 +112,16 @@ end
--------------------------------------------------------------------------------
local function handle_events(self,event)
-
+
if self.hidden then
return false
end
-
+
if self.glb_evt_handler ~= nil and
self.glb_evt_handler(self,event) then
return true
end
-
+
if self.tablist[self.last_tab_index].evt_handler ~= nil then
return
self.tablist[self.last_tab_index].evt_handler(
@@ -131,7 +131,7 @@ local function handle_events(self,event)
self.tablist[self.last_tab_index].tabdata
)
end
-
+
return false
end
@@ -160,16 +160,16 @@ local function switch_to_tab(self, index)
self.tablist[self.last_tab_index].on_change("LEAVE",
self.current_tab, self.tablist[index].name)
end
-
+
--update tabview data
self.last_tab_index = index
local old_tab = self.current_tab
self.current_tab = self.tablist[index].name
-
+
if (self.autosave_tab) then
core.setting_set(self.name .. "_LAST",self.current_tab)
end
-
+
-- call for tab to enter
if self.tablist[index].on_change ~= nil then
self.tablist[index].on_change("ENTER",
@@ -197,14 +197,14 @@ local function set_tab_by_name(self, name)
return true
end
end
-
+
return false
end
--------------------------------------------------------------------------------
local function hide_tabview(self)
self.hidden=true
-
+
--call on_change as we're not gonna show self tab any longer
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("LEAVE",
@@ -215,7 +215,7 @@ end
--------------------------------------------------------------------------------
local function show_tabview(self)
self.hidden=false
-
+
-- call for tab to enter
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("ENTER",
@@ -265,7 +265,7 @@ function tabview_create(name, size, tabheaderpos)
self.current_tab = nil
self.last_tab_index = 1
self.tablist = {}
-
+
self.autosave_tab = false
ui.add(self)
diff --git a/builtin/fstk/ui.lua b/builtin/fstk/ui.lua
index de8ae4d2c..3ac0386ca 100644
--- a/builtin/fstk/ui.lua
+++ b/builtin/fstk/ui.lua
@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
---self program is free software; you can redistribute it and/or modify
+--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.
--
---self program is distributed in the hope that it will be useful,
+--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 self program; if not, write to the Free Software Foundation, Inc.,
+--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ui = {}
@@ -127,11 +127,13 @@ function ui.update()
end
if (active_toplevel_ui_elements > 1) then
- print("WARNING: ui manager detected more then one active ui element, self most likely isn't intended")
+ core.log("warning", "more than one active ui "..
+ "element, self most likely isn't intended")
end
if (active_toplevel_ui_elements == 0) then
- print("WARNING: not a single toplevel ui element active switching to default")
+ core.log("warning", "no toplevel ui element "..
+ "active; switching to default")
ui.childlist[ui.default]:show()
formspec = ui.childlist[ui.default]:get_formspec()
end
diff --git a/builtin/game/auth.lua b/builtin/game/auth.lua
index 423eb3134..deb811b14 100644
--- a/builtin/game/auth.lua
+++ b/builtin/game/auth.lua
@@ -20,7 +20,7 @@ function core.privs_to_string(privs, delim)
local list = {}
for priv, bool in pairs(privs) do
if bool then
- table.insert(list, priv)
+ list[#list + 1] = priv
end
end
return table.concat(list, delim)
diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua
index 5d317de4b..3350140ee 100644
--- a/builtin/game/chatcommands.lua
+++ b/builtin/game/chatcommands.lua
@@ -51,6 +51,27 @@ core.register_on_chat_message(function(name, message)
return true -- Handled chat message
end)
+-- Parses a "range" string in the format of "here (number)" or
+-- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
+local function parse_range_str(player_name, str)
+ local p1, p2
+ local args = str:split(" ")
+
+ if args[1] == "here" then
+ p1, p2 = core.get_player_radius_area(player_name, tonumber(args[2]))
+ if p1 == nil then
+ return false, "Unable to get player " .. player_name .. " position"
+ end
+ else
+ p1, p2 = core.string_to_area(str)
+ if p1 == nil then
+ return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
+ end
+ end
+
+ return p1, p2
+end
+
--
-- Chat commands
--
@@ -63,6 +84,18 @@ core.register_chatcommand("me", {
end,
})
+core.register_chatcommand("admin", {
+ description = "Show the name of the server owner",
+ func = function(name)
+ local admin = minetest.setting_get("name")
+ if admin then
+ return true, "The administrator of this server is "..admin.."."
+ else
+ return false, "There's no administrator named in the config file."
+ end
+ end,
+})
+
core.register_chatcommand("help", {
privs = {},
params = "[all/privs/<cmd>]",
@@ -83,7 +116,7 @@ core.register_chatcommand("help", {
local cmds = {}
for cmd, def in pairs(core.chatcommands) do
if core.check_player_privs(name, def.privs) then
- table.insert(cmds, cmd)
+ cmds[#cmds + 1] = cmd
end
end
table.sort(cmds)
@@ -94,7 +127,7 @@ core.register_chatcommand("help", {
local cmds = {}
for cmd, def in pairs(core.chatcommands) do
if core.check_player_privs(name, def.privs) then
- table.insert(cmds, format_help_line(cmd, def))
+ cmds[#cmds + 1] = format_help_line(cmd, def)
end
end
table.sort(cmds)
@@ -102,7 +135,7 @@ core.register_chatcommand("help", {
elseif param == "privs" then
local privs = {}
for priv, def in pairs(core.registered_privileges) do
- table.insert(privs, priv .. ": " .. def.description)
+ privs[#privs + 1] = priv .. ": " .. def.description
end
table.sort(privs)
return true, "Available privileges:\n"..table.concat(privs, "\n")
@@ -148,8 +181,10 @@ core.register_chatcommand("grant", {
end
local privs = core.get_player_privs(grantname)
local privs_unknown = ""
+ local basic_privs =
+ core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
for priv, _ in pairs(grantprivs) do
- if priv ~= "interact" and priv ~= "shout" and
+ if not basic_privs[priv] and
not core.check_player_privs(name, {privs=true}) then
return false, "Your privileges are insufficient."
end
@@ -190,8 +225,10 @@ core.register_chatcommand("revoke", {
end
local revoke_privs = core.string_to_privs(revoke_priv_str)
local privs = core.get_player_privs(revoke_name)
+ local basic_privs =
+ core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
for priv, _ in pairs(revoke_privs) do
- if priv ~= "interact" and priv ~= "shout" and
+ if not basic_privs[priv] and
not core.check_player_privs(name, {privs=true}) then
return false, "Your privileges are insufficient."
end
@@ -315,10 +352,16 @@ core.register_chatcommand("teleport", {
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
- teleportee = core.get_player_by_name(name)
- if teleportee and p.x and p.y and p.z then
- teleportee:setpos(p)
- return true, "Teleporting to "..core.pos_to_string(p)
+ if p.x and p.y and p.z then
+ local lm = tonumber(minetest.setting_get("map_generation_limit") or 31000)
+ if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm or p.z < -lm or p.z > lm then
+ return false, "Cannot teleport out of map bounds!"
+ end
+ teleportee = core.get_player_by_name(name)
+ if teleportee then
+ teleportee:setpos(p)
+ return true, "Teleporting to "..core.pos_to_string(p)
+ end
end
local teleportee = nil
@@ -415,40 +458,65 @@ core.register_chatcommand("set", {
end,
})
-core.register_chatcommand("deleteblocks", {
+local function emergeblocks_callback(pos, action, num_calls_remaining, ctx)
+ if ctx.total_blocks == 0 then
+ ctx.total_blocks = num_calls_remaining + 1
+ ctx.current_blocks = 0
+ end
+ ctx.current_blocks = ctx.current_blocks + 1
+
+ if ctx.current_blocks == ctx.total_blocks then
+ core.chat_send_player(ctx.requestor_name,
+ string.format("Finished emerging %d blocks in %.2fms.",
+ ctx.total_blocks, (os.clock() - ctx.start_time) * 1000))
+ end
+end
+
+local function emergeblocks_progress_update(ctx)
+ if ctx.current_blocks ~= ctx.total_blocks then
+ core.chat_send_player(ctx.requestor_name,
+ string.format("emergeblocks update: %d/%d blocks emerged (%.1f%%)",
+ ctx.current_blocks, ctx.total_blocks,
+ (ctx.current_blocks / ctx.total_blocks) * 100))
+
+ core.after(2, emergeblocks_progress_update, ctx)
+ end
+end
+
+core.register_chatcommand("emergeblocks", {
params = "(here [radius]) | (<pos1> <pos2>)",
- description = "delete map blocks contained in area pos1 to pos2",
+ description = "starts loading (or generating, if inexistent) map blocks "
+ .. "contained in area pos1 to pos2",
privs = {server=true},
func = function(name, param)
- local p1 = {}
- local p2 = {}
- local args = param:split(" ")
- if args[1] == "here" then
- local player = core.get_player_by_name(name)
- if player == nil then
- core.log("error", "player is nil")
- return false, "Unable to get current position; player is nil"
- end
- p1 = player:getpos()
- p2 = p1
+ local p1, p2 = parse_range_str(name, param)
+ if p1 == false then
+ return false, p2
+ end
- if #args >= 2 then
- local radius = tonumber(args[2]) or 0
- p1 = vector.add(p1, radius)
- p2 = vector.subtract(p2, radius)
- end
- else
- local pos1, pos2 = unpack(param:split(") ("))
- if pos1 == nil or pos2 == nil then
- return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
- end
+ local context = {
+ current_blocks = 0,
+ total_blocks = 0,
+ start_time = os.clock(),
+ requestor_name = name
+ }
- p1 = core.string_to_pos(pos1 .. ")")
- p2 = core.string_to_pos("(" .. pos2)
+ core.emerge_area(p1, p2, emergeblocks_callback, context)
+ core.after(2, emergeblocks_progress_update, context)
- if p1 == nil or p2 == nil then
- return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
- end
+ return true, "Started emerge of area ranging from " ..
+ core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
+ end,
+})
+
+core.register_chatcommand("deleteblocks", {
+ params = "(here [radius]) | (<pos1> <pos2>)",
+ description = "delete map blocks contained in area pos1 to pos2",
+ privs = {server=true},
+ func = function(name, param)
+ local p1, p2 = parse_range_str(name, param)
+ if p1 == false then
+ return false, p2
end
if core.delete_area(p1, p2) then
@@ -698,7 +766,7 @@ core.register_chatcommand("time", {
local hour = (current_time - minutes) / 60
return true, ("Current time is %d:%02d"):format(hour, minutes)
end
- local player_privs = minetest.get_player_privs(name)
+ local player_privs = core.get_player_privs(name)
if not player_privs.settime then
return false, "You don't have permission to run this command " ..
"(missing privilege: settime)."
@@ -727,6 +795,13 @@ core.register_chatcommand("time", {
end,
})
+core.register_chatcommand("days", {
+ description = "Display day count",
+ func = function(name, param)
+ return true, "Current day is " .. core.get_day_count()
+ end
+})
+
core.register_chatcommand("shutdown", {
description = "shutdown server",
privs = {server=true},
@@ -790,14 +865,25 @@ core.register_chatcommand("kick", {
})
core.register_chatcommand("clearobjects", {
+ params = "[full|quick]",
description = "clear all objects in world",
privs = {server=true},
func = function(name, param)
- core.log("action", name .. " clears all objects.")
+ local options = {}
+ if param == "" or param == "full" then
+ options.mode = "full"
+ elseif param == "quick" then
+ options.mode = "quick"
+ else
+ return false, "Invalid usage, see /help clearobjects."
+ end
+
+ core.log("action", name .. " clears all objects ("
+ .. options.mode .. " mode).")
core.chat_send_all("Clearing all objects. This may take long."
.. " You may experience a timeout. (by "
.. name .. ")")
- core.clear_objects()
+ core.clear_objects(options)
core.log("action", "Object clearing done.")
core.chat_send_all("*** Cleared all objects.")
end,
diff --git a/builtin/game/constants.lua b/builtin/game/constants.lua
new file mode 100644
index 000000000..d0b7c753c
--- /dev/null
+++ b/builtin/game/constants.lua
@@ -0,0 +1,17 @@
+-- Minetest: builtin/constants.lua
+
+--
+-- Constants values for use with the Lua API
+--
+
+-- Built-in Content IDs (for use with VoxelManip API)
+core.CONTENT_UNKNOWN = 125
+core.CONTENT_AIR = 126
+core.CONTENT_IGNORE = 127
+
+-- Block emerge status constants (for use with core.emerge_area)
+core.EMERGE_CANCELLED = 0
+core.EMERGE_ERRORED = 1
+core.EMERGE_FROM_MEMORY = 2
+core.EMERGE_FROM_DISK = 3
+core.EMERGE_GENERATED = 4
diff --git a/builtin/game/deprecated.lua b/builtin/game/deprecated.lua
index bbe68be3e..cd1cf5e2d 100644
--- a/builtin/game/deprecated.lua
+++ b/builtin/game/deprecated.lua
@@ -3,9 +3,8 @@
--
-- Default material types
--
-function digprop_err()
- core.log("info", debug.traceback())
- core.log("info", "WARNING: The core.digprop_* functions are obsolete and need to be replaced by item groups.")
+local function digprop_err()
+ core.log("deprecated", "The core.digprop_* functions are obsolete and need to be replaced by item groups.")
end
core.digprop_constanttime = digprop_err
@@ -16,12 +15,12 @@ core.digprop_woodlike = digprop_err
core.digprop_leaveslike = digprop_err
core.digprop_glasslike = digprop_err
-core.node_metadata_inventory_move_allow_all = function()
- core.log("info", "WARNING: core.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
+function core.node_metadata_inventory_move_allow_all()
+ core.log("deprecated", "core.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
end
-core.add_to_creative_inventory = function(itemstring)
- core.log('info', "WARNING: core.add_to_creative_inventory: This function is deprecated and does nothing.")
+function core.add_to_creative_inventory(itemstring)
+ core.log("deprecated", "core.add_to_creative_inventory: This function is deprecated and does nothing.")
end
--
@@ -32,7 +31,7 @@ local envref_deprecation_message_printed = false
setmetatable(core.env, {
__index = function(table, key)
if not envref_deprecation_message_printed then
- core.log("info", "WARNING: core.env:[...] is deprecated and should be replaced with core.[...]")
+ core.log("deprecated", "core.env:[...] is deprecated and should be replaced with core.[...]")
envref_deprecation_message_printed = true
end
local func = core[key]
@@ -50,4 +49,3 @@ setmetatable(core.env, {
function core.rollback_get_last_node_actor(pos, range, seconds)
return core.rollback_get_node_actions(pos, range, seconds, 1)[1]
end
-
diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua
index 58f68fc56..57bb98cfd 100644
--- a/builtin/game/falling.lua
+++ b/builtin/game/falling.lua
@@ -6,52 +6,49 @@
core.register_entity(":__builtin:falling_node", {
initial_properties = {
- physical = true,
- collide_with_objects = false,
- collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
visual = "wielditem",
+ visual_size = {x = 0.667, y = 0.667},
textures = {},
- visual_size = {x=0.667, y=0.667},
+ physical = true,
+ is_visible = false,
+ collide_with_objects = false,
+ collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
node = {},
set_node = function(self, node)
self.node = node
- local stack = ItemStack(node.name)
- local itemtable = stack:to_table()
- local itemname = nil
- if itemtable then
- itemname = stack:to_table().name
- end
- local item_texture = nil
- local item_type = ""
- if core.registered_items[itemname] then
- item_texture = core.registered_items[itemname].inventory_image
- item_type = core.registered_items[itemname].type
- end
- local prop = {
+ self.object:set_properties({
is_visible = true,
textures = {node.name},
- }
- self.object:set_properties(prop)
+ })
end,
get_staticdata = function(self)
- return self.node.name
+ return core.serialize(self.node)
end,
on_activate = function(self, staticdata)
- self.object:set_armor_groups({immortal=1})
- self:set_node({name=staticdata})
+ self.object:set_armor_groups({immortal = 1})
+
+ local node = core.deserialize(staticdata)
+ if node then
+ self:set_node(node)
+ elseif staticdata ~= "" then
+ self:set_node({name = staticdata})
+ end
end,
on_step = function(self, dtime)
- -- Set gravity
- self.object:setacceleration({x=0, y=-10, z=0})
+ -- Set gravity
+ local acceleration = self.object:getacceleration()
+ if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
+ self.object:setacceleration({x = 0, y = -10, z = 0})
+ end
-- Turn to actual sand when collides to ground or just move
local pos = self.object:getpos()
- local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
+ local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z} -- Position of bottom center point
local bcn = core.get_node(bcp)
local bcd = core.registered_nodes[bcn.name]
-- Note: walkable is in the node definition, not in item groups
@@ -62,7 +59,7 @@ core.register_entity(":__builtin:falling_node", {
if bcd and bcd.leveled and
bcn.name == self.node.name then
local addlevel = self.node.level
- if addlevel == nil or addlevel <= 0 then
+ if not addlevel or addlevel <= 0 then
addlevel = bcd.leveled
end
if core.add_node_level(bcp, addlevel) == 0 then
@@ -75,7 +72,7 @@ core.register_entity(":__builtin:falling_node", {
core.remove_node(bcp)
return
end
- local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
+ local np = {x = bcp.x, y = bcp.y + 1, z = bcp.z}
-- Check what's here
local n2 = core.get_node(np)
-- If it's not air or liquid, remove node and replace it with
@@ -86,25 +83,25 @@ core.register_entity(":__builtin:falling_node", {
if core.registered_nodes[n2.name].buildable_to == false then
-- Add dropped items
local drops = core.get_node_drops(n2.name, "")
- local _, dropped_item
for _, dropped_item in ipairs(drops) do
core.add_item(np, dropped_item)
end
end
-- Run script hook
- local _, callback
for _, callback in ipairs(core.registered_on_dignodes) do
- callback(np, n2, nil)
+ callback(np, n2)
end
end
-- Create node and remove entity
- core.add_node(np, self.node)
+ if core.registered_nodes[self.node.name] then
+ core.add_node(np, self.node)
+ end
self.object:remove()
nodeupdate(np)
return
end
local vel = self.object:getvelocity()
- if vector.equals(vel, {x=0,y=0,z=0}) then
+ if vector.equals(vel, {x = 0, y = 0, z = 0}) then
local npos = self.object:getpos()
self.object:setpos(vector.round(npos))
end
@@ -119,7 +116,7 @@ end
function drop_attached_node(p)
local nn = core.get_node(p).name
core.remove_node(p)
- for _,item in ipairs(core.get_node_drops(nn, "")) do
+ for _, item in ipairs(core.get_node_drops(nn, "")) do
local pos = {
x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25,
@@ -131,25 +128,13 @@ end
function check_attached_node(p, n)
local def = core.registered_nodes[n.name]
- local d = {x=0, y=0, z=0}
+ local d = {x = 0, y = 0, z = 0}
if def.paramtype2 == "wallmounted" then
- if n.param2 == 0 then
- d.y = 1
- elseif n.param2 == 1 then
- d.y = -1
- elseif n.param2 == 2 then
- d.x = 1
- elseif n.param2 == 3 then
- d.x = -1
- elseif n.param2 == 4 then
- d.z = 1
- elseif n.param2 == 5 then
- d.z = -1
- end
+ d = core.wallmounted_to_dir(n.param2)
else
d.y = -1
end
- local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
+ local p2 = vector.add(p, d)
local nn = core.get_node(p2).name
local def2 = core.registered_nodes[nn]
if def2 and not def2.walkable then
@@ -162,10 +147,10 @@ end
-- Some common functions
--
-function nodeupdate_single(p, delay)
+function nodeupdate_single(p)
local n = core.get_node(p)
if core.get_item_group(n.name, "falling_node") ~= 0 then
- local p_bottom = {x=p.x, y=p.y-1, z=p.z}
+ local p_bottom = {x = p.x, y = p.y - 1, z = p.z}
local n_bottom = core.get_node(p_bottom)
-- Note: walkable is in the node definition, not in item groups
if core.registered_nodes[n_bottom.name] and
@@ -175,37 +160,88 @@ function nodeupdate_single(p, delay)
core.get_node_level(p_bottom) < core.get_node_max_level(p_bottom))) and
(not core.registered_nodes[n_bottom.name].walkable or
core.registered_nodes[n_bottom.name].buildable_to) then
- if delay then
- core.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
- else
- n.level = core.get_node_level(p)
- core.remove_node(p)
- spawn_falling_node(p, n)
- nodeupdate(p)
- end
+ n.level = core.get_node_level(p)
+ core.remove_node(p)
+ spawn_falling_node(p, n)
+ return true
end
end
if core.get_item_group(n.name, "attached_node") ~= 0 then
if not check_attached_node(p, n) then
drop_attached_node(p)
- nodeupdate(p)
+ return true
end
end
+
+ return false
end
-function nodeupdate(p, delay)
- -- Round p to prevent falling entities to get stuck
- p.x = math.floor(p.x+0.5)
- p.y = math.floor(p.y+0.5)
- p.z = math.floor(p.z+0.5)
+-- This table is specifically ordered.
+-- We don't walk diagonals, only our direct neighbors, and self.
+-- Down first as likely case, but always before self. The same with sides.
+-- Up must come last, so that things above self will also fall all at once.
+local nodeupdate_neighbors = {
+ {x = -1, y = -1, z = 0},
+ {x = 1, y = -1, z = 0},
+ {x = 0, y = -1, z = -1},
+ {x = 0, y = -1, z = 1},
+ {x = 0, y = -1, z = 0},
+ {x = -1, y = 0, z = 0},
+ {x = 1, y = 0, z = 0},
+ {x = 0, y = 0, z = 1},
+ {x = 0, y = 0, z = -1},
+ {x = 0, y = 0, z = 0},
+ {x = 0, y = 1, z = 0},
+}
- for x = -1,1 do
- for y = -1,1 do
- for z = -1,1 do
- nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, delay or not (x==0 and y==0 and z==0))
- end
- end
+function nodeupdate(p)
+ -- Round p to prevent falling entities to get stuck.
+ p = vector.round(p)
+
+ -- We make a stack, and manually maintain size for performance.
+ -- Stored in the stack, we will maintain tables with pos, and
+ -- last neighbor visited. This way, when we get back to each
+ -- node, we know which directions we have already walked, and
+ -- which direction is the next to walk.
+ local s = {}
+ local n = 0
+ -- The neighbor order we will visit from our table.
+ local v = 1
+
+ while true do
+ -- Push current pos onto the stack.
+ n = n + 1
+ s[n] = {p = p, v = v}
+ -- Select next node from neighbor list.
+ p = vector.add(p, nodeupdate_neighbors[v])
+ -- Now we check out the node. If it is in need of an update,
+ -- it will let us know in the return value (true = updated).
+ if not nodeupdate_single(p) then
+ -- If we don't need to "recurse" (walk) to it then pop
+ -- our previous pos off the stack and continue from there,
+ -- with the v value we were at when we last were at that
+ -- node
+ repeat
+ local pop = s[n]
+ p = pop.p
+ v = pop.v
+ s[n] = nil
+ n = n - 1
+ -- If there's nothing left on the stack, and no
+ -- more sides to walk to, we're done and can exit
+ if n == 0 and v == 11 then
+ return
+ end
+ until v < 11
+ -- The next round walk the next neighbor in list.
+ v = v + 1
+ else
+ -- If we did need to walk the neighbor, then
+ -- start walking it from the walk order start (1),
+ -- and not the order we just pushed up the stack.
+ v = 1
+ end
end
end
diff --git a/builtin/game/features.lua b/builtin/game/features.lua
index f082b0db8..2aad458da 100644
--- a/builtin/game/features.lua
+++ b/builtin/game/features.lua
@@ -8,13 +8,14 @@ core.features = {
use_texture_alpha = true,
no_legacy_abms = true,
texture_names_parens = true,
+ area_store_custom_ids = true,
}
function core.has_feature(arg)
if type(arg) == "table" then
- missing_features = {}
- result = true
- for ft, _ in pairs(arg) do
+ local missing_features = {}
+ local result = true
+ for ftr in pairs(arg) do
if not core.features[ftr] then
missing_features[ftr] = true
result = false
diff --git a/builtin/game/init.lua b/builtin/game/init.lua
index 3f82f85c7..a6cfa3bf8 100644
--- a/builtin/game/init.lua
+++ b/builtin/game/init.lua
@@ -1,10 +1,11 @@
-local scriptpath = minetest.get_builtin_path()..DIR_DELIM
+local scriptpath = core.get_builtin_path()..DIR_DELIM
local commonpath = scriptpath.."common"..DIR_DELIM
local gamepath = scriptpath.."game"..DIR_DELIM
dofile(commonpath.."vector.lua")
+dofile(gamepath.."constants.lua")
dofile(gamepath.."item.lua")
dofile(gamepath.."register.lua")
@@ -25,4 +26,3 @@ dofile(gamepath.."features.lua")
dofile(gamepath.."voxelarea.lua")
dofile(gamepath.."forceloading.lua")
dofile(gamepath.."statbars.lua")
-
diff --git a/builtin/game/item.lua b/builtin/game/item.lua
index 6628a4081..36c2c1a68 100644
--- a/builtin/game/item.lua
+++ b/builtin/game/item.lua
@@ -27,19 +27,11 @@ function core.get_pointed_thing_position(pointed_thing, above)
if above then
-- The position where a node would be placed
return pointed_thing.above
- else
- -- The position where a node would be dug
- return pointed_thing.under
end
+ -- The position where a node would be dug
+ return pointed_thing.under
elseif pointed_thing.type == "object" then
- obj = pointed_thing.ref
- if obj ~= nil then
- return obj:getpos()
- else
- return nil
- end
- else
- return nil
+ return pointed_thing.ref and pointed_thing.ref:getpos()
end
end
@@ -96,25 +88,26 @@ function core.dir_to_facedir(dir, is6d)
end
end
+-- Table of possible dirs
+local facedir_to_dir = {
+ {x= 0, y=0, z= 1},
+ {x= 1, y=0, z= 0},
+ {x= 0, y=0, z=-1},
+ {x=-1, y=0, z= 0},
+ {x= 0, y=-1, z= 0},
+ {x= 0, y=1, z= 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)
- --a table of possible dirs
- return ({{x=0, y=0, z=1},
- {x=1, y=0, z=0},
- {x=0, y=0, z=-1},
- {x=-1, y=0, z=0},
- {x=0, y=-1, z=0},
- {x=0, y=1, z=0}})
-
- --indexed into by a table of correlating facedirs
- [({[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})
-
- --indexed into by the facedir in question
- [facedir]]
+ return facedir_to_dir[facedir_to_dir_map[facedir]]
end
function core.dir_to_wallmounted(dir)
@@ -139,6 +132,19 @@ function core.dir_to_wallmounted(dir)
end
end
+-- table of dirs in wallmounted order
+local wallmounted_to_dir = {
+ [0] = {x = 0, y = 1, z = 0},
+ {x = 0, y = -1, z = 0},
+ {x = 1, y = 0, z = 0},
+ {x = -1, y = 0, z = 0},
+ {x = 0, y = 0, z = 1},
+ {x = 0, y = 0, z = -1},
+}
+function core.wallmounted_to_dir(wallmounted)
+ return wallmounted_to_dir[wallmounted]
+end
+
function core.get_node_drops(nodename, toolname)
local drop = ItemStack({name=nodename}):get_definition().drop
if drop == nil then
@@ -227,7 +233,8 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
place_to = {x = under.x, y = under.y, z = under.z}
end
- if core.is_protected(place_to, placer:get_player_name()) then
+ if core.is_protected(place_to, placer:get_player_name()) and
+ not minetest.check_player_privs(placer, "protection_bypass") then
core.log("action", placer:get_player_name()
.. " tried to place " .. def.name
.. " at protected position "
@@ -334,8 +341,12 @@ function core.item_place(itemstack, placer, pointed_thing, param2)
return itemstack
end
+function core.item_secondary_use(itemstack, placer)
+ return itemstack
+end
+
function core.item_drop(itemstack, dropper, pos)
- if dropper.is_player then
+ if dropper and dropper:is_player() then
local v = dropper:get_look_dir()
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
local cs = itemstack:get_count()
@@ -349,12 +360,17 @@ function core.item_drop(itemstack, dropper, pos)
v.y = v.y*2 + 2
v.z = v.z*2
obj:setvelocity(v)
+ obj:get_luaentity().dropped_by = dropper:get_player_name()
+ return itemstack
end
else
- core.add_item(pos, itemstack)
+ if core.add_item(pos, itemstack) then
+ return itemstack
+ end
end
- return itemstack
+ -- If we reach this, adding the object to the
+ -- environment failed
end
function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
@@ -429,7 +445,8 @@ function core.node_dig(pos, node, digger)
return
end
- if core.is_protected(pos, digger:get_player_name()) then
+ if core.is_protected(pos, digger:get_player_name()) and
+ not minetest.check_player_privs(digger, "protection_bypass") then
core.log("action", digger:get_player_name()
.. " tried to dig " .. node.name
.. " at protected position "
@@ -560,6 +577,7 @@ core.nodedef_default = {
diggable = true,
climbable = false,
buildable_to = false,
+ floodable = false,
liquidtype = "none",
liquid_alternative_flowing = "",
liquid_alternative_source = "",
@@ -587,6 +605,7 @@ core.craftitemdef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
+ on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_use = nil,
}
@@ -604,6 +623,7 @@ core.tooldef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
+ on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_use = nil,
}
@@ -622,6 +642,7 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'),
+ on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = nil,
on_use = nil,
}
diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua
index 6425a10aa..a66bf33d0 100644
--- a/builtin/game/item_entity.lua
+++ b/builtin/game/item_entity.lua
@@ -4,11 +4,14 @@ function core.spawn_item(pos, item)
-- Take item in any format
local stack = ItemStack(item)
local obj = core.add_entity(pos, "__builtin:item")
- obj:get_luaentity():set_item(stack:to_string())
+ -- Don't use obj if it couldn't be added to the map.
+ if obj then
+ obj:get_luaentity():set_item(stack:to_string())
+ end
return obj
end
--- If item_entity_ttl is not set, enity will have default life time
+-- If item_entity_ttl is not set, enity will have default life time
-- Setting it to -1 disables the feature
local time_to_live = tonumber(core.setting_get("item_entity_ttl"))
@@ -28,6 +31,7 @@ core.register_entity(":__builtin:item", {
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = false,
+ infotext = "",
},
itemstring = '',
@@ -47,6 +51,7 @@ core.register_entity(":__builtin:item", {
local c = s
local itemtable = stack:to_table()
local itemname = nil
+ local description = ""
if itemtable then
itemname = stack:to_table().name
end
@@ -55,6 +60,7 @@ core.register_entity(":__builtin:item", {
if core.registered_items[itemname] then
item_texture = core.registered_items[itemname].inventory_image
item_type = core.registered_items[itemname].type
+ description = core.registered_items[itemname].description
end
local prop = {
is_visible = true,
@@ -63,6 +69,7 @@ core.register_entity(":__builtin:item", {
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c},
automatic_rotate = math.pi * 0.5,
+ infotext = description,
}
self.object:set_properties(prop)
end,
@@ -71,7 +78,8 @@ core.register_entity(":__builtin:item", {
return core.serialize({
itemstring = self.itemstring,
always_collect = self.always_collect,
- age = self.age
+ age = self.age,
+ dropped_by = self.dropped_by
})
end,
@@ -81,11 +89,12 @@ core.register_entity(":__builtin:item", {
if data and type(data) == "table" then
self.itemstring = data.itemstring
self.always_collect = data.always_collect
- if data.age then
+ if data.age then
self.age = data.age + dtime_s
else
self.age = dtime_s
end
+ self.dropped_by = data.dropped_by
end
else
self.itemstring = staticdata
@@ -197,9 +206,10 @@ core.register_entity(":__builtin:item", {
end,
on_punch = function(self, hitter)
- if self.itemstring ~= '' then
- local left = hitter:get_inventory():add_item("main", self.itemstring)
- if not left:is_empty() then
+ local inv = hitter:get_inventory()
+ if inv and self.itemstring ~= '' then
+ local left = inv:add_item("main", self.itemstring)
+ if left and not left:is_empty() then
self.itemstring = left:to_string()
return
end
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index e3b7d82bc..de41cfc91 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -4,88 +4,81 @@
-- Misc. API functions
--
-local timers = {}
-local mintime
-local function update_timers(delay)
- mintime = false
- local sub = 0
- for index = 1, #timers do
- index = index - sub
- local timer = timers[index]
- timer.time = timer.time - delay
- if timer.time <= 0 then
- core.set_last_run_mod(timer.mod_origin)
- timer.func(unpack(timer.args or {}))
- table.remove(timers, index)
- sub = sub + 1
- elseif mintime then
- mintime = math.min(mintime, timer.time)
- else
- mintime = timer.time
- end
- end
-end
+local jobs = {}
+local time = 0.0
+local last = core.get_us_time() / 1000000
-local timers_to_add
-local function add_timers()
- for _, timer in ipairs(timers_to_add) do
- table.insert(timers, timer)
+core.register_globalstep(function(dtime)
+ local new = core.get_us_time() / 1000000
+ if new > last then
+ time = time + (new - last)
+ else
+ -- Overflow, we may lose a little bit of time here but
+ -- only 1 tick max, potentially running timers slightly
+ -- too early.
+ time = time + new
end
- timers_to_add = false
-end
+ last = new
-local delay = 0
-core.register_globalstep(function(dtime)
- if not mintime then
- -- abort if no timers are running
+ if #jobs < 1 then
return
end
- if timers_to_add then
- add_timers()
- end
- delay = delay + dtime
- if delay < mintime then
- return
+
+ -- Iterate backwards so that we miss any new timers added by
+ -- a timer callback, and so that we don't skip the next timer
+ -- in the list if we remove one.
+ for i = #jobs, 1, -1 do
+ local job = jobs[i]
+ if time >= job.expire then
+ core.set_last_run_mod(job.mod_origin)
+ job.func(unpack(job.arg))
+ table.remove(jobs, i)
+ end
end
- update_timers(delay)
- delay = 0
end)
-function core.after(time, func, ...)
+function core.after(after, func, ...)
assert(tonumber(time) and type(func) == "function",
"Invalid core.after invocation")
- if not mintime then
- mintime = time
- timers_to_add = {{
- time = time+delay,
- func = func,
- args = {...},
- mod_origin = core.get_last_run_mod(),
- }}
- return
- end
- mintime = math.min(mintime, time)
- timers_to_add = timers_to_add or {}
- timers_to_add[#timers_to_add+1] = {
- time = time+delay,
- func = func,
- args = {...},
- mod_origin = core.get_last_run_mod(),
+ jobs[#jobs + 1] = {
+ func = func,
+ expire = time + after,
+ arg = {...},
+ mod_origin = core.get_last_run_mod()
}
end
-function core.check_player_privs(name, privs)
+function core.check_player_privs(player_or_name, ...)
+ local name = player_or_name
+ -- Check if we have been provided with a Player object.
+ if type(name) ~= "string" then
+ name = name:get_player_name()
+ end
+
+ local requested_privs = {...}
local player_privs = core.get_player_privs(name)
local missing_privileges = {}
- for priv, val in pairs(privs) do
- if val
- and not player_privs[priv] then
- table.insert(missing_privileges, priv)
+
+ if type(requested_privs[1]) == "table" then
+ -- We were provided with a table like { privA = true, privB = true }.
+ for priv, value in pairs(requested_privs[1]) do
+ if value and not player_privs[priv] then
+ missing_privileges[#missing_privileges + 1] = priv
+ end
+ end
+ else
+ -- Only a list, we can process it directly.
+ for key, priv in pairs(requested_privs) do
+ if not player_privs[priv] then
+ missing_privileges[#missing_privileges + 1] = priv
+ end
end
end
+
if #missing_privileges > 0 then
return false, missing_privileges
end
+
return true, ""
end
@@ -103,12 +96,31 @@ function core.get_connected_players()
local temp_table = {}
for index, value in pairs(player_list) do
if value:is_player_connected() then
- table.insert(temp_table, value)
+ temp_table[#temp_table + 1] = value
end
end
return temp_table
end
+-- Returns two position vectors representing a box of `radius` in each
+-- direction centered around the player corresponding to `player_name`
+function core.get_player_radius_area(player_name, radius)
+ local player = core.get_player_by_name(player_name)
+ if player == nil then
+ return nil
+ end
+
+ local p1 = player:getpos()
+ local p2 = p1
+
+ if radius then
+ p1 = vector.subtract(p1, radius)
+ p2 = vector.add(p2, radius)
+ end
+
+ return p1, p2
+end
+
function core.hash_node_position(pos)
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
end
@@ -166,3 +178,22 @@ function core.raillike_group(name)
end
return id
end
+
+-- HTTP callback interface
+function core.http_add_fetch(httpenv)
+ httpenv.fetch = function(req, callback)
+ local handle = httpenv.fetch_async(req)
+
+ local function update_http_status()
+ local res = httpenv.fetch_async_get(handle)
+ if res.completed then
+ callback(res)
+ else
+ core.after(0, update_http_status)
+ end
+ end
+ core.after(0, update_http_status)
+ end
+
+ return httpenv
+end
diff --git a/builtin/game/privileges.lua b/builtin/game/privileges.lua
index 7e6387c72..bd5ead624 100644
--- a/builtin/game/privileges.lua
+++ b/builtin/game/privileges.lua
@@ -32,6 +32,7 @@ core.register_privilege("settime", "Can use /time")
core.register_privilege("privs", "Can modify privileges")
core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
core.register_privilege("server", "Can do server maintenance stuff")
+core.register_privilege("protection_bypass", "Can bypass node protection in the world")
core.register_privilege("shout", "Can speak in chat")
core.register_privilege("ban", "Can ban and unban players")
core.register_privilege("kick", "Can kick players")
diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index d0e04bfc3..f330491a2 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -11,10 +11,11 @@ local register_alias_raw = core.register_alias_raw
core.register_alias_raw = nil
--
--- Item / entity / ABM registration functions
+-- Item / entity / ABM / LBM registration functions
--
core.registered_abms = {}
+core.registered_lbms = {}
core.registered_entities = {}
core.registered_items = {}
core.registered_nodes = {}
@@ -51,27 +52,38 @@ local forbidden_item_names = {
local function check_modname_prefix(name)
if name:sub(1,1) == ":" then
- -- Escape the modname prefix enforcement mechanism
+ -- If the name starts with a colon, we can skip the modname prefix
+ -- mechanism.
return name:sub(2)
else
- -- Modname prefix enforcement
+ -- Enforce that the name starts with the correct mod name.
local expected_prefix = core.get_current_modname() .. ":"
if name:sub(1, #expected_prefix) ~= expected_prefix then
error("Name " .. name .. " does not follow naming conventions: " ..
- "\"modname:\" or \":\" prefix required")
+ "\"" .. expected_prefix .. "\" or \":\" prefix required")
end
+
+ -- Enforce that the name only contains letters, numbers and underscores.
local subname = name:sub(#expected_prefix+1)
- if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
+ if subname:find("[^%w_]") then
error("Name " .. name .. " does not follow naming conventions: " ..
"contains unallowed characters")
end
+
return name
end
end
function core.register_abm(spec)
-- Add to core.registered_abms
- core.registered_abms[#core.registered_abms+1] = spec
+ core.registered_abms[#core.registered_abms + 1] = spec
+ spec.mod_origin = core.get_current_modname() or "??"
+end
+
+function core.register_lbm(spec)
+ -- Add to core.registered_lbms
+ check_modname_prefix(spec.name)
+ core.registered_lbms[#core.registered_lbms + 1] = spec
spec.mod_origin = core.get_current_modname() or "??"
end
@@ -221,7 +233,7 @@ function core.register_alias(name, convert_to)
error("Unable to register alias: Name is forbidden: " .. name)
end
if core.registered_items[name] ~= nil then
- core.log("WARNING: Not registering alias, item with same name" ..
+ core.log("warning", "Not registering alias, item with same name" ..
" is already defined: " .. name .. " -> " .. convert_to)
else
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
@@ -268,6 +280,7 @@ core.register_item(":unknown", {
description = "Unknown Item",
inventory_image = "unknown_item.png",
on_place = core.item_place,
+ on_secondary_use = core.item_secondary_use,
on_drop = core.item_drop,
groups = {not_in_creative_inventory=1},
diggable = true,
@@ -284,6 +297,7 @@ core.register_node(":air", {
pointable = false,
diggable = false,
buildable_to = true,
+ floodable = true,
air_equivalent = true,
drop = "",
groups = {not_in_creative_inventory=1},
@@ -385,7 +399,7 @@ end
local function make_registration()
local t = {}
local registerfunc = function(func)
- table.insert(t, func)
+ t[#t + 1] = func
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
@@ -461,9 +475,9 @@ end
function core.register_on_player_hpchange(func, modifier)
if modifier then
- table.insert(core.registered_on_player_hpchanges.modifiers, func)
+ core.registered_on_player_hpchanges.modifiers[#core.registered_on_player_hpchanges.modifiers + 1] = func
else
- table.insert(core.registered_on_player_hpchanges.loggers, func)
+ core.registered_on_player_hpchanges.loggers[#core.registered_on_player_hpchanges.loggers + 1] = func
end
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
diff --git a/builtin/game/static_spawn.lua b/builtin/game/static_spawn.lua
index 492ab6ca6..100334226 100644
--- a/builtin/game/static_spawn.lua
+++ b/builtin/game/static_spawn.lua
@@ -3,31 +3,23 @@
local function warn_invalid_static_spawnpoint()
if core.setting_get("static_spawnpoint") and
not core.setting_get_pos("static_spawnpoint") then
- core.log('error', "The static_spawnpoint setting is invalid: \""..
+ core.log("error", "The static_spawnpoint setting is invalid: \""..
core.setting_get("static_spawnpoint").."\"")
end
end
warn_invalid_static_spawnpoint()
-local function put_player_in_spawn(obj)
- warn_invalid_static_spawnpoint()
+local function put_player_in_spawn(player_obj)
local static_spawnpoint = core.setting_get_pos("static_spawnpoint")
if not static_spawnpoint then
return false
end
- core.log('action', "Moving "..obj:get_player_name()..
- " to static spawnpoint at "..
- core.pos_to_string(static_spawnpoint))
- obj:setpos(static_spawnpoint)
+ core.log("action", "Moving " .. player_obj:get_player_name() ..
+ " to static spawnpoint at " .. core.pos_to_string(static_spawnpoint))
+ player_obj:setpos(static_spawnpoint)
return true
end
-core.register_on_newplayer(function(obj)
- put_player_in_spawn(obj)
-end)
-
-core.register_on_respawnplayer(function(obj)
- return put_player_in_spawn(obj)
-end)
-
+core.register_on_newplayer(put_player_in_spawn)
+core.register_on_respawnplayer(put_player_in_spawn)
diff --git a/builtin/init.lua b/builtin/init.lua
index 095771d19..4400a19d6 100644
--- a/builtin/init.lua
+++ b/builtin/init.lua
@@ -6,32 +6,45 @@
--
-- Initialize some very basic things
-print = core.debug
+function core.debug(...) core.log(table.concat({...}, "\t")) end
+if core.print then
+ local core_print = core.print
+ -- Override native print and use
+ -- terminal if that's turned on
+ function print(...)
+ local n, t = select("#", ...), {...}
+ for i = 1, n do
+ t[i] = tostring(t[i])
+ end
+ core_print(table.concat(t, "\t"))
+ end
+ core.print = nil -- don't pollute our namespace
+end
math.randomseed(os.time())
os.setlocale("C", "numeric")
minetest = core
-- Load other files
-local scriptdir = core.get_builtin_path()..DIR_DELIM
-local gamepath = scriptdir.."game"..DIR_DELIM
-local commonpath = scriptdir.."common"..DIR_DELIM
-local asyncpath = scriptdir.."async"..DIR_DELIM
+local scriptdir = core.get_builtin_path() .. DIR_DELIM
+local gamepath = scriptdir .. "game" .. DIR_DELIM
+local commonpath = scriptdir .. "common" .. DIR_DELIM
+local asyncpath = scriptdir .. "async" .. DIR_DELIM
-dofile(commonpath.."strict.lua")
-dofile(commonpath.."serialize.lua")
-dofile(commonpath.."misc_helpers.lua")
+dofile(commonpath .. "strict.lua")
+dofile(commonpath .. "serialize.lua")
+dofile(commonpath .. "misc_helpers.lua")
if INIT == "game" then
- dofile(gamepath.."init.lua")
+ dofile(gamepath .. "init.lua")
elseif INIT == "mainmenu" then
local mainmenuscript = core.setting_get("main_menu_script")
if mainmenuscript ~= nil and mainmenuscript ~= "" then
dofile(mainmenuscript)
else
- dofile(core.get_mainmenu_path()..DIR_DELIM.."init.lua")
+ dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
end
elseif INIT == "async" then
- dofile(asyncpath.."init.lua")
+ dofile(asyncpath .. "init.lua")
else
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
end
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
index 6266d0220..1fd89ff77 100644
--- a/builtin/mainmenu/common.lua
+++ b/builtin/mainmenu/common.lua
@@ -22,40 +22,37 @@ menudata = {}
--------------------------------------------------------------------------------
-- Local cached values
--------------------------------------------------------------------------------
-local min_supp_proto = core.get_min_supp_proto()
-local max_supp_proto = core.get_max_supp_proto()
+local min_supp_proto, max_supp_proto
+function common_update_cached_supp_proto()
+ min_supp_proto = core.get_min_supp_proto()
+ max_supp_proto = core.get_max_supp_proto()
+end
+common_update_cached_supp_proto()
--------------------------------------------------------------------------------
-- Menu helper functions
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function render_client_count(n)
- if n > 99 then
- return '99+'
- elseif n >= 0 then
- return tostring(n)
- else
- return '?'
- end
+ if n > 99 then return '99+'
+ elseif n >= 0 then return tostring(n)
+ else return '?' end
end
local function configure_selected_world_params(idx)
- local worldconfig = modmgr.get_worldconfig(
- menudata.worldlist:get_list()[idx].path)
-
- if worldconfig.creative_mode ~= nil then
+ local worldconfig = modmgr.get_worldconfig(menudata.worldlist:get_list()[idx].path)
+ if worldconfig.creative_mode then
core.setting_set("creative_mode", worldconfig.creative_mode)
end
- if worldconfig.enable_damage ~= nil then
+ if worldconfig.enable_damage then
core.setting_set("enable_damage", worldconfig.enable_damage)
end
end
--------------------------------------------------------------------------------
function image_column(tooltip, flagname)
- return "image," ..
- "tooltip=" .. core.formspec_escape(tooltip) .. "," ..
+ return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png")
end
@@ -64,76 +61,60 @@ end
function order_favorite_list(list)
local res = {}
--orders the favorite list after support
- for i=1,#list,1 do
+ for i = 1, #list do
local fav = list[i]
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
- table.insert(res, fav)
+ res[#res + 1] = fav
end
end
- for i=1,#list,1 do
+ for i = 1, #list do
local fav = list[i]
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
- table.insert(res, fav)
+ res[#res + 1] = fav
end
end
return res
end
--------------------------------------------------------------------------------
-function render_favorite(spec,render_details)
+function render_favorite(spec, is_favorite)
local text = ""
-
- if spec.name ~= nil then
+ if spec.name then
text = text .. core.formspec_escape(spec.name:trim())
-
--- if spec.description ~= nil and
--- core.formspec_escape(spec.description):trim() ~= "" then
--- text = text .. " (" .. core.formspec_escape(spec.description) .. ")"
--- end
- else
- if spec.address ~= nil then
- text = text .. spec.address:trim()
-
- if spec.port ~= nil then
- text = text .. ":" .. spec.port
- end
+ elseif spec.address then
+ text = text .. spec.address:trim()
+ if spec.port then
+ text = text .. ":" .. spec.port
end
end
- if not render_details then
- return text
- end
-
local details = ""
- local grey_out = not is_server_protocol_compat(spec.proto_max, spec.proto_min)
+ local grey_out = not is_server_protocol_compat(spec.proto_min, spec.proto_max)
- if spec.clients ~= nil and spec.clients_max ~= nil then
+ if is_favorite then
+ details = "1,"
+ else
+ details = "0,"
+ end
+
+ if spec.clients and spec.clients_max then
local clients_color = ''
local clients_percent = 100 * spec.clients / spec.clients_max
-- Choose a color depending on how many clients are connected
-- (relatively to clients_max)
- if spec.clients == 0 then
- clients_color = '' -- 0 players: default/white
- elseif spec.clients == spec.clients_max then
- clients_color = '#dd5b5b' -- full server: red (darker)
- elseif clients_percent <= 60 then
- clients_color = '#a1e587' -- 0-60%: green
- elseif clients_percent <= 90 then
- clients_color = '#ffdc97' -- 60-90%: yellow
- else
- clients_color = '#ffba97' -- 90-100%: orange
+ if grey_out then clients_color = '#aaaaaa'
+ elseif spec.clients == 0 then clients_color = '' -- 0 players: default/white
+ elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green
+ elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow
+ elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker)
+ else clients_color = '#ffba97' -- 90-100%: orange
end
- if grey_out then
- clients_color = '#aaaaaa'
- end
+ details = details .. clients_color .. ',' ..
+ render_client_count(spec.clients) .. ',/,' ..
+ render_client_count(spec.clients_max) .. ','
- details = details ..
- clients_color .. ',' ..
- render_client_count(spec.clients) .. ',' ..
- '/,' ..
- render_client_count(spec.clients_max) .. ','
elseif grey_out then
details = details .. '#aaaaaa,?,/,?,'
else
@@ -184,56 +165,36 @@ end
--------------------------------------------------------------------------------
function menu_render_worldlist()
local retval = ""
-
local current_worldlist = menudata.worldlist:get_list()
- for i,v in ipairs(current_worldlist) do
- if retval ~= "" then
- retval = retval ..","
- end
-
+ for i, v in ipairs(current_worldlist) do
+ if retval ~= "" then retval = retval .. "," end
retval = retval .. core.formspec_escape(v.name) ..
- " \\[" .. core.formspec_escape(v.gameid) .. "\\]"
+ " \\[" .. core.formspec_escape(v.gameid) .. "\\]"
end
return retval
end
--------------------------------------------------------------------------------
-function menu_handle_key_up_down(fields,textlist,settingname)
- if fields["key_up"] then
- local oldidx = core.get_textlist_index(textlist)
-
- if oldidx ~= nil and oldidx > 1 then
- local newidx = oldidx -1
- core.setting_set(settingname,
- menudata.worldlist:get_raw_index(newidx))
-
- configure_selected_world_params(newidx)
+function menu_handle_key_up_down(fields, textlist, settingname)
+ local oldidx, newidx = core.get_textlist_index(textlist), 1
+ if fields.key_up or fields.key_down then
+ if fields.key_up and oldidx and oldidx > 1 then
+ newidx = oldidx - 1
+ elseif fields.key_down and oldidx and
+ oldidx < menudata.worldlist:size() then
+ newidx = oldidx + 1
end
+ core.setting_set(settingname, menudata.worldlist:get_raw_index(newidx))
+ configure_selected_world_params(newidx)
return true
end
-
- if fields["key_down"] then
- local oldidx = core.get_textlist_index(textlist)
-
- if oldidx ~= nil and oldidx < menudata.worldlist:size() then
- local newidx = oldidx + 1
- core.setting_set(settingname,
- menudata.worldlist:get_raw_index(newidx))
-
- configure_selected_world_params(newidx)
- end
-
- return true
- end
-
return false
end
--------------------------------------------------------------------------------
function asyncOnlineFavourites()
-
if not menudata.public_known then
menudata.public_known = {{
name = fgettext("Loading..."),
@@ -241,60 +202,77 @@ function asyncOnlineFavourites()
}}
end
menudata.favorites = menudata.public_known
+ menudata.favorites_is_public = true
+
+ if not menudata.public_downloading then
+ menudata.public_downloading = true
+ else
+ return
+ end
+
core.handle_async(
function(param)
return core.get_favorites("online")
end,
nil,
function(result)
- if core.setting_getbool("public_serverlist") then
- local favs = order_favorite_list(result)
- if favs[1] then
- menudata.public_known = favs
- menudata.favorites = menudata.public_known
- end
- core.event_handler("Refresh")
+ menudata.public_downloading = nil
+ local favs = order_favorite_list(result)
+ if favs[1] then
+ menudata.public_known = favs
+ menudata.favorites = menudata.public_known
+ menudata.favorites_is_public = true
end
+ core.event_handler("Refresh")
end
)
end
--------------------------------------------------------------------------------
-function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
- local textlines = core.splittext(text,textlen)
-
- local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
- .. width .. "," .. height .. ";"
- .. tl_name .. ";"
+function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
+ local textlines = core.splittext(text, textlen)
+ local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
+ "," .. height .. ";" .. tl_name .. ";"
- for i=1, #textlines, 1 do
- textlines[i] = textlines[i]:gsub("\r","")
+ for i = 1, #textlines do
+ textlines[i] = textlines[i]:gsub("\r", "")
retval = retval .. core.formspec_escape(textlines[i]) .. ","
end
retval = retval .. ";0;"
-
- if transparency then
- retval = retval .. "true"
- end
-
+ if transparency then retval = retval .. "true" end
retval = retval .. "]"
return retval
end
--------------------------------------------------------------------------------
-function is_server_protocol_compat(proto_min, proto_max)
- return not ((min_supp_proto > (proto_max or 24)) or (max_supp_proto < (proto_min or 13)))
+function is_server_protocol_compat(server_proto_min, server_proto_max)
+ return min_supp_proto <= (server_proto_max or 24) and max_supp_proto >= (server_proto_min or 13)
end
--------------------------------------------------------------------------------
-function is_server_protocol_compat_or_error(proto_min, proto_max)
- if not is_server_protocol_compat(proto_min, proto_max) then
- gamedata.errormessage = fgettext_ne("Protocol version mismatch, server " ..
- ((proto_min ~= proto_max) and "supports protocols between $1 and $2" or "enforces protocol version $1") ..
- ", we " ..
- ((min_supp_proto ~= max_supp_proto) and "support protocols between version $3 and $4." or "only support protocol version $3"),
- proto_min or 13, proto_max or 24, min_supp_proto, max_supp_proto)
+function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
+ if not is_server_protocol_compat(server_proto_min, server_proto_max) then
+ local server_prot_ver_info, client_prot_ver_info
+ local s_p_min = server_proto_min or 13
+ local s_p_max = server_proto_max or 24
+
+ if s_p_min ~= s_p_max then
+ server_prot_ver_info = fgettext_ne("Server supports protocol versions between $1 and $2. ",
+ s_p_min, s_p_max)
+ else
+ server_prot_ver_info = fgettext_ne("Server enforces protocol version $1. ",
+ s_p_min)
+ end
+ if min_supp_proto ~= max_supp_proto then
+ client_prot_ver_info= fgettext_ne("We support protocol versions between version $1 and $2.",
+ min_supp_proto, max_supp_proto)
+ else
+ client_prot_ver_info = fgettext_ne("We only support protocol version $1.", min_supp_proto)
+ end
+ gamedata.errormessage = fgettext_ne("Protocol version mismatch. ")
+ .. server_prot_ver_info
+ .. client_prot_ver_info
return false
end
@@ -307,7 +285,7 @@ function menu_worldmt(selected, setting, value)
local filename = world.path .. DIR_DELIM .. "world.mt"
local world_conf = Settings(filename)
- if value ~= nil then
+ if value then
if not world_conf:write() then
core.log("error", "Failed to write world config file")
end
@@ -325,7 +303,7 @@ function menu_worldmt_legacy(selected)
local modes_names = {"creative_mode", "enable_damage", "server_announce"}
for _, mode_name in pairs(modes_names) do
local mode_val = menu_worldmt(selected, mode_name)
- if mode_val ~= nil then
+ if mode_val then
core.setting_set(mode_name, mode_val)
else
menu_worldmt(selected, mode_name, core.setting_get(mode_name))
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
index 4d13faea8..eb0319ba0 100644
--- a/builtin/mainmenu/dlg_config_world.lua
+++ b/builtin/mainmenu/dlg_config_world.lua
@@ -25,20 +25,20 @@ local function get_formspec(data)
local mod = data.list:get_list()[data.selected_mod]
local retval =
- "size[11,6.5,true]" ..
- "label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
- "label[1.75,-0.25;" .. data.worldspec.name .. "]"
+ "size[11.5,7.5,true]" ..
+ "label[0.5,0;" .. fgettext("World:") .. "]" ..
+ "label[1.75,0;" .. data.worldspec.name .. "]"
if data.hide_gamemods then
- retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
+ retval = retval .. "checkbox[1,6;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
else
- retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
+ retval = retval .. "checkbox[1,6;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
end
if data.hide_modpackcontents then
- retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
+ retval = retval .. "checkbox[6,6;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
else
- retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
+ retval = retval .. "checkbox[6,6;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
end
if mod == nil then
@@ -46,13 +46,13 @@ local function get_formspec(data)
end
retval = retval ..
- "label[0,0.45;" .. fgettext("Mod:") .. "]" ..
- "label[0.75,0.45;" .. mod.name .. "]" ..
- "label[0,1;" .. fgettext("Depends:") .. "]" ..
- "textlist[0,1.5;5,4.25;world_config_depends;" ..
+ "label[0,0.7;" .. fgettext("Mod:") .. "]" ..
+ "label[0.75,0.7;" .. mod.name .. "]" ..
+ "label[0,1.25;" .. fgettext("Depends:") .. "]" ..
+ "textlist[0,1.75;5,4.25;world_config_depends;" ..
modmgr.get_dependencies(mod.path) .. ";0]" ..
- "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
- "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
+ "button[3.25,7;2.5,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
+ "button[5.75,7;2.5,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
if mod.is_modpack then
@@ -68,22 +68,22 @@ local function get_formspec(data)
end
if all_enabled == false then
- retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
+ retval = retval .. "button[5.5,0.125;2.5,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
else
- retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
+ retval = retval .. "button[5.5,0.125;2.5,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
end
else
if mod.enabled then
- retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
+ retval = retval .. "checkbox[5.5,-0.125;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
else
- retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
+ retval = retval .. "checkbox[5.5,-0.125;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
end
end
end
retval = retval ..
- "button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
- "textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
+ "button[8.75,0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
+ "textlist[5.5,0.75;5.75,5.25;world_config_modlist;"
retval = retval .. modmgr.render_modlist(data.list)
retval = retval .. ";" .. data.selected_mod .."]"
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index b42d119e0..477b8bcb9 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -46,7 +46,7 @@ local function create_world_formspec(dialogdata)
current_seed = core.formspec_escape(current_seed)
local retval =
- "size[12,6,true]" ..
+ "size[11.5,6.5,true]" ..
"label[2,0;" .. fgettext("World name") .. "]"..
"field[4.5,0.4;6,0.5;te_world_name;;]" ..
@@ -60,8 +60,8 @@ local function create_world_formspec(dialogdata)
"textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
";" .. gameidx .. ";true]" ..
- "button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
- "button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+ "button[3.25,6;2.5,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
+ "button[5.75,6;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
if #gamemgr.games == 0 then
retval = retval .. "box[2,4;8,1;#ff8800]label[2.25,4;" ..
diff --git a/builtin/mainmenu/dlg_delete_mod.lua b/builtin/mainmenu/dlg_delete_mod.lua
index 6e00b8045..2efd70414 100644
--- a/builtin/mainmenu/dlg_delete_mod.lua
+++ b/builtin/mainmenu/dlg_delete_mod.lua
@@ -22,10 +22,11 @@ local function delete_mod_formspec(dialogdata)
dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
local retval =
- "size[12.4,5,true]" ..
- "field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", dialogdata.mod.name) .. ";]"..
- "button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
- "button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
+ "size[11.5,4.5,true]" ..
+ "label[2,2;" ..
+ fgettext("Are you sure you want to delete \"$1\"?", dialogdata.mod.name) .. "]"..
+ "button[3.25,3.5;2.5,0.5;dlg_delete_mod_confirm;" .. fgettext("Delete") .. "]" ..
+ "button[5.75,3.5;2.5,0.5;dlg_delete_mod_cancel;" .. fgettext("Cancel") .. "]"
return retval
end
diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua
index aa710ef3b..1e5af1feb 100644
--- a/builtin/mainmenu/dlg_delete_world.lua
+++ b/builtin/mainmenu/dlg_delete_world.lua
@@ -19,11 +19,11 @@
local function delete_world_formspec(dialogdata)
local retval =
- "size[12,6,true]" ..
+ "size[11.5,4.5,true]" ..
"label[2,2;" ..
- fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]"..
- "button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
- "button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
+ fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
+ "button[3.25,3.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
+ "button[5.75,3.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
return retval
end
diff --git a/builtin/mainmenu/dlg_rename_modpack.lua b/builtin/mainmenu/dlg_rename_modpack.lua
index 9e252408a..959c65d9b 100644
--- a/builtin/mainmenu/dlg_rename_modpack.lua
+++ b/builtin/mainmenu/dlg_rename_modpack.lua
@@ -22,14 +22,12 @@ local function rename_modpack_formspec(dialogdata)
dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
local retval =
- "size[12.4,5,true]" ..
- "label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
- "field[4.5,1.4;6,0.5;te_modpack_name;;" ..
- dialogdata.mod.name ..
- "]" ..
- "button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
+ "size[11.5,4.5,true]" ..
+ "field[2.5,2;7,0.5;te_modpack_name;".. fgettext("Rename Modpack:") .. ";" ..
+ dialogdata.mod.name .. "]" ..
+ "button[3.25,3.5;2.5,0.5;dlg_rename_modpack_confirm;"..
fgettext("Accept") .. "]" ..
- "button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
+ "button[5.75,3.5;2.5,0.5;dlg_rename_modpack_cancel;"..
fgettext("Cancel") .. "]"
return retval
diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua
new file mode 100644
index 000000000..f5e80c252
--- /dev/null
+++ b/builtin/mainmenu/dlg_settings_advanced.lua
@@ -0,0 +1,760 @@
+--Minetest
+--Copyright (C) 2015 PilzAdam
+--
+--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 FILENAME = "settingtypes.txt"
+
+local CHAR_CLASSES = {
+ SPACE = "[%s]",
+ VARIABLE = "[%w_%-%.]",
+ INTEGER = "[+-]?[%d]",
+ FLOAT = "[+-]?[%d%.]",
+ FLAGS = "[%w_%-%.,]",
+}
+
+-- returns error message, or nil
+local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
+ -- comment
+ local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
+ if comment then
+ if settings.current_comment == "" then
+ settings.current_comment = comment
+ else
+ settings.current_comment = settings.current_comment .. "\n" .. comment
+ end
+ return
+ end
+
+ -- clear current_comment so only comments directly above a setting are bound to it
+ -- but keep a local reference to it for variables in the current line
+ local current_comment = settings.current_comment
+ settings.current_comment = ""
+
+ -- empty lines
+ if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
+ return
+ end
+
+ -- category
+ local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
+ if category then
+ table.insert(settings, {
+ name = category,
+ level = stars:len() + base_level,
+ type = "category",
+ })
+ return
+ end
+
+ -- settings
+ local first_part, name, readable_name, setting_type = line:match("^"
+ -- this first capture group matches the whole first part,
+ -- so we can later strip it from the rest of the line
+ .. "("
+ .. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name
+ .. CHAR_CLASSES.SPACE .. "*"
+ .. "%(([^%)]*)%)" -- readable name
+ .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
+ .. CHAR_CLASSES.SPACE .. "*"
+ .. ")")
+
+ if not first_part then
+ return "Invalid line"
+ end
+
+ if name:match("secure%.[.]*") and not allow_secure then
+ return "Tried to add \"secure.\" setting"
+ end
+
+ if readable_name == "" then
+ readable_name = nil
+ end
+ local remaining_line = line:sub(first_part:len() + 1)
+
+ if setting_type == "int" then
+ local default, min, max = remaining_line:match("^"
+ -- first int is required, the last 2 are optional
+ .. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.INTEGER .. "*)"
+ .. "$")
+
+ if not default or not tonumber(default) then
+ return "Invalid integer setting"
+ end
+
+ min = tonumber(min)
+ max = tonumber(max)
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "int",
+ default = default,
+ min = min,
+ max = max,
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "string" or setting_type == "noise_params"
+ or setting_type == "key" or setting_type == "v3f" then
+ local default = remaining_line:match("^(.*)$")
+
+ if not default then
+ return "Invalid string setting"
+ end
+ if setting_type == "key" and not read_all then
+ -- ignore key type if read_all is false
+ return
+ end
+
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = setting_type,
+ default = default,
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "bool" then
+ if remaining_line ~= "false" and remaining_line ~= "true" then
+ return "Invalid boolean setting"
+ end
+
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "bool",
+ default = remaining_line,
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "float" then
+ local default, min, max = remaining_line:match("^"
+ -- first float is required, the last 2 are optional
+ .. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.FLOAT .. "*)"
+ .."$")
+
+ if not default or not tonumber(default) then
+ return "Invalid float setting"
+ end
+
+ min = tonumber(min)
+ max = tonumber(max)
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "float",
+ default = default,
+ min = min,
+ max = max,
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "enum" then
+ local default, values = remaining_line:match("^"
+ -- first value (default) may be empty (i.e. is optional)
+ .. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.FLAGS .. "+)"
+ .. "$")
+
+ if not default or values == "" then
+ return "Invalid enum setting"
+ end
+
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "enum",
+ default = default,
+ values = values:split(",", true),
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "path" then
+ local default = remaining_line:match("^(.*)$")
+
+ if not default then
+ return "Invalid path setting"
+ end
+
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "path",
+ default = default,
+ comment = current_comment,
+ })
+ return
+ end
+
+ if setting_type == "flags" then
+ local default, possible = remaining_line:match("^"
+ -- first value (default) may be empty (i.e. is optional)
+ -- this is implemented by making the last value optional, and
+ -- swapping them around if it turns out empty.
+ .. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*"
+ .. "(" .. CHAR_CLASSES.FLAGS .. "*)"
+ .. "$")
+
+ if not default or not possible then
+ return "Invalid flags setting"
+ end
+
+ if possible == "" then
+ possible = default
+ default = ""
+ end
+
+ table.insert(settings, {
+ name = name,
+ readable_name = readable_name,
+ type = "flags",
+ default = default,
+ possible = possible,
+ comment = current_comment,
+ })
+ return
+ end
+
+ return "Invalid setting type \"" .. setting_type .. "\""
+end
+
+local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
+ -- store this helper variable in the table so it's easier to pass to parse_setting_line()
+ result.current_comment = ""
+
+ local line = file:read("*line")
+ while line do
+ local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
+ if error_msg then
+ core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
+ end
+ line = file:read("*line")
+ end
+
+ result.current_comment = nil
+end
+
+-- read_all: whether to ignore certain setting types for GUI or not
+-- parse_mods: whether to parse settingtypes.txt in mods and games
+local function parse_config_file(read_all, parse_mods)
+ local builtin_path = core.get_builtin_path() .. DIR_DELIM .. FILENAME
+ local file = io.open(builtin_path, "r")
+ local settings = {}
+ if not file then
+ core.log("error", "Can't load " .. FILENAME)
+ return settings
+ end
+
+ parse_single_file(file, builtin_path, read_all, settings, 0, true)
+
+ file:close()
+
+ if parse_mods then
+ -- Parse games
+ local games_category_initialized = false
+ local index = 1
+ local game = gamemgr.get_game(index)
+ while game do
+ local path = game.path .. DIR_DELIM .. FILENAME
+ local file = io.open(path, "r")
+ if file then
+ if not games_category_initialized then
+ local translation = fgettext_ne("Games"), -- not used, but needed for xgettext
+ table.insert(settings, {
+ name = "Games",
+ level = 0,
+ type = "category",
+ })
+ games_category_initialized = true
+ end
+
+ table.insert(settings, {
+ name = game.name,
+ level = 1,
+ type = "category",
+ })
+
+ parse_single_file(file, path, read_all, settings, 2, false)
+
+ file:close()
+ end
+
+ index = index + 1
+ game = gamemgr.get_game(index)
+ end
+
+ -- Parse mods
+ local mods_category_initialized = false
+ local mods = {}
+ get_mods(core.get_modpath(), 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
+ local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext
+ table.insert(settings, {
+ name = "Mods",
+ level = 0,
+ type = "category",
+ })
+ mods_category_initialized = true
+ end
+
+ table.insert(settings, {
+ name = mod.name,
+ level = 1,
+ type = "category",
+ })
+
+ parse_single_file(file, path, read_all, settings, 2, false)
+
+ file:close()
+ end
+ end
+ end
+
+ return settings
+end
+
+local settings = parse_config_file(false, true)
+local selected_setting = 1
+
+local function get_current_value(setting)
+ local value = core.setting_get(setting.name)
+ if value == nil then
+ value = setting.default
+ end
+ return value
+end
+
+local function create_change_setting_formspec(dialogdata)
+ local setting = settings[selected_setting]
+ local formspec = "size[10,5.2,true]" ..
+ "button[5,4.5;2,1;btn_done;" .. fgettext("Save") .. "]" ..
+ "button[3,4.5;2,1;btn_cancel;" .. fgettext("Cancel") .. "]" ..
+ "tablecolumns[color;text]" ..
+ "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
+ "table[0,0;10,3;info;"
+
+ if setting.readable_name then
+ formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name)
+ .. " (" .. core.formspec_escape(setting.name) .. "),"
+ else
+ formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. ","
+ end
+
+ formspec = formspec .. ",,"
+
+ local comment_text = ""
+
+ if setting.comment == "" then
+ comment_text = fgettext_ne("(No description of setting given)")
+ else
+ comment_text = fgettext_ne(setting.comment)
+ end
+ for _, comment_line in ipairs(comment_text:split("\n", true)) do
+ formspec = formspec .. "," .. core.formspec_escape(comment_line) .. ","
+ end
+
+ if setting.type == "flags" then
+ formspec = formspec .. ",,"
+ .. "," .. fgettext("Please enter a comma seperated list of flags.") .. ","
+ .. "," .. fgettext("Possible values are: ")
+ .. core.formspec_escape(setting.possible:gsub(",", ", ")) .. ","
+ elseif setting.type == "noise_params" then
+ formspec = formspec .. ",,"
+ .. "," .. fgettext("Format: <offset>, <scale>, (<spreadX>, <spreadY>, <spreadZ>), <seed>, <octaves>, <persistence>") .. ","
+ .. "," .. fgettext("Optionally the lacunarity can be appended with a leading comma.") .. ","
+ elseif setting.type == "v3f" then
+ formspec = formspec .. ",,"
+ .. "," .. fgettext_ne("Format is 3 numbers separated by commas and inside brackets.") .. ","
+ end
+
+ formspec = formspec:sub(1, -2) -- remove trailing comma
+
+ formspec = formspec .. ";1]"
+
+ if setting.type == "bool" then
+ local selected_index
+ if core.is_yes(get_current_value(setting)) then
+ selected_index = 2
+ else
+ selected_index = 1
+ end
+ formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
+ .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
+ .. selected_index .. "]"
+
+ elseif setting.type == "enum" then
+ local selected_index = 0
+ formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
+ for index, value in ipairs(setting.values) do
+ -- translating value is not possible, since it's the value
+ -- that we set the setting to
+ formspec = formspec .. core.formspec_escape(value) .. ","
+ if get_current_value(setting) == value then
+ selected_index = index
+ end
+ end
+ if #setting.values > 0 then
+ formspec = formspec:sub(1, -2) -- remove trailing comma
+ end
+ formspec = formspec .. ";" .. selected_index .. "]"
+
+ elseif setting.type == "path" then
+ local current_value = dialogdata.selected_path
+ if not current_value then
+ current_value = get_current_value(setting)
+ end
+ formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;"
+ .. core.formspec_escape(current_value) .. "]"
+ .. "button[8,3.75;2,1;btn_browser_path;" .. fgettext("Browse") .. "]"
+
+ else
+ -- TODO: fancy input for float, int, flags, noise_params, v3f
+ local width = 10
+ local text = get_current_value(setting)
+ if dialogdata.error_message then
+ formspec = formspec .. "tablecolumns[color;text]" ..
+ "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
+ "table[5,3.9;5,0.6;error_message;#FF0000,"
+ .. core.formspec_escape(dialogdata.error_message) .. ";0]"
+ width = 5
+ if dialogdata.entered_text then
+ text = dialogdata.entered_text
+ end
+ end
+ formspec = formspec .. "field[0.5,4;" .. width .. ",1;te_setting_value;;"
+ .. core.formspec_escape(text) .. "]"
+ end
+ return formspec
+end
+
+local function handle_change_setting_buttons(this, fields)
+ if fields["btn_done"] or fields["key_enter"] then
+ local setting = settings[selected_setting]
+ if setting.type == "bool" then
+ local new_value = fields["dd_setting_value"]
+ -- Note: new_value is the actual (translated) value shown in the dropdown
+ core.setting_setbool(setting.name, new_value == fgettext("Enabled"))
+
+ elseif setting.type == "enum" then
+ local new_value = fields["dd_setting_value"]
+ core.setting_set(setting.name, new_value)
+
+ elseif setting.type == "int" then
+ local new_value = tonumber(fields["te_setting_value"])
+ if not new_value or math.floor(new_value) ~= new_value then
+ this.data.error_message = fgettext_ne("Please enter a valid integer.")
+ this.data.entered_text = fields["te_setting_value"]
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+ if setting.min and new_value < setting.min then
+ this.data.error_message = fgettext_ne("The value must be greater than $1.", setting.min)
+ this.data.entered_text = fields["te_setting_value"]
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+ if setting.max and new_value > setting.max then
+ this.data.error_message = fgettext_ne("The value must be lower than $1.", setting.max)
+ this.data.entered_text = fields["te_setting_value"]
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+ core.setting_set(setting.name, new_value)
+
+ elseif setting.type == "float" then
+ local new_value = tonumber(fields["te_setting_value"])
+ if not new_value then
+ this.data.error_message = fgettext_ne("Please enter a valid number.")
+ this.data.entered_text = fields["te_setting_value"]
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+ core.setting_set(setting.name, new_value)
+
+ elseif setting.type == "flags" then
+ local new_value = fields["te_setting_value"]
+ for _,value in ipairs(new_value:split(",", true)) do
+ value = value:trim()
+ local possible = "," .. setting.possible .. ","
+ if not possible:find("," .. value .. ",", 0, true) then
+ this.data.error_message = fgettext_ne("\"$1\" is not a valid flag.", value)
+ this.data.entered_text = fields["te_setting_value"]
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+ end
+ core.setting_set(setting.name, new_value)
+
+ else
+ local new_value = fields["te_setting_value"]
+ core.setting_set(setting.name, new_value)
+ end
+ core.setting_save()
+ this:delete()
+ return true
+ end
+
+ if fields["btn_cancel"] then
+ this:delete()
+ return true
+ end
+
+ if fields["btn_browser_path"] then
+ core.show_file_open_dialog("dlg_browse_path", fgettext_ne("Select path"))
+ end
+
+ if fields["dlg_browse_path_accepted"] then
+ this.data.selected_path = fields["dlg_browse_path_accepted"]
+ core.update_formspec(this:get_formspec())
+ end
+
+ return false
+end
+
+local function create_settings_formspec(tabview, name, tabdata)
+ local formspec = "size[12,6.5;true]" ..
+ "tablecolumns[color;tree;text;text]" ..
+ "tableoptions[background=#00000000;border=false]" ..
+ "table[0,0;12,5.5;list_settings;"
+
+ local current_level = 0
+ for _, entry in ipairs(settings) do
+ local name
+ if not core.setting_getbool("main_menu_technical_settings") and entry.readable_name then
+ name = fgettext_ne(entry.readable_name)
+ else
+ name = entry.name
+ end
+
+ if entry.type == "category" then
+ current_level = entry.level
+ formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
+
+ elseif entry.type == "bool" then
+ local value = get_current_value(entry)
+ if core.is_yes(value) then
+ value = fgettext("Enabled")
+ else
+ value = fgettext("Disabled")
+ end
+ formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
+ .. value .. ","
+
+ elseif entry.type == "key" then
+ -- ignore key settings, since we have a special dialog for them
+
+ else
+ formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
+ .. core.formspec_escape(get_current_value(entry)) .. ","
+ end
+ end
+
+ if #settings > 0 then
+ formspec = formspec:sub(1, -2) -- remove trailing comma
+ end
+ formspec = formspec .. ";" .. selected_setting .. "]" ..
+ "button[0,6;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
+ "button[10,6;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
+ "button[7,6;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
+ "checkbox[0,5.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
+ .. dump(core.setting_getbool("main_menu_technical_settings")) .. "]"
+
+ return formspec
+end
+
+local function handle_settings_buttons(this, fields, tabname, tabdata)
+ local list_enter = false
+ if fields["list_settings"] then
+ selected_setting = core.get_table_index("list_settings")
+ if core.explode_table_event(fields["list_settings"]).type == "DCL" then
+ -- Directly toggle booleans
+ local setting = settings[selected_setting]
+ if setting.type == "bool" then
+ local current_value = get_current_value(setting)
+ core.setting_setbool(setting.name, not core.is_yes(current_value))
+ core.setting_save()
+ return true
+ else
+ list_enter = true
+ end
+ else
+ return true
+ end
+ end
+
+ if fields["btn_edit"] or list_enter then
+ local setting = settings[selected_setting]
+ if setting.type ~= "category" then
+ local edit_dialog = dialog_create("change_setting", create_change_setting_formspec,
+ handle_change_setting_buttons)
+ edit_dialog:set_parent(this)
+ this:hide()
+ edit_dialog:show()
+ end
+ return true
+ end
+
+ if fields["btn_restore"] then
+ local setting = settings[selected_setting]
+ if setting.type ~= "category" then
+ core.setting_set(setting.name, setting.default)
+ core.setting_save()
+ core.update_formspec(this:get_formspec())
+ end
+ return true
+ end
+
+ if fields["btn_back"] then
+ this:delete()
+ return true
+ end
+
+ if fields["cb_tech_settings"] then
+ core.setting_set("main_menu_technical_settings", fields["cb_tech_settings"])
+ core.setting_save()
+ core.update_formspec(this:get_formspec())
+ return true
+ end
+
+ return false
+end
+
+function create_adv_settings_dlg()
+ local dlg = dialog_create("settings_advanced",
+ create_settings_formspec,
+ handle_settings_buttons,
+ nil)
+
+ return dlg
+end
+
+local function create_minetest_conf_example()
+ local result = "# This file contains a list of all available settings and their default value for minetest.conf\n" ..
+ "\n" ..
+ "# By default, all the settings are commented and not functional.\n" ..
+ "# Uncomment settings by removing the preceding #.\n" ..
+ "\n" ..
+ "# minetest.conf is read by default from:\n" ..
+ "# ../minetest.conf\n" ..
+ "# ../../minetest.conf\n" ..
+ "# Any other path can be chosen by passing the path as a parameter\n" ..
+ "# to the program, eg. \"minetest.exe --config ../minetest.conf.example\".\n" ..
+ "\n" ..
+ "# Further documentation:\n" ..
+ "# http://wiki.minetest.net/\n" ..
+ "\n"
+
+ local settings = parse_config_file(true, false)
+ for _, entry in ipairs(settings) do
+ if entry.type == "category" then
+ if entry.level == 0 then
+ result = result .. "#\n# " .. entry.name .. "\n#\n\n"
+ else
+ for i = 1, entry.level do
+ result = result .. "#"
+ end
+ result = result .. "# " .. entry.name .. "\n\n"
+ end
+ else
+ if entry.comment ~= "" then
+ for _, comment_line in ipairs(entry.comment:split("\n", true)) do
+ result = result .."# " .. comment_line .. "\n"
+ end
+ end
+ result = result .. "# type: " .. entry.type
+ if entry.min then
+ result = result .. " min: " .. entry.min
+ end
+ if entry.max then
+ result = result .. " max: " .. entry.max
+ end
+ if entry.values then
+ result = result .. " values: " .. table.concat(entry.values, ", ")
+ end
+ if entry.possible then
+ result = result .. " possible values: " .. entry.possible:gsub(",", ", ")
+ end
+ result = result .. "\n"
+ local append = ""
+ if entry.default ~= "" then
+ append = " " .. entry.default
+ end
+ result = result .. "# " .. entry.name .. " =" .. append .. "\n\n"
+ end
+ end
+ return result
+end
+
+local function create_translation_file()
+ local result = "// This file is automatically generated\n" ..
+ "// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files\n" ..
+ "// To update it, refer to the bottom of builtin/mainmenu/tab_settings.lua\n\n" ..
+ "fake_function() {\n"
+
+ local settings = parse_config_file(true, false)
+ for _, entry in ipairs(settings) do
+ if entry.type == "category" then
+ local name_escaped = entry.name:gsub("\"", "\\\"")
+ result = result .. "\tgettext(\"" .. name_escaped .. "\");\n"
+ else
+ if entry.readable_name then
+ local readable_name_escaped = entry.readable_name:gsub("\"", "\\\"")
+ result = result .. "\tgettext(\"" .. readable_name_escaped .. "\");\n"
+ end
+ if entry.comment ~= "" then
+ local comment_escaped = entry.comment:gsub("\n", "\\n")
+ comment_escaped = comment_escaped:gsub("\"", "\\\"")
+ result = result .. "\tgettext(\"" .. comment_escaped .. "\");\n"
+ end
+ end
+ end
+ result = result .. "}\n"
+ return result
+end
+
+if false then
+ local file = io.open("minetest.conf.example", "w")
+ if file then
+ file:write(create_minetest_conf_example())
+ file:close()
+ end
+end
+
+if false then
+ local file = io.open("src/settings_translation_file.cpp", "w")
+ if file then
+ file:write(create_translation_file())
+ file:close()
+ end
+end
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index 176796bef..7f0c1e386 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -37,22 +37,29 @@ dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "gamemgr.lua")
dofile(menupath .. DIR_DELIM .. "modmgr.lua")
dofile(menupath .. DIR_DELIM .. "store.lua")
+dofile(menupath .. DIR_DELIM .. "textures.lua")
+
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
-dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
-dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
-dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
if PLATFORM ~= "Android" then
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
- dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
- dofile(menupath .. DIR_DELIM .. "tab_server.lua")
- dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
- dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
- dofile(menupath .. DIR_DELIM .. "textures.lua")
+end
+
+local tabs = {}
+
+tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
+tabs.mods = dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
+tabs.credits = dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
+if PLATFORM == "Android" then
+ tabs.simple_main = dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
else
- dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
+ tabs.singleplayer = dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
+ tabs.multiplayer = dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
+ tabs.server = dofile(menupath .. DIR_DELIM .. "tab_server.lua")
+ tabs.texturepacks = dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
end
--------------------------------------------------------------------------------
@@ -68,8 +75,34 @@ local function init_globals()
-- Init gamedata
gamedata.worldindex = 0
+ if PLATFORM == "Android" then
+ local world_list = core.get_worlds()
+ local world_index
- if PLATFORM ~= "Android" then
+ local found_singleplayerworld = false
+ for i, world in ipairs(world_list) do
+ if world.name == "singleplayerworld" then
+ found_singleplayerworld = true
+ world_index = i
+ break
+ end
+ end
+
+ if not found_singleplayerworld then
+ core.create_world("singleplayerworld", 1)
+
+ world_list = core.get_worlds()
+
+ for i, world in ipairs(world_list) do
+ if world.name == "singleplayerworld" then
+ world_index = i
+ break
+ end
+ end
+ end
+
+ gamedata.worldindex = world_index
+ else
menudata.worldlist = filterlist.create(
core.get_worlds,
compare_worlds,
@@ -88,61 +121,34 @@ local function init_globals()
if not core.setting_get("menu_last_game") then
local default_game = core.setting_get("default_game") or "minetest"
- core.setting_set("menu_last_game", default_game )
+ core.setting_set("menu_last_game", default_game)
end
mm_texture.init()
- else
- local world_list = core.get_worlds()
-
- local found_singleplayerworld = false
-
- for i,world in pairs(world_list) do
- if world.name == "singleplayerworld" then
- found_singleplayerworld = true
- gamedata.worldindex = i
- break
- end
- end
-
- if not found_singleplayerworld then
- core.create_world("singleplayerworld", 1)
-
- local world_list = core.get_worlds()
-
- for i,world in pairs(world_list) do
- if world.name == "singleplayerworld" then
- gamedata.worldindex = i
- break
- end
- end
- end
end
-- Create main tabview
- local tv_main = tabview_create("maintab",{x=12,y=5.2},{x=0,y=0})
- if PLATFORM ~= "Android" then
- tv_main:set_autosave_tab(true)
- end
- if PLATFORM ~= "Android" then
- tv_main:add(tab_singleplayer)
- tv_main:add(tab_multiplayer)
- tv_main:add(tab_server)
+ local tv_main = tabview_create("maintab", {x = 12, y = 5.2}, {x = 0, y = 0})
+
+ if PLATFORM == "Android" then
+ tv_main:add(tabs.simple_main)
+ tv_main:add(tabs.settings)
else
- tv_main:add(tab_simple_main)
- end
- tv_main:add(tab_settings)
- if PLATFORM ~= "Android" then
- tv_main:add(tab_texturepacks)
+ tv_main:set_autosave_tab(true)
+ tv_main:add(tabs.singleplayer)
+ tv_main:add(tabs.multiplayer)
+ tv_main:add(tabs.server)
+ tv_main:add(tabs.settings)
+ tv_main:add(tabs.texturepacks)
end
- tv_main:add(tab_mods)
- tv_main:add(tab_credits)
- tv_main:set_global_event_handler(main_event_handler)
+ tv_main:add(tabs.mods)
+ tv_main:add(tabs.credits)
+ tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false)
- if not (PLATFORM == "Android") then
+ if PLATFORM ~= "Android" then
tv_main:set_tab(core.setting_get("maintab_LAST"))
end
ui.set_default("maintab")
@@ -150,9 +156,9 @@ local function init_globals()
-- Create modstore ui
if PLATFORM == "Android" then
- modstore.init({x=12, y=6}, 3, 2)
+ modstore.init({x = 12, y = 6}, 3, 2)
else
- modstore.init({x=12, y=8}, 4, 3)
+ modstore.init({x = 12, y = 8}, 4, 3)
end
ui.update()
diff --git a/builtin/mainmenu/init_simple.lua b/builtin/mainmenu/init_simple.lua
index c3891d21c..298bd834e 100644
--- a/builtin/mainmenu/init_simple.lua
+++ b/builtin/mainmenu/init_simple.lua
@@ -1,4 +1,4 @@
-- helper file to be able to debug the simple menu on PC
-- without messing around with actual menu code!
-PLATFORM="Android"
+PLATFORM = "Android"
dofile("builtin/mainmenu/init.lua")
diff --git a/builtin/mainmenu/modmgr.lua b/builtin/mainmenu/modmgr.lua
index 89292ed52..f996df7ba 100644
--- a/builtin/mainmenu/modmgr.lua
+++ b/builtin/mainmenu/modmgr.lua
@@ -19,29 +19,29 @@
function get_mods(path,retval,modpack)
local mods = core.get_dir_list(path, true)
- for i=1, #mods, 1 do
- if mods[i]:sub(1,1) ~= "." then
+ for _, name in ipairs(mods) do
+ if name:sub(1, 1) ~= "." then
+ local prefix = path .. DIR_DELIM .. name .. DIR_DELIM
local toadd = {}
- local modpackfile = nil
+ retval[#retval + 1] = toadd
- toadd.name = mods[i]
- toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
- if modpack ~= nil and
- modpack ~= "" then
- toadd.modpack = modpack
- else
- local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
- local error = nil
- modpackfile,error = io.open(filename,"r")
+ local mod_conf = Settings(prefix .. "mod.conf"):to_table()
+ if mod_conf.name then
+ name = mod_conf.name
end
- if modpackfile ~= nil then
- modpackfile:close()
- toadd.is_modpack = true
- table.insert(retval,toadd)
- get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
+ toadd.name = name
+ toadd.path = prefix
+
+ if modpack ~= nil and modpack ~= "" then
+ toadd.modpack = modpack
else
- table.insert(retval,toadd)
+ local modpackfile = io.open(prefix .. "modpack.txt")
+ if modpackfile then
+ modpackfile:close()
+ toadd.is_modpack = true
+ get_mods(prefix, retval, name)
+ end
end
end
end
@@ -412,7 +412,7 @@ function modmgr.preparemodlist(data)
for i=1,#global_mods,1 do
global_mods[i].typ = "global_mod"
- table.insert(retval,global_mods[i])
+ retval[#retval + 1] = global_mods[i]
end
--read game mods
@@ -421,7 +421,7 @@ function modmgr.preparemodlist(data)
for i=1,#game_mods,1 do
game_mods[i].typ = "game_mod"
- table.insert(retval,game_mods[i])
+ retval[#retval + 1] = game_mods[i]
end
if data.worldpath == nil then
diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua
index 33c84f58f..4d2ffd7f4 100644
--- a/builtin/mainmenu/tab_credits.lua
+++ b/builtin/mainmenu/tab_credits.lua
@@ -17,64 +17,84 @@
--------------------------------------------------------------------------------
-tab_credits = {
+local core_developers = {
+ "Perttu Ahola (celeron55) <celeron55@gmail.com>",
+ "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
+ "PilzAdam <pilzadam@minetest.net>",
+ "sfan5 <sfan5@live.de>",
+ "kahrl <kahrl@gmx.net>",
+ "sapier",
+ "ShadowNinja <shadowninja@minetest.net>",
+ "Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>",
+ "Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
+ "Matt Gregory (paramat)",
+ "est31 <MTest31@outlook.com>",
+ "Craig Robbins (Zeno)",
+}
+
+local active_contributors = {
+ "Auke Kok (sofar) <sofar@foo-projects.org>",
+ "Duane Robertson <duane@duanerobertson.com>",
+ "SmallJoker <mk939@ymail.com>",
+ "Andrew Ward (rubenwardy) <rubenwardy@gmail.com>",
+ "Jeija <jeija@mesecons.net>",
+ "Gregory Currie (gregorycu)",
+ "Sokomine <wegwerf@anarres.dyndns.org>",
+ "TeTpaAka",
+ "Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com>",
+ "Diego Martínez (kaeza) <kaeza@users.sf.net>",
+}
+
+local previous_core_developers = {
+ "BlockMen",
+ "Maciej Kasatkin (RealBadAngel) <maciej.kasatkin@o2.pl>",
+ "Lisa Milne (darkrose) <lisa@ltmnet.com>",
+ "proller",
+ "Ilya Zhuravlev (xyz) <xyz@minetest.net>",
+}
+
+local previous_contributors = {
+ "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>",
+ "Jurgen Doser (doserj) <jurgen.doser@gmail.com>",
+ "MirceaKitsune <mirceakitsune@gmail.com>",
+ "dannydark <the_skeleton_of_a_child@yahoo.co.uk>",
+ "0gb.us <0gb.us@0gb.us>",
+ "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>",
+ "Jonathan Neuschafer <j.neuschaefer@gmx.net>",
+ "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>",
+ "Břetislav Štec (t0suj4/TBC_x)",
+ "Aaron Suen <warr1024@gmail.com>",
+ "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>",
+ "matttpt <matttpt@gmail.com>",
+ "JacobF <queatz@gmail.com>",
+ "TriBlade9 <triblade9@mail.com>",
+ "Zefram <zefram@fysh.org>",
+}
+
+return {
name = "credits",
caption = fgettext("Credits"),
- cbf_formspec = function (tabview, name, tabdata)
- local logofile = defaulttexturedir .. "logo.png"
- return "label[0.5,3.2;Minetest " .. core.get_version() .. "]" ..
- "label[0.5,3.5;http://minetest.net]" ..
- "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..
- "tablecolumns[color;text]" ..
- "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
- "table[3.5,-0.25;8.5,5.8;list_credits;" ..
- "#FFFF00," .. fgettext("Core Developers") .."," ..
- ",Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
- ",Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
- ",PilzAdam <pilzadam@minetest.net>," ..
- ",sfan5 <sfan5@live.de>,"..
- ",kahrl <kahrl@gmx.net>,"..
- ",sapier,"..
- ",ShadowNinja <shadowninja@minetest.net>,"..
- ",Nathanael Courant (Nore/Ekdohibs) <nore@mesecons.net>,"..
- ",BlockMen,"..
- ",Craig Robbins (Zeno),"..
- ",Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>,"..
- ",Mat Gregory (paramat),"..
- ",est31 <MTest31@outlook.com>," ..
- ",,"..
- "#FFFF00," .. fgettext("Active Contributors") .. "," ..
- ",SmallJoker <mk939@ymail.com>," ..
- ",Andrew Ward (rubenwardy) <rubenwardy@gmail.com>," ..
- ",Aaron Suen <warr1024@gmail.com>," ..
- ",Sokomine <wegwerf@anarres.dyndns.org>," ..
- ",Břetislav Štec (TeTpaAka)," ..
- ",Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com>," ..
- ",Rui <mrrst0914@gmail.com>," ..
- ",Diego Martinez (kaeza) <kaeza@users.sf.net>," ..
- ",," ..
- "#FFFF00," .. fgettext("Previous Core Developers") .."," ..
- ",Maciej Kasatkin (RealBadAngel) <maciej.kasatkin@o2.pl>,"..
- ",Lisa Milne (darkrose) <lisa@ltmnet.com>," ..
- ",proller," ..
- ",Ilya Zhuravlev (xyz) <xyz@minetest.net>," ..
- ",," ..
- "#FFFF00," .. fgettext("Previous Contributors") .. "," ..
- ",Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
- ",Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
- ",Gregory Currie (gregorycu)," ..
- ",Jeija <jeija@mesecons.net>,"..
- ",MirceaKitsune <mirceakitsune@gmail.com>,"..
- ",dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
- ",0gb.us <0gb.us@0gb.us>,"..
- ",Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
- ",Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
- ",Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
- ",Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
- ",matttpt <matttpt@gmail.com>,"..
- ",JacobF <queatz@gmail.com>,"..
- ",TriBlade9 <triblade9@mail.com>,"..
- ",Zefram <zefram@fysh.org>,"..
- ";1]"
- end
- }
+ cbf_formspec = function(tabview, name, tabdata)
+ local logofile = defaulttexturedir .. "logo.png"
+ return "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..
+ "label[0.5,3.2;Minetest " .. core.get_version() .. "]" ..
+ "label[0.5,3.5;http://minetest.net]" ..
+ "tablecolumns[color;text]" ..
+ "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
+ "table[3.5,-0.25;8.5,5.8;list_credits;" ..
+ "#FFFF00," .. "Dedication of the current release" .. ",," ..
+ "The 0.4.14 release is dedicated to the memory of" .. ",," ..
+ "Minetest developer Maciej Kasatkin (RealBadAngel)" .. ",," ..
+ "who died on March 24 2016." .. ",," ..
+ "Our thoughts are with his family and friends." .. ",,," ..
+ "#FFFF00," .. fgettext("Core Developers") .. ",," ..
+ table.concat(core_developers, ",,") .. ",,," ..
+ "#FFFF00," .. fgettext("Active Contributors") .. ",," ..
+ table.concat(active_contributors, ",,") .. ",,," ..
+ "#FFFF00," .. fgettext("Previous Core Developers") ..",," ..
+ table.concat(previous_core_developers, ",,") .. ",,," ..
+ "#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
+ table.concat(previous_contributors, ",,") .. "," ..
+ ";1]"
+ end
+}
diff --git a/builtin/mainmenu/tab_mods.lua b/builtin/mainmenu/tab_mods.lua
index 2ddc9b07c..5b59aa110 100644
--- a/builtin/mainmenu/tab_mods.lua
+++ b/builtin/mainmenu/tab_mods.lua
@@ -28,7 +28,7 @@ local function get_formspec(tabview, name, tabdata)
local retval =
"label[0.05,-0.25;".. fgettext("Installed Mods:") .. "]" ..
- "textlist[0,0.25;5.1,4.35;modlist;" ..
+ "textlist[0,0.25;5.1,5;modlist;" ..
modmgr.render_modlist(modmgr.global_mods) ..
";" .. tabdata.selected_mod .. "]"
@@ -78,7 +78,7 @@ local function get_formspec(tabview, name, tabdata)
descriptionfile:close()
else
descriptionlines = {}
- table.insert(descriptionlines,fgettext("No mod description available"))
+ descriptionlines[#descriptionlines + 1] = fgettext("No mod description available")
end
retval = retval ..
@@ -163,7 +163,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
end
--------------------------------------------------------------------------------
-tab_mods = {
+return {
name = "mods",
caption = fgettext("Mods"),
cbf_formspec = get_formspec,
diff --git a/builtin/mainmenu/tab_multiplayer.lua b/builtin/mainmenu/tab_multiplayer.lua
index 570259718..00150f26d 100644
--- a/builtin/mainmenu/tab_multiplayer.lua
+++ b/builtin/mainmenu/tab_multiplayer.lua
@@ -17,68 +17,71 @@
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
- local render_details = core.is_yes(core.setting_getbool("public_serverlist"))
-
- local retval =
- "label[7.75,-0.15;" .. fgettext("Address / Port :") .. "]" ..
- "label[7.75,1.05;" .. fgettext("Name / Password :") .. "]" ..
- "field[8,0.75;3.4,0.5;te_address;;" ..
- core.formspec_escape(core.setting_get("address")) .. "]" ..
- "field[11.25,0.75;1.3,0.5;te_port;;" ..
- core.formspec_escape(core.setting_get("remote_port")) .. "]" ..
- "checkbox[0,4.85;cb_public_serverlist;" .. fgettext("Public Serverlist") .. ";" ..
- dump(core.setting_getbool("public_serverlist")) .. "]"
-
- if not core.setting_getbool("public_serverlist") then
- retval = retval ..
- "button[8,4.9;2,0.5;btn_delete_favorite;" .. fgettext("Delete") .. "]"
- end
+ -- Update the cached supported proto info,
+ -- it may have changed after a change by the settings menu.
+ common_update_cached_supp_proto()
+ local fav_selected = menudata.favorites[tabdata.fav_selected]
- retval = retval ..
- "button[10,4.9;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" ..
+ local retval =
+ "label[7.75,-0.15;" .. fgettext("Address / Port") .. "]" ..
+ "label[7.75,1.05;" .. fgettext("Name / Password") .. "]" ..
+ "field[8,0.75;3.3,0.5;te_address;;" ..
+ core.formspec_escape(core.setting_get("address")) .. "]" ..
+ "field[11.15,0.75;1.4,0.5;te_port;;" ..
+ core.formspec_escape(core.setting_get("remote_port")) .. "]" ..
+ "button[10.1,4.9;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" ..
"field[8,1.95;2.95,0.5;te_name;;" ..
- core.formspec_escape(core.setting_get("name")) .. "]" ..
+ core.formspec_escape(core.setting_get("name")) .. "]" ..
"pwdfield[10.78,1.95;1.77,0.5;te_pwd;]" ..
- "box[7.73,2.35;4.3,2.28;#999999]" ..
- "textarea[8.1,2.4;4.26,2.6;;"
-
- if tabdata.fav_selected ~= nil and
- menudata.favorites[tabdata.fav_selected] ~= nil and
- menudata.favorites[tabdata.fav_selected].description ~= nil then
- retval = retval ..
- core.formspec_escape(menudata.favorites[tabdata.fav_selected].description,true)
- end
+ "box[7.73,2.35;4.3,2.28;#999999]"
- retval = retval ..
- ";]"
+ if tabdata.fav_selected and fav_selected then
+ if gamedata.fav then
+ retval = retval .. "button[7.85,4.9;2.3,0.5;btn_delete_favorite;" ..
+ fgettext("Del. Favorite") .. "]"
+ end
+ if fav_selected.description then
+ retval = retval .. "textarea[8.1,2.4;4.26,2.6;;" ..
+ core.formspec_escape((gamedata.serverdescription or ""), true) .. ";]"
+ end
+ end
--favourites
- if render_details then
- retval = retval .. "tablecolumns[" ..
- "color,span=3;" ..
- "text,align=right;" .. -- clients
- "text,align=center,padding=0.25;" .. -- "/"
- "text,align=right,padding=0.25;" .. -- clients_max
- image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
- image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
- image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
- "color,span=1;" ..
- "text,padding=1]" -- name
- else
- retval = retval .. "tablecolumns[text]"
- end
- retval = retval ..
- "table[-0.15,-0.1;7.75,5;favourites;"
+ retval = retval .. "tablecolumns[" ..
+ image_column(fgettext("Favorite"), "favorite") .. ";" ..
+ "color,span=3;" ..
+ "text,align=right;" .. -- clients
+ "text,align=center,padding=0.25;" .. -- "/"
+ "text,align=right,padding=0.25;" .. -- clients_max
+ image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
+ image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
+ image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
+ "color,span=1;" ..
+ "text,padding=1]" ..
+ "table[-0.15,-0.1;7.75,5.5;favourites;"
if #menudata.favorites > 0 then
- retval = retval .. render_favorite(menudata.favorites[1],render_details)
-
- for i=2,#menudata.favorites,1 do
- retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
+ local favs = core.get_favorites("local")
+ if #favs > 0 then
+ for i = 1, #favs do
+ for j = 1, #menudata.favorites do
+ if menudata.favorites[j].address == favs[i].address and
+ menudata.favorites[j].port == favs[i].port then
+ table.insert(menudata.favorites, i, table.remove(menudata.favorites, j))
+ end
+ end
+ if favs[i].address ~= menudata.favorites[i].address then
+ table.insert(menudata.favorites, i, favs[i])
+ end
+ end
+ end
+ retval = retval .. render_favorite(menudata.favorites[1], (#favs > 0))
+ for i = 2, #menudata.favorites do
+ retval = retval .. "," .. render_favorite(menudata.favorites[i], (i <= #favs))
end
end
- if tabdata.fav_selected ~= nil then
+ if tabdata.fav_selected then
retval = retval .. ";" .. tabdata.fav_selected .. "]"
else
retval = retval .. ";0]"
@@ -89,36 +92,38 @@ end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
- if fields["te_name"] ~= nil then
- gamedata.playername = fields["te_name"]
- core.setting_set("name", fields["te_name"])
+ if fields.te_name then
+ gamedata.playername = fields.te_name
+ core.setting_set("name", fields.te_name)
end
- if fields["favourites"] ~= nil then
- local event = core.explode_table_event(fields["favourites"])
+ if fields.favourites then
+ local event = core.explode_table_event(fields.favourites)
+ local fav = menudata.favorites[event.row]
+
if event.type == "DCL" then
if event.row <= #menudata.favorites then
- if not is_server_protocol_compat_or_error(menudata.favorites[event.row].proto_min,
- menudata.favorites[event.row].proto_max) then
+ if menudata.favorites_is_public and
+ not is_server_protocol_compat_or_error(
+ fav.proto_min, fav.proto_max) then
return true
end
- gamedata.address = menudata.favorites[event.row].address
- gamedata.port = menudata.favorites[event.row].port
- gamedata.playername = fields["te_name"]
- if fields["te_pwd"] ~= nil then
- gamedata.password = fields["te_pwd"]
- end
+
+ gamedata.address = fav.address
+ gamedata.port = fav.port
+ gamedata.playername = fields.te_name
gamedata.selected_world = 0
- if menudata.favorites ~= nil then
- gamedata.servername = menudata.favorites[event.row].name
- gamedata.serverdescription = menudata.favorites[event.row].description
+ if fields.te_pwd then
+ gamedata.password = fields.te_pwd
end
- if gamedata.address ~= nil and
- gamedata.port ~= nil then
- core.setting_set("address",gamedata.address)
- core.setting_set("remote_port",gamedata.port)
+ gamedata.servername = fav.name
+ gamedata.serverdescription = fav.description
+
+ if gamedata.address and gamedata.port then
+ core.setting_set("address", gamedata.address)
+ core.setting_set("remote_port", gamedata.port)
core.start()
end
end
@@ -127,101 +132,92 @@ local function main_button_handler(tabview, fields, name, tabdata)
if event.type == "CHG" then
if event.row <= #menudata.favorites then
- local address = menudata.favorites[event.row].address
- local port = menudata.favorites[event.row].port
-
- if address ~= nil and
- port ~= nil then
- core.setting_set("address",address)
- core.setting_set("remote_port",port)
+ gamedata.fav = false
+ local favs = core.get_favorites("local")
+ local address = fav.address
+ local port = fav.port
+ gamedata.serverdescription = fav.description
+
+ for i = 1, #favs do
+ if fav.address == favs[i].address and
+ fav.port == favs[i].port then
+ gamedata.fav = true
+ end
end
+ if address and port then
+ core.setting_set("address", address)
+ core.setting_set("remote_port", port)
+ end
tabdata.fav_selected = event.row
end
-
return true
end
end
- if fields["key_up"] ~= nil or
- fields["key_down"] ~= nil then
-
+ if fields.key_up or fields.key_down then
local fav_idx = core.get_table_index("favourites")
+ local fav = menudata.favorites[fav_idx]
- if fav_idx ~= nil then
- if fields["key_up"] ~= nil and fav_idx > 1 then
- fav_idx = fav_idx -1
- else if fields["key_down"] and fav_idx < #menudata.favorites then
- fav_idx = fav_idx +1
- end end
+ if fav_idx then
+ if fields.key_up and fav_idx > 1 then
+ fav_idx = fav_idx - 1
+ elseif fields.key_down and fav_idx < #menudata.favorites then
+ fav_idx = fav_idx + 1
+ end
else
fav_idx = 1
end
-
- if menudata.favorites == nil or
- menudata.favorites[fav_idx] == nil then
+
+ if not menudata.favorites or not fav then
tabdata.fav_selected = 0
return true
end
-
- local address = menudata.favorites[fav_idx].address
- local port = menudata.favorites[fav_idx].port
-
- if address ~= nil and
- port ~= nil then
- core.setting_set("address",address)
- core.setting_set("remote_port",port)
- end
-
- tabdata.fav_selected = fav_idx
- return true
- end
- if fields["cb_public_serverlist"] ~= nil then
- core.setting_set("public_serverlist", fields["cb_public_serverlist"])
+ local address = fav.address
+ local port = fav.port
- if core.setting_getbool("public_serverlist") then
- asyncOnlineFavourites()
- else
- menudata.favorites = core.get_favorites("local")
+ if address and port then
+ core.setting_set("address", address)
+ core.setting_set("remote_port", port)
end
- tabdata.fav_selected = nil
+
+ tabdata.fav_selected = fav_idx
return true
end
- if fields["btn_delete_favorite"] ~= nil then
+ if fields.btn_delete_favorite then
local current_favourite = core.get_table_index("favourites")
- if current_favourite == nil then return end
+ if not current_favourite then return end
+
core.delete_favorite(current_favourite)
- menudata.favorites = order_favorite_list(core.get_favorites())
+ asyncOnlineFavourites()
tabdata.fav_selected = nil
- core.setting_set("address","")
- core.setting_set("remote_port","30000")
-
+ core.setting_set("address", "")
+ core.setting_set("remote_port", "30000")
return true
end
- if (fields["btn_mp_connect"] ~= nil or
- fields["key_enter"] ~= nil) and fields["te_address"] ~= nil and
- fields["te_port"] ~= nil then
-
- gamedata.playername = fields["te_name"]
- gamedata.password = fields["te_pwd"]
- gamedata.address = fields["te_address"]
- gamedata.port = fields["te_port"]
-
+ if (fields.btn_mp_connect 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 = fields.te_port
+ gamedata.selected_world = 0
local fav_idx = core.get_table_index("favourites")
+ local fav = menudata.favorites[fav_idx]
- if fav_idx ~= nil and fav_idx <= #menudata.favorites and
- menudata.favorites[fav_idx].address == fields["te_address"] and
- menudata.favorites[fav_idx].port == fields["te_port"] then
+ if fav_idx and fav_idx <= #menudata.favorites and
+ fav.address == fields.te_address and
+ fav.port == fields.te_port then
- gamedata.servername = menudata.favorites[fav_idx].name
- gamedata.serverdescription = menudata.favorites[fav_idx].description
+ gamedata.servername = fav.name
+ gamedata.serverdescription = fav.description
- if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
- menudata.favorites[fav_idx].proto_max)then
+ if menudata.favorites_is_public and
+ not is_server_protocol_compat_or_error(
+ fav.proto_min, fav.proto_max) then
return true
end
else
@@ -229,10 +225,8 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.serverdescription = ""
end
- gamedata.selected_world = 0
-
- core.setting_set("address", fields["te_address"])
- core.setting_set("remote_port",fields["te_port"])
+ core.setting_set("address", fields.te_address)
+ core.setting_set("remote_port", fields.te_port)
core.start()
return true
@@ -240,22 +234,16 @@ local function main_button_handler(tabview, fields, name, tabdata)
return false
end
-local function on_change(type,old_tab,new_tab)
- if type == "LEAVE" then
- return
- end
- if core.setting_getbool("public_serverlist") then
- asyncOnlineFavourites()
- else
- menudata.favorites = core.get_favorites("local")
- end
+local function on_change(type, old_tab, new_tab)
+ if type == "LEAVE" then return end
+ asyncOnlineFavourites()
end
--------------------------------------------------------------------------------
-tab_multiplayer = {
+return {
name = "multiplayer",
caption = fgettext("Client"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_change
- }
+}
diff --git a/builtin/mainmenu/tab_server.lua b/builtin/mainmenu/tab_server.lua
index d08eecc21..6b96825a0 100644
--- a/builtin/mainmenu/tab_server.lua
+++ b/builtin/mainmenu/tab_server.lua
@@ -186,10 +186,10 @@ local function main_button_handler(this, fields, name, tabdata)
end
--------------------------------------------------------------------------------
-tab_server = {
+return {
name = "server",
caption = fgettext("Server"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = nil
- }
+}
diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
index c17a39432..af8df0ccb 100644
--- a/builtin/mainmenu/tab_settings.lua
+++ b/builtin/mainmenu/tab_settings.lua
@@ -17,110 +17,115 @@
--------------------------------------------------------------------------------
-local leaves_style_labels = {
- fgettext("Opaque Leaves"),
- fgettext("Simple Leaves"),
- fgettext("Fancy Leaves")
+local labels = {
+ leaves = {
+ fgettext("Opaque Leaves"),
+ fgettext("Simple Leaves"),
+ fgettext("Fancy Leaves")
+ },
+ node_highlighting = {
+ fgettext("Node Outlining"),
+ fgettext("Node Highlighting")
+ },
+ filters = {
+ fgettext("No Filter"),
+ fgettext("Bilinear Filter"),
+ fgettext("Trilinear Filter")
+ },
+ mipmap = {
+ fgettext("No Mipmap"),
+ fgettext("Mipmap"),
+ fgettext("Mipmap + Aniso. Filter")
+ },
+ antialiasing = {
+ fgettext("None"),
+ fgettext("2x"),
+ fgettext("4x"),
+ fgettext("8x")
+ }
}
-local leaves_style = {
- {leaves_style_labels[1]..","..leaves_style_labels[2]..","..leaves_style_labels[3]},
- {"opaque", "simple", "fancy"},
+local dd_options = {
+ leaves = {
+ table.concat(labels.leaves, ","),
+ {"opaque", "simple", "fancy"}
+ },
+ node_highlighting = {
+ table.concat(labels.node_highlighting, ","),
+ {"box", "halo"}
+ },
+ filters = {
+ table.concat(labels.filters, ","),
+ {"", "bilinear_filter", "trilinear_filter"}
+ },
+ mipmap = {
+ table.concat(labels.mipmap, ","),
+ {"", "mip_map", "anisotropic_filter"}
+ },
+ antialiasing = {
+ table.concat(labels.antialiasing, ","),
+ {"0", "2", "4", "8"}
+ }
}
-local dd_filter_labels = {
- fgettext("No Filter"),
- fgettext("Bilinear Filter"),
- fgettext("Trilinear Filter")
-}
-
-local filters = {
- {dd_filter_labels[1]..","..dd_filter_labels[2]..","..dd_filter_labels[3]},
- {"", "bilinear_filter", "trilinear_filter"},
-}
-
-local dd_mipmap_labels = {
- fgettext("No Mipmap"),
- fgettext("Mipmap"),
- fgettext("Mipmap + Aniso. Filter")
-}
-
-local mipmap = {
- {dd_mipmap_labels[1]..","..dd_mipmap_labels[2]..","..dd_mipmap_labels[3]},
- {"", "mip_map", "anisotropic_filter"},
-}
-
-local function getLeavesStyleSettingIndex()
- local style = core.setting_get("leaves_style")
- if (style == leaves_style[2][3]) then
- return 3
- elseif (style == leaves_style[2][2]) then
- return 2
- end
- return 1
-end
-
-local dd_antialiasing_labels = {
- fgettext("None"),
- fgettext("2x"),
- fgettext("4x"),
- fgettext("8x"),
-}
-
-local antialiasing = {
- {dd_antialiasing_labels[1]..","..dd_antialiasing_labels[2]..","..
- dd_antialiasing_labels[3]..","..dd_antialiasing_labels[4]},
- {"0", "2", "4", "8"}
-}
-
-local function getFilterSettingIndex()
- if (core.setting_get(filters[2][3]) == "true") then
- return 3
- end
- if (core.setting_get(filters[2][3]) == "false" and core.setting_get(filters[2][2]) == "true") then
- return 2
- end
- return 1
-end
-
-local function getMipmapSettingIndex()
- if (core.setting_get(mipmap[2][3]) == "true") then
- return 3
- end
- if (core.setting_get(mipmap[2][3]) == "false" and core.setting_get(mipmap[2][2]) == "true") then
- return 2
- end
- return 1
-end
-
-local function getAntialiasingSettingIndex()
- local antialiasing_setting = core.setting_get("fsaa")
- for i = 1, #(antialiasing[2]) do
- if antialiasing_setting == antialiasing[2][i] then
- return i
+local getSettingIndex = {
+ Leaves = function()
+ local style = core.setting_get("leaves_style")
+ for idx, name in pairs(dd_options.leaves[2]) do
+ if style == name then return idx end
+ end
+ return 1
+ end,
+ NodeHighlighting = function()
+ local style = core.setting_get("node_highlighting")
+ for idx, name in pairs(dd_options.node_highlighting[2]) do
+ if style == name then return idx end
end
+ return 1
+ end,
+ Filter = function()
+ if core.setting_get(dd_options.filters[2][3]) == "true" then
+ return 3
+ elseif core.setting_get(dd_options.filters[2][3]) == "false" and
+ core.setting_get(dd_options.filters[2][2]) == "true" then
+ return 2
+ end
+ return 1
+ end,
+ Mipmap = function()
+ if core.setting_get(dd_options.mipmap[2][3]) == "true" then
+ return 3
+ elseif core.setting_get(dd_options.mipmap[2][3]) == "false" and
+ core.setting_get(dd_options.mipmap[2][2]) == "true" then
+ return 2
+ end
+ return 1
+ end,
+ Antialiasing = function()
+ local antialiasing_setting = core.setting_get("fsaa")
+ for i = 1, #dd_options.antialiasing[2] do
+ if antialiasing_setting == dd_options.antialiasing[2][i] then
+ return i
+ end
+ end
+ return 1
end
- return 1
-end
+}
local function antialiasing_fname_to_name(fname)
- for i = 1, #(dd_antialiasing_labels) do
- if fname == dd_antialiasing_labels[i] then
- return antialiasing[2][i]
+ for i = 1, #labels.antialiasing do
+ if fname == labels.antialiasing[i] then
+ return dd_options.antialiasing[2][i]
end
end
return 0
end
local function dlg_confirm_reset_formspec(data)
- local retval =
- "size[8,3]" ..
- "label[1,1;".. fgettext("Are you sure to reset your singleplayer world?") .. "]"..
- "button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;"..
- fgettext("Yes") .. "]" ..
- "button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;"..
- fgettext("No!!!") .. "]"
- return retval
+ return "size[8,3]" ..
+ "label[1,1;" .. fgettext("Are you sure to reset your singleplayer world?") .. "]" ..
+ "button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;" .. fgettext("Yes") .. "]" ..
+ "button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;" .. fgettext("No") .. "]"
end
local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
@@ -129,7 +134,7 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
local worldlist = core.get_worlds()
local found_singleplayerworld = false
- for i=1,#worldlist,1 do
+ for i = 1, #worldlist do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@@ -141,12 +146,10 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
end
core.create_world("singleplayerworld", 1)
-
worldlist = core.get_worlds()
-
found_singleplayerworld = false
- for i=1,#worldlist,1 do
+ for i = 1, #worldlist do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@@ -170,131 +173,111 @@ local function showconfirm_reset(tabview)
new_dlg:show()
end
-local function gui_scale_to_scrollbar()
- local current_value = tonumber(core.setting_get("gui_scaling"))
-
- if (current_value == nil) or current_value < 0.25 then
- return 0
- end
- if current_value <= 1.25 then
- return ((current_value - 0.25)/ 1.0) * 700
- end
- if current_value <= 6 then
- return ((current_value -1.25) * 100) + 700
- end
-
- return 1000
-end
-
-local function scrollbar_to_gui_scale(value)
- value = tonumber(value)
-
- if (value <= 700) then
- return ((value / 700) * 1.0) + 0.25
- end
- if (value <=1000) then
- return ((value - 700) / 100) + 1.25
- end
-
- return 1
-end
-
local function formspec(tabview, name, tabdata)
local tab_string =
- "box[0,0;3.5,4.0;#999999]" ..
- "checkbox[0.25,0;cb_smooth_lighting;".. fgettext("Smooth Lighting")
- .. ";".. dump(core.setting_getbool("smooth_lighting")) .. "]"..
- "checkbox[0.25,0.5;cb_particles;".. fgettext("Enable Particles") .. ";"
- .. dump(core.setting_getbool("enable_particles")) .. "]"..
- "checkbox[0.25,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
- .. dump(core.setting_getbool("enable_3d_clouds")) .. "]"..
- "checkbox[0.25,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
- .. dump(core.setting_getbool("opaque_water")) .. "]"..
- "checkbox[0.25,2.0;cb_connected_glass;".. fgettext("Connected Glass") .. ";"
- .. dump(core.setting_getbool("connected_glass")) .. "]"..
- "checkbox[0.25,2.5;cb_node_highlighting;".. fgettext("Node Highlighting") .. ";"
- .. dump(core.setting_getbool("enable_node_highlighting")) .. "]"..
- "dropdown[0.25,3.2;3.3;dd_leaves_style;" .. leaves_style[1][1] .. ";"
- .. getLeavesStyleSettingIndex() .. "]" ..
+ "box[0,0;3.5,4.5;#999999]" ..
+ "checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") .. ";"
+ .. dump(core.setting_getbool("smooth_lighting")) .. "]" ..
+ "checkbox[0.25,0.5;cb_particles;" .. fgettext("Particles") .. ";"
+ .. dump(core.setting_getbool("enable_particles")) .. "]" ..
+ "checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";"
+ .. dump(core.setting_getbool("enable_3d_clouds")) .. "]" ..
+ "checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";"
+ .. dump(core.setting_getbool("opaque_water")) .. "]" ..
+ "checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
+ .. dump(core.setting_getbool("connected_glass")) .. "]" ..
+ "dropdown[0.25,2.8;3.3;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
+ .. getSettingIndex.NodeHighlighting() .. "]" ..
+ "dropdown[0.25,3.6;3.3;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
+ .. getSettingIndex.Leaves() .. "]" ..
"box[3.75,0;3.75,3.45;#999999]" ..
- "label[3.85,0.1;".. fgettext("Texturing:") .. "]"..
- "dropdown[3.85,0.55;3.85;dd_filters;" .. filters[1][1] .. ";"
- .. getFilterSettingIndex() .. "]" ..
- "dropdown[3.85,1.35;3.85;dd_mipmap;" .. mipmap[1][1] .. ";"
- .. getMipmapSettingIndex() .. "]" ..
- "label[3.85,2.15;".. fgettext("Antialiasing:") .. "]"..
- "dropdown[3.85,2.6;3.85;dd_antialiasing;" .. antialiasing[1][1] .. ";"
- .. getAntialiasingSettingIndex() .. "]" ..
- "box[7.75,0;4,4;#999999]" ..
- "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
+ "label[3.85,0.1;" .. fgettext("Texturing:") .. "]" ..
+ "dropdown[3.85,0.55;3.85;dd_filters;" .. dd_options.filters[1] .. ";"
+ .. getSettingIndex.Filter() .. "]" ..
+ "dropdown[3.85,1.35;3.85;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
+ .. getSettingIndex.Mipmap() .. "]" ..
+ "label[3.85,2.15;" .. fgettext("Antialiasing:") .. "]" ..
+ "dropdown[3.85,2.6;3.85;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
+ .. getSettingIndex.Antialiasing() .. "]" ..
+ "box[7.75,0;4,4.4;#999999]" ..
+ "checkbox[8,0;cb_shaders;" .. fgettext("Shaders") .. ";"
.. dump(core.setting_getbool("enable_shaders")) .. "]"
- if PLATFORM ~= "Android" then
+ if PLATFORM == "Android" then
tab_string = tab_string ..
- "button[8,4.75;3.75,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
+ "button[8,4.75;3.75,0.5;btn_reset_singleplayer;"
+ .. fgettext("Reset singleplayer world") .. "]"
else
tab_string = tab_string ..
- "button[8,4.75;3.75,0.5;btn_reset_singleplayer;".. fgettext("Reset singleplayer world") .. "]"
+ "button[8,4.75;3.75,0.5;btn_change_keys;"
+ .. fgettext("Change keys") .. "]"
end
+
tab_string = tab_string ..
- "box[0,4.25;3.5,1.1;#999999]" ..
- "label[0.25,4.25;" .. fgettext("GUI scale factor") .. "]" ..
- "scrollbar[0.25,4.75;3,0.4;sb_gui_scaling;horizontal;" ..
- gui_scale_to_scrollbar() .. "]" ..
- "tooltip[sb_gui_scaling;" ..
- fgettext("Scaling factor applied to menu elements: ") ..
- dump(core.setting_get("gui_scaling")) .. "]"
+ "button[0,4.75;3.75,0.5;btn_advanced_settings;"
+ .. fgettext("Advanced Settings") .. "]"
- if PLATFORM == "Android" then
- tab_string = tab_string ..
- "box[3.75,3.55;3.75,1.8;#999999]" ..
- "checkbox[3.9,3.45;cb_touchscreen_target;".. fgettext("Touch free target") .. ";"
- .. dump(core.setting_getbool("touchtarget")) .. "]"
- end
if core.setting_get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
- "label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" ..
- "dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" ..
- ((tonumber(core.setting_get("touchscreen_threshold"))/10)+1) .. "]"
+ "label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" ..
+ "dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" ..
+ ((tonumber(core.setting_get("touchscreen_threshold")) / 10) + 1) .. "]"
end
if core.setting_getbool("enable_shaders") then
tab_string = tab_string ..
- "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
- .. dump(core.setting_getbool("enable_bumpmapping")) .. "]"..
- "checkbox[8,1.0;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
- .. dump(core.setting_getbool("generate_normalmaps")) .. "]"..
- "checkbox[8,1.5;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
- .. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]"..
- "checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
- .. dump(core.setting_getbool("enable_waving_water")) .. "]"..
- "checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
- .. dump(core.setting_getbool("enable_waving_leaves")) .. "]"..
- "checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
- .. dump(core.setting_getbool("enable_waving_plants")) .. "]"
+ "checkbox[8,0.5;cb_bumpmapping;" .. fgettext("Bump Mapping") .. ";"
+ .. dump(core.setting_getbool("enable_bumpmapping")) .. "]" ..
+ "checkbox[8,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
+ .. dump(core.setting_getbool("tone_mapping")) .. "]" ..
+ "checkbox[8,1.5;cb_generate_normalmaps;" .. fgettext("Normal Mapping") .. ";"
+ .. dump(core.setting_getbool("generate_normalmaps")) .. "]" ..
+ "checkbox[8,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
+ .. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]" ..
+ "checkbox[8,2.5;cb_waving_water;" .. fgettext("Waving Water") .. ";"
+ .. dump(core.setting_getbool("enable_waving_water")) .. "]" ..
+ "checkbox[8,3;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
+ .. dump(core.setting_getbool("enable_waving_leaves")) .. "]" ..
+ "checkbox[8,3.5;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
+ .. dump(core.setting_getbool("enable_waving_plants")) .. "]"
else
tab_string = tab_string ..
- "textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
- "textlist[8.33,1.2;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
- "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
- "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
- "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
- "textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
- end
+ "tablecolumns[color;text]" ..
+ "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
+ "table[8.33,0.7;3.5,4;shaders;" ..
+ "#888888," .. fgettext("Bump Mapping") .. "," ..
+ "#888888," .. fgettext("Tone Mapping") .. "," ..
+ "#888888," .. fgettext("Normal Mapping") .. "," ..
+ "#888888," .. fgettext("Parallax Occlusion") .. "," ..
+ "#888888," .. fgettext("Waving Water") .. "," ..
+ "#888888," .. fgettext("Waving Leaves") .. "," ..
+ "#888888," .. fgettext("Waving Plants") .. "," ..
+ ";1]"
+ end
+
return tab_string
end
--------------------------------------------------------------------------------
local function handle_settings_buttons(this, fields, tabname, tabdata)
- if fields["cb_fancy_trees"] then
- core.setting_set("new_style_leaves", fields["cb_fancy_trees"])
+
+ if fields["btn_advanced_settings"] ~= nil then
+ local adv_settings_dlg = create_adv_settings_dlg()
+ adv_settings_dlg:set_parent(this)
+ this:hide()
+ adv_settings_dlg:show()
+ --mm_texture.update("singleplayer", current_game())
return true
end
if fields["cb_smooth_lighting"] then
core.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
return true
end
+ if fields["cb_particles"] then
+ core.setting_set("enable_particles", fields["cb_particles"])
+ return true
+ end
if fields["cb_3d_clouds"] then
core.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
return true
@@ -303,8 +286,13 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("opaque_water", fields["cb_opaque_water"])
return true
end
+ if fields["cb_connected_glass"] then
+ core.setting_set("connected_glass", fields["cb_connected_glass"])
+ return true
+ end
if fields["cb_shaders"] then
- if (core.setting_get("video_driver") == "direct3d8" or core.setting_get("video_driver") == "direct3d9") then
+ if (core.setting_get("video_driver") == "direct3d8" or
+ core.setting_get("video_driver") == "direct3d9") then
core.setting_set("enable_shaders", "false")
gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
else
@@ -312,23 +300,17 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
return true
end
- if fields["cb_connected_glass"] then
- core.setting_set("connected_glass", fields["cb_connected_glass"])
- return true
- end
- if fields["cb_node_highlighting"] then
- core.setting_set("enable_node_highlighting", fields["cb_node_highlighting"])
+ if fields["cb_bumpmapping"] then
+ core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
return true
end
- if fields["cb_particles"] then
- core.setting_set("enable_particles", fields["cb_particles"])
+ if fields["cb_tonemapping"] then
+ core.setting_set("tone_mapping", fields["cb_tonemapping"])
return true
end
- if fields["cb_bumpmapping"] then
- core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
- end
if fields["cb_generate_normalmaps"] then
core.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"])
+ return true
end
if fields["cb_parallax"] then
core.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
@@ -345,20 +327,10 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("enable_waving_plants", fields["cb_waving_plants"])
return true
end
- if fields["btn_change_keys"] ~= nil then
+ if fields["btn_change_keys"] then
core.show_keys_menu()
return true
end
-
- if fields["sb_gui_scaling"] then
- local event = core.explode_scrollbar_event(fields["sb_gui_scaling"])
-
- if event.type == "CHG" then
- local tosave = string.format("%.2f",scrollbar_to_gui_scale(event.value))
- core.setting_set("gui_scaling",tosave)
- return true
- end
- end
if fields["cb_touchscreen_target"] then
core.setting_set("touchtarget", fields["cb_touchscreen_target"])
return true
@@ -371,48 +343,40 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
--Note dropdowns have to be handled LAST!
local ddhandled = false
- if fields["dd_touchthreshold"] then
- core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"])
- ddhandled = true
- end
- if fields["dd_leaves_style"] == leaves_style_labels[3] then
- core.setting_set("leaves_style", leaves_style[2][3])
- ddhandled = true
- end
- if fields["dd_leaves_style"] == leaves_style_labels[2] then
- core.setting_set("leaves_style", leaves_style[2][2])
- ddhandled = true
+ for i = 1, #labels.leaves do
+ if fields["dd_leaves_style"] == labels.leaves[i] then
+ core.setting_set("leaves_style", dd_options.leaves[2][i])
+ ddhandled = true
+ end
end
- if fields["dd_leaves_style"] == leaves_style_labels[1] then
- core.setting_set("leaves_style", leaves_style[2][1])
- ddhandled = true
+ for i = 1, #labels.node_highlighting do
+ if fields["dd_node_highlighting"] == labels.node_highlighting[i] then
+ core.setting_set("node_highlighting", dd_options.node_highlighting[2][i])
+ ddhandled = true
+ end
end
- if fields["dd_filters"] == dd_filter_labels[1] then
+ if fields["dd_filters"] == labels.filters[1] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "false")
ddhandled = true
- end
- if fields["dd_filters"] == dd_filter_labels[2] then
+ elseif fields["dd_filters"] == labels.filters[2] then
core.setting_set("bilinear_filter", "true")
core.setting_set("trilinear_filter", "false")
ddhandled = true
- end
- if fields["dd_filters"] == dd_filter_labels[3] then
+ elseif fields["dd_filters"] == labels.filters[3] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "true")
ddhandled = true
end
- if fields["dd_mipmap"] == dd_mipmap_labels[1] then
+ if fields["dd_mipmap"] == labels.mipmap[1] then
core.setting_set("mip_map", "false")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
- end
- if fields["dd_mipmap"] == dd_mipmap_labels[2] then
+ elseif fields["dd_mipmap"] == labels.mipmap[2] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
- end
- if fields["dd_mipmap"] == dd_mipmap_labels[3] then
+ elseif fields["dd_mipmap"] == labels.mipmap[3] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "true")
ddhandled = true
@@ -422,11 +386,15 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
antialiasing_fname_to_name(fields["dd_antialiasing"]))
ddhandled = true
end
+ if fields["dd_touchthreshold"] then
+ core.setting_set("touchscreen_threshold", fields["dd_touchthreshold"])
+ ddhandled = true
+ end
return ddhandled
end
-tab_settings = {
+return {
name = "settings",
caption = fgettext("Settings"),
cbf_formspec = formspec,
diff --git a/builtin/mainmenu/tab_simple_main.lua b/builtin/mainmenu/tab_simple_main.lua
index 434113b5f..3818f321f 100644
--- a/builtin/mainmenu/tab_simple_main.lua
+++ b/builtin/mainmenu/tab_simple_main.lua
@@ -17,66 +17,80 @@
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
- local retval = ""
-
- local render_details = dump(core.setting_getbool("public_serverlist"))
-
- retval = retval ..
- "label[8,0.5;".. fgettext("Name/Password") .. "]" ..
- "field[0.25,3.25;5.5,0.5;te_address;;" ..
- core.formspec_escape(core.setting_get("address")) .."]" ..
- "field[5.75,3.25;2.25,0.5;te_port;;" ..
- core.formspec_escape(core.setting_get("remote_port")) .."]" ..
- "checkbox[8,-0.25;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
- render_details .. "]"
-
- retval = retval ..
- "button[8,2.5;4,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
- "field[8.75,1.5;3.5,0.5;te_name;;" ..
- core.formspec_escape(core.setting_get("name")) .."]" ..
- "pwdfield[8.75,2.3;3.5,0.5;te_pwd;]"
-
- if render_details then
- retval = retval .. "tablecolumns[" ..
- "color,span=3;" ..
- "text,align=right;" .. -- clients
- "text,align=center,padding=0.25;" .. -- "/"
- "text,align=right,padding=0.25;" .. -- clients_max
- image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
- image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
- image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
- "color,span=1;" ..
- "text,padding=1]" -- name
- else
- retval = retval .. "tablecolumns[text]"
+ -- Update the cached supported proto info,
+ -- it may have changed after a change by the settings menu.
+ common_update_cached_supp_proto()
+ local fav_selected = menudata.favorites[tabdata.fav_selected]
+
+ local retval =
+ "label[9.5,0;".. fgettext("Name / Password") .. "]" ..
+ "field[0.25,3.35;5.5,0.5;te_address;;" ..
+ core.formspec_escape(core.setting_get("address")) .."]" ..
+ "field[5.75,3.35;2.25,0.5;te_port;;" ..
+ core.formspec_escape(core.setting_get("remote_port")) .."]" ..
+ "button[10,2.6;2,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
+ "field[9.8,1;2.6,0.5;te_name;;" ..
+ core.formspec_escape(core.setting_get("name")) .."]" ..
+ "pwdfield[9.8,2;2.6,0.5;te_pwd;]"
+
+
+ if tabdata.fav_selected and fav_selected then
+ if gamedata.fav then
+ retval = retval .. "button[7.7,2.6;2.3,1.5;btn_delete_favorite;" ..
+ fgettext("Del. Favorite") .. "]"
+ end
end
- retval = retval ..
- "table[-0.05,0;7.55,2.75;favourites;"
- if #menudata.favorites > 0 then
- retval = retval .. render_favorite(menudata.favorites[1],render_details)
+ retval = retval .. "tablecolumns[" ..
+ image_column(fgettext("Favorite"), "favorite") .. ";" ..
+ "color,span=3;" ..
+ "text,align=right;" .. -- clients
+ "text,align=center,padding=0.25;" .. -- "/"
+ "text,align=right,padding=0.25;" .. -- clients_max
+ image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
+ image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
+ image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
+ "color,span=1;" ..
+ "text,padding=1]" .. -- name
+ "table[-0.05,0;9.2,2.75;favourites;"
- for i=2,#menudata.favorites,1 do
- retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
+ if #menudata.favorites > 0 then
+ local favs = core.get_favorites("local")
+ if #favs > 0 then
+ for i = 1, #favs do
+ for j = 1, #menudata.favorites do
+ if menudata.favorites[j].address == favs[i].address and
+ menudata.favorites[j].port == favs[i].port then
+ table.insert(menudata.favorites, i,
+ table.remove(menudata.favorites, j))
+ end
+ end
+ if favs[i].address ~= menudata.favorites[i].address then
+ table.insert(menudata.favorites, i, favs[i])
+ end
+ end
+ end
+ retval = retval .. render_favorite(menudata.favorites[1], (#favs > 0))
+ for i = 2, #menudata.favorites do
+ retval = retval .. "," .. render_favorite(menudata.favorites[i], (i <= #favs))
end
end
- if tabdata.fav_selected ~= nil then
+ if tabdata.fav_selected then
retval = retval .. ";" .. tabdata.fav_selected .. "]"
else
retval = retval .. ";0]"
end
-- separator
- retval = retval ..
- "box[-0.28,3.75;12.4,0.1;#FFFFFF]"
+ retval = retval .. "box[-0.28,3.75;12.4,0.1;#FFFFFF]"
-- checkboxes
retval = retval ..
"checkbox[8.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
- dump(core.setting_getbool("creative_mode")) .. "]"..
+ dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[8.0,4.4;cb_damage;".. fgettext("Enable Damage") .. ";" ..
- dump(core.setting_getbool("enable_damage")) .. "]"
+ dump(core.setting_getbool("enable_damage")) .. "]"
-- buttons
retval = retval ..
"button[0,3.7;8,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" ..
@@ -87,94 +101,100 @@ end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
-
- if fields["btn_start_singleplayer"] then
+ if fields.btn_start_singleplayer then
gamedata.selected_world = gamedata.worldindex
gamedata.singleplayer = true
core.start()
return true
end
- if fields["favourites"] ~= nil then
- local event = core.explode_table_event(fields["favourites"])
-
+ if fields.favourites then
+ local event = core.explode_table_event(fields.favourites)
if event.type == "CHG" then
if event.row <= #menudata.favorites then
- local address = menudata.favorites[event.row].address
- local port = menudata.favorites[event.row].port
-
- if address ~= nil and
- port ~= nil then
- core.setting_set("address",address)
- core.setting_set("remote_port",port)
+ gamedata.fav = false
+ local favs = core.get_favorites("local")
+ local fav = menudata.favorites[event.row]
+ local address = fav.address
+ local port = fav.port
+ gamedata.serverdescription = fav.description
+
+ for i = 1, #favs do
+ if fav.address == favs[i].address and
+ fav.port == favs[i].port then
+ gamedata.fav = true
+ end
end
+ if address and port then
+ core.setting_set("address", address)
+ core.setting_set("remote_port", port)
+ end
tabdata.fav_selected = event.row
end
+ return true
end
- return true
end
- if fields["cb_public_serverlist"] ~= nil then
- core.setting_set("public_serverlist", fields["cb_public_serverlist"])
+ if fields.btn_delete_favorite then
+ local current_favourite = core.get_table_index("favourites")
+ if not current_favourite then return end
- if core.setting_getbool("public_serverlist") then
- asyncOnlineFavourites()
- else
- menudata.favorites = core.get_favorites("local")
- end
+ core.delete_favorite(current_favourite)
+ asyncOnlineFavourites()
+ tabdata.fav_selected = nil
+
+ core.setting_set("address", "")
+ core.setting_set("remote_port", "30000")
return true
end
- if fields["cb_creative"] then
- core.setting_set("creative_mode", fields["cb_creative"])
+ if fields.cb_creative then
+ core.setting_set("creative_mode", fields.cb_creative)
return true
end
- if fields["cb_damage"] then
- core.setting_set("enable_damage", fields["cb_damage"])
+ if fields.cb_damage then
+ core.setting_set("enable_damage", fields.cb_damage)
return true
end
- if fields["btn_mp_connect"] ~= nil or
- fields["key_enter"] ~= nil then
-
- gamedata.playername = fields["te_name"]
- gamedata.password = fields["te_pwd"]
- gamedata.address = fields["te_address"]
- gamedata.port = fields["te_port"]
-
+ if fields.btn_mp_connect or fields.key_enter then
+ gamedata.playername = fields.te_name
+ gamedata.password = fields.te_pwd
+ gamedata.address = fields.te_address
+ gamedata.port = fields.te_port
local fav_idx = core.get_textlist_index("favourites")
- if fav_idx ~= nil and fav_idx <= #menudata.favorites and
- menudata.favorites[fav_idx].address == fields["te_address"] and
- menudata.favorites[fav_idx].port == fields["te_port"] then
+ if fav_idx and fav_idx <= #menudata.favorites and
+ menudata.favorites[fav_idx].address == fields.te_address and
+ menudata.favorites[fav_idx].port == fields.te_port then
+ local fav = menudata.favorites[fav_idx]
+ gamedata.servername = fav.name
+ gamedata.serverdescription = fav.description
- gamedata.servername = menudata.favorites[fav_idx].name
- gamedata.serverdescription = menudata.favorites[fav_idx].description
-
- if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
- menudata.favorites[fav_idx].proto_max) then
+ if menudata.favorites_is_public and
+ not is_server_protocol_compat_or_error(
+ fav.proto_min, fav.proto_max) then
return true
end
else
- gamedata.servername = ""
- gamedata.serverdescription = ""
+ gamedata.servername = ""
+ gamedata.serverdescription = ""
end
gamedata.selected_world = 0
- core.setting_set("address",fields["te_address"])
- core.setting_set("remote_port",fields["te_port"])
+ core.setting_set("address", fields.te_address)
+ core.setting_set("remote_port", fields.te_port)
core.start()
return true
end
- if fields["btn_config_sp_world"] ~= nil then
+ if fields.btn_config_sp_world then
local configdialog = create_configure_world_dlg(1)
-
- if (configdialog ~= nil) then
+ if configdialog then
configdialog:set_parent(tabview)
tabview:hide()
configdialog:show()
@@ -185,21 +205,15 @@ end
--------------------------------------------------------------------------------
local function on_activate(type,old_tab,new_tab)
- if type == "LEAVE" then
- return
- end
- if core.setting_getbool("public_serverlist") then
- asyncOnlineFavourites()
- else
- menudata.favorites = core.get_favorites("local")
- end
+ if type == "LEAVE" then return end
+ asyncOnlineFavourites()
end
--------------------------------------------------------------------------------
-tab_simple_main = {
+return {
name = "main",
caption = fgettext("Main"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_activate
- }
+}
diff --git a/builtin/mainmenu/tab_singleplayer.lua b/builtin/mainmenu/tab_singleplayer.lua
index a40918af9..05060cbc6 100644
--- a/builtin/mainmenu/tab_singleplayer.lua
+++ b/builtin/mainmenu/tab_singleplayer.lua
@@ -241,10 +241,10 @@ local function on_change(type, old_tab, new_tab)
end
--------------------------------------------------------------------------------
-tab_singleplayer = {
+return {
name = "singleplayer",
caption = fgettext("Singleplayer"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_change
- }
+}
diff --git a/builtin/mainmenu/tab_texturepacks.lua b/builtin/mainmenu/tab_texturepacks.lua
index 3fb7b8598..a102fd61d 100644
--- a/builtin/mainmenu/tab_texturepacks.lua
+++ b/builtin/mainmenu/tab_texturepacks.lua
@@ -17,12 +17,17 @@
--------------------------------------------------------------------------------
local function filter_texture_pack_list(list)
- local retval = {"None"}
+ local retval = {}
+
for _, item in ipairs(list) do
if item ~= "base" then
- table.insert(retval, item)
+ retval[#retval + 1] = item
end
end
+
+ table.sort(retval)
+ table.insert(retval, 1, fgettext("None"))
+
return retval
end
@@ -31,9 +36,9 @@ local function render_texture_pack_list(list)
local retval = ""
for i, v in ipairs(list) do
- if v:sub(1,1) ~= "." then
+ if v:sub(1, 1) ~= "." then
if retval ~= "" then
- retval = retval ..","
+ retval = retval .. ","
end
retval = retval .. core.formspec_escape(v)
@@ -46,14 +51,14 @@ end
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
- local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
+ local retval = "label[4,-0.25;" .. fgettext("Select texture pack:") .. "]" ..
"textlist[4,0.25;7.5,5.0;TPs;"
local current_texture_path = core.setting_get("texture_path")
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
local index = tonumber(core.setting_get("mainmenu_last_selected_TP"))
- if index == nil then index = 1 end
+ if not index then index = 1 end
if current_texture_path == "" then
retval = retval ..
@@ -62,15 +67,16 @@ local function get_formspec(tabview, name, tabdata)
return retval
end
- local infofile = current_texture_path ..DIR_DELIM.."description.txt"
+ local infofile = current_texture_path .. DIR_DELIM .. "description.txt"
-- This adds backwards compatibility for old texture pack description files named
-- "info.txt", and should be removed once all such texture packs have been updated
if not file_exists(infofile) then
- infofile = current_texture_path ..DIR_DELIM.."info.txt"
+ infofile = current_texture_path .. DIR_DELIM .. "info.txt"
if file_exists(infofile) then
- minetest.log("info.txt is depreciated. description.txt should be used instead.");
+ core.log("info.txt is depreciated. description.txt should be used instead.")
end
end
+
local infotext = ""
local f = io.open(infofile, "r")
if not f then
@@ -80,8 +86,8 @@ local function get_formspec(tabview, name, tabdata)
f:close()
end
- local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
- local no_screenshot = nil
+ local screenfile = current_texture_path .. DIR_DELIM .. "screenshot.png"
+ local no_screenshot
if not file_exists(screenfile) then
screenfile = nil
no_screenshot = defaulttexturedir .. "no_screenshot.png"
@@ -90,24 +96,24 @@ local function get_formspec(tabview, name, tabdata)
return retval ..
render_texture_pack_list(list) ..
";" .. index .. "]" ..
- "image[0.25,0.25;4.0,3.7;"..core.formspec_escape(screenfile or no_screenshot).."]"..
- "textarea[0.6,3.25;3.7,1.5;;"..core.formspec_escape(infotext or "")..";]"
+ "image[0.25,0.25;4.0,3.7;" .. core.formspec_escape(screenfile or no_screenshot) .. "]" ..
+ "textarea[0.6,3.5;3.7,1.5;;" .. core.formspec_escape(infotext or "") .. ";]"
end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
- if fields["TPs"] ~= nil then
+ if fields["TPs"] then
local event = core.explode_textlist_event(fields["TPs"])
if event.type == "CHG" or event.type == "DCL" then
local index = core.get_textlist_index("TPs")
- core.setting_set("mainmenu_last_selected_TP",
- index)
+ core.setting_set("mainmenu_last_selected_TP", index)
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
local current_index = core.get_textlist_index("TPs")
- if current_index ~= nil and #list >= current_index then
- local new_path = core.get_texturepath()..DIR_DELIM..list[current_index]
- if list[current_index] == "None" then new_path = "" end
-
+ if current_index and #list >= current_index then
+ local new_path = core.get_texturepath() .. DIR_DELIM .. list[current_index]
+ if list[current_index] == fgettext("None") then
+ new_path = ""
+ end
core.setting_set("texture_path", new_path)
end
end
@@ -117,10 +123,10 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
--------------------------------------------------------------------------------
-tab_texturepacks = {
+return {
name = "texturepacks",
caption = fgettext("Texturepacks"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = nil
- }
+}
diff --git a/builtin/mainmenu/textures.lua b/builtin/mainmenu/textures.lua
index 075f38ee0..dadbb093e 100644
--- a/builtin/mainmenu/textures.lua
+++ b/builtin/mainmenu/textures.lua
@@ -179,7 +179,7 @@ function mm_texture.set_dirt_bg()
end
end
- --use base pack
- local minimalpath = defaulttexturedir .. "dirt_bg.png"
+ -- Use universal fallback texture in textures/base/pack
+ local minimalpath = defaulttexturedir .. "menu_bg.png"
core.set_background("background", minimalpath, true, 128)
end
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
new file mode 100644
index 000000000..ad269d8b0
--- /dev/null
+++ b/builtin/settingtypes.txt
@@ -0,0 +1,1214 @@
+# This file contains all settings displayed in the settings menu.
+#
+# General format:
+# name (Readable name) type type_args
+#
+# Note that the parts are seperated by exactly one space
+#
+# `type` can be:
+# - int
+# - string
+# - bool
+# - float
+# - enum
+# - path
+# - key (will be ignored in GUI, since a special key change dialog exists)
+# - flags
+# - noise_params
+#
+# `type_args` can be:
+# * int:
+# - default
+# - default min max
+# * string:
+# - default (if default is not specified then "" is set)
+# * bool:
+# - default
+# * float:
+# - default
+# - default min max
+# * enum:
+# - default value1,value2,...
+# * path:
+# - default (if default is not specified then "" is set)
+# * key:
+# - default
+# * flags:
+# Flags are always separated by comma without spaces.
+# - default possible_flags
+# * noise_params:
+# TODO: these are currently treated like strings
+#
+# Comments directly above a setting are bound to this setting.
+# All other comments are ignored.
+#
+# Comments and (Readable name) are handled by gettext.
+# Comments should be complete sentences that describe the setting and possibly
+# give the user additional useful insight.
+# Sections are marked by a single line in the format: [Section Name]
+# Sub-section are marked by adding * in front of the section name: [*Sub-section]
+# Sub-sub-sections have two * etc.
+# 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".
+
+[Client]
+
+[*Controls]
+# 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
+
+# Fast movement (via use 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 moving and looking around.
+# Useful for recording videos.
+cinematic (Cinematic mode) bool false
+
+# Smooths rotation of camera. 0 to disable.
+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, "use" key instead of "sneak" key is used for climbing down and descending.
+aux1_descends (Key use for climbing/descending) bool false
+
+# Double-tapping the jump key toggles fly mode.
+doubletap_jump (Double tap jump for fly) bool false
+
+# If disabled "use" key is used to fly fast if both fly and fast mode are enabled.
+always_fly_fast (Always fly and fast) bool true
+
+# The time in seconds it takes between repeated right clicks when holding the right mouse button.
+repeat_rightclick_time (Rightclick repetition interval) float 0.25
+
+# Enable random user input (only used for testing).
+random_input (Random input) bool false
+
+# Continuous forward movement (only used for testing).
+continuous_forward (Continuous forward) bool false
+
+# 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.
+# 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 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_special1 (Use 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 console.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keyman_console (Console key) key KEY_F10
+
+# 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 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 toggling cinematic mode.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_cinematic (Cinematic mode key) key KEY_F8
+
+# Key for toggling display of minimap.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_minimap (Minimap key) key KEY_F9
+
+# 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 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 the 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 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 camrea 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_F7
+
+# 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 -
+
+# Key for printing debug stacks. Used for development.
+# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_print_debug_stacks (Print stacks) key KEY_KEY_P
+
+[*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
+
+# 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
+
+# Whether to support older servers before protocol version 25.
+# Enable if you want to connect to 0.4.12 servers and before.
+# Servers starting with 0.4.13 will work, 0.4.12-dev servers may work.
+# Disabling this option will protect your password better.
+send_pre_v25_init (Support older servers) bool true
+
+# Save the map received by the client on disk.
+enable_local_map_saving (Saving map received from server) bool false
+
+# Show entity selection boxes
+show_entity_selectionbox (Show entity selection boxes) bool true
+
+# 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
+
+# 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.txt
+
+[*Graphics]
+
+[**In-Game]
+
+[***Basic]
+
+# Enable VBO
+enable_vbo (VBO) bool true
+
+# 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
+
+# Enable smooth lighting with simple ambient occlusion.
+# Disable for speed or for different looks.
+smooth_lighting (Smooth lighting) bool true
+
+# Clouds are a client side effect.
+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
+
+[***Filtering]
+
+# Use mip mapping to scale textures. May slightly increase performance.
+mip_map (Mipmapping) bool false
+
+# Use anisotropic filtering when viewing at textures from an angle.
+anisotropic_filter (Anisotropic filtering) bool false
+
+# Use bilinear filtering when scaling textures.
+bilinear_filter (Bilinear filtering) bool false
+
+# Use trilinear filtering when scaling textures.
+trilinear_filter (Trilinear filtering) bool false
+
+# Filtered textures can blend RGB values with fully-transparent neighbors,
+# which PNG optimizers usually discard, sometimes resulting in a dark or
+# light edge to transparent textures. Apply this filter to clean that up
+# at texture load time.
+texture_clean_transparent (Clean transparent textures) bool false
+
+# When using bilinear/trilinear/anisotropic filters, low-resolution textures
+# can be blurred, so automatically upscale them with nearest-neighbor
+# interpolation to preserve crisp pixels. This sets the minimum texture size
+# for the upscaled textures; higher values look sharper, but require more
+# memory. Powers of 2 are recommended. Setting this higher than 1 may not
+# have a visible effect unless bilinear/trilinear/anisotropic filtering is
+# enabled.
+texture_min_size (Minimum texture size for filters) int 64
+
+# Experimental option, might cause visible spaces between blocks
+# when set to higher number than 0.
+fsaa (FSAA) enum 0 0,1,2,4,8,16
+
+[***Shaders]
+
+# Shaders allow advanced visul effects and may increase performance on some video cards.
+# Thy only work with the OpenGL video backend.
+enable_shaders (Shaders) bool true
+
+[****Tone Mapping]
+
+# Enables filmic tone mapping
+tone_mapping (Filmic tone mapping) bool false
+
+[****Bumpmapping]
+
+# Enables bumpmapping for textures. Normalmaps need to be supplied by the texture pack
+# or need to be auto-generated.
+# Requires shaders to be enabled.
+enable_bumpmapping (Bumpmapping) bool false
+
+# Enables on the fly normalmap generation (Emboss effect).
+# Requires bumpmapping to be enabled.
+generate_normalmaps (Generate normalmaps) bool false
+
+# Strength of generated normalmaps.
+normalmaps_strength (Normalmaps strength) float 0.6
+
+# Defines sampling step of texture.
+# A higher value results in smoother normal maps.
+normalmaps_smooth (Normalmaps sampling) int 0 0 2
+
+[****Parallax Occlusion]
+
+# Enables parallax occlusion mapping.
+# Requires shaders to be enabled.
+enable_parallax_occlusion (Parallax occlusion) bool false
+
+# 0 = parallax occlusion with slope information (faster).
+# 1 = relief mapping (slower, more accurate).
+parallax_occlusion_mode (Parallax occlusion mode) int 1 0 1
+
+# Strength of parallax.
+3d_parallax_strength (Parallax occlusion strength) float 0.025
+
+# Number of parallax occlusion iterations.
+parallax_occlusion_iterations (Parallax occlusion iterations) int 4
+
+# Overall scale of parallax occlusion effect.
+parallax_occlusion_scale (Parallax occlusion Scale) float 0.08
+
+# Overall bias of parallax occlusion effect, usually scale/2.
+parallax_occlusion_bias (Parallax occlusion bias) float 0.04
+
+[****Waving Nodes]
+
+# Set to true enables waving water.
+# Requires shaders to be enabled.
+enable_waving_water (Waving water) bool false
+
+water_wave_height (Waving water height) float 1.0
+
+water_wave_length (Waving water length) float 20.0
+
+water_wave_speed (Waving water speed) float 5.0
+
+# Set to true enables waving leaves.
+# Requires shaders to be enabled.
+enable_waving_leaves (Waving leaves) bool false
+
+# Set to true enables waving plants.
+# Requires shaders to be enabled.
+enable_waving_plants (Waving plants) bool false
+
+[***Advanced]
+
+# 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
+
+# Maximum FPS when game is paused.
+pause_fps_max (FPS in pause menu) int 20
+
+# View distance in nodes.
+# Min = 20
+viewing_range (Viewing range) int 100
+
+# Width component of the initial window size.
+screenW (Screen width) int 800
+
+# Height component of the initial window size.
+screenH (Screen height) int 600
+
+# Fullscreen mode.
+fullscreen (Full screen) bool false
+
+# Bits per pixel (aka color depth) in fullscreen mode.
+fullscreen_bpp (Full screen BPP) int 24
+
+# Vertical screen synchronization.
+vsync (V-Sync) bool false
+
+# Field of view in degrees.
+fov (Field of view) int 72 30 160
+
+# Adjust the gamma encoding for the light tables. Lower numbers are brighter.
+# This setting is for the client only and is ignored by the server.
+display_gamma (Gamma) float 1.8 1.0 3.0
+
+# Path to texture directory. All textures are first searched from here.
+texture_path (Texture path) path
+
+# The rendering back-end for Irrlicht.
+video_driver (Video driver) enum opengl null,software,burningsvideo,direct3d8,direct3d9,opengl
+
+# Height on which clouds are appearing.
+cloud_height (Cloud height) int 120
+
+# 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
+
+# Multiplier for view bobbing.
+# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
+view_bobbing_amount (View bobbing) 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) float 0.0
+
+# 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.
+# - pageflip: quadbuffer based 3d.
+3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,pageflip
+
+# In-game chat console background color (R,G,B).
+console_color (Console color) string (0,0,0)
+
+# In-game chat console background alpha (opaqueness, between 0 and 255).
+console_alpha (Console alpha) int 200 0 255
+
+# Selection box border color (R,G,B).
+selectionbox_color (Selection box color) string (0,0,0)
+
+# Width of the selectionbox's lines around nodes.
+selectionbox_width (Selection box width) int 2 1 5
+
+# Crosshair color (R,G,B).
+crosshair_color (Crosshair color) string (255,255,255)
+
+# Crosshair alpha (opaqueness, between 0 and 255).
+crosshair_alpha (Crosshair alpha) int 255 0 255
+
+# 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
+
+# Enables caching of facedir rotated meshes.
+enable_mesh_cache (Mesh cache) bool false
+
+# 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
+# Useable 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
+
+[**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
+
+# 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).
+gui_scaling_filter (GUI scaling filter) bool false
+
+# When gui_scaling_filter_txr2img is true, copy those images
+# from hardware to software for scaling. When false, fall back
+# to the old scaling method, for video drivers that don't
+# propery support downloading textures back from hardware.
+gui_scaling_filter_txr2img (GUI scaling filter txr2img) bool true
+
+# Delay showing tooltips, stated in milliseconds.
+tooltip_show_delay (Tooltip delay) int 400
+
+# Whether freetype fonts are used, requires freetype support to be compiled in.
+freetype (Freetype fonts) bool true
+
+# Path to TrueTypeFont or bitmap.
+font_path (Font path) path fonts/liberationsans.ttf
+
+font_size (Font size) int 15
+
+# Font shadow offset, if 0 then shadow will not be drawn.
+font_shadow (Font shadow) int 1
+
+# Font shadow alpha (opaqueness, between 0 and 255).
+font_shadow_alpha (Font shadow alpha) int 128 0 255
+
+mono_font_path (Monospace font path) path fonts/liberationmono.ttf
+
+mono_font_size (Monospace font size) int 15
+
+# This font will be used for certain languages.
+fallback_font_path (Fallback font) path fonts/DroidSansFallbackFull.ttf
+fallback_font_size (Fallback font size) int 15
+fallback_font_shadow (Fallback font shadow) int 1
+fallback_font_shadow_alpha (Fallback font shadow alpha) int 128 0 255
+
+# Path to save screenshots at.
+screenshot_path (Screenshot folder) path
+
+# Format of screenshots.
+screenshot_format (Screenshot format) enum png png,jpg,bmp,pcx,ppm,tga
+
+# 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]
+
+# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
+screen_dpi (DPI) int 72
+
+[*Sound]
+
+enable_sound (Sound) bool true
+
+sound_volume (Volume) float 0.7 0.0 1.0
+
+[*Advanced]
+
+# Timeout for client to remove unused map data from memory.
+client_unload_unused_data_timeout (Mapblock unload timeout) int 600
+
+# Maximum number of mapblocks for client to be kept in memory.
+# Set to -1 for unlimited amount.
+client_mapblock_limit (Mapblock limit) int 5000
+
+# Whether to show the client debug info (has the same effect as hitting F5).
+show_debug (Show debug info) bool false
+
+[Server / Singleplayer]
+
+# Name of the server, to be displayed when players join and in the serverlist.
+server_name (Server name) string Minetest server
+
+# Description of server, to be displayed when players join and in the serverlist.
+server_description (Server description) string mine here
+
+# Domain name of server, to be displayed in the serverlist.
+server_address (Server address) string game.minetest.net
+
+# Homepage of server, to be displayed in the serverlist.
+server_url (Server URL) string http://minetest.net
+
+# Automaticaly report to the serverlist.
+server_announce (Announce server) bool false
+
+# Announce to this serverlist.
+# If you want to announce your ipv6 address, use serverlist_url = v6.servers.minetest.net.
+serverlist_url (Serverlist URL) string servers.minetest.net
+
+[*Network]
+
+# Network port to listen (UDP).
+# This value will be overridden when starting from the main menu.
+port (Server port) int 30000
+
+# The network interface that the server listens on.
+bind_address (Bind address) string
+
+# Enable to disallow old clients from connecting.
+# Older clients are compatible in the sense that they will not crash when connecting
+# to new servers, but they may not support all new features that you are expecting.
+strict_protocol_version_checking (Strict protocol checking) bool false
+
+# Specifies URL from which client fetches media instead of using UDP.
+# $filename should be accessible from $remote_media$filename via cURL
+# (obviously, remote_media should end with a slash).
+# Files that are not present will be fetched the usual way.
+remote_media (Remote media) string
+
+# Enable/disable running an IPv6 server. An IPv6 server may be restricted
+# to IPv6 clients, depending on system configuration.
+# Ignored if bind_address is set.
+ipv6_server (IPv6 server) bool false
+
+[**Advanced]
+
+# How many blocks are flying in the wire simultaneously per client.
+max_simultaneous_block_sends_per_client (Maximum simultaneously blocks send per client) int 10
+
+# How many blocks are flying in the wire simultaneously for the whole server.
+max_simultaneous_block_sends_server_total (Maximum simultaneously bocks send total) 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 () 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
+
+[*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 connect 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
+
+# Enable players getting damage and dying.
+enable_damage (Damage) 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
+
+# New users need to input this password.
+default_password (Default password) string
+
+# 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
+
+# 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
+
+# If this is set, players will always (re)spawn at the given position.
+static_spawnpoint (Static spawnpoint) string
+
+# If enabled, new players cannot join with an empty password.
+disallow_empty_password (Disallow empty passwords) bool false
+
+# If enabled, disable cheat prevention in multiplayer.
+disable_anticheat (Disable anticheat) bool false
+
+# If enabled, actions are recorded for rollback.
+# This option is only read when server starts.
+enable_rollback_recording (Rollback recording) bool false
+
+# 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
+
+# From how far clients know about objects, stated in mapblocks (16 nodes).
+active_object_send_range_blocks (Active object send range) int 3
+
+# How large area of blocks are subject to the active block stuff, stated in mapblocks (16 nodes).
+# In active blocks objects are loaded and ABMs run.
+active_block_range (Active block range) int 2
+
+# From how far blocks are sent to clients, stated in mapblocks (16 nodes).
+max_block_send_distance (Max block send distance) int 10
+
+# Maximum number of forceloaded mapblocks.
+max_forceloaded_blocks (Maximum forceloaded blocks) int 16
+
+# Interval of sending time of day to clients.
+time_send_interval (Time send interval) int 5
+
+# 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
+
+# Interval of saving important changes in the world, stated in seconds.
+server_map_save_interval (Map save interval) float 5.3
+
+[**Physics]
+
+movement_acceleration_default (Default acceleration) float 3
+movement_acceleration_air (Acceleration in air) float 2
+movement_acceleration_fast (Fast mode acceleration) float 10
+movement_speed_walk (Walking speed) float 4
+movement_speed_crouch (Crouch speed) float 1.35
+movement_speed_fast (Fast mode speed) float 20
+movement_speed_climb (Climbing speed) float 2
+movement_speed_jump (Jumping speed) float 6.5
+movement_speed_descend (Descending speed) float 6
+movement_liquid_fluidity (Liquid fluidity) float 1
+movement_liquid_fluidity_smooth (Liquid fluidity smoothing) float 0.5
+movement_liquid_sink (Liquid sink) float 10
+movement_gravity (Gravity) float 9.81
+
+[**Advanced]
+
+# Handling for deprecated lua api calls:
+# - legacy: (try to) mimic old behaviour (default for release).
+# - log: mimic and log backtrace of deprecated call (default for debug).
+# - error: abort on usage of deprecated call (suggested for mod developers).
+deprecated_lua_api_handling (Deprecated Lua API handling) enum legacy legacy,log,error
+
+# Useful for mod developers.
+mod_profiling (Mod profiling) bool false
+
+# Detailed mod profile data. Useful for mod developers.
+detailed_profiling (Detailed mod profiling) bool false
+
+# Profiler data print interval. 0 = disable. Useful for developers.
+profiler_print_interval (Profiling print interval) int 0
+
+# 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 (Maxmimum objects per block) int 49
+
+# See http://www.sqlite.org/pragma.html#pragma_synchronous
+sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
+
+# Length of a server tick and the interval at which objects are generally updated over network.
+dedicated_server_step (Dedicated server step) float 0.1
+
+# Time in between active block management cycles
+active_block_mgmt_interval (Active Block Management interval) float 2.0
+
+# Length of time between ABM execution cycles
+abm_interval (Active Block Modifier interval) float 1.0
+
+# Length of time between NodeTimer execution cycles
+nodetimer_interval (NodeTimer interval) float 1.0
+
+# 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
+
+[*Mapgen]
+
+# Name of map generator to be used when creating a new world.
+# Creating a world in the main menu will override this.
+mg_name (Mapgen name) enum v6 v5,v6,v7,flat,valleys,fractal,singlenode
+
+# Water surface level of the world.
+water_level (Water level) int 1
+
+# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
+max_block_generate_distance (Max block generate distance) int 6
+
+# Where the map generator stops.
+# Please note:
+# - Limited to 31000 (setting above has no effect)
+# - The map generator works in groups of 80x80x80 nodes (5x5x5 MapBlocks).
+# - Those groups have an offset of -32, -32 nodes from the origin.
+# - Only groups which are within the map_generation_limit are generated
+map_generation_limit (Map generation limit) int 31000 0 31000
+
+# Global map generation attributes.
+# In Mapgen v6 the 'decorations' flag controls all decorations except trees
+# and junglegrass, in all other mapgens this flag controls all decorations.
+# The default flags set in the engine are: caves, light, decorations
+# The flags string modifies the engine defaults.
+# Flags that are not specified in the flag string are not modified from the default.
+# Flags starting with 'no' are used to explicitly disable them.
+mg_flags (Mapgen flags) flags caves,dungeons,light,decorations caves,dungeons,light,decorations,nocaves,nodungeons,nolight,nodecorations
+
+[**Advanced]
+
+# Size of chunks to be generated at once by mapgen, stated in mapblocks (16 nodes).
+chunksize (Chunk size) int 5
+
+# Dump the mapgen debug infos.
+enable_mapgen_debug_info (Mapgen debug) bool false
+
+# Maximum number of blocks that can be queued for loading.
+emergequeue_limit_total (Absolute limit of emerge queues) int 256
+
+# Maximum number of blocks to be queued that are to be loaded from file.
+# Set to blank for an appropriate amount to be chosen automatically.
+emergequeue_limit_diskonly (Limit of emerge queues on disk) int 32
+
+# Maximum number of blocks to be queued that are to be generated.
+# Set to blank for an appropriate amount to be chosen automatically.
+emergequeue_limit_generate (Limit of emerge queues to generate) int 32
+
+# Number of emerge threads to use. Make this field blank, or increase this number
+# to use multiple threads. On multiprocessor systems, this will improve mapgen speed greatly
+# at the cost of slightly buggy caves.
+num_emerge_threads (Number of emerge threads) int 1
+
+# Noise parameters for biome API temperature, humidity and biome blend.
+mg_biome_np_heat (Mapgen biome heat noise parameters) noise_params 50, 50, (750, 750, 750), 5349, 3, 0.5, 2.0
+mg_biome_np_heat_blend (Mapgen heat blend noise parameters) noise_params 0, 1.5, (8, 8, 8), 13, 2, 1.0, 2.0
+mg_biome_np_humidity (Mapgen biome humidity noise parameters) noise_params 50, 50, (750, 750, 750), 842, 3, 0.5, 2.0
+mg_biome_np_humidity_blend (Mapgen biome humidity blend noise parameters) noise_params 0, 1.5, (8, 8, 8), 90003, 2, 1.0, 2.0
+
+[***Mapgen v5]
+
+# Controls width of tunnels, a smaller value creates wider tunnels.
+mgv5_cave_width (Mapgen v5 cave width) float 0.125
+
+mgv5_np_filler_depth (Mapgen v5 filler depth noise parameters) noise_params 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0
+mgv5_np_factor (Mapgen v5 factor noise parameters) noise_params 0, 1, (250, 250, 250), 920381, 3, 0.45, 2.0
+mgv5_np_height (Mapgen v5 height noise parameters) noise_params 0, 10, (250, 250, 250), 84174, 4, 0.5, 2.0
+mgv5_np_cave1 (Mapgen v5 cave1 noise parameters) noise_params 0, 12, (50, 50, 50), 52534, 4, 0.5, 2.0
+mgv5_np_cave2 (Mapgen v5 cave2 noise parameters) noise_params 0, 12, (50, 50, 50), 10325, 4, 0.5, 2.0
+# TODO
+#mgv5_np_ground = {
+# offset = 0
+# scale = 40
+# spread = (80, 80, 80)
+# seed = 983240
+# octaves = 4
+# persistence = 0.55
+# lacunarity = 2.0
+# flags = "eased"
+#}
+
+[***Mapgen v6]
+
+# Map generation attributes specific to Mapgen v6.
+# When snowbiomes are enabled jungles are automatically enabled, the 'jungles' flag is ignored.
+# The default flags set in the engine are: biomeblend, mudflow
+# The flags string modifies the engine defaults.
+# Flags that are not specified in the flag string are not modified from the default.
+# Flags starting with 'no' are used to explicitly disable them.
+mgv6_spflags (Mapgen v6 flags) flags jungles,biomeblend,mudflow,snowbiomes,trees jungles,biomeblend,mudflow,snowbiomes,flat,trees,nojungles,nobiomeblend,nomudflow,nosnowbiomes,noflat,notrees
+
+# Controls size of deserts and beaches in Mapgen v6.
+# When snowbiomes are enabled 'mgv6_freq_desert' is ignored.
+mgv6_freq_desert (Mapgen v6 desert frequency) float 0.45
+mgv6_freq_beach (Mapgen v6 beach frequency) float 0.15
+
+mgv6_np_terrain_base (Mapgen v6 terrain base noise parameters) noise_params -4, 20, (250, 250, 250), 82341, 5, 0.6, 2.0
+mgv6_np_terrain_higher (Mapgen v6 terrain altitude noise parameters) noise_params 20, 16, (500, 500, 500), 85039, 5, 0.6, 2.0
+mgv6_np_steepness (Mapgen v6 steepness noise parameters) noise_params 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2.0
+mgv6_np_height_select (Mapgen v6 height select noise parameters) noise_params 0.5, 1, (250, 250, 250), 4213, 5, 0.69, 2.0
+mgv6_np_mud (Mapgen v6 mud noise parameters) noise_params 4, 2, (200, 200, 200), 91013, 3, 0.55, 2.0
+mgv6_np_beach (Mapgen v6 beach noise parameters) noise_params 0, 1, (250, 250, 250), 59420, 3, 0.50, 2.0
+mgv6_np_biome (Mapgen v6 biome noise parameters) noise_params 0, 1, (500, 500, 500), 9130, 3, 0.50, 2.0
+mgv6_np_cave (Mapgen v6 cave noise parameters) noise_params 6, 6, (250, 250, 250), 34329, 3, 0.50, 2.0
+mgv6_np_humidity (Mapgen v6 humidity noise parameters) noise_params 0.5, 0.5, (500, 500, 500), 72384, 3, 0.50, 2.0
+mgv6_np_trees (Mapgen v6 trees noise parameters) noise_params 0, 1, (125, 125, 125), 2, 4, 0.66, 2.0
+mgv6_np_apple_trees (Mapgen v6 apple trees noise parameters) noise_params 0, 1, (100, 100, 100), 342902, 3, 0.45, 2.0
+
+[***Mapgen v7]
+
+# Map generation attributes specific to Mapgen v7.
+# The 'ridges' flag controls the rivers.
+# The default flags set in the engine are: mountains, ridges
+# The flags string modifies the engine defaults.
+# Flags that are not specified in the flag string are not modified from the default.
+# Flags starting with 'no' are used to explicitly disable them.
+mgv7_spflags (Mapgen v7 flags) flags mountains,ridges mountains,ridges,nomountains,noridges
+
+# Controls width of tunnels, a smaller value creates wider tunnels.
+mgv7_cave_width (Mapgen v7 cave width) float 0.3
+
+mgv7_np_terrain_base (Mapgen v7 terrain base noise parameters) noise_params 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0
+mgv7_np_terrain_alt (Mapgen v7 terrain altitude noise parameters) noise_params 4, 25, (600, 600, 600), 5934, 5, 0.6, 2.0
+mgv7_np_terrain_persist (Mapgen v7 terrain persistation noise parameters) noise_params 0.6, 0.1, (2000, 2000, 2000), 539, 3, 0.6, 2.0
+mgv7_np_height_select (Mapgen v7 height select noise parameters) noise_params -8, 16, (500, 500, 500), 4213, 6, 0.7, 2.0
+mgv7_np_filler_depth (Mapgen v7 filler depth noise parameters) noise_params 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
+mgv7_np_mount_height (Mapgen v7 mount height noise parameters) noise_params 256, 112, (1000, 1000, 1000), 72449, 3, 0.6, 2.0
+mgv7_np_ridge_uwater (Mapgen v7 ridge water noise parameters) noise_params 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0
+mgv7_np_mountain (Mapgen v7 mountain noise parameters) noise_params -0.6, 1, (250, 350, 250), 5333, 5, 0.63, 2.0
+mgv7_np_ridge (Mapgen v7 ridge noise parameters) noise_params 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0
+mgv7_np_cave1 (Mapgen v7 cave1 noise parameters) noise_params 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
+mgv7_np_cave2 (Mapgen v7 cave2 noise parameters) noise_params 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
+
+[***Mapgen flat]
+
+# Map generation attributes specific to Mapgen flat.
+# Occasional lakes and hills can be added to the flat world.
+# The default flags set in the engine are: none
+# The flags string modifies the engine defaults.
+# Flags that are not specified in the flag string are not modified from the default.
+# Flags starting with 'no' are used to explicitly disable them.
+mgflat_spflags (Mapgen flat flags) flags lakes,hills,,nolakes,nohills
+
+# Y of flat ground.
+mgflat_ground_level (Mapgen flat ground level) int 8
+
+# Y of upper limit of large pseudorandom caves.
+mgflat_large_cave_depth (Mapgen flat large cave depth) int -33
+
+# Controls width of tunnels, a smaller value creates wider tunnels.
+mgflat_cave_width (Mapgen flat cave width) float 0.3
+
+# Terrain noise threshold for lakes.
+# Controls proportion of world area covered by lakes.
+# Adjust towards 0.0 for a larger proportion.
+mgflat_lake_threshold (Mapgen flat lake threshold) float -0.45
+
+# Controls steepness/depth of lake depressions.
+mgflat_lake_steepness (Mapgen flat lake steepness) float 48.0
+
+# Terrain noise threshold for hills.
+# Controls proportion of world area covered by hills.
+# Adjust towards 0.0 for a larger proportion.
+mgflat_hill_threshold (Mapgen flat hill threshold) float 0.45
+
+# Controls steepness/height of hills.
+mgflat_hill_steepness (Mapgen flat hill steepness) float 64.0
+
+# Determines terrain shape.
+# The 3 numbers in brackets control the scale of the
+# terrain, the 3 numbers should be identical.
+mgflat_np_terrain (Mapgen flat terrain noise parameters) noise_params 0, 1, (600, 600, 600), 7244, 5, 0.6, 2.0
+
+mgflat_np_filler_depth (Mapgen flat filler depth noise parameters) noise_params 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
+mgflat_np_cave1 (Mapgen flat cave1 noise parameters) noise_params 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
+mgflat_np_cave2 (Mapgen flat cave2 noise parameters) noise_params 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
+
+[***Mapgen fractal]
+
+# Controls width of tunnels, a smaller value creates wider tunnels.
+mgfractal_cave_width (Mapgen fractal cave width) float 0.3
+
+# Choice of 18 fractals from 9 formulas.
+# 1 = 4D "Roundy" mandelbrot set.
+# 2 = 4D "Roundy" julia set.
+# 3 = 4D "Squarry" mandelbrot set.
+# 4 = 4D "Squarry" julia set.
+# 5 = 4D "Mandy Cousin" mandelbrot set.
+# 6 = 4D "Mandy Cousin" julia set.
+# 7 = 4D "Variation" mandelbrot set.
+# 8 = 4D "Variation" julia set.
+# 9 = 3D "Mandelbrot/Mandelbar" mandelbrot set.
+# 10 = 3D "Mandelbrot/Mandelbar" julia set.
+# 11 = 3D "Christmas Tree" mandelbrot set.
+# 12 = 3D "Christmas Tree" julia set.
+# 13 = 3D "Mandelbulb" mandelbrot set.
+# 14 = 3D "Mandelbulb" julia set.
+# 15 = 3D "Cosine Mandelbulb" mandelbrot set.
+# 16 = 3D "Cosine Mandelbulb" julia set.
+# 17 = 4D "Mandelbulb" mandelbrot set.
+# 18 = 4D "Mandelbulb" julia set.
+mgfractal_fractal (Mapgen fractal fractal) int 1 1 18
+
+# Iterations of the recursive function.
+# Controls the amount of fine detail.
+mgfractal_iterations (Mapgen fractal iterations) int 11
+
+# Approximate (X,Y,Z) scale of fractal in nodes.
+mgfractal_scale (Mapgen fractal scale) v3f (4096.0, 1024.0, 4096.0)
+
+# (X,Y,Z) offset of fractal from world centre in units of 'scale'.
+# Used to move a suitable spawn area of low land close to (0, 0).
+# The default is suitable for mandelbrot sets, it needs to be edited for julia sets.
+# Range roughly -2 to 2. Multiply by 'scale' for offset in nodes.
+mgfractal_offset (Mapgen fractal offset) v3f (1.79, 0.0, 0.0)
+
+# W co-ordinate of the generated 3D slice of a 4D fractal.
+# Determines which 3D slice of the 4D shape is generated.
+# Has no effect on 3D fractals.
+# Range roughly -2 to 2.
+mgfractal_slice_w (Mapgen fractal slice w) float 0.0
+
+# Julia set only: X component of hypercomplex constant determining julia shape.
+# Range roughly -2 to 2.
+mgfractal_julia_x (Mapgen fractal julia x) float 0.33
+
+# Julia set only: Y component of hypercomplex constant determining julia shape.
+# Range roughly -2 to 2.
+mgfractal_julia_y (Mapgen fractal julia y) float 0.33
+
+# Julia set only: Z component of hypercomplex constant determining julia shape.
+# Range roughly -2 to 2.
+mgfractal_julia_z (Mapgen fractal julia z) float 0.33
+
+# Julia set only: W component of hypercomplex constant determining julia shape.
+# Has no effect on 3D fractals.
+# Range roughly -2 to 2.
+mgfractal_julia_w (Mapgen fractal julia w) float 0.33
+
+mgfractal_np_seabed (Mapgen fractal seabed noise parameters) noise_params -14, 9, (600, 600, 600), 41900, 5, 0.6, 2.0
+mgfractal_np_filler_depth (Mapgen fractal filler depth noise parameters) noise_params 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
+mgfractal_np_cave1 (Mapgen fractal cave1 noise parameters) noise_params 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
+mgfractal_np_cave2 (Mapgen fractal cave2 noise parameters) noise_params 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
+
+# Mapgen Valleys parameters
+[***Mapgen Valleys]
+
+# General parameters
+[****General]
+
+# Map generation attributes specific to Mapgen Valleys.
+# 'altitude_chill' makes higher elevations colder, which may cause biome issues.
+# 'humid_rivers' modifies the humidity around rivers and in areas where water would tend to pool,
+# it may interfere with delicately adjusted biomes.
+# The default flags set in the engine are: altitude_chill, humid_rivers
+# The flags string modifies the engine defaults.
+# Flags that are not specified in the flag string are not modified from the default.
+# Flags starting with 'no' are used to explicitly disable them.
+mg_valleys_spflags (Valleys C Flags) flags altitude_chill,humid_rivers altitude_chill,noaltitude_chill,humid_rivers,nohumid_rivers
+
+# The altitude at which temperature drops by 20C
+mgvalleys_altitude_chill (Altitude Chill) int 90
+
+# Depth below which you'll find large caves.
+mgvalleys_large_cave_depth (Large cave depth) int -33
+
+# Creates unpredictable lava features in caves.
+# These can make mining difficult. Zero disables them. (0-10)
+mgvalleys_lava_features (Lava Features) int 0
+
+# Depth below which you'll find massive caves.
+mgvalleys_massive_cave_depth (Massive cave depth) int -256
+
+# How deep to make rivers
+mgvalleys_river_depth (River Depth) int 4
+
+# How wide to make rivers
+mgvalleys_river_size (River Size) int 5
+
+# Creates unpredictable water features in caves.
+# These can make mining difficult. Zero disables them. (0-10)
+mgvalleys_water_features (Water Features) int 0
+
+# Controls width of tunnels, a smaller value creates wider tunnels.
+mgvalleys_cave_width (Cave width) float 0.3
+
+# Noise parameters
+[****Noises]
+
+# Caves and tunnels form at the intersection of the two noises
+mgvalleys_np_cave1 (Cave noise #1) noise_params 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
+
+# Caves and tunnels form at the intersection of the two noises
+mgvalleys_np_cave2 (Cave noise #2) noise_params 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
+
+# The depth of dirt or other filler
+mgvalleys_np_filler_depth (Filler Depth) noise_params 0, 1.2, (256, 256, 256), 1605, 3, 0.5, 2.0
+
+# Massive caves form here.
+mgvalleys_np_massive_caves (Massive cave noise) noise_params 0, 1, (768, 256, 768), 59033, 6, 0.63, 2.0
+
+# River noise -- rivers occur close to zero
+mgvalleys_np_rivers (River Noise) noise_params 0, 1, (256, 256, 256), -6050, 5, 0.6, 2.0
+
+# Base terrain height
+mgvalleys_np_terrain_height (Terrain Height) noise_params -10, 50, (1024, 1024, 1024), 5202, 6, 0.4, 2.0
+
+# Raises terrain to make valleys around the rivers
+mgvalleys_np_valley_depth (Valley Depth) noise_params 5, 4, (512, 512, 512), -1914, 1, 1.0, 2.0
+
+# Slope and fill work together to modify the heights
+mgvalleys_np_inter_valley_fill (Valley Fill) noise_params 0, 1, (256, 512, 256), 1993, 6, 0.8, 2.0
+
+# Amplifies the valleys
+mgvalleys_np_valley_profile (Valley Profile) noise_params 0.6, 0.5, (512, 512, 512), 777, 1, 1.0, 2.0
+
+# Slope and fill work together to modify the heights
+mgvalleys_np_inter_valley_slope (Valley Slope) noise_params 0.5, 0.5, (128, 128, 128), 746, 1, 1.0, 2.0
+
+[*Security]
+
+# Prevent mods from doing insecure things like running shell commands.
+secure.enable_security (Enable mod security) bool false
+
+# 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-seperated 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
+
+[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,cs,da,de,eo,es,et,fr,hu,id,it,ja,jbo,ko,ky,lt,nb,nl,pl,pt,pt_BR,ro,ru,tr,uk,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 ,warning,action,info,verbose
+
+# IPv6 support.
+enable_ipv6 (IPv6) bool true
+
+[*Advanced]
+
+# Default timeout for cURL, stated in milliseconds.
+# Only has an effect if compiled with cURL.
+curl_timeout (cURL timeout) int 5000
+
+# 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 in ms a file download (e.g. a mod download) may take.
+curl_file_download_timeout (cURL file download timeout) int 300000
+
+# Makes DirectX work with LuaJIT. Disable if it causes troubles.
+high_precision_fpu (High-precision FPU) bool true
+
+# Replaces the default main menu with a custom one.
+main_menu_script (Main menu script) string
+
+main_menu_game_mgr (Main menu game manager) int 0
+
+main_menu_mod_mgr (Main menu mod manager) int 1
+
+modstore_download_url (Modstore download URL) string https://forum.minetest.net/media/
+
+modstore_listmods_url (Modstore mods list URL) string https://forum.minetest.net/mmdb/mods/
+
+modstore_details_url (Modstore details URL) string https://forum.minetest.net/mmdb/mod/*/