summaryrefslogtreecommitdiff
path: root/builtin/mainmenu
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/mainmenu')
-rw-r--r--builtin/mainmenu/common.lua18
-rw-r--r--builtin/mainmenu/dlg_config_world.lua117
-rw-r--r--builtin/mainmenu/dlg_contentstore.lua28
-rw-r--r--builtin/mainmenu/dlg_create_world.lua89
-rw-r--r--builtin/mainmenu/dlg_delete_content.lua13
-rw-r--r--builtin/mainmenu/dlg_delete_world.lua12
-rw-r--r--builtin/mainmenu/dlg_register.lua123
-rw-r--r--builtin/mainmenu/dlg_settings_advanced.lua105
-rw-r--r--builtin/mainmenu/dlg_version_info.lua172
-rw-r--r--builtin/mainmenu/generate_from_settingtypes.lua17
-rw-r--r--builtin/mainmenu/init.lua7
-rw-r--r--builtin/mainmenu/pkgmgr.lua165
-rw-r--r--builtin/mainmenu/tab_about.lua144
-rw-r--r--builtin/mainmenu/tab_content.lua35
-rw-r--r--builtin/mainmenu/tab_local.lua167
-rw-r--r--builtin/mainmenu/tab_online.lua57
-rw-r--r--builtin/mainmenu/tab_settings.lua49
-rw-r--r--builtin/mainmenu/tests/serverlistmgr_spec.lua1
18 files changed, 950 insertions, 369 deletions
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
index 8db8bb8d1..81e28f2bb 100644
--- a/builtin/mainmenu/common.lua
+++ b/builtin/mainmenu/common.lua
@@ -125,18 +125,12 @@ os.tmpname = function()
end
--------------------------------------------------------------------------------
-function menu_render_worldlist(show_gameid)
+function menu_render_worldlist()
local retval = {}
local current_worldlist = menudata.worldlist:get_list()
- local row
for i, v in ipairs(current_worldlist) do
- row = v.name
- if show_gameid == nil or show_gameid == true then
- row = row .. " [" .. v.gameid .. "]"
- end
- retval[#retval+1] = core.formspec_escape(row)
-
+ retval[#retval+1] = core.formspec_escape(v.name)
end
return table.concat(retval, ",")
@@ -242,3 +236,11 @@ function menu_worldmt_legacy(selected)
end
end
end
+
+function confirmation_formspec(message, confirm_id, confirm_label, cancel_id, cancel_label)
+ return "size[10,2.5,true]" ..
+ "label[0.5,0.5;" .. message .. "]" ..
+ "style[" .. confirm_id .. ";bgcolor=red]" ..
+ "button[0.5,1.5;2.5,0.5;" .. confirm_id .. ";" .. confirm_label .. "]" ..
+ "button[7.0,1.5;2.5,0.5;" .. cancel_id .. ";" .. cancel_label .. "]"
+end
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
index 9bdf92a74..e76e10ef7 100644
--- a/builtin/mainmenu/dlg_config_world.lua
+++ b/builtin/mainmenu/dlg_config_world.lua
@@ -61,12 +61,68 @@ local function init_data(data)
data.list:set_sortmode("alphabetic")
end
+
+-- Returns errors errors and a list of all enabled mods (inc. game and world mods)
+--
+-- `with_errors` is a table from mod virtual path to `{ type = "error" | "warning" }`.
+-- `enabled_mods_by_name` is a table from mod virtual path to `true`.
+--
+-- @param world_path Path to the world
+-- @param all_mods List of mods, with `enabled` property.
+-- @returns with_errors, enabled_mods_by_name
+local function check_mod_configuration(world_path, all_mods)
+ -- Build up lookup tables for enabled mods and all mods by vpath
+ local enabled_mod_paths = {}
+ local all_mods_by_vpath = {}
+ for _, mod in ipairs(all_mods) do
+ if mod.type == "mod" then
+ all_mods_by_vpath[mod.virtual_path] = mod
+ end
+ if mod.enabled then
+ enabled_mod_paths[mod.virtual_path] = mod.path
+ end
+ end
+
+ -- Use the engine's mod configuration code to resolve dependencies and return any errors
+ local config_status = core.check_mod_configuration(world_path, enabled_mod_paths)
+
+ -- Build the list of enabled mod virtual paths
+ local enabled_mods_by_name = {}
+ for _, mod in ipairs(config_status.satisfied_mods) do
+ assert(mod.virtual_path ~= "")
+ enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
+ end
+ for _, mod in ipairs(config_status.unsatisfied_mods) do
+ assert(mod.virtual_path ~= "")
+ enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
+ end
+
+ -- Build the table of errors
+ local with_error = {}
+ for _, mod in ipairs(config_status.unsatisfied_mods) do
+ local error = { type = "warning" }
+ with_error[mod.virtual_path] = error
+
+ for _, depname in ipairs(mod.unsatisfied_depends) do
+ if not enabled_mods_by_name[depname] then
+ error.type = "error"
+ break
+ end
+ end
+ end
+
+ return with_error, enabled_mods_by_name
+end
+
local function get_formspec(data)
if not data.list then
init_data(data)
end
- local mod = data.list:get_list()[data.selected_mod] or {name = ""}
+ local all_mods = data.list:get_list()
+ local with_error, enabled_mods_by_name = check_mod_configuration(data.worldspec.path, all_mods)
+
+ local mod = all_mods[data.selected_mod] or {name = ""}
local retval =
"size[11.5,7.5,true]" ..
@@ -87,6 +143,29 @@ local function get_formspec(data)
"textarea[0.25,0.7;5.75,7.2;;" .. info .. ";]"
else
local hard_deps, soft_deps = pkgmgr.get_dependencies(mod.path)
+
+ -- Add error messages to dep lists
+ if mod.enabled or mod.is_game_content then
+ for i, dep_name in ipairs(hard_deps) do
+ local dep = enabled_mods_by_name[dep_name]
+ if not dep then
+ hard_deps[i] = mt_color_red .. dep_name .. " " .. fgettext("(Unsatisfied)")
+ elseif with_error[dep.virtual_path] then
+ hard_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
+ else
+ hard_deps[i] = mt_color_green .. dep_name
+ end
+ end
+ for i, dep_name in ipairs(soft_deps) do
+ local dep = enabled_mods_by_name[dep_name]
+ if dep and with_error[dep.virtual_path] then
+ soft_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
+ elseif dep then
+ soft_deps[i] = mt_color_green .. dep_name
+ end
+ end
+ end
+
local hard_deps_str = table.concat(hard_deps, ",")
local soft_deps_str = table.concat(soft_deps, ",")
@@ -138,7 +217,6 @@ local function get_formspec(data)
if mod.name ~= "" and not mod.is_game_content then
if mod.is_modpack then
-
if pkgmgr.is_modpack_entirely_enabled(data, mod.name) then
retval = retval ..
"button[5.5,0.125;3,0.5;btn_mp_disable;" ..
@@ -163,10 +241,16 @@ local function get_formspec(data)
"button[8.95,0.125;2.5,0.5;btn_enable_all_mods;" ..
fgettext("Enable all") .. "]"
end
+
+ local use_technical_names = core.settings:get_bool("show_technical_names")
+
return retval ..
- "tablecolumns[color;tree;text]" ..
+ "tablecolumns[color;tree;image,align=inline,width=1.5,0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") ..
+ ",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16_white.png") ..
+ ",2=" .. core.formspec_escape(defaulttexturedir .. "error_icon_orange.png") ..
+ ",3=" .. core.formspec_escape(defaulttexturedir .. "error_icon_red.png") .. ";text]" ..
"table[5.5,0.75;5.75,6;world_config_modlist;" ..
- pkgmgr.render_packagelist(data.list) .. ";" .. data.selected_mod .."]"
+ pkgmgr.render_packagelist(data.list, use_technical_names, with_error) .. ";" .. data.selected_mod .."]"
end
local function handle_buttons(this, fields)
@@ -205,14 +289,19 @@ local function handle_buttons(this, fields)
local mods = worldfile:to_table()
local rawlist = this.data.list:get_raw_list()
+ local was_set = {}
for i = 1, #rawlist do
local mod = rawlist[i]
if not mod.is_modpack and
not mod.is_game_content then
if modname_valid(mod.name) then
- worldfile:set("load_mod_" .. mod.name,
- mod.enabled and "true" or "false")
+ if mod.enabled then
+ worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
+ was_set[mod.name] = true
+ elseif not was_set[mod.name] then
+ worldfile:set("load_mod_" .. mod.name, "false")
+ end
elseif mod.enabled then
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
"d \"$1\" as it contains disallowed characters. " ..
@@ -256,12 +345,26 @@ local function handle_buttons(this, fields)
if fields.btn_enable_all_mods then
local list = this.data.list:get_raw_list()
+ -- When multiple copies of a mod are installed, we need to avoid enabling multiple of them
+ -- at a time. So lets first collect all the enabled mods, and then use this to exclude
+ -- multiple enables.
+
+ local was_enabled = {}
for i = 1, #list do
if not list[i].is_game_content
- and not list[i].is_modpack then
+ and not list[i].is_modpack and list[i].enabled then
+ was_enabled[list[i].name] = true
+ end
+ end
+
+ for i = 1, #list do
+ if not list[i].is_game_content and not list[i].is_modpack and
+ not was_enabled[list[i].name] then
list[i].enabled = true
+ was_enabled[list[i].name] = true
end
end
+
enabled_all = true
return true
end
diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
index 276a7b096..2152b8a39 100644
--- a/builtin/mainmenu/dlg_contentstore.lua
+++ b/builtin/mainmenu/dlg_contentstore.lua
@@ -151,11 +151,9 @@ local function start_install(package, reason)
if conf_path then
local conf = Settings(conf_path)
- if name_is_title then
- conf:set("name", package.title)
- else
- conf:set("title", package.title)
- conf:set("name", package.name)
+ conf:set("title", package.title)
+ if not name_is_title then
+ conf:set("name", package.name)
end
if not conf:get("description") then
conf:set("description", package.short_description)
@@ -193,7 +191,7 @@ end
local function queue_download(package, reason)
local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
- if number_downloading < max_concurrent_downloads then
+ if number_downloading < math.max(max_concurrent_downloads, 1) then
start_install(package, reason)
else
table.insert(download_queue, { package = package, reason = reason })
@@ -360,7 +358,7 @@ function install_dialog.get_formspec()
selected_game_idx = i
end
- games[i] = core.formspec_escape(games[i].name)
+ games[i] = core.formspec_escape(games[i].title)
end
local selected_game = pkgmgr.games[selected_game_idx]
@@ -410,7 +408,7 @@ function install_dialog.get_formspec()
"container[0.375,0.70]",
"label[0,0.25;", fgettext("Base Game:"), "]",
- "dropdown[2,0;4.25,0.5;gameid;", table.concat(games, ","), ";", selected_game_idx, "]",
+ "dropdown[2,0;4.25,0.5;selected_game;", table.concat(games, ","), ";", selected_game_idx, "]",
"label[0,0.8;", fgettext("Dependencies:"), "]",
@@ -461,9 +459,9 @@ function install_dialog.handle_submit(this, fields)
return true
end
- if fields.gameid then
+ if fields.selected_game then
for _, game in pairs(pkgmgr.games) do
- if game.name == fields.gameid then
+ if game.title == fields.selected_game then
core.settings:set("menu_last_game", game.id)
break
end
@@ -490,12 +488,10 @@ local confirm_overwrite = {}
function confirm_overwrite.get_formspec()
local package = confirm_overwrite.package
- return "size[11.5,4.5,true]" ..
- "label[2,2;" ..
- fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name) .. "]"..
- "style[install;bgcolor=red]" ..
- "button[3.25,3.5;2.5,0.5;install;" .. fgettext("Overwrite") .. "]" ..
- "button[5.75,3.5;2.5,0.5;cancel;" .. fgettext("Cancel") .. "]"
+ return confirmation_formspec(
+ fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name),
+ 'install', fgettext("Overwrite"),
+ 'cancel', fgettext("Cancel"))
end
function confirm_overwrite.handle_submit(this, fields)
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 8d1509f33..806e019a9 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -15,9 +15,6 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--- cf. tab_local, the gamebar already provides game selection so we hide the list from here
-local hide_gamelist = PLATFORM ~= "Android"
-
local function table_to_flags(ftable)
-- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
local str = {}
@@ -94,14 +91,14 @@ local mgv6_biomes = {
local function create_world_formspec(dialogdata)
- -- Error out when no games found
+ -- Point the player to ContentDB when no games are found
if #pkgmgr.games == 0 then
- return "size[12.25,3,true]" ..
- "box[0,0;12,2;" .. mt_color_orange .. "]" ..
- "textarea[0.3,0;11.7,2;;;"..
- fgettext("You have no games installed.") .. "\n" ..
- fgettext("Download one from minetest.net") .. "]" ..
- "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+ return "size[8,2.5,true]" ..
+ "style[label_button;border=false]" ..
+ "button[0.5,0.5;7,0.5;label_button;" ..
+ fgettext("You have no games installed.") .. "]" ..
+ "button[0.5,1.5;2.5,0.5;world_create_open_cdb;" .. fgettext("Install a game") .. "]" ..
+ "button[5.0,1.5;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
end
local current_mg = dialogdata.mg
@@ -111,14 +108,11 @@ local function create_world_formspec(dialogdata)
local flags = dialogdata.flags
- local game, gameidx = pkgmgr.find_by_gameid(gameid)
- if game == nil and hide_gamelist then
+ local game = pkgmgr.find_by_gameid(gameid)
+ if game == nil then
-- should never happen but just pick the first game
game = pkgmgr.get_game(1)
- gameidx = 1
core.settings:set("menu_last_game", game.id)
- elseif game == nil then
- gameidx = 0
end
local disallowed_mapgen_settings = {}
@@ -296,17 +290,6 @@ local function create_world_formspec(dialogdata)
label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
end
- -- Warning if only devtest is installed
- local devtest_only = ""
- local gamelist_height = 2.3
- if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
- devtest_only = "box[0,0;5.8,1.7;#ff8800]" ..
- "textarea[0.3,0;6,1.8;;;"..
- fgettext("Warning: The Development Test is meant for developers.") .. "\n" ..
- fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
- gamelist_height = 0.5
- end
-
local retval =
"size[12.25,7,true]" ..
@@ -315,22 +298,28 @@ local function create_world_formspec(dialogdata)
"field[0.3,0.6;6,0.5;te_world_name;" ..
fgettext("World name") ..
";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
- "set_focus[te_world_name;false]" ..
+ "set_focus[te_world_name;false]"
- "field[0.3,1.7;6,0.5;te_seed;" ..
- fgettext("Seed") ..
- ";".. core.formspec_escape(dialogdata.seed) .. "]" ..
+ if not disallowed_mapgen_settings["seed"] then
+ retval = retval .. "field[0.3,1.7;6,0.5;te_seed;" ..
+ fgettext("Seed") ..
+ ";".. core.formspec_escape(dialogdata.seed) .. "]"
+
+ end
+
+ retval = retval ..
"label[0,2;" .. fgettext("Mapgen") .. "]"..
"dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
- if not hide_gamelist or devtest_only ~= "" then
+ -- Warning if only devtest is installed
+ if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
retval = retval ..
- "label[0,3.35;" .. fgettext("Game") .. "]"..
- "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
- pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
- "container[0,4.5]" ..
- devtest_only ..
+ "container[0,3.5]" ..
+ "box[0,0;5.8,1.7;#ff8800]" ..
+ "textarea[0.4,0.1;6,1.8;;;"..
+ fgettext("Development Test is meant for developers.") .. "]" ..
+ "button[1,1;4,0.5;world_create_open_cdb;" .. fgettext("Install another game") .. "]" ..
"container_end[]"
end
@@ -353,17 +342,20 @@ end
local function create_world_buttonhandler(this, fields)
+ if fields["world_create_open_cdb"] then
+ local dlg = create_store_dlg("game")
+ dlg:set_parent(this.parent)
+ this:delete()
+ this.parent:hide()
+ dlg:show()
+ return true
+ end
+
if fields["world_create_confirm"] or
fields["key_enter"] then
local worldname = fields["te_world_name"]
- local game, gameindex
- if hide_gamelist then
- game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
- else
- gameindex = core.get_textlist_index("games")
- game = pkgmgr.get_game(gameindex)
- end
+ local game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
local message
if game == nil then
@@ -391,7 +383,7 @@ local function create_world_buttonhandler(this, fields)
end
if message == nil then
- this.data.seed = fields["te_seed"]
+ this.data.seed = fields["te_seed"] or ""
this.data.mg = fields["dd_mapgen"]
-- actual names as used by engine
@@ -412,9 +404,7 @@ local function create_world_buttonhandler(this, fields)
if message == nil then
core.settings:set("menu_last_game", game.id)
- if this.data.update_worldlist_filter then
- menudata.worldlist:set_filtercriteria(game.id)
- end
+ menudata.worldlist:set_filtercriteria(game.id)
menudata.worldlist:refresh()
core.settings:set("mainmenu_last_selected_world",
menudata.worldlist:raw_index_by_uid(worldname))
@@ -426,7 +416,7 @@ local function create_world_buttonhandler(this, fields)
end
this.data.worldname = fields["te_world_name"]
- this.data.seed = fields["te_seed"]
+ this.data.seed = fields["te_seed"] or ""
if fields["games"] then
local gameindex = core.get_textlist_index("games")
@@ -472,13 +462,12 @@ local function create_world_buttonhandler(this, fields)
end
-function create_create_world_dlg(update_worldlistfilter)
+function create_create_world_dlg()
local retval = dialog_create("sp_create_world",
create_world_formspec,
create_world_buttonhandler,
nil)
retval.data = {
- update_worldlist_filter = update_worldlistfilter,
worldname = "",
-- settings the world is created with:
seed = core.settings:get("fixed_map_seed") or "",
diff --git a/builtin/mainmenu/dlg_delete_content.lua b/builtin/mainmenu/dlg_delete_content.lua
index a24171541..4463825f7 100644
--- a/builtin/mainmenu/dlg_delete_content.lua
+++ b/builtin/mainmenu/dlg_delete_content.lua
@@ -18,15 +18,10 @@
--------------------------------------------------------------------------------
local function delete_content_formspec(dialogdata)
- local retval =
- "size[11.5,4.5,true]" ..
- "label[2,2;" ..
- fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name) .. "]"..
- "style[dlg_delete_content_confirm;bgcolor=red]" ..
- "button[3.25,3.5;2.5,0.5;dlg_delete_content_confirm;" .. fgettext("Delete") .. "]" ..
- "button[5.75,3.5;2.5,0.5;dlg_delete_content_cancel;" .. fgettext("Cancel") .. "]"
-
- return retval
+ return confirmation_formspec(
+ fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name),
+ 'dlg_delete_content_confirm', fgettext("Delete"),
+ 'dlg_delete_content_cancel', fgettext("Cancel"))
end
--------------------------------------------------------------------------------
diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua
index 33e7bc945..67c0612bd 100644
--- a/builtin/mainmenu/dlg_delete_world.lua
+++ b/builtin/mainmenu/dlg_delete_world.lua
@@ -17,14 +17,10 @@
local function delete_world_formspec(dialogdata)
- local retval =
- "size[10,2.5,true]" ..
- "label[0.5,0.5;" ..
- fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
- "style[world_delete_confirm;bgcolor=red]" ..
- "button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
- "button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
- return retval
+ return confirmation_formspec(
+ fgettext("Delete World \"$1\"?", dialogdata.delete_name),
+ 'world_delete_confirm', fgettext("Delete"),
+ 'world_delete_cancel', fgettext("Cancel"))
end
local function delete_world_buttonhandler(this, fields)
diff --git a/builtin/mainmenu/dlg_register.lua b/builtin/mainmenu/dlg_register.lua
new file mode 100644
index 000000000..a7658249c
--- /dev/null
+++ b/builtin/mainmenu/dlg_register.lua
@@ -0,0 +1,123 @@
+--Minetest
+--Copyright (C) 2022 rubenwardy
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function register_formspec(dialogdata)
+ local title = fgettext("Joining $1", dialogdata.server and dialogdata.server.name or dialogdata.address)
+ local buttons_y = 4 + 1.3
+ if dialogdata.error then
+ buttons_y = buttons_y + 0.8
+ end
+
+ local retval = {
+ "formspec_version[4]",
+ "size[8,", tostring(buttons_y + 1.175), "]",
+ "set_focus[", (dialogdata.name ~= "" and "password" or "name"), "]",
+ "label[0.375,0.8;", title, "]",
+ "field[0.375,1.575;7.25,0.8;name;", core.formspec_escape(fgettext("Name")), ";",
+ core.formspec_escape(dialogdata.name), "]",
+ "pwdfield[0.375,2.875;7.25,0.8;password;", core.formspec_escape(fgettext("Password")), "]",
+ "pwdfield[0.375,4.175;7.25,0.8;password_2;", core.formspec_escape(fgettext("Confirm Password")), "]"
+ }
+
+ if dialogdata.error then
+ table.insert_all(retval, {
+ "box[0.375,", tostring(buttons_y - 0.9), ";7.25,0.6;darkred]",
+ "label[0.625,", tostring(buttons_y - 0.6), ";", core.formspec_escape(dialogdata.error), "]",
+ })
+ end
+
+ table.insert_all(retval, {
+ "container[0.375,", tostring(buttons_y), "]",
+ "button[0,0;2.5,0.8;dlg_register_confirm;", fgettext("Register"), "]",
+ "button[4.75,0;2.5,0.8;dlg_register_cancel;", fgettext("Cancel"), "]",
+ "container_end[]",
+ })
+
+ return table.concat(retval, "")
+end
+
+--------------------------------------------------------------------------------
+local function register_buttonhandler(this, fields)
+ this.data.name = fields.name
+ this.data.error = nil
+
+ if fields.dlg_register_confirm or fields.key_enter then
+ if fields.name == "" then
+ this.data.error = fgettext("Missing name")
+ return true
+ end
+ if fields.password ~= fields.password_2 then
+ this.data.error = fgettext("Passwords do not match")
+ return true
+ end
+
+ gamedata.playername = fields.name
+ gamedata.password = fields.password
+ gamedata.address = this.data.address
+ gamedata.port = this.data.port
+ gamedata.allow_login_or_register = "register"
+ gamedata.selected_world = 0
+
+ assert(gamedata.address and gamedata.port)
+
+ local server = this.data.server
+ if server then
+ serverlistmgr.add_favorite(server)
+ gamedata.servername = server.name
+ gamedata.serverdescription = server.description
+ else
+ gamedata.servername = ""
+ gamedata.serverdescription = ""
+
+ serverlistmgr.add_favorite({
+ address = gamedata.address,
+ port = gamedata.port,
+ })
+ end
+
+ core.settings:set("name", fields.name)
+ core.settings:set("address", gamedata.address)
+ core.settings:set("remote_port", gamedata.port)
+
+ core.start()
+ end
+
+ if fields["dlg_register_cancel"] then
+ this:delete()
+ return true
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function create_register_dialog(address, port, server)
+ assert(address)
+ assert(type(port) == "number")
+
+ local retval = dialog_create("dlg_register",
+ register_formspec,
+ register_buttonhandler,
+ nil)
+ retval.data.address = address
+ retval.data.port = port
+ retval.data.server = server
+ retval.data.name = core.settings:get("name") or ""
+ return retval
+end
diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua
index 06fd32d84..69562e6a5 100644
--- a/builtin/mainmenu/dlg_settings_advanced.lua
+++ b/builtin/mainmenu/dlg_settings_advanced.lua
@@ -351,9 +351,9 @@ local function parse_config_file(read_all, parse_mods)
local file = io.open(path, "r")
if file then
if not games_category_initialized then
- fgettext_ne("Games") -- not used, but needed for xgettext
+ fgettext_ne("Content: Games") -- not used, but needed for xgettext
table.insert(settings, {
- name = "Games",
+ name = "Content: Games",
level = 0,
type = "category",
})
@@ -378,15 +378,15 @@ local function parse_config_file(read_all, parse_mods)
-- Parse mods
local mods_category_initialized = false
local mods = {}
- get_mods(core.get_modpath(), mods)
+ get_mods(core.get_modpath(), "mods", mods)
for _, mod in ipairs(mods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not mods_category_initialized then
- fgettext_ne("Mods") -- not used, but needed for xgettext
+ fgettext_ne("Content: Mods") -- not used, but needed for xgettext
table.insert(settings, {
- name = "Mods",
+ name = "Content: Mods",
level = 0,
type = "category",
})
@@ -395,6 +395,37 @@ local function parse_config_file(read_all, parse_mods)
table.insert(settings, {
name = mod.name,
+ readable_name = mod.title,
+ level = 1,
+ type = "category",
+ })
+
+ parse_single_file(file, path, read_all, settings, 2, false)
+
+ file:close()
+ end
+ end
+
+ -- Parse client mods
+ local clientmods_category_initialized = false
+ local clientmods = {}
+ get_mods(core.get_clientmodpath(), "clientmods", clientmods)
+ for _, mod in ipairs(clientmods) do
+ local path = mod.path .. DIR_DELIM .. FILENAME
+ local file = io.open(path, "r")
+ if file then
+ if not clientmods_category_initialized then
+ fgettext_ne("Client Mods") -- not used, but needed for xgettext
+ table.insert(settings, {
+ name = "Client Mods",
+ level = 0,
+ type = "category",
+ })
+ clientmods_category_initialized = true
+ end
+
+ table.insert(settings, {
+ name = mod.name,
level = 1,
type = "category",
})
@@ -497,44 +528,40 @@ end
local function get_current_np_group(setting)
local value = core.settings:get_np_group(setting.name)
- local t = {}
if value == nil then
- t = setting.values
- else
- table.insert(t, value.offset)
- table.insert(t, value.scale)
- table.insert(t, value.spread.x)
- table.insert(t, value.spread.y)
- table.insert(t, value.spread.z)
- table.insert(t, value.seed)
- table.insert(t, value.octaves)
- table.insert(t, value.persistence)
- table.insert(t, value.lacunarity)
- table.insert(t, value.flags)
+ return setting.values
end
- return t
+ local p = "%g"
+ return {
+ p:format(value.offset),
+ p:format(value.scale),
+ p:format(value.spread.x),
+ p:format(value.spread.y),
+ p:format(value.spread.z),
+ p:format(value.seed),
+ p:format(value.octaves),
+ p:format(value.persistence),
+ p:format(value.lacunarity),
+ value.flags
+ }
end
local function get_current_np_group_as_string(setting)
local value = core.settings:get_np_group(setting.name)
- local t
if value == nil then
- t = setting.default
- else
- t = value.offset .. ", " ..
- value.scale .. ", (" ..
- value.spread.x .. ", " ..
- value.spread.y .. ", " ..
- value.spread.z .. "), " ..
- value.seed .. ", " ..
- value.octaves .. ", " ..
- value.persistence .. ", " ..
- value.lacunarity
- if value.flags ~= "" then
- t = t .. ", " .. value.flags
- end
+ return setting.default
end
- return t
+ return ("%g, %g, (%g, %g, %g), %g, %g, %g, %g"):format(
+ value.offset,
+ value.scale,
+ value.spread.x,
+ value.spread.y,
+ value.spread.z,
+ value.seed,
+ value.octaves,
+ value.persistence,
+ value.lacunarity
+ ) .. (value.flags ~= "" and (", " .. value.flags) or "")
end
local checkboxes = {} -- handle checkboxes events
@@ -667,7 +694,7 @@ local function create_change_setting_formspec(dialogdata)
elseif setting.type == "v3f" then
local val = get_current_value(setting)
local v3f = {}
- for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
+ for line in val:gmatch("[+-]?[%d.+-eE]+") do -- All numeric characters
table.insert(v3f, line)
end
@@ -960,7 +987,7 @@ local function create_settings_formspec(tabview, _, tabdata)
local current_level = 0
for _, entry in ipairs(settings) do
local name
- if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
+ if not core.settings:get_bool("show_technical_names") and entry.readable_name then
name = fgettext_ne(entry.readable_name)
else
name = entry.name
@@ -1001,7 +1028,7 @@ local function create_settings_formspec(tabview, _, tabdata)
"button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
"button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
"checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
- .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
+ .. dump(core.settings:get_bool("show_technical_names")) .. "]"
return formspec
end
@@ -1084,7 +1111,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
if fields["cb_tech_settings"] then
- core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
+ core.settings:set("show_technical_names", fields["cb_tech_settings"])
core.settings:write()
core.update_formspec(this:get_formspec())
return true
diff --git a/builtin/mainmenu/dlg_version_info.lua b/builtin/mainmenu/dlg_version_info.lua
new file mode 100644
index 000000000..568fca3f4
--- /dev/null
+++ b/builtin/mainmenu/dlg_version_info.lua
@@ -0,0 +1,172 @@
+--[[
+Minetest
+Copyright (C) 2018-2020 SmallJoker, 2022 rubenwardy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+]]
+
+if not core.get_http_api then
+ function check_new_version()
+ end
+ return
+end
+
+local function version_info_formspec(data)
+ local cur_ver = core.get_version()
+ local title = fgettext("A new $1 version is available", cur_ver.project)
+ local message =
+ fgettext("Installed version: $1\nNew version: $2\n" ..
+ "Visit $3 to find out how to get the newest version and stay up to date" ..
+ " with features and bugfixes.",
+ cur_ver.string, data.new_version or "", data.url or "")
+
+ local fs = {
+ "formspec_version[3]",
+ "size[12.8,7]",
+ "style_type[label;textcolor=#0E0]",
+ "label[0.5,0.8;", core.formspec_escape(title), "]",
+ "textarea[0.4,1.6;12,3.4;;;",
+ core.formspec_escape(message), "]",
+ "container[0.4,5.8]",
+ "button[0.0,0;4.0,0.8;version_check_visit;", fgettext("Visit website"), "]",
+ "button[4.5,0;3.5,0.8;version_check_remind;", fgettext("Later"), "]",
+ "button[8.5.5,0;3.5,0.8;version_check_never;", fgettext("Never"), "]",
+ "container_end[]",
+ }
+
+ return table.concat(fs, "")
+end
+
+local function version_info_buttonhandler(this, fields)
+ if fields.version_check_remind then
+ -- Erase last known, user will be reminded again at next check
+ core.settings:set("update_last_known", "")
+ this:delete()
+ return true
+ end
+ if fields.version_check_never then
+ core.settings:set("update_last_checked", "disabled")
+ this:delete()
+ return true
+ end
+ if fields.version_check_visit then
+ if type(this.data.url) == "string" then
+ core.open_url(this.data.url)
+ end
+ this:delete()
+ return true
+ end
+
+ return false
+end
+
+local function create_version_info_dlg(new_version, url)
+ assert(type(new_version) == "string")
+ assert(type(url) == "string")
+
+ local retval = dialog_create("version_info",
+ version_info_formspec,
+ version_info_buttonhandler,
+ nil)
+
+ retval.data.new_version = new_version
+ retval.data.url = url
+
+ return retval
+end
+
+local function get_current_version_code()
+ -- Format: Major.Minor.Patch
+ -- Convert to MMMNNNPPP
+ local cur_string = core.get_version().string
+ local cur_major, cur_minor, cur_patch = cur_string:match("^(%d+).(%d+).(%d+)")
+
+ if not cur_patch then
+ core.log("error", "Failed to parse version numbers (invalid tag format?)")
+ return
+ end
+
+ return (cur_major * 1000 + cur_minor) * 1000 + cur_patch
+end
+
+local function on_version_info_received(json)
+ local maintab = ui.find_by_name("maintab")
+ if maintab.hidden then
+ -- Another dialog is open, abort.
+ return
+ end
+
+ local known_update = tonumber(core.settings:get("update_last_known")) or 0
+
+ -- Format: MMNNPPP (Major, Minor, Patch)
+ local new_number = type(json.latest) == "table" and json.latest.version_code
+ if type(new_number) ~= "number" then
+ core.log("error", "Failed to read version number (invalid response?)")
+ return
+ end
+
+ local cur_number = get_current_version_code()
+ if new_number <= known_update or new_number < cur_number then
+ return
+ end
+
+ -- Also consider updating from 1.2.3-dev to 1.2.3
+ if new_number == cur_number and not core.get_version().is_dev then
+ return
+ end
+
+ core.settings:set("update_last_known", tostring(new_number))
+
+ -- Show version info dialog (once)
+ maintab:hide()
+
+ local version_info_dlg = create_version_info_dlg(json.latest.version, json.latest.url)
+ version_info_dlg:set_parent(maintab)
+ version_info_dlg:show()
+
+ ui.update()
+end
+
+function check_new_version()
+ local url = core.settings:get("update_information_url")
+ if core.settings:get("update_last_checked") == "disabled" or
+ url == "" then
+ -- Never show any updates
+ return
+ end
+
+ local time_now = os.time()
+ local time_checked = tonumber(core.settings:get("update_last_checked")) or 0
+ if time_now - time_checked < 2 * 24 * 3600 then
+ -- Check interval of 2 entire days
+ return
+ end
+
+ core.settings:set("update_last_checked", tostring(time_now))
+
+ core.handle_async(function(params)
+ local http = core.get_http_api()
+ return http.fetch_sync(params)
+ end, { url = url }, function(result)
+ local json = result.succeeded and core.parse_json(result.data)
+ if type(json) ~= "table" or not json.latest then
+ core.log("error", "Failed to read JSON output from " .. url ..
+ ", status code = " .. result.code)
+ return
+ end
+
+ on_version_info_received(json)
+ end)
+end
diff --git a/builtin/mainmenu/generate_from_settingtypes.lua b/builtin/mainmenu/generate_from_settingtypes.lua
index 43fc57bb9..0f551fbb1 100644
--- a/builtin/mainmenu/generate_from_settingtypes.lua
+++ b/builtin/mainmenu/generate_from_settingtypes.lua
@@ -31,7 +31,7 @@ local group_format_template = [[
# octaves = %s,
# persistence = %s,
# lacunarity = %s,
-# flags = %s
+# flags =%s
# }
]]
@@ -55,7 +55,11 @@ local function create_minetest_conf_example()
end
if entry.comment ~= "" then
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
- insert(result, "# " .. comment_line .. "\n")
+ if comment_line == "" then
+ insert(result, "#\n")
+ else
+ insert(result, "# " .. comment_line .. "\n")
+ end
end
end
insert(result, "# type: " .. entry.type)
@@ -73,10 +77,14 @@ local function create_minetest_conf_example()
end
insert(result, "\n")
if group_format == true then
+ local flags = entry.values[10]
+ if flags ~= "" then
+ flags = " "..flags
+ end
insert(result, sprintf(group_format_template, entry.name, entry.values[1],
entry.values[2], entry.values[3], entry.values[4], entry.values[5],
entry.values[6], entry.values[7], entry.values[8], entry.values[9],
- entry.values[10]))
+ flags))
else
local append
if entry.default ~= "" then
@@ -91,7 +99,7 @@ end
local translation_file_header = [[
// This file is automatically generated
-// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files
+// It contains a bunch of fake gettext calls, to tell xgettext about the strings in config files
// To update it, refer to the bottom of builtin/mainmenu/dlg_settings_advanced.lua
fake_function() {]]
@@ -126,4 +134,3 @@ file = assert(io.open("src/settings_translation_file.cpp", "w"))
--file = assert(io.open("settings_translation_file.cpp", "w"))
file:write(create_translation_file())
file:close()
-
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index 8e716c2eb..c3a28a570 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -17,9 +17,11 @@
mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF"
+mt_color_lightblue = "#99CCFF"
mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
+mt_color_red = "#FF3300"
local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path()
@@ -43,7 +45,9 @@ dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
local tabs = {}
@@ -91,6 +95,7 @@ local function init_globals()
-- Create main tabview
local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0})
+ -- note: size would be 15.5,7.1 in real coordinates mode
tv_main:set_autosave_tab(true)
tv_main:add(tabs.local_game)
@@ -118,8 +123,8 @@ local function init_globals()
end
ui.set_default("maintab")
+ check_new_version()
tv_main:show()
-
ui.update()
end
diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
index 23f24d617..32a65fd08 100644
--- a/builtin/mainmenu/pkgmgr.lua
+++ b/builtin/mainmenu/pkgmgr.lua
@@ -78,34 +78,35 @@ local function load_texture_packs(txtpath, retval)
for _, item in ipairs(list) do
if item ~= "base" then
- local name = item
-
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
- if path == current_texture_path then
- name = fgettext("$1 (Enabled)", name)
- end
-
local conf = Settings(path .. "texture_pack.conf")
+ local enabled = path == current_texture_path
+ local title = conf:get("title") or item
+
+ -- list_* is only used if non-nil, else the regular versions are used.
retval[#retval + 1] = {
name = item,
+ title = title,
+ list_name = enabled and fgettext("$1 (Enabled)", item) or nil,
+ list_title = enabled and fgettext("$1 (Enabled)", title) or nil,
author = conf:get("author"),
release = tonumber(conf:get("release")) or 0,
- list_name = name,
type = "txp",
path = path,
- enabled = path == current_texture_path,
+ enabled = enabled,
}
end
end
end
-function get_mods(path,retval,modpack)
+function get_mods(path, virtual_path, retval, modpack)
local mods = core.get_dir_list(path, true)
for _, name in ipairs(mods) do
if name:sub(1, 1) ~= "." then
- local prefix = path .. DIR_DELIM .. name
+ local mod_path = path .. DIR_DELIM .. name
+ local mod_virtual_path = virtual_path .. "/" .. name
local toadd = {
dir_name = name,
parent_dir = path,
@@ -114,18 +115,18 @@ function get_mods(path,retval,modpack)
-- Get config file
local mod_conf
- local modpack_conf = io.open(prefix .. DIR_DELIM .. "modpack.conf")
+ local modpack_conf = io.open(mod_path .. DIR_DELIM .. "modpack.conf")
if modpack_conf then
toadd.is_modpack = true
modpack_conf:close()
- mod_conf = Settings(prefix .. DIR_DELIM .. "modpack.conf"):to_table()
+ mod_conf = Settings(mod_path .. DIR_DELIM .. "modpack.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
toadd.is_name_explicit = true
end
else
- mod_conf = Settings(prefix .. DIR_DELIM .. "mod.conf"):to_table()
+ mod_conf = Settings(mod_path .. DIR_DELIM .. "mod.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
toadd.is_name_explicit = true
@@ -134,14 +135,16 @@ function get_mods(path,retval,modpack)
-- Read from config
toadd.name = name
+ toadd.title = mod_conf.title
toadd.author = mod_conf.author
toadd.release = tonumber(mod_conf.release) or 0
- toadd.path = prefix
+ toadd.path = mod_path
+ toadd.virtual_path = mod_virtual_path
toadd.type = "mod"
-- Check modpack.txt
-- Note: modpack.conf is already checked above
- local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt")
+ local modpackfile = io.open(mod_path .. DIR_DELIM .. "modpack.txt")
if modpackfile then
modpackfile:close()
toadd.is_modpack = true
@@ -153,7 +156,7 @@ function get_mods(path,retval,modpack)
elseif toadd.is_modpack then
toadd.type = "modpack"
toadd.is_modpack = true
- get_mods(prefix, retval, name)
+ get_mods(mod_path, mod_virtual_path, retval, name)
end
end
end
@@ -334,7 +337,7 @@ function pkgmgr.identify_modname(modpath,filename)
return nil
end
--------------------------------------------------------------------------------
-function pkgmgr.render_packagelist(render_list)
+function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
@@ -346,31 +349,75 @@ function pkgmgr.render_packagelist(render_list)
local retval = {}
for i, v in ipairs(list) do
local color = ""
+ local icon = 0
+ local error = with_error and with_error[v.virtual_path]
+ local function update_error(val)
+ if val and (not error or (error.type == "warning" and val.type == "error")) then
+ error = val
+ end
+ end
+
if v.is_modpack then
local rawlist = render_list:get_raw_list()
color = mt_color_dark_green
- for j = 1, #rawlist, 1 do
- if rawlist[j].modpack == list[i].name and
- not rawlist[j].enabled then
- -- Modpack not entirely enabled so showing as grey
- color = mt_color_grey
- break
+ for j = 1, #rawlist do
+ if rawlist[j].modpack == list[i].name then
+ if with_error then
+ update_error(with_error[rawlist[j].virtual_path])
+ end
+
+ if rawlist[j].enabled then
+ icon = 1
+ else
+ -- Modpack not entirely enabled so showing as grey
+ color = mt_color_grey
+ end
end
end
elseif v.is_game_content or v.type == "game" then
+ icon = 1
color = mt_color_blue
+
+ local rawlist = render_list:get_raw_list()
+ if v.type == "game" and with_error then
+ for j = 1, #rawlist do
+ if rawlist[j].is_game_content then
+ update_error(with_error[rawlist[j].virtual_path])
+ end
+ end
+ end
elseif v.enabled or v.type == "txp" then
+ icon = 1
color = mt_color_green
end
+ if error then
+ if error.type == "warning" then
+ color = mt_color_orange
+ icon = 2
+ else
+ color = mt_color_red
+ icon = 3
+ end
+ end
+
retval[#retval + 1] = color
if v.modpack ~= nil or v.loc == "game" then
retval[#retval + 1] = "1"
else
retval[#retval + 1] = "0"
end
- retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
+
+ if with_error then
+ retval[#retval + 1] = icon
+ end
+
+ if use_technical_names then
+ retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
+ else
+ retval[#retval + 1] = core.formspec_escape(v.list_title or v.list_name or v.title or v.name)
+ end
end
return table.concat(retval, ",")
@@ -397,6 +444,14 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
return true
end
+local function disable_all_by_name(list, name, except)
+ for i=1, #list do
+ if list[i].name == name and list[i] ~= except then
+ list[i].enabled = false
+ end
+ end
+end
+
---------- toggles or en/disables a mod or modpack and its dependencies --------
local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
if not mod.is_modpack then
@@ -405,13 +460,16 @@ local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mo
toset = not mod.enabled
end
if mod.enabled ~= toset then
- mod.enabled = toset
toggled_mods[#toggled_mods+1] = mod.name
end
if toset then
-- Mark this mod for recursive dependency traversal
enabled_mods[mod.name] = true
+
+ -- Disable other mods with the same name
+ disable_all_by_name(list, mod.name, mod)
end
+ mod.enabled = toset
else
-- Toggle or en/disable every mod in the modpack,
-- interleaved unsupported
@@ -472,6 +530,7 @@ function pkgmgr.enable_mod(this, toset)
end
end
end
+
-- If sp is 0, every dependency is already activated
while sp > 0 do
local name = to_enable[sp]
@@ -483,8 +542,8 @@ function pkgmgr.enable_mod(this, toset)
if not mod_to_enable then
core.log("warning", "Mod dependency \"" .. name ..
"\" not found!")
- else
- if not mod_to_enable.enabled then
+ elseif not mod_to_enable.is_game_content then
+ if not mod_to_enable.enabled then
mod_to_enable.enabled = true
toggled_mods[#toggled_mods+1] = mod_to_enable.name
end
@@ -626,6 +685,8 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
else
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
end
+ else
+ error("basefolder didn't return a recognised type, this shouldn't happen")
end
-- Copy it
@@ -652,13 +713,14 @@ function pkgmgr.preparemodlist(data)
--read global mods
local modpaths = core.get_modpaths()
- for _, modpath in ipairs(modpaths) do
- get_mods(modpath, global_mods)
+ for key, modpath in pairs(modpaths) do
+ get_mods(modpath, key, global_mods)
end
for i=1,#global_mods,1 do
global_mods[i].type = "mod"
global_mods[i].loc = "global"
+ global_mods[i].enabled = false
retval[#retval + 1] = global_mods[i]
end
@@ -671,7 +733,7 @@ function pkgmgr.preparemodlist(data)
retval[#retval + 1] = {
type = "game",
is_game_content = true,
- name = fgettext("$1 mods", gamespec.name),
+ name = fgettext("$1 mods", gamespec.title),
path = gamespec.path
}
end
@@ -692,22 +754,37 @@ function pkgmgr.preparemodlist(data)
DIR_DELIM .. "world.mt"
local worldfile = Settings(filename)
-
- for key,value in pairs(worldfile:to_table()) do
+ for key, value in pairs(worldfile:to_table()) do
if key:sub(1, 9) == "load_mod_" then
key = key:sub(10)
- local element = nil
- for i=1,#retval,1 do
+ local mod_found = false
+
+ local fallback_found = false
+ local fallback_mod = nil
+
+ for i=1, #retval do
if retval[i].name == key and
- not retval[i].is_modpack then
- element = retval[i]
- break
+ not retval[i].is_modpack then
+ if core.is_yes(value) or retval[i].virtual_path == value then
+ retval[i].enabled = true
+ mod_found = true
+ break
+ elseif fallback_found then
+ -- Only allow fallback if only one mod matches
+ fallback_mod = nil
+ else
+ fallback_found = true
+ fallback_mod = retval[i]
+ end
end
end
- if element ~= nil then
- element.enabled = value ~= "false" and value ~= "nil" and value
- else
- core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+
+ if not mod_found then
+ if fallback_mod and value:find("/") then
+ fallback_mod.enabled = true
+ else
+ core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+ end
end
end
end
@@ -801,7 +878,7 @@ function pkgmgr.get_game_mods(gamespec, retval)
if gamespec ~= nil and
gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
- get_mods(gamespec.gamemods_path, retval)
+ get_mods(gamespec.gamemods_path, ("games/%s/mods"):format(gamespec.id), retval)
end
end
@@ -837,10 +914,10 @@ end
function pkgmgr.gamelist()
local retval = ""
if #pkgmgr.games > 0 then
- retval = retval .. core.formspec_escape(pkgmgr.games[1].name)
+ retval = retval .. core.formspec_escape(pkgmgr.games[1].title)
for i=2,#pkgmgr.games,1 do
- retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].name)
+ retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title)
end
end
return retval
diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua
index ba258fd2d..a84ebce3f 100644
--- a/builtin/mainmenu/tab_about.lua
+++ b/builtin/mainmenu/tab_about.lua
@@ -15,48 +15,46 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---------------------------------------------------------------------------------
+-- https://github.com/orgs/minetest/teams/engine/members
local core_developers = {
- "Perttu Ahola (celeron55) <celeron55@gmail.com>",
+ "Perttu Ahola (celeron55) <celeron55@gmail.com> [Project founder]",
"sfan5 <sfan5@live.de>",
- "Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>",
+ "ShadowNinja <shadowninja@minetest.net>",
+ "Nathanaëlle Courant (Nore/Ekdohibs) <nore@mesecons.net>",
"Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
- "paramat",
"Andrew Ward (rubenwardy) <rw@rubenwardy.com>",
"Krock/SmallJoker <mk939@ymail.com>",
"Lars Hofhansl <larsh@apache.org>",
- "Pierre-Yves Rollo <dev@pyrollo.com>",
"v-rob <robinsonvincent89@gmail.com>",
"hecks",
"Hugues Ross <hugues.ross@gmail.com>",
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
}
+local core_team = {
+ "Zughy [Issue triager]",
+}
+
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
local active_contributors = {
- "Wuzzy [I18n for builtin, liquid features, fixes]",
- "Zughy [Various features and fixes]",
- "numzero [Graphics and rendering]",
- "Desour [Internal fixes, Clipboard on X11]",
- "Lars Müller [Various internal fixes]",
- "JosiahWI [CMake, cleanups and fixes]",
- "HybridDog [builtin, documentation]",
- "Jude Melton-Houghton [Database implementation]",
- "savilli [Fixes]",
+ "Wuzzy [Features, translations, devtest]",
+ "Lars Müller [Lua optimizations and fixes]",
+ "Jude Melton-Houghton [Optimizations, bugfixes]",
+ "paradust7 [Performance, fixes, Irrlicht refactoring]",
+ "Desour [Fixes]",
+ "ROllerozxa [Main menu]",
+ "savilli [Bugfixes]",
+ "Lexi Hale [Particlespawner animation]",
"Liso [Shadow Mapping]",
- "MoNTE48 [Build fix]",
- "Jean-Patrick Guerrero (kilbith) [Fixes]",
- "ROllerozxa [Code cleanups]",
- "Lejo [bitop library integration]",
- "LoneWolfHT [Build fixes]",
+ "JosiahWI [Fixes, build system]",
+ "numzero [Graphics and rendering]",
+ "HybridDog [Fixes]",
"NeroBurner [Joystick]",
- "Elias Fleckenstein [Internal fixes]",
- "David CARLIER [Unix & Haiku build fixes]",
"pecksin [Clickable web links]",
- "srfqi [Android & rendering fixes]",
- "EvidenceB [Formspec]",
+ "Daroc Alden [Fixes]",
+ "Jean-Patrick Guerrero (kilbith) [Fixes]",
}
local previous_core_developers = {
@@ -71,33 +69,50 @@ local previous_core_developers = {
"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
"sapier",
"Zeno",
- "ShadowNinja <shadowninja@minetest.net>",
"Auke Kok (sofar) <sofar@foo-projects.org>",
"Aaron Suen <warr1024@gmail.com>",
+ "paramat",
+ "Pierre-Yves Rollo <dev@pyrollo.com>",
}
local previous_contributors = {
- "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest Logo]",
+ "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest logo]",
"red-001 <red-001@outlook.ie>",
"Giuseppe Bilotta",
+ "ClobberXD",
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"MirceaKitsune <mirceakitsune@gmail.com>",
+ "MoNTE48",
"Constantin Wenger (SpeedProg)",
"Ciaran Gultnieks (CiaranG)",
"Paul Ouellette (pauloue)",
"stujones11",
+ "srifqi",
"Rogier <rogier777@gmail.com>",
"Gregory Currie (gregorycu)",
"JacobF",
- "Jeija <jeija@mesecons.net> [HTTP, particles]",
+ "Jeija <jeija@mesecons.net>",
}
-local function buildCreditList(source)
+local function prepare_credits(dest, source)
+ for _, s in ipairs(source) do
+ -- if there's text inside brackets make it gray-ish
+ s = s:gsub("%[.-%]", core.colorize("#aaa", "%1"))
+ dest[#dest+1] = s
+ end
+end
+
+local function build_hacky_list(items, spacing)
+ spacing = spacing or 0.5
+ local y = spacing / 2
local ret = {}
- for i = 1, #source do
- ret[i] = core.formspec_escape(source[i])
+ for _, item in ipairs(items) do
+ if item ~= "" then
+ ret[#ret+1] = ("label[0,%f;%s]"):format(y, core.formspec_escape(item))
+ end
+ y = y + spacing
end
- return table.concat(ret, ",,")
+ return table.concat(ret, ""), y
end
return {
@@ -106,42 +121,73 @@ return {
cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version()
- local fs = "image[0.75,0.5;2.2,2.2;" .. core.formspec_escape(logofile) .. "]" ..
+
+ local credit_list = {}
+ table.insert_all(credit_list, {
+ core.colorize("#ff0", fgettext("Core Developers"))
+ })
+ prepare_credits(credit_list, core_developers)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Core Team"))
+ })
+ prepare_credits(credit_list, core_team)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Active Contributors"))
+ })
+ prepare_credits(credit_list, active_contributors)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Previous Core Developers"))
+ })
+ prepare_credits(credit_list, previous_core_developers)
+ table.insert_all(credit_list, {
+ "",
+ core.colorize("#ff0", fgettext("Previous Contributors"))
+ })
+ prepare_credits(credit_list, previous_contributors)
+ local credit_fs, scroll_height = build_hacky_list(credit_list)
+ -- account for the visible portion
+ scroll_height = math.max(0, scroll_height - 6.9)
+
+ local fs = "image[1.5,0.6;2.5,2.5;" .. core.formspec_escape(logofile) .. "]" ..
"style[label_button;border=false]" ..
- "button[0.5,2;2.5,2;label_button;" .. version.project .. " " .. version.string .. "]" ..
- "button[0.75,2.75;2,2;homepage;minetest.net]" ..
- "tablecolumns[color;text]" ..
- "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
- "table[3.5,-0.25;8.5,6.05;list_credits;" ..
- "#FFFF00," .. fgettext("Core Developers") .. ",," ..
- buildCreditList(core_developers) .. ",,," ..
- "#FFFF00," .. fgettext("Active Contributors") .. ",," ..
- buildCreditList(active_contributors) .. ",,," ..
- "#FFFF00," .. fgettext("Previous Core Developers") ..",," ..
- buildCreditList(previous_core_developers) .. ",,," ..
- "#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
- buildCreditList(previous_contributors) .. "," ..
- ";1]"
+ "button[0.1,3.4;5.3,0.5;label_button;" ..
+ core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
+ "button[1.5,4.1;2.5,0.8;homepage;minetest.net]" ..
+ "scroll_container[5.5,0.1;9.5,6.9;scroll_credits;vertical;" ..
+ tostring(scroll_height / 1000) .. "]" .. credit_fs ..
+ "scroll_container_end[]"..
+ "scrollbar[15,0.1;0.4,6.9;vertical;scroll_credits;0]"
-- Render information
- fs = fs .. "label[0.75,4.9;" ..
+ fs = fs .. "style[label_button2;border=false]" ..
+ "button[0.1,6;5.3,1;label_button2;" ..
fgettext("Active renderer:") .. "\n" ..
core.formspec_escape(core.get_screen_info().render_info) .. "]"
- if PLATFORM ~= "Android" then
+ if PLATFORM == "Android" then
+ fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
+ else
fs = fs .. "tooltip[userdata;" ..
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
"and texture packs in a file manager / explorer.") .. "]"
- fs = fs .. "button[0,4;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]"
+ fs = fs .. "button[0.5,5.1;4.5,0.8;userdata;" .. fgettext("Open User Data Directory") .. "]"
end
- return fs
+ return fs, "size[15.5,7.1,false]real_coordinates[true]"
end,
cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then
core.open_url("https://www.minetest.net")
end
+ if fields.share_debug then
+ local path = core.get_user_path() .. DIR_DELIM .. "debug.txt"
+ core.share_file(path)
+ end
+
if fields.userdata then
core.open_dir(core.get_user_path())
end
diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua
index fb7f121f8..5e14d1902 100644
--- a/builtin/mainmenu/tab_content.lua
+++ b/builtin/mainmenu/tab_content.lua
@@ -51,12 +51,14 @@ local function get_formspec(tabview, name, tabdata)
tabdata.selected_pkg = 1
end
+ local use_technical_names = core.settings:get_bool("show_technical_names")
+
local retval =
"label[0.05,-0.25;".. fgettext("Installed Packages:") .. "]" ..
"tablecolumns[color;tree;text]" ..
"table[0,0.25;5.1,4.3;pkglist;" ..
- pkgmgr.render_packagelist(packages) ..
+ pkgmgr.render_packagelist(packages, use_technical_names) ..
";" .. tabdata.selected_pkg .. "]" ..
"button[0,4.85;5.25,0.5;btn_contentdb;".. fgettext("Browse online content") .. "]"
@@ -87,9 +89,17 @@ local function get_formspec(tabview, name, tabdata)
desc = info.description
end
+ local title_and_name
+ if selected_pkg.type == "game" then
+ title_and_name = selected_pkg.name
+ else
+ title_and_name = (selected_pkg.title or selected_pkg.name) .. "\n" ..
+ core.colorize("#BFBFBF", selected_pkg.name)
+ end
+
retval = retval ..
"image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]" ..
- "label[8.25,0.6;" .. core.formspec_escape(selected_pkg.name) .. "]" ..
+ "label[8.25,0.6;" .. core.formspec_escape(title_and_name) .. "]" ..
"box[5.5,2.2;6.15,2.35;#000]"
if selected_pkg.type == "mod" then
@@ -154,6 +164,9 @@ local function handle_doubleclick(pkg)
core.settings:set("texture_path", pkg.path)
end
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
end
end
@@ -197,17 +210,17 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
- if fields.btn_mod_mgr_use_txp then
- local txp = packages:get_list()[tabdata.selected_pkg]
- core.settings:set("texture_path", txp.path)
- packages = nil
- return true
- end
-
+ if fields.btn_mod_mgr_use_txp or fields.btn_mod_mgr_disable_txp then
+ local txp_path = ""
+ if fields.btn_mod_mgr_use_txp then
+ txp_path = packages:get_list()[tabdata.selected_pkg].path
+ end
- if fields.btn_mod_mgr_disable_txp then
- core.settings:set("texture_path", "")
+ core.settings:set("texture_path", txp_path)
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
return true
end
diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua
index e77c6f04d..f8de10db6 100644
--- a/builtin/mainmenu/tab_local.lua
+++ b/builtin/mainmenu/tab_local.lua
@@ -16,7 +16,6 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-local enable_gamebar = PLATFORM ~= "Android"
local current_game, singleplayer_refresh_gamebar
local valid_disabled_settings = {
["enable_damage"]=true,
@@ -24,95 +23,88 @@ local valid_disabled_settings = {
["enable_server"]=true,
}
-if enable_gamebar then
- -- Currently chosen game in gamebar for theming and filtering
- function current_game()
- local last_game_id = core.settings:get("menu_last_game")
- local game = pkgmgr.find_by_gameid(last_game_id)
+-- Currently chosen game in gamebar for theming and filtering
+function current_game()
+ local last_game_id = core.settings:get("menu_last_game")
+ local game = pkgmgr.find_by_gameid(last_game_id)
- return game
- end
+ return game
+end
- -- Apply menu changes from given game
- function apply_game(game)
- core.set_topleft_text(game.name)
- core.settings:set("menu_last_game", game.id)
- menudata.worldlist:set_filtercriteria(game.id)
+-- Apply menu changes from given game
+function apply_game(game)
+ core.set_topleft_text(game.name)
+ core.settings:set("menu_last_game", game.id)
+ menudata.worldlist:set_filtercriteria(game.id)
- mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
+ mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
- local index = filterlist.get_current_index(menudata.worldlist,
- tonumber(core.settings:get("mainmenu_last_selected_world")))
- if not index or index < 1 then
- local selected = core.get_textlist_index("sp_worlds")
- if selected ~= nil and selected < #menudata.worldlist:get_list() then
- index = selected
- else
- index = #menudata.worldlist:get_list()
- end
+ local index = filterlist.get_current_index(menudata.worldlist,
+ tonumber(core.settings:get("mainmenu_last_selected_world")))
+ if not index or index < 1 then
+ local selected = core.get_textlist_index("sp_worlds")
+ if selected ~= nil and selected < #menudata.worldlist:get_list() then
+ index = selected
+ else
+ index = #menudata.worldlist:get_list()
end
- menu_worldmt_legacy(index)
end
+ menu_worldmt_legacy(index)
+end
- function singleplayer_refresh_gamebar()
+function singleplayer_refresh_gamebar()
- local old_bar = ui.find_by_name("game_button_bar")
- if old_bar ~= nil then
- old_bar:delete()
+ local old_bar = ui.find_by_name("game_button_bar")
+ if old_bar ~= nil then
+ old_bar:delete()
+ end
+
+ local function game_buttonbar_button_handler(fields)
+ if fields.game_open_cdb then
+ local maintab = ui.find_by_name("maintab")
+ local dlg = create_store_dlg("game")
+ dlg:set_parent(maintab)
+ maintab:hide()
+ dlg:show()
+ return true
end
- local function game_buttonbar_button_handler(fields)
- if fields.game_open_cdb then
- local maintab = ui.find_by_name("maintab")
- local dlg = create_store_dlg("game")
- dlg:set_parent(maintab)
- maintab:hide()
- dlg:show()
+ for _, game in ipairs(pkgmgr.games) do
+ if fields["game_btnbar_" .. game.id] then
+ apply_game(game)
return true
end
-
- for _, game in ipairs(pkgmgr.games) do
- if fields["game_btnbar_" .. game.id] then
- apply_game(game)
- return true
- end
- end
end
+ end
- local btnbar = buttonbar_create("game_button_bar",
- game_buttonbar_button_handler,
- {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
+ local btnbar = buttonbar_create("game_button_bar",
+ game_buttonbar_button_handler,
+ {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
- for _, game in ipairs(pkgmgr.games) do
- local btn_name = "game_btnbar_" .. game.id
+ for _, game in ipairs(pkgmgr.games) do
+ local btn_name = "game_btnbar_" .. game.id
- local image = nil
- local text = nil
- local tooltip = core.formspec_escape(game.name)
+ local image = nil
+ local text = nil
+ local tooltip = core.formspec_escape(game.title)
- if (game.menuicon_path or "") ~= "" then
- image = core.formspec_escape(game.menuicon_path)
- else
- local part1 = game.id:sub(1,5)
- local part2 = game.id:sub(6,10)
- local part3 = game.id:sub(11)
+ if (game.menuicon_path or "") ~= "" then
+ image = core.formspec_escape(game.menuicon_path)
+ else
+ local part1 = game.id:sub(1,5)
+ local part2 = game.id:sub(6,10)
+ local part3 = game.id:sub(11)
- text = part1 .. "\n" .. part2
- if part3 ~= "" then
- text = text .. "\n" .. part3
- end
+ text = part1 .. "\n" .. part2
+ if part3 ~= "" then
+ text = text .. "\n" .. part3
end
- btnbar:add_button(btn_name, text, image, tooltip)
end
-
- local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
- btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
- end
-else
- -- Currently chosen game in gamebar: no gamebar -> no "current" game
- function current_game()
- return nil
+ btnbar:add_button(btn_name, text, image, tooltip)
end
+
+ local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
+ btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
end
local function get_disabled_settings(game)
@@ -187,7 +179,7 @@ local function get_formspec(tabview, name, tabdata)
damage ..
host ..
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
- menu_render_worldlist(not enable_gamebar) ..
+ menu_render_worldlist() ..
";" .. index .. "]"
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
@@ -324,7 +316,7 @@ local function main_button_handler(this, fields, name, tabdata)
end
if fields["world_create"] ~= nil then
- local create_world_dlg = create_create_world_dlg(enable_gamebar)
+ local create_world_dlg = create_create_world_dlg()
create_world_dlg:set_parent(this)
this:hide()
create_world_dlg:show()
@@ -371,26 +363,23 @@ local function main_button_handler(this, fields, name, tabdata)
end
end
-local on_change
-if enable_gamebar then
- function on_change(type, old_tab, new_tab)
- if (type == "ENTER") then
- local game = current_game()
- if game then
- apply_game(game)
- end
+local function on_change(type, old_tab, new_tab)
+ if (type == "ENTER") then
+ local game = current_game()
+ if game then
+ apply_game(game)
+ end
- singleplayer_refresh_gamebar()
- ui.find_by_name("game_button_bar"):show()
- else
- menudata.worldlist:set_filtercriteria(nil)
- local gamebar = ui.find_by_name("game_button_bar")
- if gamebar then
- gamebar:hide()
- end
- core.set_topleft_text("")
- mm_game_theme.update(new_tab,nil)
+ singleplayer_refresh_gamebar()
+ ui.find_by_name("game_button_bar"):show()
+ else
+ menudata.worldlist:set_filtercriteria(nil)
+ local gamebar = ui.find_by_name("game_button_bar")
+ if gamebar then
+ gamebar:hide()
end
+ core.set_topleft_text("")
+ mm_game_theme.update(new_tab,nil)
end
end
diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua
index fb7409864..899f30bd1 100644
--- a/builtin/mainmenu/tab_online.lua
+++ b/builtin/mainmenu/tab_online.lua
@@ -87,27 +87,34 @@ local function get_formspec(tabview, name, tabdata)
"field[4.25,0.5;1.25,0.75;te_port;;" ..
core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
- -- Name / Password
- "label[0.25,1.55;" .. fgettext("Name") .. "]" ..
- "label[3,1.55;" .. fgettext("Password") .. "]" ..
- "field[0.25,1.75;2.75,0.75;te_name;;" ..
- core.formspec_escape(core.settings:get("name")) .. "]" ..
- "pwdfield[3,1.75;2.5,0.75;te_pwd;]" ..
-
-- Description Background
- "label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
- "box[0.25,3;5.25,2.75;#999999]"..
+ "label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
+ "box[0.25,1.85;5.25,2.7;#999999]"..
+
+ -- Name / Password
+ "container[0,4.8]" ..
+ "label[0.25,0;" .. fgettext("Name") .. "]" ..
+ "label[3,0;" .. fgettext("Password") .. "]" ..
+ "field[0.25,0.2;2.625,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
+ "pwdfield[2.875,0.2;2.625,0.75;te_pwd;]" ..
+ "container_end[]" ..
-- Connect
- "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
+ "button[3,6;2.5,0.75;btn_mp_login;" .. fgettext("Login") .. "]"
+
+ if core.settings:get_bool("enable_split_login_register") then
+ retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
+ end
if tabdata.selected then
if gamedata.fav then
- retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
- fgettext("Del. Favorite") .. "]"
+ retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
+ retval = retval .. "style[btn_delete_favorite;padding=6]"
+ retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
+ "server_favorite_delete.png") .. ";btn_delete_favorite;]"
end
if gamedata.serverdescription then
- retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
+ retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
core.formspec_escape(gamedata.serverdescription) .. "]"
end
end
@@ -339,12 +346,15 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
- if (fields.btn_mp_connect or fields.key_enter)
+ if (fields.btn_mp_login or fields.key_enter)
and fields.te_address ~= "" and fields.te_port then
gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd
gamedata.address = fields.te_address
gamedata.port = tonumber(fields.te_port)
+
+ local enable_split_login_register = core.settings:get_bool("enable_split_login_register")
+ gamedata.allow_login_or_register = enable_split_login_register and "login" or "any"
gamedata.selected_world = 0
local idx = core.get_table_index("servers")
@@ -381,6 +391,25 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
+ if fields.btn_mp_register and fields.te_address ~= "" and fields.te_port then
+ local idx = core.get_table_index("servers")
+ local server = idx and tabdata.lookup[idx]
+ if server and (server.address ~= fields.te_address or server.port ~= tonumber(fields.te_port)) then
+ server = nil
+ end
+
+ if server and not is_server_protocol_compat_or_error(
+ server.proto_min, server.proto_max) then
+ return true
+ end
+
+ local dlg = create_register_dialog(fields.te_address, tonumber(fields.te_port), server)
+ dlg:set_parent(tabview)
+ tabview:hide()
+ dlg:show()
+ return true
+ end
+
return false
end
diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
index 700b7390f..21c77aa8e 100644
--- a/builtin/mainmenu/tab_settings.lua
+++ b/builtin/mainmenu/tab_settings.lua
@@ -50,7 +50,7 @@ local labels = {
fgettext("Low"),
fgettext("Medium"),
fgettext("High"),
- fgettext("Ultra High")
+ fgettext("Very High")
}
}
@@ -160,7 +160,7 @@ local function formspec(tabview, name, tabdata)
.. getSettingIndex.NodeHighlighting() .. "]" ..
"dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
.. getSettingIndex.Leaves() .. "]" ..
- "box[4,0;3.75,4.5;#999999]" ..
+ "box[4,0;3.75,4.9;#999999]" ..
"label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
"dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
.. getSettingIndex.Filter() .. "]" ..
@@ -169,9 +169,6 @@ local function formspec(tabview, name, tabdata)
"label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
"dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
.. getSettingIndex.Antialiasing() .. "]" ..
- "label[4.25,3.45;" .. fgettext("Screen:") .. "]" ..
- "checkbox[4.25,3.6;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
- .. dump(core.settings:get_bool("autosave_screensize")) .. "]" ..
"box[8,0;3.75,4.5;#999999]"
local video_driver = core.settings:get("video_driver")
@@ -203,10 +200,15 @@ local function formspec(tabview, name, tabdata)
if core.settings:get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
- "label[4.3,4.2;" .. fgettext("Touchthreshold: (px)") .. "]" ..
- "dropdown[4.25,4.65;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
+ "label[4.25,3.5;" .. fgettext("Touch threshold (px):") .. "]" ..
+ "dropdown[4.25,3.95;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.settings:get("touchscreen_threshold")) / 10) + 1) ..
- "]box[4.0,4.5;3.75,1.0;#999999]"
+ "]"
+ else
+ tab_string = tab_string ..
+ "label[4.25,3.65;" .. fgettext("Screen:") .. "]" ..
+ "checkbox[4.25,3.9;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
+ .. dump(core.settings:get_bool("autosave_screensize")) .. "]"
end
if shaders_enabled then
@@ -219,9 +221,18 @@ local function formspec(tabview, name, tabdata)
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
"checkbox[8.25,2;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
- --"label[8.25,3.0;" .. fgettext("Dynamic shadows: ") .. "]" ..
- --"dropdown[8.25,3.5;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
- -- .. getSettingIndex.ShadowMapping() .. "]"
+
+ if video_driver == "opengl" then
+ tab_string = tab_string ..
+ "label[8.25,2.8;" .. fgettext("Dynamic shadows:") .. "]" ..
+ "label[8.25,3.2;" .. fgettext("(game support required)") .. "]" ..
+ "dropdown[8.25,3.7;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
+ .. getSettingIndex.ShadowMapping() .. "]"
+ else
+ tab_string = tab_string ..
+ "label[8.38,2.7;" .. core.colorize("#888888",
+ fgettext("Dynamic shadows")) .. "]"
+ end
else
tab_string = tab_string ..
"label[8.38,0.7;" .. core.colorize("#888888",
@@ -231,9 +242,9 @@ local function formspec(tabview, name, tabdata)
"label[8.38,1.7;" .. core.colorize("#888888",
fgettext("Waving Leaves")) .. "]" ..
"label[8.38,2.2;" .. core.colorize("#888888",
- fgettext("Waving Plants")) .. "]"
- --"label[8.38,2.7;" .. core.colorize("#888888",
- -- fgettext("Dynamic shadows")) .. "]"
+ fgettext("Waving Plants")) .. "]"..
+ "label[8.38,2.7;" .. core.colorize("#888888",
+ fgettext("Dynamic shadows")) .. "]"
end
return tab_string
@@ -364,11 +375,11 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.settings:set("enable_dynamic_shadows", "false")
else
local shadow_presets = {
- [2] = { 80, 512, "true", 0, "false" },
- [3] = { 120, 1024, "true", 1, "false" },
- [4] = { 350, 2048, "true", 1, "false" },
- [5] = { 350, 2048, "true", 2, "true" },
- [6] = { 450, 4096, "true", 2, "true" },
+ [2] = { 62, 512, "true", 0, "false" },
+ [3] = { 93, 1024, "true", 0, "false" },
+ [4] = { 140, 2048, "true", 1, "false" },
+ [5] = { 210, 4096, "true", 2, "true" },
+ [6] = { 300, 8192, "true", 2, "true" },
}
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
if s then
diff --git a/builtin/mainmenu/tests/serverlistmgr_spec.lua b/builtin/mainmenu/tests/serverlistmgr_spec.lua
index a091959fb..ab7a6c60c 100644
--- a/builtin/mainmenu/tests/serverlistmgr_spec.lua
+++ b/builtin/mainmenu/tests/serverlistmgr_spec.lua
@@ -1,4 +1,5 @@
_G.core = {}
+_G.vector = {metatable = {}}
_G.unpack = table.unpack
_G.serverlistmgr = {}