diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua index e3505456e..2c9e80e15 100644 --- a/builtin/mainmenu/dlg_contentstore.lua +++ b/builtin/mainmenu/dlg_contentstore.lua @@ -15,6 +15,30 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +local store = {} +local package_dialog = {} + +local search_string = "" +local cur_page = 1 +local num_per_page = 5 +local filter_type = 1 +local filter_types_titles = { + fgettext("All packages"), + fgettext("Games"), + fgettext("Mods"), + fgettext("Texture packs"), +} + +local filter_types_type = { + nil, + "game", + "mod", + "txp", +} + + + + local function download_package(param) if core.download_file(param.package.url, param.filename) then return { @@ -39,7 +63,9 @@ local function start_install(calling_dialog, package) local function callback(result) if result.successful then - local path, msg = pkgmgr.install(result.package.type, result.filename, result.package.name) + local path, msg = pkgmgr.install(result.package.type, + result.filename, result.package.name, + result.package.path) if not path then gamedata.errormessage = msg else @@ -69,6 +95,7 @@ local function start_install(calling_dialog, package) end set_def("description", result.package.short_description) set_def("author", result.package.author) + conf:set("release", result.package.release) conf:write() end end @@ -85,7 +112,7 @@ local function start_install(calling_dialog, package) end if not core.handle_async(download_package, params, callback) then - minetest.log("error", "ERROR: async event failed") + core.log("error", "ERROR: async event failed") gamedata.errormessage = fgettext("Failed to download $1", package.name) end @@ -111,19 +138,35 @@ local function start_install(calling_dialog, package) end -local package_dialog = {} - function package_dialog.get_formspec() local package = package_dialog.package + store.update_paths() + local formspec = { - "size[8,4;true]", + "size[9,4;true]", "label[2.5,0.2;", core.formspec_escape(package.title), "]", - "textarea[0.2,1;8,3;;;", core.formspec_escape(package.short_description), "]", + "textarea[0.2,1;9,3;;;", core.formspec_escape(package.short_description), "]", "button[0,0;2,1;back;", fgettext("Back"), "]", - "button[6,0;2,1;install;", fgettext("Install"), "]", } + if not package.path then + formspec[#formspec + 1] = "button[7,0;2,1;install;" + formspec[#formspec + 1] = fgettext("Install") + formspec[#formspec + 1] = "]" + elseif package.installed_release < package.release then + formspec[#formspec + 1] = "button[7,0;2,1;install;" + formspec[#formspec + 1] = fgettext("Update") + formspec[#formspec + 1] = "]" + formspec[#formspec + 1] = "button[7,1;2,1;uninstall;" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + else + formspec[#formspec + 1] = "button[7,0;2,1;uninstall;" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + end + -- TODO: screenshots return table.concat(formspec, "") @@ -136,7 +179,15 @@ function package_dialog.handle_submit(this, fields, tabname, tabdata) end if fields.install then - start_install(package_dialog.package) + start_install(this, package_dialog.package) + return true + end + + if fields.uninstall then + local dlg_delmod = create_delete_content_dlg(package_dialog.package) + dlg_delmod:set_parent(this) + this:hide() + dlg_delmod:show() return true end @@ -151,28 +202,6 @@ function package_dialog.create(package) nil) end - - - -local store = {} -local search_string = "" -local cur_page = 1 -local num_per_page = 5 -local filter_type = 1 -local filter_types_titles = { - fgettext("All packages"), - fgettext("Games"), - fgettext("Mods"), - fgettext("Texture packs"), -} - -local filter_types_type = { - nil, - "game", - "mod", - "txp", -} - function store.load() store.packages_full = core.get_package_list() store.packages = store.packages_full @@ -209,6 +238,7 @@ function store.update_paths() if content and content.author == package.author then package.path = content.path + package.installed_release = content.release else package.path = nil end @@ -301,18 +331,24 @@ function store.get_formspec() formspec[#formspec + 1] = "]" -- buttons - if package.path then - formspec[#formspec + 1] = "button[6,0;1.5,1;uninstall_" - formspec[#formspec + 1] = tostring(i) - formspec[#formspec + 1] = ";" - formspec[#formspec + 1] = fgettext("Uninstall") - formspec[#formspec + 1] = "]" - else + if not package.path then formspec[#formspec + 1] = "button[6,0;1.5,1;install_" formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = ";" formspec[#formspec + 1] = fgettext("Install") formspec[#formspec + 1] = "]" + elseif package.installed_release < package.release then + formspec[#formspec + 1] = "button[6,0;1.5,1;install_" + formspec[#formspec + 1] = tostring(i) + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("Update") + formspec[#formspec + 1] = "]" + else + formspec[#formspec + 1] = "button[6,0;1.5,1;uninstall_" + formspec[#formspec + 1] = tostring(i) + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" end formspec[#formspec + 1] = "button[7.5,0;1.5,1;view_" formspec[#formspec + 1] = tostring(i) diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua index b83488848..2730612e9 100644 --- a/builtin/mainmenu/pkgmgr.lua +++ b/builtin/mainmenu/pkgmgr.lua @@ -32,6 +32,7 @@ function get_mods(path,retval,modpack) toadd.name = name toadd.author = mod_conf.author + toadd.release = tonumber(mod_conf.release or "0") toadd.path = prefix toadd.type = "mod" @@ -74,6 +75,7 @@ function pkgmgr.get_texture_packs() retval[#retval + 1] = { name = item, author = conf:get("author"), + release = tonumber(conf:get("release") or "0"), list_name = name, type = "txp", path = path, @@ -336,90 +338,113 @@ function pkgmgr.get_worldconfig(worldpath) end -------------------------------------------------------------------------------- -function pkgmgr.install_dir(type, path, basename) +function pkgmgr.install_dir(type, path, basename, targetpath) local basefolder = pkgmgr.get_base_folder(path) - local targetpath + -- There's no good way to detect a texture pack, so let's just assume + -- it's correct for now. if type == "txp" then if basefolder and basefolder.type ~= "invalid" and basefolder.type ~= "txp" then return nil, fgettext("Unable to install a $1 as a texture pack", basefolder.type) end local from = basefolder and basefolder.path or path - targetpath = core.get_texturepath() .. DIR_DELIM .. basename - core.copy_dir(from, targetpath) + 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 + return nil, + fgettext("Failed to install $1 to $2", basename, targetpath) + end return targetpath, nil elseif not basefolder then return nil, fgettext("Unable to find a valid mod or modpack") end + -- + -- Get destination + -- if basefolder.type == "modpack" then if type ~= "mod" then return nil, fgettext("Unable to install a modpack as a $1", type) end - local clean_path = nil - if basename ~= nil then - clean_path = "mp_" .. basename - end - - if clean_path == nil then - clean_path = get_last_folder(cleanup_path(basefolder.path)) - end - - if clean_path ~= nil then - targetpath = core.get_modpath() .. DIR_DELIM .. clean_path - if not core.copy_dir(basefolder.path,targetpath) then - return nil, - fgettext("Failed to install $1 to $2", basename, targetpath) - end + -- Get destination name for modpack + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) else - return nil, - fgettext("Install Mod: unable to find suitable foldername for modpack $1", - modfilename) + local clean_path = nil + if basename ~= nil then + clean_path = "mp_" .. basename + end + if not clean_path then + clean_path = get_last_folder(cleanup_path(basefolder.path)) + end + if clean_path then + targetpath = core.get_modpath() .. DIR_DELIM .. clean_path + else + return nil, + fgettext("Install Mod: unable to find suitable foldername for modpack $1", + modfilename) + end end - - pkgmgr.refresh_globals() - elseif basefolder.type == "mod" then if type ~= "mod" then return nil, fgettext("Unable to install a mod as a $1", type) end - local targetfolder = basename - if targetfolder == nil then - targetfolder = pkgmgr.identify_modname(basefolder.path,"init.lua") - end - - --if heuristic failed try to use current foldername - if targetfolder == nil then - targetfolder = get_last_folder(basefolder.path) - end - - if targetfolder ~= nil and pkgmgr.isValidModname(targetfolder) then - targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder - core.copy_dir(basefolder.path, targetpath) + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) else - return nil, fgettext("Install Mod: unable to find real modname for: $1", modfilename) - end + local targetfolder = basename + if targetfolder == nil then + targetfolder = pkgmgr.identify_modname(basefolder.path, "init.lua") + end - pkgmgr.refresh_globals() + -- If heuristic failed try to use current foldername + if targetfolder == nil then + targetfolder = get_last_folder(basefolder.path) + end + + if targetfolder ~= nil and pkgmgr.isValidModname(targetfolder) then + targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder + else + return nil, fgettext("Install Mod: unable to find real modname for: $1", modfilename) + end + end elseif basefolder.type == "game" then if type ~= "game" then return nil, fgettext("Unable to install a game as a $1", type) end - targetpath = core.get_gamepath() .. DIR_DELIM .. basename - core.copy_dir(basefolder.path, 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 + return nil, + fgettext("Failed to install $1 to $2", basename, targetpath) + end + + pkgmgr.refresh_globals() + return targetpath, nil end -------------------------------------------------------------------------------- -function pkgmgr.install(type, modfilename, basename) +function pkgmgr.install(type, modfilename, basename, dest) local archive_info = pkgmgr.identify_filetype(modfilename) local path = pkgmgr.extract(archive_info) @@ -430,7 +455,7 @@ function pkgmgr.install(type, modfilename, basename) archive_info.type) end - local targetpath, msg = pkgmgr.install_dir(type, path, basename) + local targetpath, msg = pkgmgr.install_dir(type, path, basename, dest) core.delete_dir(path) return targetpath, msg end diff --git a/src/content/content.cpp b/src/content/content.cpp index d45c5feab..d7a2c9652 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -98,6 +98,9 @@ void parseContentInfo(ContentSpec &spec) if (conf.exists("author")) spec.author = conf.get("author"); + + if (conf.exists("release")) + spec.release = conf.getS32("release"); } if (spec.desc.empty()) { diff --git a/src/content/content.h b/src/content/content.h index 782a4fd7a..e246ed411 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -20,11 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "config.h" #include "convert_json.h" +#include "irrlichttypes.h" struct ContentSpec { std::string type; std::string author; + u32 release = 0; std::string name; std::string desc; std::string path; diff --git a/src/content/mods.cpp b/src/content/mods.cpp index 694bbcca8..a3e706760 100644 --- a/src/content/mods.cpp +++ b/src/content/mods.cpp @@ -56,6 +56,9 @@ void parseModContents(ModSpec &spec) if (info.exists("author")) spec.author = info.get("author"); + if (info.exists("release")) + spec.release = info.getS32("release"); + spec.depends.clear(); spec.optdepends.clear(); spec.is_modpack = false; diff --git a/src/content/mods.h b/src/content/mods.h index a7cad07cf..6e2506dbf 100644 --- a/src/content/mods.h +++ b/src/content/mods.h @@ -39,6 +39,7 @@ struct ModSpec std::string author; std::string path; std::string desc; + int release = 0; // if normal mod: std::unordered_set depends; diff --git a/src/content/packages.cpp b/src/content/packages.cpp index a769c31af..d50e63a6b 100644 --- a/src/content/packages.cpp +++ b/src/content/packages.cpp @@ -49,6 +49,7 @@ std::vector getPackagesFromURL(const std::string &url) package.type = json[i]["type"].asString(); package.shortDesc = json[i]["shortDesc"].asString(); package.url = json[i]["url"].asString(); + package.release = json[i]["release"].asInt(); Json::Value jScreenshots = json[i]["screenshots"]; for (unsigned int j = 0; j < jScreenshots.size(); ++j) { diff --git a/src/content/packages.h b/src/content/packages.h index 6774678de..2290bd607 100644 --- a/src/content/packages.h +++ b/src/content/packages.h @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "config.h" #include "convert_json.h" +#include "irrlichttypes.h" struct Package { @@ -30,12 +31,13 @@ struct Package std::string shortDesc; std::string url; // download URL + u32 release; std::vector screenshots; bool valid() { return !(name.empty() || title.empty() || author.empty() || - type.empty() || url.empty()); + type.empty() || url.empty() || release <= 0); } }; diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp index fd6231a1f..9f05b751d 100644 --- a/src/content/subgames.cpp +++ b/src/content/subgames.cpp @@ -116,13 +116,17 @@ SubgameSpec findSubgame(const std::string &id) if (conf.exists("author")) game_author = conf.get("author"); + int game_release = 0; + if (conf.exists("release")) + game_release = conf.getS32("release"); + std::string menuicon_path; #ifndef SERVER menuicon_path = getImagePath( game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png"); #endif return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name, - menuicon_path, game_author); + menuicon_path, game_author, game_release); } SubgameSpec findWorldSubgame(const std::string &world_path) diff --git a/src/content/subgames.h b/src/content/subgames.h index 70a9d2713..4198ea860 100644 --- a/src/content/subgames.h +++ b/src/content/subgames.h @@ -30,6 +30,7 @@ struct SubgameSpec std::string id; std::string name; std::string author; + int release; std::string path; std::string gamemods_path; std::set addon_mods_paths; @@ -41,9 +42,9 @@ struct SubgameSpec std::set(), const std::string &name = "", const std::string &menuicon_path = "", - const std::string &author = "") : + const std::string &author = "", int release = 0) : id(id), - name(name), author(author), path(path), + name(name), author(author), release(release), path(path), gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths), menuicon_path(menuicon_path) { diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 241427709..812fdffe7 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -443,33 +443,37 @@ int ModApiMainMenu::l_get_games(lua_State *L) lua_newtable(L); int top_lvl2 = lua_gettop(L); - lua_pushstring(L, "id"); - lua_pushstring(L, game.id.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "id"); + lua_pushstring(L, game.id.c_str()); + lua_settable(L, top_lvl2); - lua_pushstring(L, "path"); - lua_pushstring(L, game.path.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "path"); + lua_pushstring(L, game.path.c_str()); + lua_settable(L, top_lvl2); - lua_pushstring(L, "type"); - lua_pushstring(L, "game"); - lua_settable(L, top_lvl2); + lua_pushstring(L, "type"); + lua_pushstring(L, "game"); + lua_settable(L, top_lvl2); - lua_pushstring(L, "gamemods_path"); - lua_pushstring(L, game.gamemods_path.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "gamemods_path"); + lua_pushstring(L, game.gamemods_path.c_str()); + lua_settable(L, top_lvl2); - lua_pushstring(L, "name"); - lua_pushstring(L, game.name.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "name"); + lua_pushstring(L, game.name.c_str()); + lua_settable(L, top_lvl2); - lua_pushstring(L, "author"); - lua_pushstring(L, game.author.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "author"); + lua_pushstring(L, game.author.c_str()); + lua_settable(L, top_lvl2); - lua_pushstring(L, "menuicon_path"); - lua_pushstring(L, game.menuicon_path.c_str()); - lua_settable(L, top_lvl2); + lua_pushstring(L, "release"); + lua_pushinteger(L, game.release); + lua_settable(L, top_lvl2); + + lua_pushstring(L, "menuicon_path"); + lua_pushstring(L, game.menuicon_path.c_str()); + lua_settable(L, top_lvl2); lua_pushstring(L, "addon_mods_paths"); lua_newtable(L); @@ -508,6 +512,9 @@ int ModApiMainMenu::l_get_content_info(lua_State *L) lua_pushstring(L, spec.author.c_str()); lua_setfield(L, -2, "author"); + lua_pushinteger(L, spec.release); + lua_setfield(L, -2, "release"); + lua_pushstring(L, spec.desc.c_str()); lua_setfield(L, -2, "description"); @@ -1036,6 +1043,10 @@ int ModApiMainMenu::l_get_package_list(lua_State *L) lua_pushstring(L, package.url.c_str()); lua_settable (L, top_lvl2); + lua_pushstring(L, "release"); + lua_pushinteger(L, package.release); + lua_settable (L, top_lvl2); + lua_settable(L, top); index++; }