From 30cbec7ad5de5cde2f63f669139ea06e9e925aa7 Mon Sep 17 00:00:00 2001 From: Maufeat Date: Mon, 19 Jan 2026 04:18:55 +0100 Subject: [core/hle] Adds sorting game titles and prevents hard crashes in qlaunch (#3330) Adds correct sorting in qlaunch (tested with FW 19 and FW20-21) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3330 Reviewed-by: DraVee Reviewed-by: CamilleLaVey Reviewed-by: MaranBr Co-authored-by: Maufeat Co-committed-by: Maufeat --- src/core/launch_timestamp_cache.cpp | 55 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) (limited to 'src/core/launch_timestamp_cache.cpp') diff --git a/src/core/launch_timestamp_cache.cpp b/src/core/launch_timestamp_cache.cpp index 5a154a5c2f..037992d69a 100644 --- a/src/core/launch_timestamp_cache.cpp +++ b/src/core/launch_timestamp_cache.cpp @@ -22,10 +22,12 @@ namespace Core::LaunchTimestampCache { namespace { using CacheMap = std::unordered_map; +using CountMap = std::unordered_map; -std::mutex mutex; -CacheMap cache; -bool loaded = false; +std::mutex g_mutex; +CacheMap g_cache; +CountMap g_counts; +bool g_loaded = false; std::filesystem::path GetCachePath() { return Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "launched.json"; @@ -54,11 +56,11 @@ bool WriteStringToFile(const std::filesystem::path& path, const std::string& dat } void Load() { - if (loaded) { + if (g_loaded) { return; } - loaded = true; + g_loaded = true; const auto path = GetCachePath(); if (!std::filesystem::exists(path)) { @@ -86,19 +88,31 @@ void Load() { } catch (...) { continue; } - if (value.is_number_integer()) { - cache[key] = value.get(); + if (value.is_object()) { + if (value.contains("timestamp") && value["timestamp"].is_number_integer()) { + g_cache[key] = value["timestamp"].get(); + } + if (value.contains("launch_count") && value["launch_count"].is_number_unsigned()) { + g_counts[key] = value["launch_count"].get(); + } + } else if (value.is_number_integer()) { + // Legacy format: raw timestamp only + g_cache[key] = value.get(); } } } catch (const std::exception& e) { - LOG_WARNING(Core, "Failed to parse launch timestamp cache"); + LOG_WARNING(Core, "Failed to parse launch timestamp cache: {}", e.what()); } } void Save() { nlohmann::json json = nlohmann::json::object(); - for (const auto& [key, value] : cache) { - json[fmt::format("{:016X}", key)] = value; + for (const auto& [key, value] : g_cache) { + nlohmann::json entry = nlohmann::json::object(); + entry["timestamp"] = value; + const auto count_it = g_counts.find(key); + entry["launch_count"] = count_it != g_counts.end() ? count_it->second : 0; + json[fmt::format("{:016X}", key)] = entry; } const auto path = GetCachePath(); @@ -115,21 +129,32 @@ s64 NowSeconds() { } // namespace void SaveLaunchTimestamp(u64 title_id) { - std::scoped_lock lk{mutex}; + std::scoped_lock lk{g_mutex}; Load(); - cache[title_id] = NowSeconds(); + g_cache[title_id] = NowSeconds(); + g_counts[title_id] = g_counts[title_id] + 1; Save(); } s64 GetLaunchTimestamp(u64 title_id) { - std::scoped_lock lk{mutex}; + std::scoped_lock lk{g_mutex}; Load(); - const auto it = cache.find(title_id); - if (it != cache.end()) { + const auto it = g_cache.find(title_id); + if (it != g_cache.end()) { return it->second; } // we need a timestamp, i decided on 01/01/2026 00:00 return 1767225600; } +u64 GetLaunchCount(u64 title_id) { + std::scoped_lock lk{g_mutex}; + Load(); + const auto it = g_counts.find(title_id); + if (it != g_counts.end()) { + return it->second; + } + return 0; +} + } // namespace Core::LaunchTimestampCache -- cgit v1.2.3