diff options
Diffstat (limited to 'builtin/mainmenu')
-rw-r--r-- | builtin/mainmenu/common.lua | 28 | ||||
-rw-r--r-- | builtin/mainmenu/dlg_config_world.lua | 30 | ||||
-rw-r--r-- | builtin/mainmenu/dlg_contentstore.lua | 85 | ||||
-rw-r--r-- | builtin/mainmenu/dlg_create_world.lua | 275 | ||||
-rw-r--r-- | builtin/mainmenu/dlg_settings_advanced.lua | 69 | ||||
-rw-r--r-- | builtin/mainmenu/game_theme.lua (renamed from builtin/mainmenu/textures.lua) | 98 | ||||
-rw-r--r-- | builtin/mainmenu/generate_from_settingtypes.lua | 17 | ||||
-rw-r--r-- | builtin/mainmenu/init.lua | 8 | ||||
-rw-r--r-- | builtin/mainmenu/pkgmgr.lua | 205 | ||||
-rw-r--r-- | builtin/mainmenu/tab_about.lua | 50 | ||||
-rw-r--r-- | builtin/mainmenu/tab_content.lua | 35 | ||||
-rw-r--r-- | builtin/mainmenu/tab_local.lua | 92 | ||||
-rw-r--r-- | builtin/mainmenu/tab_settings.lua | 20 | ||||
-rw-r--r-- | builtin/mainmenu/tests/serverlistmgr_spec.lua | 1 |
14 files changed, 541 insertions, 472 deletions
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index 6db351048..8db8bb8d1 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -119,31 +119,27 @@ function render_serverlist_row(spec) return table.concat(details, ",") end - --------------------------------------------------------------------------------- -os.tempfolder = function() - local temp = core.get_temp_path() - return temp .. DIR_DELIM .. "MT_" .. math.random(0, 10000) -end - +--------------------------------------------------------------------------------- os.tmpname = function() - local path = os.tempfolder() - io.open(path, "w"):close() - return path + error('do not use') -- instead use core.get_temp_path() end -------------------------------------------------------------------------------- -function menu_render_worldlist() - local retval = "" +function menu_render_worldlist(show_gameid) + local retval = {} local current_worldlist = menudata.worldlist:get_list() + local row 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) .. "\\]" + row = v.name + if show_gameid == nil or show_gameid == true then + row = row .. " [" .. v.gameid .. "]" + end + retval[#retval+1] = core.formspec_escape(row) + end - return retval + return table.concat(retval, ",") end function menu_handle_key_up_down(fields, textlist, settingname) diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua index 9bdf92a74..f73256612 100644 --- a/builtin/mainmenu/dlg_config_world.lua +++ b/builtin/mainmenu/dlg_config_world.lua @@ -163,10 +163,13 @@ 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]" .. "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) .. ";" .. data.selected_mod .."]" end local function handle_buttons(this, fields) @@ -205,14 +208,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 +264,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 790da03ba..ff32c8c9f 100644 --- a/builtin/mainmenu/dlg_contentstore.lua +++ b/builtin/mainmenu/dlg_contentstore.lua @@ -25,7 +25,7 @@ end -- Unordered preserves the original order of the ContentDB API, -- before the package list is ordered based on installed state. -local store = { packages = {}, packages_full = {}, packages_full_unordered = {} } +local store = { packages = {}, packages_full = {}, packages_full_unordered = {}, aliases = {} } local http = core.get_http_api() @@ -62,9 +62,19 @@ local REASON_UPDATE = "update" local REASON_DEPENDENCY = "dependency" +-- encodes for use as URL parameter or path component +local function urlencode(str) + return str:gsub("[^%a%d()._~-]", function(char) + return string.format("%%%02X", string.byte(char)) + end) +end +assert(urlencode("sample text?") == "sample%20text%3F") + + local function get_download_url(package, reason) local base_url = core.settings:get("contentdb_url") - local ret = base_url .. ("/packages/%s/%s/releases/%d/download/"):format(package.author, package.name, package.release) + local ret = base_url .. ("/packages/%s/releases/%d/download/"):format( + package.url_part, package.release) if reason then ret = ret .. "?reason=" .. reason end @@ -72,34 +82,52 @@ local function get_download_url(package, reason) end -local function download_package(param) - if core.download_file(param.url, param.filename) then +local function download_and_extract(param) + local package = param.package + + local filename = core.get_temp_path(true) + if filename == "" or not core.download_file(param.url, filename) then + core.log("error", "Downloading " .. dump(param.url) .. " failed") return { - filename = param.filename, - successful = true, + msg = fgettext("Failed to download $1", package.name) } + end + + local tempfolder = core.get_temp_path() + if tempfolder ~= "" then + tempfolder = tempfolder .. DIR_DELIM .. "MT_" .. math.random(1, 1024000) + if not core.extract_zip(filename, tempfolder) then + tempfolder = nil + end else - core.log("error", "downloading " .. dump(param.url) .. " failed") + tempfolder = nil + end + os.remove(filename) + if not tempfolder then return { - successful = false, + msg = fgettext("Install: Unsupported file type or broken archive"), } end + + return { + path = tempfolder + } end local function start_install(package, reason) local params = { package = package, url = get_download_url(package, reason), - filename = os.tempfolder() .. "_MODNAME_" .. package.name .. ".zip", } number_downloading = number_downloading + 1 local function callback(result) - if result.successful then - local path, msg = pkgmgr.install(package.type, - result.filename, package.name, - package.path) + if result.msg then + gamedata.errormessage = result.msg + else + local path, msg = pkgmgr.install_dir(package.type, result.path, package.name, package.path) + core.delete_dir(result.path) if not path then gamedata.errormessage = msg else @@ -137,9 +165,6 @@ local function start_install(package, reason) conf:write() end end - os.remove(result.filename) - else - gamedata.errormessage = fgettext("Failed to download $1", package.name) end package.downloading = false @@ -159,7 +184,7 @@ local function start_install(package, reason) package.queued = false package.downloading = true - if not core.handle_async(download_package, params, callback) then + if not core.handle_async(download_and_extract, params, callback) then core.log("error", "ERROR: async event failed") gamedata.errormessage = fgettext("Failed to download $1", package.name) return @@ -184,7 +209,7 @@ local function get_raw_dependencies(package) local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s" local version = core.get_version() local base_url = core.settings:get("contentdb_url") - local url = base_url .. url_fmt:format(package.id, core.get_max_supp_proto(), version.string) + local url = base_url .. url_fmt:format(package.url_part, core.get_max_supp_proto(), urlencode(version.string)) local response = http.fetch_sync({ url = url }) if not response.succeeded then @@ -559,17 +584,16 @@ function store.load() local base_url = core.settings:get("contentdb_url") local url = base_url .. "/api/packages/?type=mod&type=game&type=txp&protocol_version=" .. - core.get_max_supp_proto() .. "&engine_version=" .. version.string + core.get_max_supp_proto() .. "&engine_version=" .. urlencode(version.string) for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do item = item:trim() if item ~= "" then - url = url .. "&hide=" .. item + url = url .. "&hide=" .. urlencode(item) end end - local timeout = tonumber(core.settings:get("curl_file_download_timeout")) - local response = http.fetch_sync({ url = url, timeout = timeout }) + local response = http.fetch_sync({ url = url }) if not response.succeeded then return end @@ -579,12 +603,16 @@ function store.load() for _, package in pairs(store.packages_full) do local name_len = #package.name + -- This must match what store.update_paths() does! + package.id = package.author:lower() .. "/" if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then - package.id = package.author:lower() .. "/" .. package.name:sub(1, name_len - 5) + package.id = package.id .. package.name:sub(1, name_len - 5) else - package.id = package.author:lower() .. "/" .. package.name + package.id = package.id .. package.name end + package.url_part = urlencode(package.author) .. "/" .. urlencode(package.name) + if package.aliases then for _, alias in ipairs(package.aliases) do -- We currently don't support name changing @@ -834,8 +862,7 @@ function store.get_formspec(dlgdata) formspec[#formspec + 1] = "cdb_downloading.png;3;400;]" elseif package.queued then formspec[#formspec + 1] = left_base - formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir) - formspec[#formspec + 1] = "cdb_queued.png;queued]" + formspec[#formspec + 1] = "cdb_queued.png;queued;]" elseif not package.path then local elem_name = "install_" .. i .. ";" formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]" @@ -998,9 +1025,9 @@ function store.handle_submit(this, fields) end if fields["view_" .. i] then - local url = ("%s/packages/%s/%s?protocol_version=%d"):format( - core.settings:get("contentdb_url"), - package.author, package.name, core.get_max_supp_proto()) + local url = ("%s/packages/%s?protocol_version=%d"):format( + core.settings:get("contentdb_url"), package.url_part, + core.get_max_supp_proto()) core.open_url(url) return true end diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua index 1938747fe..76ceb0f16 100644 --- a/builtin/mainmenu/dlg_create_world.lua +++ b/builtin/mainmenu/dlg_create_world.lua @@ -15,7 +15,8 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -local worldname = "" +-- 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" @@ -31,9 +32,8 @@ local function strflag(flags, flag) return (flags[flag] == true) and "true" or "false" end -local cb_caverns = { "caverns", fgettext("Caverns"), "caverns", +local cb_caverns = { "caverns", fgettext("Caverns"), fgettext("Very large caverns deep in the underground") } -local tt_sea_rivers = fgettext("Sea level rivers") local flag_checkboxes = { v5 = { @@ -41,39 +41,38 @@ local flag_checkboxes = { }, v7 = { cb_caverns, - { "ridges", fgettext("Rivers"), "ridges", tt_sea_rivers }, - { "mountains", fgettext("Mountains"), "mountains" }, - { "floatlands", fgettext("Floatlands (experimental)"), "floatlands", + { "ridges", fgettext("Rivers"), fgettext("Sea level rivers") }, + { "mountains", fgettext("Mountains") }, + { "floatlands", fgettext("Floatlands (experimental)"), fgettext("Floating landmasses in the sky") }, }, carpathian = { cb_caverns, - { "rivers", fgettext("Rivers"), "rivers", tt_sea_rivers }, + { "rivers", fgettext("Rivers"), fgettext("Sea level rivers") }, }, valleys = { - { "altitude-chill", fgettext("Altitude chill"), "altitude_chill", + { "altitude_chill", fgettext("Altitude chill"), fgettext("Reduces heat with altitude") }, - { "altitude-dry", fgettext("Altitude dry"), "altitude_dry", + { "altitude_dry", fgettext("Altitude dry"), fgettext("Reduces humidity with altitude") }, - { "humid-rivers", fgettext("Humid rivers"), "humid_rivers", + { "humid_rivers", fgettext("Humid rivers"), fgettext("Increases humidity around rivers") }, - { "vary-river-depth", fgettext("Vary river depth"), "vary_river_depth", + { "vary_river_depth", fgettext("Vary river depth"), fgettext("Low humidity and high heat causes shallow or dry rivers") }, }, flat = { cb_caverns, - { "hills", fgettext("Hills"), "hills" }, - { "lakes", fgettext("Lakes"), "lakes" }, + { "hills", fgettext("Hills") }, + { "lakes", fgettext("Lakes") }, }, fractal = { - { "terrain", fgettext("Additional terrain"), "terrain", + { "terrain", fgettext("Additional terrain"), fgettext("Generate non-fractal terrain: Oceans and underground") }, }, v6 = { - { "trees", fgettext("Trees and jungle grass"), "trees" }, - { "flat", fgettext("Flat terrain"), "flat" }, - { "mudflow", fgettext("Mud flow"), "mudflow", - fgettext("Terrain surface erosion") }, + { "trees", fgettext("Trees and jungle grass") }, + { "flat", fgettext("Flat terrain") }, + { "mudflow", fgettext("Mud flow"), fgettext("Terrain surface erosion") }, -- Biome settings are in mgv6_biomes below }, } @@ -105,38 +104,26 @@ local function create_world_formspec(dialogdata) "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]" end + local current_mg = dialogdata.mg local mapgens = core.get_mapgen_names() - local current_seed = core.settings:get("fixed_map_seed") or "" - local current_mg = core.settings:get("mg_name") local gameid = core.settings:get("menu_last_game") - local flags = { - main = core.settings:get_flags("mg_flags"), - v5 = core.settings:get_flags("mgv5_spflags"), - v6 = core.settings:get_flags("mgv6_spflags"), - v7 = core.settings:get_flags("mgv7_spflags"), - fractal = core.settings:get_flags("mgfractal_spflags"), - carpathian = core.settings:get_flags("mgcarpathian_spflags"), - valleys = core.settings:get_flags("mgvalleys_spflags"), - flat = core.settings:get_flags("mgflat_spflags"), - } - - local gameidx = 0 - if gameid ~= nil then - local _ - _, gameidx = pkgmgr.find_by_gameid(gameid) + local flags = dialogdata.flags - if gameidx == nil then - gameidx = 0 - end + local game, gameidx = pkgmgr.find_by_gameid(gameid) + if game == nil and hide_gamelist 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 game_by_gameidx = core.get_game(gameidx) local disallowed_mapgen_settings = {} - if game_by_gameidx ~= nil then - local gamepath = game_by_gameidx.path - local gameconfig = Settings(gamepath.."/game.conf") + if game ~= nil then + local gameconfig = Settings(game.path.."/game.conf") local allowed_mapgens = (gameconfig:get("allowed_mapgens") or ""):split() for key, value in pairs(allowed_mapgens) do @@ -156,7 +143,7 @@ local function create_world_formspec(dialogdata) end end - if disallowed_mapgens then + if #disallowed_mapgens > 0 then for i = #mapgens, 1, -1 do if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then table.remove(mapgens, i) @@ -172,23 +159,29 @@ local function create_world_formspec(dialogdata) local mglist = "" local selindex - local i = 1 - local first_mg - for k,v in pairs(mapgens) do - if not first_mg then - first_mg = v + do -- build the list of mapgens + local i = 1 + local first_mg + for k, v in pairs(mapgens) do + if not first_mg then + first_mg = v + end + if current_mg == v then + selindex = i + end + i = i + 1 + mglist = mglist .. core.formspec_escape(v) .. "," end - if current_mg == v then - selindex = i + if not selindex then + selindex = 1 + current_mg = first_mg end - i = i + 1 - mglist = mglist .. v .. "," - end - if not selindex then - selindex = 1 - current_mg = first_mg + mglist = mglist:sub(1, -2) end - mglist = mglist:sub(1, -2) + + -- The logic of the flag element IDs is as follows: + -- "flag_main_foo-bar-baz" controls dialogdata.flags["main"]["foo_bar_baz"] + -- see the buttonhandler for the implementation of this local mg_main_flags = function(mapgen, y) if mapgen == "singlenode" then @@ -198,11 +191,11 @@ local function create_world_formspec(dialogdata) return "", y end - local form = "checkbox[0," .. y .. ";flag_mg_caves;" .. + local form = "checkbox[0," .. y .. ";flag_main_caves;" .. fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]" y = y + 0.5 - form = form .. "checkbox[0,"..y..";flag_mg_dungeons;" .. + form = form .. "checkbox[0,"..y..";flag_main_dungeons;" .. fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]" y = y + 0.5 @@ -213,7 +206,7 @@ local function create_world_formspec(dialogdata) else d_tt = fgettext("Structures appearing on the terrain, typically trees and plants") end - form = form .. "checkbox[0,"..y..";flag_mg_decorations;" .. + form = form .. "checkbox[0,"..y..";flag_main_decorations;" .. d_name .. ";" .. strflag(flags.main, "decorations").."]" .. "tooltip[flag_mg_decorations;" .. @@ -221,7 +214,7 @@ local function create_world_formspec(dialogdata) "]" y = y + 0.5 - form = form .. "tooltip[flag_mg_caves;" .. + form = form .. "tooltip[flag_main_caves;" .. fgettext("Network of tunnels and caves") .. "]" return form, y @@ -235,13 +228,13 @@ local function create_world_formspec(dialogdata) return "", y end local form = "" - for _,tab in pairs(flag_checkboxes[mapgen]) do - local id = "flag_mg"..mapgen.."_"..tab[1] + for _, tab in pairs(flag_checkboxes[mapgen]) do + local id = "flag_"..mapgen.."_"..tab[1]:gsub("_", "-") form = form .. ("checkbox[0,%f;%s;%s;%s]"): - format(y, id, tab[2], strflag(flags[mapgen], tab[3])) + format(y, id, tab[2], strflag(flags[mapgen], tab[1])) - if tab[4] then - form = form .. "tooltip["..id..";"..tab[4].."]" + if tab[3] then + form = form .. "tooltip["..id..";"..tab[3].."]" end y = y + 0.5 end @@ -277,16 +270,14 @@ local function create_world_formspec(dialogdata) -- biomeblend y = y + 0.55 - form = form .. "checkbox[0,"..y..";flag_mgv6_biomeblend;" .. + form = form .. "checkbox[0,"..y..";flag_v6_biomeblend;" .. fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" .. - "tooltip[flag_mgv6_biomeblend;" .. + "tooltip[flag_v6_biomeblend;" .. fgettext("Smooth transition between biomes") .. "]" return form, y end - current_seed = core.formspec_escape(current_seed) - local y_start = 0.0 local y = y_start local str_flags, str_spflags @@ -323,21 +314,32 @@ local function create_world_formspec(dialogdata) "container[0,0]".. "field[0.3,0.6;6,0.5;te_world_name;" .. fgettext("World name") .. - ";" .. core.formspec_escape(worldname) .. "]" .. + ";" .. core.formspec_escape(dialogdata.worldname) .. "]" .. + "set_focus[te_world_name;false]" + + if not disallowed_mapgen_settings["seed"] then - "field[0.3,1.7;6,0.5;te_seed;" .. - fgettext("Seed") .. - ";".. current_seed .. "]" .. + 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 .. "]" .. + "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" + + if not hide_gamelist or devtest_only ~= "" 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_end[]" + end - "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_end[]" .. + retval = retval .. "container_end[]" .. -- Right side @@ -360,9 +362,20 @@ local function create_world_buttonhandler(this, fields) fields["key_enter"] then local worldname = fields["te_world_name"] - local gameindex = core.get_textlist_index("games") + 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 message + if game == nil then + message = fgettext("No game selected") + end - if gameindex ~= nil then + if message == nil then -- For unnamed worlds use the generated name 'world<number>', -- where the number increments: it is set to 1 larger than the largest -- generated name number found. @@ -377,36 +390,48 @@ local function create_world_buttonhandler(this, fields) worldname = "world" .. worldnum_max + 1 end - core.settings:set("fixed_map_seed", fields["te_seed"]) - - local message - if not menudata.worldlist:uid_exists_raw(worldname) then - core.settings:set("mg_name",fields["dd_mapgen"]) - message = core.create_world(worldname,gameindex) - else + if menudata.worldlist:uid_exists_raw(worldname) then message = fgettext("A world named \"$1\" already exists", worldname) end + end - if message ~= nil then - gamedata.errormessage = message - else - core.settings:set("menu_last_game",pkgmgr.games[gameindex].id) - if this.data.update_worldlist_filter then - menudata.worldlist:set_filtercriteria(pkgmgr.games[gameindex].id) - mm_texture.update("singleplayer", pkgmgr.games[gameindex].id) - end - menudata.worldlist:refresh() - core.settings:set("mainmenu_last_selected_world", - menudata.worldlist:raw_index_by_uid(worldname)) + if message == nil then + this.data.seed = fields["te_seed"] or "" + this.data.mg = fields["dd_mapgen"] + + -- actual names as used by engine + local settings = { + fixed_map_seed = this.data.seed, + mg_name = this.data.mg, + mg_flags = table_to_flags(this.data.flags.main), + mgv5_spflags = table_to_flags(this.data.flags.v5), + mgv6_spflags = table_to_flags(this.data.flags.v6), + mgv7_spflags = table_to_flags(this.data.flags.v7), + mgfractal_spflags = table_to_flags(this.data.flags.fractal), + mgcarpathian_spflags = table_to_flags(this.data.flags.carpathian), + mgvalleys_spflags = table_to_flags(this.data.flags.valleys), + mgflat_spflags = table_to_flags(this.data.flags.flat), + } + message = core.create_world(worldname, gameindex, settings) + end + + 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 - else - gamedata.errormessage = fgettext("No game selected") + menudata.worldlist:refresh() + core.settings:set("mainmenu_last_selected_world", + menudata.worldlist:raw_index_by_uid(worldname)) end + + gamedata.errormessage = message this:delete() return true end - worldname = fields.te_world_name + this.data.worldname = fields["te_world_name"] + this.data.seed = fields["te_seed"] or "" if fields["games"] then local gameindex = core.get_textlist_index("games") @@ -417,22 +442,11 @@ local function create_world_buttonhandler(this, fields) for k,v in pairs(fields) do local split = string.split(k, "_", nil, 3) if split and split[1] == "flag" then - local setting - if split[2] == "mg" then - setting = "mg_flags" - else - setting = split[2].."_spflags" - end -- We replaced the underscore of flag names with a dash. local flag = string.gsub(split[3], "-", "_") - local ftable = core.settings:get_flags(setting) - if v == "true" then - ftable[flag] = true - else - ftable[flag] = false - end - local flags = table_to_flags(ftable) - core.settings:set(setting, flags) + local ftable = this.data.flags[split[2]] + assert(ftable) + ftable[flag] = v == "true" return true end end @@ -446,18 +460,16 @@ local function create_world_buttonhandler(this, fields) local entry = core.formspec_escape(fields["mgv6_biomes"]) for b=1, #mgv6_biomes do if entry == mgv6_biomes[b][1] then - local ftable = core.settings:get_flags("mgv6_spflags") + local ftable = this.data.flags.v6 ftable.jungles = mgv6_biomes[b][2].jungles ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes - local flags = table_to_flags(ftable) - core.settings:set("mgv6_spflags", flags) return true end end end if fields["dd_mapgen"] then - core.settings:set("mg_name", fields["dd_mapgen"]) + this.data.mg = fields["dd_mapgen"] return true end @@ -466,12 +478,27 @@ end function create_create_world_dlg(update_worldlistfilter) - worldname = "" local retval = dialog_create("sp_create_world", create_world_formspec, create_world_buttonhandler, nil) - retval.update_worldlist_filter = update_worldlistfilter + retval.data = { + update_worldlist_filter = update_worldlistfilter, + worldname = "", + -- settings the world is created with: + seed = core.settings:get("fixed_map_seed") or "", + mg = core.settings:get("mg_name"), + flags = { + main = core.settings:get_flags("mg_flags"), + v5 = core.settings:get_flags("mgv5_spflags"), + v6 = core.settings:get_flags("mgv6_spflags"), + v7 = core.settings:get_flags("mgv7_spflags"), + fractal = core.settings:get_flags("mgfractal_spflags"), + carpathian = core.settings:get_flags("mgcarpathian_spflags"), + valleys = core.settings:get_flags("mgvalleys_spflags"), + flat = core.settings:get_flags("mgflat_spflags"), + } + } return retval end diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua index 38a658969..d6f485cf7 100644 --- a/builtin/mainmenu/dlg_settings_advanced.lua +++ b/builtin/mainmenu/dlg_settings_advanced.lua @@ -378,7 +378,7 @@ 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") @@ -395,6 +395,7 @@ local function parse_config_file(read_all, parse_mods) table.insert(settings, { name = mod.name, + readable_name = mod.title, level = 1, type = "category", }) @@ -408,7 +409,7 @@ local function parse_config_file(read_all, parse_mods) -- Parse clientmods local clientmods_category_initialized = false local clientmods = {} - get_mods(core.get_clientmodpath(), clientmods) + get_mods(core.get_clientmodpath(), "clientmods", clientmods) for _, clientmod in ipairs(clientmods) do local path = clientmod.path .. DIR_DELIM .. FILENAME local file = io.open(path, "r") @@ -527,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 @@ -697,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 @@ -990,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 @@ -1031,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 @@ -1114,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/textures.lua b/builtin/mainmenu/game_theme.lua index a3acbbdec..89e1b66c8 100644 --- a/builtin/mainmenu/textures.lua +++ b/builtin/mainmenu/game_theme.lua @@ -16,23 +16,25 @@ --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -mm_texture = {} +mm_game_theme = {} -------------------------------------------------------------------------------- -function mm_texture.init() - mm_texture.defaulttexturedir = core.get_texturepath() .. DIR_DELIM .. "base" .. +function mm_game_theme.init() + mm_game_theme.defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. DIR_DELIM .. "pack" .. DIR_DELIM - mm_texture.basetexturedir = mm_texture.defaulttexturedir + mm_game_theme.basetexturedir = mm_game_theme.defaulttexturedir - mm_texture.texturepack = core.settings:get("texture_path") + mm_game_theme.texturepack = core.settings:get("texture_path") - mm_texture.gameid = nil + mm_game_theme.gameid = nil + + mm_game_theme.music_handle = nil end -------------------------------------------------------------------------------- -function mm_texture.update(tab,gamedetails) +function mm_game_theme.update(tab,gamedetails) if tab ~= "singleplayer" then - mm_texture.reset() + mm_game_theme.reset() return end @@ -40,50 +42,54 @@ function mm_texture.update(tab,gamedetails) return end - mm_texture.update_game(gamedetails) + mm_game_theme.update_game(gamedetails) end -------------------------------------------------------------------------------- -function mm_texture.reset() - mm_texture.gameid = nil +function mm_game_theme.reset() + mm_game_theme.gameid = nil local have_bg = false - local have_overlay = mm_texture.set_generic("overlay") + local have_overlay = mm_game_theme.set_generic("overlay") if not have_overlay then - have_bg = mm_texture.set_generic("background") + have_bg = mm_game_theme.set_generic("background") end - mm_texture.clear("header") - mm_texture.clear("footer") + mm_game_theme.clear("header") + mm_game_theme.clear("footer") core.set_clouds(false) - mm_texture.set_generic("footer") - mm_texture.set_generic("header") + mm_game_theme.set_generic("footer") + mm_game_theme.set_generic("header") if not have_bg then if core.settings:get_bool("menu_clouds") then core.set_clouds(true) else - mm_texture.set_dirt_bg() + mm_game_theme.set_dirt_bg() end end + + if mm_game_theme.music_handle ~= nil then + core.sound_stop(mm_game_theme.music_handle) + end end -------------------------------------------------------------------------------- -function mm_texture.update_game(gamedetails) - if mm_texture.gameid == gamedetails.id then +function mm_game_theme.update_game(gamedetails) + if mm_game_theme.gameid == gamedetails.id then return end local have_bg = false - local have_overlay = mm_texture.set_game("overlay",gamedetails) + local have_overlay = mm_game_theme.set_game("overlay",gamedetails) if not have_overlay then - have_bg = mm_texture.set_game("background",gamedetails) + have_bg = mm_game_theme.set_game("background",gamedetails) end - mm_texture.clear("header") - mm_texture.clear("footer") + mm_game_theme.clear("header") + mm_game_theme.clear("footer") core.set_clouds(false) if not have_bg then @@ -91,34 +97,34 @@ function mm_texture.update_game(gamedetails) if core.settings:get_bool("menu_clouds") then core.set_clouds(true) else - mm_texture.set_dirt_bg() + mm_game_theme.set_dirt_bg() end end - mm_texture.set_game("footer",gamedetails) - mm_texture.set_game("header",gamedetails) + mm_game_theme.set_game("footer",gamedetails) + mm_game_theme.set_game("header",gamedetails) - mm_texture.gameid = gamedetails.id + mm_game_theme.gameid = gamedetails.id end -------------------------------------------------------------------------------- -function mm_texture.clear(identifier) +function mm_game_theme.clear(identifier) core.set_background(identifier,"") end -------------------------------------------------------------------------------- -function mm_texture.set_generic(identifier) +function mm_game_theme.set_generic(identifier) --try texture pack first - if mm_texture.texturepack ~= nil then - local path = mm_texture.texturepack .. DIR_DELIM .."menu_" .. + if mm_game_theme.texturepack ~= nil then + local path = mm_game_theme.texturepack .. DIR_DELIM .."menu_" .. identifier .. ".png" if core.set_background(identifier,path) then return true end end - if mm_texture.defaulttexturedir ~= nil then - local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" .. + if mm_game_theme.defaulttexturedir ~= nil then + local path = mm_game_theme.defaulttexturedir .. DIR_DELIM .."menu_" .. identifier .. ".png" if core.set_background(identifier,path) then return true @@ -129,14 +135,16 @@ function mm_texture.set_generic(identifier) end -------------------------------------------------------------------------------- -function mm_texture.set_game(identifier, gamedetails) +function mm_game_theme.set_game(identifier, gamedetails) if gamedetails == nil then return false end - if mm_texture.texturepack ~= nil then - local path = mm_texture.texturepack .. DIR_DELIM .. + mm_game_theme.set_music(gamedetails) + + if mm_game_theme.texturepack ~= nil then + local path = mm_game_theme.texturepack .. DIR_DELIM .. gamedetails.id .. "_menu_" .. identifier .. ".png" if core.set_background(identifier, path) then return true @@ -171,9 +179,10 @@ function mm_texture.set_game(identifier, gamedetails) return false end -function mm_texture.set_dirt_bg() - if mm_texture.texturepack ~= nil then - local path = mm_texture.texturepack .. DIR_DELIM .."default_dirt.png" +-------------------------------------------------------------------------------- +function mm_game_theme.set_dirt_bg() + if mm_game_theme.texturepack ~= nil then + local path = mm_game_theme.texturepack .. DIR_DELIM .."default_dirt.png" if core.set_background("background", path, true, 128) then return true end @@ -183,3 +192,12 @@ function mm_texture.set_dirt_bg() local minimalpath = defaulttexturedir .. "menu_bg.png" core.set_background("background", minimalpath, true, 128) end + +-------------------------------------------------------------------------------- +function mm_game_theme.set_music(gamedetails) + if mm_game_theme.music_handle ~= nil then + core.sound_stop(mm_game_theme.music_handle) + end + local music_path = gamedetails.path .. DIR_DELIM .. "menu" .. DIR_DELIM .. "theme" + mm_game_theme.music_handle = core.sound_play(music_path, true) +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 2481078e2..943454677 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -35,7 +35,7 @@ dofile(menupath .. DIR_DELIM .. "async_event.lua") dofile(menupath .. DIR_DELIM .. "common.lua") dofile(menupath .. DIR_DELIM .. "pkgmgr.lua") dofile(menupath .. DIR_DELIM .. "serverlistmgr.lua") -dofile(menupath .. DIR_DELIM .. "textures.lua") +dofile(menupath .. DIR_DELIM .. "game_theme.lua") dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua") dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua") @@ -87,7 +87,7 @@ local function init_globals() core.settings:set("menu_last_game", default_game) end - mm_texture.init() + mm_game_theme.init() -- Create main tabview local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0}) @@ -113,7 +113,7 @@ local function init_globals() if tv_main.current_tab == "local" then local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game")) if game == nil then - mm_texture.reset() + mm_game_theme.reset() end end @@ -121,8 +121,6 @@ local function init_globals() tv_main:show() ui.update() - - core.sound_play("main_menu", true) end init_globals() diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua index 58a4ed8c1..072c41f0c 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 @@ -181,21 +184,6 @@ function pkgmgr.get_texture_packs() end -------------------------------------------------------------------------------- -function pkgmgr.extract(modfile) - if modfile.type == "zip" then - local tempfolder = os.tempfolder() - - if tempfolder ~= nil and - tempfolder ~= "" then - core.create_dir(tempfolder) - if core.extract_zip(modfile.name,tempfolder) then - return tempfolder - end - end - end - return nil -end - function pkgmgr.get_folder_type(path) local testfile = io.open(path .. DIR_DELIM .. "init.lua","r") if testfile ~= nil then @@ -349,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) if not render_list then if not pkgmgr.global_mods then pkgmgr.refresh_globals() @@ -385,7 +373,12 @@ function pkgmgr.render_packagelist(render_list) else retval[#retval + 1] = "0" end - retval[#retval + 1] = core.formspec_escape(v.list_name or v.name) + + 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, ",") @@ -412,6 +405,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 @@ -420,13 +421,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 @@ -451,7 +455,7 @@ function pkgmgr.enable_mod(this, toset) local enabled_mods = {} toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod) - if not toset then + if next(enabled_mods) == nil then -- Mod(s) were disabled, so no dependencies need to be enabled table.sort(toggled_mods) core.log("info", "Following mods were disabled: " .. @@ -461,11 +465,16 @@ function pkgmgr.enable_mod(this, toset) -- Enable mods' depends after activation - -- Make a list of mod ids indexed by their names + -- Make a list of mod ids indexed by their names. Among mods with the + -- same name, enabled mods take precedence, after which game mods take + -- precedence, being last in the mod list. local mod_ids = {} for id, mod2 in pairs(list) do if mod2.type == "mod" and not mod2.is_modpack then - mod_ids[mod2.name] = id + local prev_id = mod_ids[mod2.name] + if not prev_id or not list[prev_id].enabled then + mod_ids[mod2.name] = id + end end end @@ -482,6 +491,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] @@ -494,14 +504,14 @@ function pkgmgr.enable_mod(this, toset) core.log("warning", "Mod dependency \"" .. name .. "\" not found!") else - if mod_to_enable.enabled == false then + if not mod_to_enable.enabled then mod_to_enable.enabled = true toggled_mods[#toggled_mods+1] = mod_to_enable.name end -- Push the dependencies of the dependency onto the stack local depends = pkgmgr.get_dependencies(mod_to_enable.path) for i = 1, #depends do - if not enabled_mods[name] then + if not enabled_mods[depends[i]] then sp = sp+1 to_enable[sp] = depends[i] end @@ -561,11 +571,10 @@ function pkgmgr.install_dir(type, path, basename, targetpath) local from = basefolder and basefolder.path or path if targetpath then core.delete_dir(targetpath) - core.create_dir(targetpath) else targetpath = core.get_texturepath() .. DIR_DELIM .. basename end - if not core.copy_dir(from, targetpath) then + if not core.copy_dir(from, targetpath, false) then return nil, fgettext("Failed to install $1 to $2", basename, targetpath) end @@ -586,7 +595,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath) -- Get destination name for modpack if targetpath then core.delete_dir(targetpath) - core.create_dir(targetpath) else local clean_path = nil if basename ~= nil then @@ -610,7 +618,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath) if targetpath then core.delete_dir(targetpath) - core.create_dir(targetpath) else local targetfolder = basename if targetfolder == nil then @@ -636,14 +643,13 @@ function pkgmgr.install_dir(type, path, basename, targetpath) if targetpath then core.delete_dir(targetpath) - core.create_dir(targetpath) else targetpath = core.get_gamepath() .. DIR_DELIM .. basename end end -- Copy it - if not core.copy_dir(basefolder.path, targetpath) then + if not core.copy_dir(basefolder.path, targetpath, false) then return nil, fgettext("Failed to install $1 to $2", basename, targetpath) end @@ -658,23 +664,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath) end -------------------------------------------------------------------------------- -function pkgmgr.install(type, modfilename, basename, dest) - local archive_info = pkgmgr.identify_filetype(modfilename) - local path = pkgmgr.extract(archive_info) - - if path == nil then - return nil, - fgettext("Install: file: \"$1\"", archive_info.name) .. "\n" .. - fgettext("Install: Unsupported file type \"$1\" or broken archive", - archive_info.type) - end - - local targetpath, msg = pkgmgr.install_dir(type, path, basename, dest) - core.delete_dir(path) - return targetpath, msg -end - --------------------------------------------------------------------------------- function pkgmgr.prepareclientmodlist(data) local retval = {} @@ -683,9 +672,8 @@ function pkgmgr.prepareclientmodlist(data) --read clientmods local modpath = core.get_clientmodpath() - if modpath ~= nil and - modpath ~= "" then - get_mods(modpath,clientmods) + if modpath ~= nil and modpath ~= "" then + get_mods(modpath, "clientmods", clientmods) end for i=1,#clientmods,1 do @@ -730,16 +718,15 @@ function pkgmgr.preparemodlist(data) local game_mods = {} --read global mods - local modpath = core.get_modpath() - - if modpath ~= nil and - modpath ~= "" then - get_mods(modpath,global_mods) + local modpaths = core.get_modpaths() + 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 @@ -773,22 +760,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 @@ -872,45 +874,6 @@ function pkgmgr.refresh_globals() end -------------------------------------------------------------------------------- -function pkgmgr.identify_filetype(name) - - if name:sub(-3):lower() == "zip" then - return { - name = name, - type = "zip" - } - end - - if name:sub(-6):lower() == "tar.gz" or - name:sub(-3):lower() == "tgz"then - return { - name = name, - type = "tgz" - } - end - - if name:sub(-6):lower() == "tar.bz2" then - return { - name = name, - type = "tbz" - } - end - - if name:sub(-2):lower() == "7z" then - return { - name = name, - type = "7z" - } - end - - return { - name = name, - type = "ukn" - } -end - - --------------------------------------------------------------------------------- function pkgmgr.find_by_gameid(gameid) for i=1,#pkgmgr.games,1 do if pkgmgr.games[i].id == gameid then @@ -925,7 +888,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 diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua index cb566f773..3336786ba 100644 --- a/builtin/mainmenu/tab_about.lua +++ b/builtin/mainmenu/tab_about.lua @@ -38,32 +38,35 @@ local core_developers = { "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>", } -- For updating active/previous contributors, see the script in ./util/gather_git_credits.py local active_contributors = { - "Wuzzy [devtest game, visual corrections]", - "Zughy [Visual improvements, various fixes]", - "Maksim (MoNTE48) [Android]", + "Wuzzy [I18n for builtin, liquid features, fixes]", + "Zughy [Various features and fixes]", "numzero [Graphics and rendering]", - "appgurueu [Various internal fixes]", - "Desour [Formspec and vector API changes]", - "HybridDog [Rendering fixes and documentation]", - "Hugues Ross [Graphics-related improvements]", - "ANAND (ClobberXD) [Mouse buttons rebinding]", - "luk3yx [Fixes]", - "hecks [Audiovisuals, Lua API]", - "LoneWolfHT [Object crosshair, documentation fixes]", - "Lejo [Server-related improvements]", - "EvidenceB [Compass HUD element]", - "Paul Ouellette (pauloue) [Lua API, documentation]", - "TheTermos [Collision detection, physics]", + "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]", + "Liso [Shadow Mapping]", + "MoNTE48 [Build fix]", + "Jean-Patrick Guerrero (kilbith) [Fixes]", + "ROllerozxa [Code cleanups]", + "Lejo [bitop library integration]", + "LoneWolfHT [Build fixes]", + "NeroBurner [Joystick]", + "Elias Fleckenstein [Internal fixes]", "David CARLIER [Unix & Haiku build fixes]", - "dcbrwn [Object shading]", - "Elias Fleckenstein [API features/fixes]", - "Jean-Patrick Guerrero (kilbith) [model element, visual fixes]", - "k.h.lai [Memory leak fixes, documentation]", + "pecksin [Clickable web links]", + "srfqi [Android & rendering fixes]", + "EvidenceB [Formspec]", } local previous_core_developers = { @@ -80,6 +83,7 @@ local previous_core_developers = { "Zeno", "ShadowNinja <shadowninja@minetest.net>", "Auke Kok (sofar) <sofar@foo-projects.org>", + "Aaron Suen <warr1024@gmail.com>", } local previous_contributors = { @@ -90,10 +94,10 @@ local previous_contributors = { "MirceaKitsune <mirceakitsune@gmail.com>", "Constantin Wenger (SpeedProg)", "Ciaran Gultnieks (CiaranG)", - "stujones11 [Android UX improvements]", - "Rogier <rogier777@gmail.com> [Fixes]", - "Gregory Currie (gregorycu) [optimisation]", - "srifqi [Fixes]", + "Paul Ouellette (pauloue)", + "stujones11", + "Rogier <rogier777@gmail.com>", + "Gregory Currie (gregorycu)", "JacobF", "Jeija <jeija@mesecons.net> [HTTP, particles]", } diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua index 1bffeeb22..a366d4ab4 100644 --- a/builtin/mainmenu/tab_content.lua +++ b/builtin/mainmenu/tab_content.lua @@ -88,12 +88,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") .. "]" @@ -124,9 +126,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 @@ -214,6 +224,9 @@ local function handle_doubleclick(pkg, pkg_name) core.settings:set("texture_path", pkg.path) end packages = nil + + mm_game_theme.init() + mm_game_theme.reset() elseif pkg.is_clientside then pkgmgr.enable_mod({data = {list = packages, selected_mod = pkg_name}}) packages = nil @@ -276,17 +289,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 be5f905ac..e77c6f04d 100644 --- a/builtin/mainmenu/tab_local.lua +++ b/builtin/mainmenu/tab_local.lua @@ -33,10 +33,30 @@ if enable_gamebar then 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) + + 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 + end + menu_worldmt_legacy(index) + end + function singleplayer_refresh_gamebar() local old_bar = ui.find_by_name("game_button_bar") - if old_bar ~= nil then old_bar:delete() end @@ -51,26 +71,10 @@ if enable_gamebar then return true end - for key,value in pairs(fields) do - for j=1,#pkgmgr.games,1 do - if ("game_btnbar_" .. pkgmgr.games[j].id == key) then - mm_texture.update("singleplayer", pkgmgr.games[j]) - core.set_topleft_text(pkgmgr.games[j].name) - core.settings:set("menu_last_game",pkgmgr.games[j].id) - menudata.worldlist:set_filtercriteria(pkgmgr.games[j].id) - 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 - end - menu_worldmt_legacy(index) - 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 @@ -79,25 +83,22 @@ if enable_gamebar then game_buttonbar_button_handler, {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15}) - for i=1,#pkgmgr.games,1 do - local btn_name = "game_btnbar_" .. pkgmgr.games[i].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(pkgmgr.games[i].name) + local tooltip = core.formspec_escape(game.name) - if pkgmgr.games[i].menuicon_path ~= nil and - pkgmgr.games[i].menuicon_path ~= "" then - image = core.formspec_escape(pkgmgr.games[i].menuicon_path) + if (game.menuicon_path or "") ~= "" then + image = core.formspec_escape(game.menuicon_path) else - - local part1 = pkgmgr.games[i].id:sub(1,5) - local part2 = pkgmgr.games[i].id:sub(6,10) - local part3 = pkgmgr.games[i].id:sub(11) + 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 ~= nil and - part3 ~= "" then + if part3 ~= "" then text = text .. "\n" .. part3 end end @@ -147,8 +148,12 @@ local function get_formspec(tabview, name, tabdata) tonumber(core.settings:get("mainmenu_last_selected_world"))) local list = menudata.worldlist:get_list() local world = list and index and list[index] - local gameid = world and world.gameid - local game = gameid and pkgmgr.find_by_gameid(gameid) + local game + if world then + game = pkgmgr.find_by_gameid(world.gameid) + else + game = current_game() + end local disabled_settings = get_disabled_settings(game) local creative, damage, host = "", "", "" @@ -182,7 +187,7 @@ local function get_formspec(tabview, name, tabdata) damage .. host .. "textlist[3.9,0.4;7.9,3.45;sp_worlds;" .. - menu_render_worldlist() .. + menu_render_worldlist(not enable_gamebar) .. ";" .. index .. "]" if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then @@ -319,11 +324,11 @@ local function main_button_handler(this, fields, name, tabdata) end if fields["world_create"] ~= nil then - local create_world_dlg = create_create_world_dlg(true) + local create_world_dlg = create_create_world_dlg(enable_gamebar) create_world_dlg:set_parent(this) this:hide() create_world_dlg:show() - mm_texture.update("singleplayer", current_game()) + mm_game_theme.update("singleplayer", current_game()) return true end @@ -340,7 +345,7 @@ local function main_button_handler(this, fields, name, tabdata) delete_world_dlg:set_parent(this) this:hide() delete_world_dlg:show() - mm_texture.update("singleplayer",current_game()) + mm_game_theme.update("singleplayer",current_game()) end end @@ -358,7 +363,7 @@ local function main_button_handler(this, fields, name, tabdata) configdialog:set_parent(this) this:hide() configdialog:show() - mm_texture.update("singleplayer",current_game()) + mm_game_theme.update("singleplayer",current_game()) end end @@ -371,11 +376,8 @@ if enable_gamebar then function on_change(type, old_tab, new_tab) if (type == "ENTER") then local game = current_game() - if game then - menudata.worldlist:set_filtercriteria(game.id) - core.set_topleft_text(game.name) - mm_texture.update("singleplayer",game) + apply_game(game) end singleplayer_refresh_gamebar() @@ -387,7 +389,7 @@ if enable_gamebar then gamebar:hide() end core.set_topleft_text("") - mm_texture.update(new_tab,nil) + mm_game_theme.update(new_tab,nil) end end end diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index f06e35872..0e761d324 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -247,7 +247,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) adv_settings_dlg:set_parent(this) this:hide() adv_settings_dlg:show() - --mm_texture.update("singleplayer", current_game()) + --mm_game_theme.update("singleplayer", current_game()) return true end if fields["cb_smooth_lighting"] then @@ -275,13 +275,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) return true end if fields["cb_shaders"] then - if (core.settings:get("video_driver") == "direct3d8" or - core.settings:get("video_driver") == "direct3d9") then - core.settings:set("enable_shaders", "false") - gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.") - else - core.settings:set("enable_shaders", fields["cb_shaders"]) - end + core.settings:set("enable_shaders", fields["cb_shaders"]) return true end if fields["cb_tonemapping"] then @@ -370,11 +364,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] = { 55, 512, "true", 0, "false" }, + [3] = { 82, 1024, "true", 1, "false" }, + [4] = { 240, 2048, "true", 1, "false" }, + [5] = { 240, 2048, "true", 2, "true" }, + [6] = { 300, 4096, "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 = {} |