game_list.h (5978B)
1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "game_database.h" 7 #include "types.h" 8 9 #include "util/cd_image.h" 10 11 #include "common/small_string.h" 12 13 #include <ctime> 14 #include <functional> 15 #include <mutex> 16 #include <span> 17 #include <string> 18 19 class ByteStream; 20 class ProgressCallback; 21 22 struct SystemBootParameters; 23 24 namespace GameList { 25 enum class EntryType 26 { 27 Disc, 28 DiscSet, 29 PSExe, 30 Playlist, 31 PSF, 32 Count 33 }; 34 35 struct Entry 36 { 37 EntryType type = EntryType::Disc; 38 DiscRegion region = DiscRegion::Other; 39 40 std::string path; 41 std::string serial; 42 std::string title; 43 std::string disc_set_name; 44 std::string genre; 45 std::string publisher; 46 std::string developer; 47 u64 hash = 0; 48 s64 file_size = 0; 49 u64 uncompressed_size = 0; 50 std::time_t last_modified_time = 0; 51 std::time_t last_played_time = 0; 52 std::time_t total_played_time = 0; 53 54 u64 release_date = 0; 55 u16 supported_controllers = static_cast<u16>(~0u); 56 u8 min_players = 1; 57 u8 max_players = 1; 58 u8 min_blocks = 0; 59 u8 max_blocks = 0; 60 s8 disc_set_index = -1; 61 bool disc_set_member = false; 62 bool has_custom_title = false; 63 bool has_custom_region = false; 64 65 GameDatabase::CompatibilityRating compatibility = GameDatabase::CompatibilityRating::Unknown; 66 67 size_t GetReleaseDateString(char* buffer, size_t buffer_size) const; 68 69 ALWAYS_INLINE bool IsDisc() const { return (type == EntryType::Disc); } 70 ALWAYS_INLINE bool IsDiscSet() const { return (type == EntryType::DiscSet); } 71 ALWAYS_INLINE EntryType GetSortType() const { return (type == EntryType::DiscSet) ? EntryType::Disc : type; } 72 }; 73 74 using EntryList = std::vector<Entry>; 75 76 const char* GetEntryTypeName(EntryType type); 77 const char* GetEntryTypeDisplayName(EntryType type); 78 79 bool IsScannableFilename(std::string_view path); 80 81 /// Populates a game list entry struct with information from the iso/elf. 82 /// Do *not* call while the system is running, it will mess with CDVD state. 83 bool PopulateEntryFromPath(const std::string& path, Entry* entry); 84 85 // Game list access. It's the caller's responsibility to hold the lock while manipulating the entry in any way. 86 std::unique_lock<std::recursive_mutex> GetLock(); 87 const Entry* GetEntryByIndex(u32 index); 88 const Entry* GetEntryForPath(std::string_view path); 89 const Entry* GetEntryBySerial(std::string_view serial); 90 const Entry* GetEntryBySerialAndHash(std::string_view serial, u64 hash); 91 std::vector<const Entry*> GetDiscSetMembers(std::string_view disc_set_name, bool sort_by_most_recent = false); 92 const Entry* GetFirstDiscSetMember(std::string_view disc_set_name); 93 u32 GetEntryCount(); 94 95 bool IsGameListLoaded(); 96 97 /// Populates the game list with files in the configured directories. 98 /// If invalidate_cache is set, all files will be re-scanned. 99 /// If only_cache is set, no new files will be scanned, only those present in the cache. 100 void Refresh(bool invalidate_cache, bool only_cache = false, ProgressCallback* progress = nullptr); 101 102 /// Moves the current game list, which can be temporarily displayed in the UI until refresh completes. 103 /// The caller **must** call Refresh() afterward, otherwise it will be permanently lost. 104 EntryList TakeEntryList(); 105 106 /// Add played time for the specified serial. 107 void AddPlayedTimeForSerial(const std::string& serial, std::time_t last_time, std::time_t add_time); 108 void ClearPlayedTimeForSerial(const std::string& serial); 109 110 /// Returns the total time played for a game. Requires the game to be scanned in the list. 111 std::time_t GetCachedPlayedTimeForSerial(const std::string& serial); 112 113 /// Formats a timestamp to something human readable (e.g. Today, Yesterday, 10/11/12). 114 TinyString FormatTimestamp(std::time_t timestamp); 115 116 /// Formats a timespan to something human readable (e.g. 1h2m3s or 1 hour). 117 TinyString FormatTimespan(std::time_t timespan, bool long_format = false); 118 119 std::string GetCoverImagePathForEntry(const Entry* entry); 120 std::string GetCoverImagePath(const std::string& path, const std::string& serial, const std::string& title); 121 std::string GetNewCoverImagePathForEntry(const Entry* entry, const char* new_filename, bool use_serial); 122 123 /// Returns a list of (title, entry) for entries matching serials. Titles will match the gamedb title, 124 /// except when two files have the same serial, in which case the filename will be used instead. 125 std::vector<std::pair<std::string, const Entry*>> 126 GetMatchingEntriesForSerial(const std::span<const std::string> serials); 127 128 /// Downloads covers using the specified URL templates. By default, covers are saved by title, but this can be changed 129 /// with the use_serial parameter. save_callback optionall takes the entry and the path the new cover is saved to. 130 bool DownloadCovers(const std::vector<std::string>& url_templates, bool use_serial = false, 131 ProgressCallback* progress = nullptr, 132 std::function<void(const Entry*, std::string)> save_callback = {}); 133 134 // Custom properties support 135 void SaveCustomTitleForPath(const std::string& path, const std::string& custom_title); 136 void SaveCustomRegionForPath(const std::string& path, const std::optional<DiscRegion> custom_region); 137 std::string GetCustomTitleForPath(const std::string_view path); 138 std::optional<DiscRegion> GetCustomRegionForPath(const std::string_view path); 139 140 /// The purpose of this cache is to stop us trying to constantly extract memory card icons, when we know a game 141 /// doesn't have any saves yet. It caches the serial:memcard_timestamp pair, and only tries extraction when the 142 /// timestamp of the memory card has changed. 143 std::string GetGameIconPath(std::string_view serial, std::string_view path); 144 void ReloadMemcardTimestampCache(); 145 146 }; // namespace GameList 147 148 namespace Host { 149 /// Asynchronously starts refreshing the game list. 150 void RefreshGameListAsync(bool invalidate_cache); 151 152 /// Cancels game list refresh, if there is one in progress. 153 void CancelGameListRefresh(); 154 } // namespace Host