This commit is contained in:
nauta-turbidus 2024-05-17 21:46:34 +02:00 committed by GitHub
commit d251abd968
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 142 additions and 10 deletions

View File

@ -95,11 +95,22 @@ local function start_install(package, reason)
if result.msg then
gamedata.errormessage = result.msg
else
local delete_old_dir
if package.path then
local name = pkgmgr.normalize_game_id(package.path:match("[^/\\]+[/\\]?$"))
if name ~= package.name then
delete_old_dir = package.path
package.path = core.get_gamepath() .. DIR_DELIM .. package.name
end
end
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 = fgettext_ne("Error installing \"$1\": $2", package.title, msg)
else
if delete_old_dir then
core.delete_dir(delete_old_dir)
end
core.log("action", "Installed package to " .. path)
local conf_path
@ -131,6 +142,16 @@ local function start_install(package, reason)
end
conf:set("author", package.author)
conf:set("release", package.release)
if package.aliases then
local gameid_aliases = {}
for _, alias in ipairs(package.aliases) do
local alias_cut = alias:match("[^/]+$")
if alias_cut ~= package.name then
gameid_aliases[#gameid_aliases + 1] = alias_cut
end
end
conf:set("aliases", table.concat(gameid_aliases, ","))
end
conf:write()
end
end
@ -388,10 +409,11 @@ local function fetch_pkgs(params)
package.url_part = core.urlencode(package.author) .. "/" .. core.urlencode(package.name)
if package.aliases then
local suffix = "/" .. package.name
local suf_len = #suffix
local is_game = package.type == "game"
for _, alias in ipairs(package.aliases) do
-- We currently don't support name changing
local suffix = "/" .. package.name
if alias:sub(-#suffix) == suffix then
if is_game or alias:sub(suf_len) == suffix then
aliases[alias:lower()] = package.id
end
end

View File

@ -828,6 +828,13 @@ function pkgmgr.get_contentdb_id(content)
return nil
end
--------------------------------------------------------------------------------
-- Normalizes ID of a game
function pkgmgr.normalize_game_id(name)
return name:match("(.*)_game$") or name
end
--------------------------------------------------------------------------------
-- read initial data
--------------------------------------------------------------------------------

View File

@ -78,7 +78,15 @@ local function init_globals()
end,
-- Filter function
function(element, gameid)
return element.gameid == gameid
if element.gameid == gameid then
return true
end
for _, alias in ipairs(pkgmgr.find_by_gameid(gameid).aliases) do
if pkgmgr.normalize_game_id(element.gameid) == pkgmgr.normalize_game_id(alias) then
return true
end
end
return false
end
)

View File

@ -357,6 +357,19 @@ local function main_button_handler(this, fields, name, tabdata)
local game_obj
if world then
game_obj = pkgmgr.find_by_gameid(world.gameid)
if not game_obj then
local function try_to_find_alias(world)
for _, game in ipairs(pkgmgr.games) do
for _, alias in pairs(game.aliases) do
if pkgmgr.normalize_game_id(alias) == pkgmgr.normalize_game_id(world.gameid) then
world.gameid = game.id
return game
end
end
end
end
game_obj = try_to_find_alias(world)
end
core.settings:set("menu_last_game", game_obj.id)
end

View File

@ -93,6 +93,10 @@ The game directory can contain the following files:
an internal ID used to track versions.
* `textdomain`: Textdomain used to translate description. Defaults to game id.
See [Translating content meta](#translating-content-meta).
* `aliases = <comma-separated aliases>`
e.g. `aliases = aa,bb` (game has been named "aa" and then "bb" before)
This allows automatic loading of worlds using a gameid from this list.
This is intended to allow a full rename of a game, including its id.
* `minetest.conf`:
Used to set default settings when running this game.
* `settingtypes.txt`:

View File

@ -101,6 +101,15 @@ SubgameSpec findSubgame(const std::string &id)
std::string share = porting::path_share;
std::string user = porting::path_user;
auto normalize_game_id = [&](std::string_view name){
if (str_ends_with(name, "_game"))
return name.substr(0, name.size() - 5);
return name;
};
std::string idv = static_cast<std::string>(normalize_game_id(trim(id)));
// Get games install locations
Strfnd search_paths(getSubgamePathEnv());
@ -134,8 +143,53 @@ SubgameSpec findSubgame(const std::string &id)
}
}
if (game_path.empty())
return SubgameSpec();
// Failed to find the game, try to find aliased game
if (game_path.empty()) {
std::vector<GameFindPath> gamespaths;
gamespaths.emplace_back(share + DIR_DELIM + "games", false);
gamespaths.emplace_back(user + DIR_DELIM + "games", true);
Strfnd search_paths(getSubgamePathEnv());
while (!search_paths.at_end())
gamespaths.emplace_back(search_paths.next(PATH_DELIM), false);
auto look_for_alias = [&](){
for (const GameFindPath &gamespath : gamespaths) {
const std::string &path = gamespath.path;
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
for (const fs::DirListNode &dln : dirlist) {
if (!dln.dir)
continue;
// If configuration file is not found or broken, ignore game
Settings conf;
std::string conf_path = path + DIR_DELIM + dln.name +
DIR_DELIM + "game.conf";
if (!conf.readConfigFile(conf_path.c_str()))
continue;
if (conf.exists("aliases")) {
std::vector<std::string> aliases = str_split(conf.get("aliases"), ',');
for (const std::string &alias_raw : aliases) {
std::string_view alias = normalize_game_id(trim(alias_raw));
if (alias == idv) {
idv = dln.name;
game_path = path + DIR_DELIM + dln.name;
user_game = gamespath.user_specific;
return;
}
}
}
}
}
};
look_for_alias();
if (game_path.empty()) // Failed to find the game taking aliases into account
return SubgameSpec();
}
// Found the game, proceed
std::string gamemod_path = game_path + DIR_DELIM + "mods";
@ -160,7 +214,7 @@ SubgameSpec findSubgame(const std::string &id)
else if (conf.exists("name"))
game_title = conf.get("name");
else
game_title = id;
game_title = idv;
std::string game_author;
if (conf.exists("author"))
@ -170,6 +224,14 @@ SubgameSpec findSubgame(const std::string &id)
if (conf.exists("release"))
game_release = conf.getS32("release");
std::unordered_set<std::string> aliases;
if (conf.exists("aliases"))
{
std::vector<std::string> aliases_raw = str_split(conf.get("aliases"), ',');
for (const std::string &alias : aliases_raw)
aliases.insert(static_cast<std::string>(normalize_game_id(trim(alias))));
}
std::string menuicon_path;
#ifndef SERVER
menuicon_path = getImagePath(
@ -177,7 +239,7 @@ SubgameSpec findSubgame(const std::string &id)
#endif
SubgameSpec spec(id, game_path, gamemod_path, mods_paths, game_title,
menuicon_path, game_author, game_release);
menuicon_path, game_author, game_release, aliases);
if (conf.exists("name") && !conf.exists("title"))
spec.deprecation_msgs.push_back("\"name\" setting in game.conf is deprecated, please use \"title\" instead");

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class Settings;
@ -41,6 +42,8 @@ struct SubgameSpec
std::unordered_map<std::string, std::string> addon_mods_paths;
std::string menuicon_path;
std::unordered_set<std::string> aliases;
// For logging purposes
std::vector<const char *> deprecation_msgs;
@ -49,11 +52,12 @@ struct SubgameSpec
const std::unordered_map<std::string, std::string> &addon_mods_paths = {},
const std::string &title = "",
const std::string &menuicon_path = "",
const std::string &author = "", int release = 0) :
const std::string &author = "", int release = 0,
const std::unordered_set<std::string> &aliases = {}) :
id(id),
title(title), author(author), release(release), path(path),
gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths),
menuicon_path(menuicon_path)
menuicon_path(menuicon_path), aliases(aliases)
{
}

View File

@ -332,6 +332,18 @@ int ModApiMainMenu::l_get_games(lua_State *L)
lua_pushstring(L, game.menuicon_path.c_str());
lua_settable(L, top_lvl2);
lua_pushstring(L, "aliases");
lua_newtable(L);
int table_aliases = lua_gettop(L);
int alias_index = 1;
for (const auto &alias : game.aliases) {
lua_pushnumber(L, alias_index);
lua_pushstring(L, alias.c_str());
lua_settable(L, table_aliases);
alias_index++;
}
lua_settable(L, top_lvl2);
lua_pushstring(L, "addon_mods_paths");
lua_newtable(L);
int table2 = lua_gettop(L);