From 6c6e48f00607233ae6cb3cf37fa4544d727aacf2 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 30 Mar 2024 11:06:28 +0100 Subject: [PATCH] Move values the mainmenu caches to dedicated files (#14433) --- builtin/mainmenu/common.lua | 35 ++++++++-- builtin/mainmenu/content/update_detector.lua | 21 ++++-- builtin/mainmenu/dlg_reinstall_mtg.lua | 23 ++++-- builtin/mainmenu/dlg_version_info.lua | 23 +++--- builtin/mainmenu/init.lua | 2 - builtin/mainmenu/misc.lua | 6 -- builtin/mainmenu/serverlistmgr.lua | 70 +++++++++++-------- builtin/mainmenu/tests/serverlistmgr_spec.lua | 3 +- builtin/settingtypes.txt | 15 +--- doc/menu_lua_api.md | 4 -- src/defaultsettings.cpp | 5 +- src/gui/guiEngine.cpp | 2 + src/script/lua_api/l_mainmenu.cpp | 40 ----------- src/script/lua_api/l_mainmenu.h | 4 -- src/script/scripting_mainmenu.cpp | 18 +++-- src/script/scripting_mainmenu.h | 3 + 16 files changed, 142 insertions(+), 132 deletions(-) delete mode 100644 builtin/mainmenu/misc.lua diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index 471360581..16c5c9d95 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -18,6 +18,26 @@ -- Global menu data menudata = {} +-- located in user cache path, for remembering this like e.g. last update check +cache_settings = Settings(core.get_cache_path() .. DIR_DELIM .. "common.conf") + +--- Checks if the given key contains a timestamp less than a certain age. +--- Pair this with a call to `cache_settings:set(key, tostring(os.time()))` +--- after successfully refreshing the cache. +--- @param key Name of entry in cache_settings +--- @param max_age Age to check against, in seconds +--- @return true if the max age is not reached +function check_cache_age(key, max_age) + local time_now = os.time() + local time_checked = tonumber(cache_settings:get(key)) or 0 + return time_now - time_checked < max_age +end + +function core.on_before_close() + -- called before the menu is closed, either exit or to join a game + cache_settings:write() +end + -- Local cached values local min_supp_proto, max_supp_proto @@ -27,6 +47,16 @@ function common_update_cached_supp_proto() end common_update_cached_supp_proto() +-- Other global functions + +function core.sound_stop(handle, ...) + return handle:stop(...) +end + +function os.tmpname() + error('do not use') -- instead: core.get_temp_path() +end + -- Menu helper functions local function render_client_count(n) @@ -140,11 +170,6 @@ function render_serverlist_row(spec) return table.concat(details, ",") end ---------------------------------------------------------------------------------- -os.tmpname = function() - error('do not use') -- instead use core.get_temp_path() -end --------------------------------------------------------------------------------- function menu_render_worldlist() local retval = {} diff --git a/builtin/mainmenu/content/update_detector.lua b/builtin/mainmenu/content/update_detector.lua index 558a0fabb..f70220224 100644 --- a/builtin/mainmenu/content/update_detector.lua +++ b/builtin/mainmenu/content/update_detector.lua @@ -26,13 +26,23 @@ if not core.get_http_api then end +assert(core.create_dir(core.get_cache_path() .. DIR_DELIM .. "cdb")) +local cache_file_path = core.get_cache_path() .. DIR_DELIM .. "cdb" .. DIR_DELIM .. "updates.json" local has_fetched = false local latest_releases do - local tmp = core.get_once("cdb_latest_releases") - if tmp then - latest_releases = core.deserialize(tmp, true) - has_fetched = latest_releases ~= nil + if check_cache_age("cdb_updates_last_checked", 3 * 3600) then + local f = io.open(cache_file_path, "r") + local data = "" + if f then + data = f:read("*a") + f:close() + end + data = data ~= "" and core.parse_json(data) or nil + if type(data) == "table" then + latest_releases = data + has_fetched = true + end end end @@ -97,7 +107,8 @@ local function fetch() return end latest_releases = lowercase_keys(releases) - core.set_once("cdb_latest_releases", core.serialize(latest_releases)) + core.safe_file_write(cache_file_path, core.write_json(latest_releases)) + cache_settings:set("cdb_updates_last_checked", tostring(os.time())) if update_detector.get_count() > 0 then local maintab = ui.find_by_name("maintab") diff --git a/builtin/mainmenu/dlg_reinstall_mtg.lua b/builtin/mainmenu/dlg_reinstall_mtg.lua index 77652e968..c86c75d2b 100644 --- a/builtin/mainmenu/dlg_reinstall_mtg.lua +++ b/builtin/mainmenu/dlg_reinstall_mtg.lua @@ -15,15 +15,30 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +---- IMPORTANT ---- +-- This whole file can be removed after a while. +-- It was only directly useful for upgrades from 5.7.0 to 5.8.0, but +-- maybe some odd fellow directly upgrades from 5.6.1 to 5.9.0 in the future... +-- see in case it's not obvious +---- ---- + +local SETTING_NAME = "no_mtg_notification" + function check_reinstall_mtg() - if core.settings:get_bool("no_mtg_notification") then + -- used to be in minetest.conf + if core.settings:get_bool(SETTING_NAME) then + cache_settings:set_bool(SETTING_NAME, true) + core.settings:remove(SETTING_NAME) + end + + if cache_settings:get_bool(SETTING_NAME) then return end local games = core.get_games() for _, game in ipairs(games) do if game.id == "minetest" then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool(SETTING_NAME, true) return end end @@ -37,7 +52,7 @@ function check_reinstall_mtg() end end if not mtg_world_found then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool(SETTING_NAME, true) return end @@ -87,7 +102,7 @@ local function buttonhandler(this, fields) end if fields.dismiss then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool("no_mtg_notification", true) this:delete() return true end diff --git a/builtin/mainmenu/dlg_version_info.lua b/builtin/mainmenu/dlg_version_info.lua index 98085ee4a..483cd30bd 100644 --- a/builtin/mainmenu/dlg_version_info.lua +++ b/builtin/mainmenu/dlg_version_info.lua @@ -51,12 +51,13 @@ end local function version_info_buttonhandler(this, fields) if fields.version_check_remind then -- Erase last known, user will be reminded again at next check - core.settings:set("update_last_known", "") + cache_settings:set("update_last_known", "") this:delete() return true end if fields.version_check_never then - core.settings:set("update_last_checked", "disabled") + -- clear checked URL + core.settings:set("update_information_url", "") this:delete() return true end @@ -116,7 +117,7 @@ local function on_version_info_received(json) return end - local known_update = tonumber(core.settings:get("update_last_known")) or 0 + local known_update = tonumber(cache_settings:get("update_last_known")) or 0 -- Format: MMNNPPP (Major, Minor, Patch) local new_number = type(json.latest) == "table" and json.latest.version_code @@ -135,7 +136,7 @@ local function on_version_info_received(json) return end - core.settings:set("update_last_known", tostring(new_number)) + cache_settings:set("update_last_known", tostring(new_number)) -- Show version info dialog (once) maintab:hide() @@ -149,20 +150,20 @@ end function check_new_version() local url = core.settings:get("update_information_url") - if core.settings:get("update_last_checked") == "disabled" or - url == "" then + if url == "" then -- Never show any updates return end - local time_now = os.time() - local time_checked = tonumber(core.settings:get("update_last_checked")) or 0 - if time_now - time_checked < 2 * 24 * 3600 then - -- Check interval of 2 entire days + -- every 2 days + if check_cache_age("update_last_checked", 2 * 24 * 3600) then return end + cache_settings:set("update_last_checked", tostring(os.time())) - core.settings:set("update_last_checked", tostring(time_now)) + -- Clean old leftovers (this can be removed after 5.9.0 or so) + core.settings:remove("update_last_checked") + core.settings:remove("update_last_known") core.handle_async(function(params) local http = core.get_http_api() diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 388ab458d..41885e298 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -28,8 +28,6 @@ local basepath = core.get_builtin_path() defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. DIR_DELIM .. "pack" .. DIR_DELIM -dofile(menupath .. DIR_DELIM .. "misc.lua") - dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua") diff --git a/builtin/mainmenu/misc.lua b/builtin/mainmenu/misc.lua deleted file mode 100644 index 0677e96a3..000000000 --- a/builtin/mainmenu/misc.lua +++ /dev/null @@ -1,6 +0,0 @@ - --- old non-method sound function - -function core.sound_stop(handle, ...) - return handle:stop(...) -end diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua index ab686ded0..997768c15 100644 --- a/builtin/mainmenu/serverlistmgr.lua +++ b/builtin/mainmenu/serverlistmgr.lua @@ -17,7 +17,7 @@ serverlistmgr = { -- continent code we detected for ourselves - my_continent = core.get_once("continent"), + my_continent = nil, -- list of locally favorites servers favorites = nil, @@ -26,6 +26,15 @@ serverlistmgr = { servers = nil, } +do + if check_cache_age("geoip_last_checked", 3600) then + local tmp = cache_settings:get("geoip") or "" + if tmp:match("^[A-Z][A-Z]$") then + serverlistmgr.my_continent = tmp + end + end +end + -------------------------------------------------------------------------------- -- Efficient data structure for normalizing arbitrary scores attached to objects -- e.g. {{"a", 3.14}, {"b", 3.14}, {"c", 20}, {"d", 0}} @@ -112,6 +121,22 @@ local public_downloading = false local geoip_downloading = false -------------------------------------------------------------------------------- +local function fetch_geoip() + local http = core.get_http_api() + local url = core.settings:get("serverlist_url") .. "/geoip" + + local response = http.fetch_sync({ url = url }) + if not response.succeeded then + return + end + + local retval = core.parse_json(response.data) + if type(retval) ~= "table" then + return + end + return type(retval.continent) == "string" and retval.continent +end + function serverlistmgr.sync() if not serverlistmgr.servers then serverlistmgr.servers = {{ @@ -129,37 +154,23 @@ function serverlistmgr.sync() return end - -- only fetched once per MT instance if not serverlistmgr.my_continent and not geoip_downloading then geoip_downloading = true - core.handle_async( - function(param) - local http = core.get_http_api() - local url = core.settings:get("serverlist_url") .. "/geoip" - - local response = http.fetch_sync({ url = url }) - if not response.succeeded then - return - end - - local retval = core.parse_json(response.data) - return retval and type(retval.continent) == "string" and retval.continent - end, - nil, - function(result) - geoip_downloading = false - if not result then - return - end - serverlistmgr.my_continent = result - core.set_once("continent", result) - -- reorder list if we already have it - if serverlistmgr.servers then - serverlistmgr.servers = order_server_list(serverlistmgr.servers) - core.event_handler("Refresh") - end + core.handle_async(fetch_geoip, nil, function(result) + geoip_downloading = false + if not result then + return end - ) + serverlistmgr.my_continent = result + cache_settings:set("geoip", result) + cache_settings:set("geoip_last_checked", tostring(os.time())) + + -- re-sort list if applicable + if serverlistmgr.servers then + serverlistmgr.servers = order_server_list(serverlistmgr.servers) + core.event_handler("Refresh") + end + end) end if public_downloading then @@ -167,6 +178,7 @@ function serverlistmgr.sync() end public_downloading = true + -- note: this isn't cached because it's way too dynamic core.handle_async( function(param) local http = core.get_http_api() diff --git a/builtin/mainmenu/tests/serverlistmgr_spec.lua b/builtin/mainmenu/tests/serverlistmgr_spec.lua index 25e208d10..21ce8a226 100644 --- a/builtin/mainmenu/tests/serverlistmgr_spec.lua +++ b/builtin/mainmenu/tests/serverlistmgr_spec.lua @@ -1,5 +1,6 @@ -_G.core = {get_once = function(_) end} +_G.core = {} _G.unpack = table.unpack +_G.check_cache_age = function() return false end _G.serverlistmgr = {} dofile("builtin/common/vector.lua") diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 517a83012..b039780bc 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -776,6 +776,7 @@ serverlist_url (Serverlist URL) string servers.minetest.net enable_split_login_register (Enable split login/register) bool true # URL to JSON file which provides information about the newest Minetest release +# If this is empty the engine will never check for updates. update_information_url (Update information URL) string https://www.minetest.net/release_info.json [*Server] @@ -2291,20 +2292,6 @@ show_advanced (Show advanced settings) bool false # Changing this setting requires a restart. enable_sound (Sound) bool true -# Unix timestamp (integer) of when the client last checked for an update -# Set this value to "disabled" to never check for updates. -update_last_checked (Last update check) string - -# Version number which was last seen during an update check. -# -# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch -# Ex: 5.5.0 is 005005000 -update_last_known (Last known version update) int 0 - -# If this is set to true, the user will never (again) be shown the -# "reinstall Minetest Game" notification. -no_mtg_notification (Don't show "reinstall Minetest Game" notification) bool false - # Key for moving the player forward. keymap_forward (Forward key) key KEY_KEY_W diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index 3e8bb3583..979ef868f 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -55,10 +55,6 @@ Functions * Android only. Shares file using the share popup * `core.get_version()` (possible in async calls) * returns current core version -* `core.set_once(key, value)`: - * save a string value that persists even if menu is closed -* `core.get_once(key)`: - * get a string value saved by above function, or `nil` diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index e018e591b..bb50a00aa 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -356,11 +356,10 @@ void set_default_settings() settings->setDefault("contentdb_flag_blacklist", "nonfree, desktop_default"); #endif - settings->setDefault("update_information_url", "https://www.minetest.net/release_info.json"); #if ENABLE_UPDATE_CHECKER - settings->setDefault("update_last_checked", ""); + settings->setDefault("update_information_url", "https://www.minetest.net/release_info.json"); #else - settings->setDefault("update_last_checked", "disabled"); + settings->setDefault("update_information_url", ""); #endif // Server diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index ea74f6afa..4d35f38ab 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -369,6 +369,8 @@ void GUIEngine::run() #endif } + m_script->beforeClose(); + RenderingEngine::autosaveScreensizeAndCo(initial_screen_size, initial_window_maximized); } diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index c98f974d2..fdb9e3740 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1080,44 +1080,6 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L) return 1; } -/******************************************************************************/ -// this is intentionally a global and not part of MainMenuScripting or such -namespace { - std::unordered_map once_values; - std::mutex once_mutex; -} - -int ModApiMainMenu::l_set_once(lua_State *L) -{ - std::string key = readParam(L, 1); - if (lua_isnil(L, 2)) - return 0; - std::string value = readParam(L, 2); - - { - MutexAutoLock lock(once_mutex); - once_values[key] = value; - } - - return 0; -} - -int ModApiMainMenu::l_get_once(lua_State *L) -{ - std::string key = readParam(L, 1); - - { - MutexAutoLock lock(once_mutex); - auto it = once_values.find(key); - if (it == once_values.end()) - lua_pushnil(L); - else - lua_pushstring(L, it->second.c_str()); - } - - return 1; -} - /******************************************************************************/ void ModApiMainMenu::Initialize(lua_State *L, int top) { @@ -1170,8 +1132,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(open_dir); API_FCT(share_file); API_FCT(do_async_callback); - API_FCT(set_once); - API_FCT(get_once); } /******************************************************************************/ diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 780e3b5b8..5535d2170 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -166,10 +166,6 @@ private: static int l_share_file(lua_State *L); - static int l_set_once(lua_State *L); - - static int l_get_once(lua_State *L); - // async static int l_do_async_callback(lua_State *L); diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp index d88082b7d..e5cb81cab 100644 --- a/src/script/scripting_mainmenu.cpp +++ b/src/script/scripting_mainmenu.cpp @@ -58,7 +58,6 @@ MainMenuScripting::MainMenuScripting(GUIEngine* guiengine): infostream << "SCRIPTAPI: Initialized main menu modules" << std::endl; } -/******************************************************************************/ void MainMenuScripting::initializeModApi(lua_State *L, int top) { registerLuaClasses(L, top); @@ -79,20 +78,31 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top) asyncEngine.initialize(MAINMENU_NUM_ASYNC_THREADS); } -/******************************************************************************/ void MainMenuScripting::registerLuaClasses(lua_State *L, int top) { LuaSettings::Register(L); MainMenuSoundHandle::Register(L); } -/******************************************************************************/ +void MainMenuScripting::beforeClose() +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "on_before_close"); + + PCALL_RES(lua_pcall(L, 0, 0, error_handler)); + + lua_pop(L, 2); // Pop core, error handler +} + void MainMenuScripting::step() { asyncEngine.step(getStack()); } -/******************************************************************************/ u32 MainMenuScripting::queueAsync(std::string &&serialized_func, std::string &&serialized_param) { diff --git a/src/script/scripting_mainmenu.h b/src/script/scripting_mainmenu.h index 3c329654a..d2e5716e2 100644 --- a/src/script/scripting_mainmenu.h +++ b/src/script/scripting_mainmenu.h @@ -37,6 +37,9 @@ public: // Global step handler to pass back async events void step(); + // Calls core.on_before_close() + void beforeClose(); + // Pass async events from engine to async threads u32 queueAsync(std::string &&serialized_func, std::string &&serialized_param);