Browse Source

Mainmenu: Properly sort mods and games (#12758)

This also removes trivial and unused pkgmgr functions
Fixes a bug caused by sorting in 2133fc8
SmallJoker 1 year ago
parent
commit
bc3dccca5c

+ 0 - 12
builtin/common/misc_helpers.lua

@@ -519,18 +519,6 @@ end
 --------------------------------------------------------------------------------
 -- mainmenu only functions
 --------------------------------------------------------------------------------
-if INIT == "mainmenu" then
-	function core.get_game(index)
-		local games = core.get_games()
-
-		if index > 0 and index <= #games then
-			return games[index]
-		end
-
-		return nil
-	end
-end
-
 if core.gettext then -- for client and mainmenu
 	function fgettext_ne(text, ...)
 		text = core.gettext(text)

+ 1 - 2
builtin/mainmenu/dlg_config_world.lua

@@ -57,8 +57,7 @@ local function init_data(data)
 		hide_game = data.hide_gamemods,
 		hide_modpackcontents = data.hide_modpackcontents
 	})
-	data.list:add_sort_mechanism("alphabetic", sort_mod_list)
-	data.list:set_sortmode("alphabetic")
+	-- Sorting is already done by pgkmgr.get_mods
 end
 
 

+ 12 - 13
builtin/mainmenu/dlg_contentstore.lua

@@ -346,22 +346,21 @@ end
 
 local install_dialog = {}
 function install_dialog.get_formspec()
+	local selected_game, selected_game_idx = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
+	if not selected_game_idx then
+		selected_game_idx = 1
+		selected_game = pkgmgr.games[1]
+	end
+
+	local game_list = {}
+	for i, game in ipairs(pkgmgr.games) do
+		game_list[i] = core.formspec_escape(game[i].title)
+	end
+
 	local package = install_dialog.package
 	local raw_deps = install_dialog.raw_deps
 	local will_install_deps = install_dialog.will_install_deps
 
-	local selected_game_idx = 1
-	local selected_gameid = core.settings:get("menu_last_game")
-	local games = table.copy(pkgmgr.games)
-	for i=1, #games do
-		if selected_gameid and games[i].id == selected_gameid then
-			selected_game_idx = i
-		end
-
-		games[i] = core.formspec_escape(games[i].title)
-	end
-
-	local selected_game = pkgmgr.games[selected_game_idx]
 	local deps_to_install = 0
 	local deps_not_found = 0
 
@@ -408,7 +407,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;selected_game;", table.concat(games, ","), ";", selected_game_idx, "]",
+		"dropdown[2,0;4.25,0.5;selected_game;", table.concat(game_list, ","), ";", selected_game_idx, "]",
 
 		"label[0,0.8;", fgettext("Dependencies:"), "]",
 

+ 4 - 6
builtin/mainmenu/dlg_create_world.lua

@@ -104,14 +104,12 @@ local function create_world_formspec(dialogdata)
 	local current_mg = dialogdata.mg
 	local mapgens = core.get_mapgen_names()
 
-	local gameid = core.settings:get("menu_last_game")
-
 	local flags = dialogdata.flags
 
-	local game = pkgmgr.find_by_gameid(gameid)
+	local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
 	if game == nil then
 		-- should never happen but just pick the first game
-		game = pkgmgr.get_game(1)
+		game = pkgmgr.games[1]
 		core.settings:set("menu_last_game", game.id)
 	end
 
@@ -355,7 +353,7 @@ local function create_world_buttonhandler(this, fields)
 		fields["key_enter"] then
 
 		local worldname = fields["te_world_name"]
-		local game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
+		local game, _ = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
 
 		local message
 		if game == nil then
@@ -399,7 +397,7 @@ local function create_world_buttonhandler(this, fields)
 				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)
+			message = core.create_world(worldname, game.id, settings)
 		end
 
 		if message == nil then

+ 3 - 8
builtin/mainmenu/dlg_settings_advanced.lua

@@ -344,9 +344,7 @@ local function parse_config_file(read_all, parse_mods)
 	if parse_mods then
 		-- Parse games
 		local games_category_initialized = false
-		local index = 1
-		local game = pkgmgr.get_game(index)
-		while game do
+		for _, game in ipairs(pkgmgr.games) do
 			local path = game.path .. DIR_DELIM .. FILENAME
 			local file = io.open(path, "r")
 			if file then
@@ -370,15 +368,12 @@ local function parse_config_file(read_all, parse_mods)
 
 				file:close()
 			end
-
-			index = index + 1
-			game = pkgmgr.get_game(index)
 		end
 
 		-- Parse mods
 		local mods_category_initialized = false
 		local mods = {}
-		get_mods(core.get_modpath(), "mods", mods)
+		pkgmgr.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")
@@ -409,7 +404,7 @@ local function parse_config_file(read_all, parse_mods)
 		-- Parse client mods
 		local clientmods_category_initialized = false
 		local clientmods = {}
-		get_mods(core.get_clientmodpath(), "clientmods", clientmods)
+		pkgmgr.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")

+ 23 - 76
builtin/mainmenu/pkgmgr.lua

@@ -100,7 +100,15 @@ local function load_texture_packs(txtpath, retval)
 	end
 end
 
-function get_mods(path, virtual_path, retval, modpack)
+--modmanager implementation
+pkgmgr = {}
+
+--- Scans a directory recursively for mods and adds them to `listing`
+-- @param path         Absolute directory path to scan recursively
+-- @param virtual_path Prettified unique path (e.g. "mods", "mods/mt_modpack")
+-- @param listing      Input. Flat array to insert located mods and modpacks
+-- @param modpack      Currently processing modpack or nil/"" if none (recursion)
+function pkgmgr.get_mods(path, virtual_path, listing, modpack)
 	local mods = core.get_dir_list(path, true)
 
 	for _, name in ipairs(mods) do
@@ -111,7 +119,7 @@ function get_mods(path, virtual_path, retval, modpack)
 				dir_name = name,
 				parent_dir = path,
 			}
-			retval[#retval + 1] = toadd
+			listing[#listing + 1] = toadd
 
 			-- Get config file
 			local mod_conf
@@ -156,14 +164,18 @@ function get_mods(path, virtual_path, retval, modpack)
 			elseif toadd.is_modpack then
 				toadd.type = "modpack"
 				toadd.is_modpack = true
-				get_mods(mod_path, mod_virtual_path, retval, name)
+				pkgmgr.get_mods(mod_path, mod_virtual_path, listing, name)
 			end
 		end
 	end
-end
 
---modmanager implementation
-pkgmgr = {}
+	if not modpack then
+		-- Sort all when the recursion is done
+		table.sort(listing, function(a, b)
+			return a.virtual_path:lower() < b.virtual_path:lower()
+		end)
+	end
+end
 
 function pkgmgr.get_texture_packs()
 	local txtpath = core.get_texturepath()
@@ -593,7 +605,7 @@ function pkgmgr.preparemodlist(data)
 	--read global mods
 	local modpaths = core.get_modpaths()
 	for key, modpath in pairs(modpaths) do
-		get_mods(modpath, key, global_mods)
+		pkgmgr.get_mods(modpath, key, global_mods)
 	end
 
 	for i=1,#global_mods,1 do
@@ -700,35 +712,6 @@ function pkgmgr.comparemod(elem1,elem2)
 	return true
 end
 
---------------------------------------------------------------------------------
-function pkgmgr.mod_exists(basename)
-
-	if pkgmgr.global_mods == nil then
-		pkgmgr.refresh_globals()
-	end
-
-	if pkgmgr.global_mods:raw_index_by_uid(basename) > 0 then
-		return true
-	end
-
-	return false
-end
-
---------------------------------------------------------------------------------
-function pkgmgr.get_global_mod(idx)
-
-	if pkgmgr.global_mods == nil then
-		return nil
-	end
-
-	if idx == nil or idx < 1 or
-		idx > pkgmgr.global_mods:size() then
-		return nil
-	end
-
-	return pkgmgr.global_mods:get_list()[idx]
-end
-
 --------------------------------------------------------------------------------
 function pkgmgr.refresh_globals()
 	local function is_equal(element,uid) --uid match
@@ -744,9 +727,9 @@ end
 
 --------------------------------------------------------------------------------
 function pkgmgr.find_by_gameid(gameid)
-	for i=1,#pkgmgr.games,1 do
-		if pkgmgr.games[i].id == gameid then
-			return pkgmgr.games[i], i
+	for i, game in ipairs(pkgmgr.games) do
+		if game.id == gameid then
+			return game, i
 		end
 	end
 	return nil, nil
@@ -757,33 +740,10 @@ 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, ("games/%s/mods"):format(gamespec.id), retval)
+		pkgmgr.get_mods(gamespec.gamemods_path, ("games/%s/mods"):format(gamespec.id), retval)
 	end
 end
 
---------------------------------------------------------------------------------
-function pkgmgr.get_game_modlist(gamespec)
-	local retval = ""
-	local game_mods = {}
-	pkgmgr.get_game_mods(gamespec, game_mods)
-	for i=1,#game_mods,1 do
-		if retval ~= "" then
-			retval = retval..","
-		end
-		retval = retval .. game_mods[i].name
-	end
-	return retval
-end
-
---------------------------------------------------------------------------------
-function pkgmgr.get_game(index)
-	if index > 0 and index <= #pkgmgr.games then
-		return pkgmgr.games[index]
-	end
-
-	return nil
-end
-
 --------------------------------------------------------------------------------
 function pkgmgr.update_gamelist()
 	pkgmgr.games = core.get_games()
@@ -792,19 +752,6 @@ function pkgmgr.update_gamelist()
 	end)
 end
 
---------------------------------------------------------------------------------
-function pkgmgr.gamelist()
-	local retval = ""
-	if #pkgmgr.games > 0 then
-		retval = retval .. core.formspec_escape(pkgmgr.games[1].title)
-
-		for i=2,#pkgmgr.games,1 do
-			retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title)
-		end
-	end
-	return retval
-end
-
 --------------------------------------------------------------------------------
 -- read initial data
 --------------------------------------------------------------------------------

+ 3 - 5
doc/menu_lua_api.txt

@@ -247,9 +247,9 @@ Package - content which is downloadable from the content db, may or may not be i
     * returns path to global gamepath
 * core.get_texturepath() (possible in async calls)
     * returns path to default textures
-* core.get_game(index)
+* core.get_games() -> table of all games (possible in async calls)
     * `name` in return value is deprecated, use `title` instead.
-    * returns:
+    * returns a table (ipairs) with values:
 
         {
             id               = <id>,
@@ -261,8 +261,6 @@ Package - content which is downloadable from the content db, may or may not be i
             DEPRECATED:
             addon_mods_paths = {[1] = <path>,},
         }
-
-* core.get_games() -> table of all games in upper format (possible in async calls)
 * core.get_content_info(path)
     * returns
 
@@ -323,7 +321,7 @@ core.get_worlds() -> list of worlds (possible in async calls)
     gameid = <gameid of world>,
     },
 }
-core.create_world(worldname, gameid)
+core.create_world(worldname, gameid, init_settings)
 core.delete_world(index)
 
 

+ 8 - 5
src/script/lua_api/l_mainmenu.cpp

@@ -522,8 +522,8 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L)
 /******************************************************************************/
 int ModApiMainMenu::l_create_world(lua_State *L)
 {
-	const char *name	= luaL_checkstring(L, 1);
-	int gameidx			= luaL_checkinteger(L,2) -1;
+	const char *name   = luaL_checkstring(L, 1);
+	const char *gameid = luaL_checkstring(L, 2);
 
 	StringMap use_settings;
 	luaL_checktype(L, 3, LUA_TTABLE);
@@ -540,8 +540,11 @@ int ModApiMainMenu::l_create_world(lua_State *L)
 			+ sanitizeDirName(name, "world_");
 
 	std::vector<SubgameSpec> games = getAvailableGames();
-	if (gameidx < 0 || gameidx >= (int) games.size()) {
-		lua_pushstring(L, "Invalid game index");
+	auto game_it = std::find_if(games.begin(), games.end(), [gameid] (const SubgameSpec &spec) {
+		return spec.id == gameid;
+	});
+	if (game_it == games.end()) {
+		lua_pushstring(L, "Game ID not found");
 		return 1;
 	}
 
@@ -556,7 +559,7 @@ int ModApiMainMenu::l_create_world(lua_State *L)
 
 	// Create world if it doesn't exist
 	try {
-		loadGameConfAndInitWorld(path, name, games[gameidx], true);
+		loadGameConfAndInitWorld(path, name, *game_it, true);
 		lua_pushnil(L);
 	} catch (const BaseException &e) {
 		auto err = std::string("Failed to initialize world: ") + e.what();