diff options
Diffstat (limited to 'builtin')
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/*/ |