azahar/src/citra_qt/game_list_cache.h
Masamune3210 db11399785 citra_qt: cache game list to disk, rescan only on explicit request
Previously the game list rescanned game directories on every launch and
after any event that might have changed game files. This commit replaces
that with a persistent JSON cache so subsequent launches populate the
list instantly from disk.

Key changes:
- game_list_cache.h/cpp: new JSON cache at ConfigDir/game_list_cache.json.
  Keyed by a DirsSignature fingerprint (path + deep_scan for every dir);
  invalidated automatically when the directory list changes.
- GameListWorker: emits CacheEntryReady in parallel with EntryReady,
  carrying raw metadata so entries can be rebuilt without touching ROMs.
- GameList::PopulateAsync: checks cache first. On a hit it rebuilds the
  model synchronously from cached data (PopulateFromCache) with no worker
  thread. On a miss it runs the full scan and saves the new cache in
  DonePopulating.
- GameList::ForceRescan: invalidates the cache then calls PopulateAsync.
- GameList::RefreshPlayTimes: updates only the play-time column in-place;
  called after a game session ends instead of a full rescan.
- QFileSystemWatcher is kept for CIA-install plumbing but is no longer
  connected to any automatic rescan.
- File menu: new "Refresh Game List" action (F5) triggers ForceRescan.
- OnCIAInstallFinished: uses ForceRescan (new title needs a fresh scan).
- OnStopGame: uses RefreshPlayTimes (only play time changed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 16:33:28 -05:00

50 lines
1.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QByteArray>
#include <QString>
#include <QVector>
#include "citra_qt/uisettings.h"
#include "common/common_types.h"
namespace Service::FS {
enum class MediaType : u32;
}
/// Cached metadata for a single game entry, sufficient to rebuild all model columns.
struct GameListCacheEntry {
QString path;
QByteArray smdh; ///< Raw SMDH bytes; empty for games that have no icon data.
u64 program_id = 0;
u64 extdata_id = 0;
Service::FS::MediaType media_type{};
bool is_encrypted = false;
bool can_insert = false;
QString compatibility; ///< Tier string: "0""5" or "99" for not tested.
QString file_type; ///< Human-readable file-type string from the loader.
quint64 file_size = 0;
int game_dir_index = 0; ///< Index into UISettings::values.game_dirs for the parent dir.
};
/**
* Attempts to load the game list cache and validates it against the current game_dirs.
*
* Returns true and populates @p out_entries when the cache exists, parses without error,
* and its stored directory list matches the caller's game_dirs exactly.
* Returns false in all other cases (missing file, parse error, stale dirs).
*/
bool LoadGameListCache(const QVector<UISettings::GameDir>& game_dirs,
QVector<GameListCacheEntry>& out_entries);
/**
* Serialises @p entries to the game list cache file, storing @p game_dirs alongside them
* so that future loads can detect when the directory list has changed.
*/
void SaveGameListCache(const QVector<UISettings::GameDir>& game_dirs,
const QVector<GameListCacheEntry>& entries);
/// Removes the cache file so the next PopulateAsync performs a full scan.
void InvalidateGameListCache();