System: Store game hash as well as serial

This commit is contained in:
Stenzek
2023-05-15 23:38:37 +10:00
parent 7681551544
commit 9aa6c24620
20 changed files with 243 additions and 211 deletions

View File

@ -470,7 +470,7 @@ void Achievements::Initialize()
s_logged_in = (!s_username.empty() && !s_api_token.empty());
if (System::IsValid())
GameChanged(System::GetRunningPath(), nullptr);
GameChanged(System::GetDiscPath(), nullptr);
}
void Achievements::UpdateSettings(const Settings& old_config)
@ -2142,7 +2142,7 @@ void Achievements::RAIntegration::RACallbackRebuildMenu()
void Achievements::RAIntegration::RACallbackEstimateTitle(char* buf)
{
StringUtil::Strlcpy(buf, System::GetRunningTitle(), 256);
StringUtil::Strlcpy(buf, System::GetGameTitle(), 256);
}
void Achievements::RAIntegration::RACallbackResetEmulator()

View File

@ -570,8 +570,8 @@ void CommonHost::UpdateDiscordPresence(bool rich_presence_only)
SmallString details_string;
if (!System::IsShutdown())
{
details_string.AppendFormattedString("%s (%s)", System::GetRunningTitle().c_str(),
System::GetRunningSerial().c_str());
details_string.AppendFormattedString("%s (%s)", System::GetGameTitle().c_str(),
System::GetGameSerial().c_str());
}
else
{
@ -635,7 +635,7 @@ static void HotkeyLoadStateSlot(bool global, s32 slot)
if (!System::IsValid())
return;
if (!global && System::GetRunningSerial().empty())
if (!global && System::GetGameSerial().empty())
{
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot load state for game without serial."),
5.0f);
@ -643,7 +643,7 @@ static void HotkeyLoadStateSlot(bool global, s32 slot)
}
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot));
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
if (!FileSystem::FileExists(path.c_str()))
{
Host::AddKeyedOSDMessage("LoadState",
@ -659,7 +659,7 @@ static void HotkeySaveStateSlot(bool global, s32 slot)
if (!System::IsValid())
return;
if (!global && System::GetRunningSerial().empty())
if (!global && System::GetGameSerial().empty())
{
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot save state for game without serial."),
5.0f);
@ -667,7 +667,7 @@ static void HotkeySaveStateSlot(bool global, s32 slot)
}
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot));
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
System::SaveState(path.c_str(), g_settings.create_save_state_backups);
}

View File

@ -654,8 +654,8 @@ void FullscreenUI::OnRunningGameChanged()
if (!IsInitialized())
return;
const std::string& path = System::GetRunningPath();
const std::string& serial = System::GetRunningSerial();
const std::string& path = System::GetDiscPath();
const std::string& serial = System::GetGameSerial();
if (!serial.empty())
s_current_game_subtitle = fmt::format("{0} - {1}", serial, Path::GetFileName(path));
else
@ -963,7 +963,7 @@ void FullscreenUI::DoChangeDiscFromFile()
};
OpenFileSelector(ICON_FA_COMPACT_DISC " Select Disc Image", false, std::move(callback), GetDiscImageFilters(),
std::string(Path::GetDirectory(System::GetRunningPath())));
std::string(Path::GetDirectory(System::GetDiscPath())));
}
void FullscreenUI::DoChangeDisc()
@ -1010,7 +1010,7 @@ void FullscreenUI::DoCheatsMenu()
{
if (!System::LoadCheatListFromDatabase() || ((cl = System::GetCheatList()) == nullptr))
{
Host::AddKeyedOSDMessage("load_cheat_list", fmt::format("No cheats found for {}.", System::GetRunningTitle()),
Host::AddKeyedOSDMessage("load_cheat_list", fmt::format("No cheats found for {}.", System::GetGameTitle()),
10.0f);
ReturnToMainWindow();
return;
@ -2325,14 +2325,14 @@ void FullscreenUI::SwitchToGameSettingsForSerial(const std::string_view& serial)
void FullscreenUI::SwitchToGameSettings()
{
if (System::GetRunningSerial().empty())
if (System::GetGameSerial().empty())
return;
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(System::GetRunningPath().c_str());
const GameList::Entry* entry = GameList::GetEntryForPath(System::GetDiscPath().c_str());
if (!entry)
{
SwitchToGameSettingsForSerial(System::GetRunningSerial());
SwitchToGameSettingsForSerial(System::GetGameSerial());
return;
}
@ -4561,12 +4561,12 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
// title info
{
const std::string& title = System::GetRunningTitle();
const std::string& serial = System::GetRunningSerial();
const std::string& title = System::GetGameTitle();
const std::string& serial = System::GetGameSerial();
if (!serial.empty())
buffer.Format("%s - ", serial.c_str());
buffer.AppendString(Path::GetFileName(System::GetRunningPath()));
buffer.AppendString(Path::GetFileName(System::GetDiscPath()));
const ImVec2 title_size(
g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f, title.c_str()));
@ -4624,7 +4624,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
DrawShadowedText(dl, g_large_font, time_pos, IM_COL32(255, 255, 255, 255), buffer.GetCharArray(),
buffer.GetCharArray() + buffer.GetLength());
const std::string& serial = System::GetRunningSerial();
const std::string& serial = System::GetGameSerial();
if (!serial.empty())
{
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
@ -4674,7 +4674,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
case PauseSubMenu::None:
{
// NOTE: Menu close must come first, because otherwise VM destruction options will race.
const bool has_game = System::IsValid() && !System::GetRunningSerial().empty();
const bool has_game = System::IsValid() && !System::GetGameSerial().empty();
if (ActiveButton(ICON_FA_PLAY " Resume Game", false) || WantsToCloseMenu())
ClosePauseMenu();
@ -4698,7 +4698,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
}
if (ActiveButton(ICON_FA_FROWN_OPEN " Cheat List", false,
!System::GetRunningSerial().empty() && !Achievements::ChallengeModeActive()))
!System::GetGameSerial().empty() && !Achievements::ChallengeModeActive()))
{
s_current_main_window = MainWindowType::None;
DoCheatsMenu();
@ -4944,7 +4944,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
s_save_state_selector_game_path = {};
s_save_state_selector_loading = is_loading;
s_save_state_selector_resuming = false;
if (PopulateSaveStateListEntries(System::GetRunningTitle().c_str(), System::GetRunningSerial().c_str()) > 0)
if (PopulateSaveStateListEntries(System::GetGameTitle().c_str(), System::GetGameSerial().c_str()) > 0)
{
s_save_state_selector_open = true;
return true;
@ -5380,7 +5380,7 @@ void FullscreenUI::DoSaveState(s32 slot, bool global)
return;
std::string filename(global ? System::GetGlobalSaveStateFileName(slot) :
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot));
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
System::SaveState(filename.c_str(), g_settings.create_save_state_backups);
});
}
@ -6172,7 +6172,7 @@ GPUTexture* FullscreenUI::GetCoverForCurrentGame()
{
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(System::GetRunningPath().c_str());
const GameList::Entry* entry = GameList::GetEntryForPath(System::GetDiscPath().c_str());
if (!entry)
return s_fallback_disc_texture.get();

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "game_list.h"
@ -18,13 +18,14 @@
#include "core/psf_loader.h"
#include "core/settings.h"
#include "core/system.h"
#include "tinyxml2.h"
#include "util/cd_image.h"
#include <algorithm>
#include <array>
#include <cctype>
#include <ctime>
#include <string_view>
#include <tinyxml2.h>
#include <type_traits>
#include <unordered_map>
#include <utility>
Log_SetChannel(GameList);
@ -37,7 +38,7 @@ namespace GameList {
enum : u32
{
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
GAME_LIST_CACHE_VERSION = 32,
GAME_LIST_CACHE_VERSION = 33,
PLAYED_TIME_SERIAL_LENGTH = 32,
PLAYED_TIME_LAST_TIME_LENGTH = 20, // uint64
@ -55,6 +56,8 @@ struct PlayedTimeEntry
using CacheMap = UnorderedStringMap<Entry>;
using PlayedTimeMap = UnorderedStringMap<PlayedTimeEntry>;
static_assert(std::is_same_v<decltype(Entry::hash), System::GameHash>);
static bool GetExeListEntry(const std::string& path, Entry* entry);
static bool GetPsfListEntry(const std::string& path, Entry* entry);
static bool GetDiscListEntry(const std::string& path, Entry* entry);
@ -204,8 +207,11 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
entry->type = EntryType::Disc;
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
std::string id;
System::GetGameDetailsFromImage(cdi.get(), &id, &entry->hash);
// try the database first
const GameDatabase::Entry* dentry = GameDatabase::GetEntryForDisc(cdi.get());
const GameDatabase::Entry* dentry = GameDatabase::GetEntryForId(id);
if (dentry)
{
// pull from database
@ -227,7 +233,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
const std::string display_name(FileSystem::GetDisplayNameFromPath(path));
// no game code, so use the filename title
entry->serial = System::GetGameIdFromImage(cdi.get(), true);
entry->serial = std::move(id);
entry->title = Path::GetFileTitle(display_name);
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
entry->release_date = 0;
@ -239,9 +245,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
}
// region detection
entry->region = System::GetRegionFromSystemArea(cdi.get());
if (entry->region == DiscRegion::Other)
entry->region = System::GetRegionForSerial(entry->serial);
entry->region = System::GetRegionForImage(cdi.get());
if (cdi->HasSubImages())
{
@ -310,12 +314,12 @@ bool GameList::LoadEntriesFromCache(ByteStream* stream)
if (!stream->ReadU8(&type) || !stream->ReadU8(&region) || !stream->ReadSizePrefixedString(&path) ||
!stream->ReadSizePrefixedString(&ge.serial) || !stream->ReadSizePrefixedString(&ge.title) ||
!stream->ReadSizePrefixedString(&ge.genre) || !stream->ReadSizePrefixedString(&ge.publisher) ||
!stream->ReadSizePrefixedString(&ge.developer) || !stream->ReadU64(&ge.total_size) ||
!stream->ReadU64(reinterpret_cast<u64*>(&ge.last_modified_time)) || !stream->ReadU64(&ge.release_date) ||
!stream->ReadU32(&ge.supported_controllers) || !stream->ReadU8(&ge.min_players) ||
!stream->ReadU8(&ge.max_players) || !stream->ReadU8(&ge.min_blocks) || !stream->ReadU8(&ge.max_blocks) ||
!stream->ReadU8(&compatibility_rating) || region >= static_cast<u8>(DiscRegion::Count) ||
type >= static_cast<u8>(EntryType::Count) ||
!stream->ReadSizePrefixedString(&ge.developer) || !stream->ReadU64(&ge.hash) ||
!stream->ReadU64(&ge.total_size) || !stream->ReadU64(reinterpret_cast<u64*>(&ge.last_modified_time)) ||
!stream->ReadU64(&ge.release_date) || !stream->ReadU32(&ge.supported_controllers) ||
!stream->ReadU8(&ge.min_players) || !stream->ReadU8(&ge.max_players) || !stream->ReadU8(&ge.min_blocks) ||
!stream->ReadU8(&ge.max_blocks) || !stream->ReadU8(&compatibility_rating) ||
region >= static_cast<u8>(DiscRegion::Count) || type >= static_cast<u8>(EntryType::Count) ||
compatibility_rating >= static_cast<u8>(GameDatabase::CompatibilityRating::Count))
{
Log_WarningPrintf("Game list cache entry is corrupted");
@ -348,6 +352,7 @@ bool GameList::WriteEntryToCache(const Entry* entry)
result &= s_cache_write_stream->WriteSizePrefixedString(entry->genre);
result &= s_cache_write_stream->WriteSizePrefixedString(entry->publisher);
result &= s_cache_write_stream->WriteSizePrefixedString(entry->developer);
result &= s_cache_write_stream->WriteU64(entry->hash);
result &= s_cache_write_stream->WriteU64(entry->total_size);
result &= s_cache_write_stream->WriteU64(entry->last_modified_time);
result &= s_cache_write_stream->WriteU64(entry->release_date);

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
@ -37,6 +37,7 @@ struct Entry
std::string genre;
std::string publisher;
std::string developer;
u64 hash = 0;
u64 total_size = 0;
std::time_t last_modified_time = 0;
std::time_t last_played_time = 0;

View File

@ -621,11 +621,11 @@ void SaveStateSelectorUI::RefreshList()
if (System::IsShutdown())
return;
if (!System::GetRunningSerial().empty())
if (!System::GetGameSerial().empty())
{
for (s32 i = 1; i <= System::PER_GAME_SAVE_STATE_SLOTS; i++)
{
std::string path(System::GetGameSaveStateFileName(System::GetRunningSerial(), i));
std::string path(System::GetGameSaveStateFileName(System::GetGameSerial(), i));
std::optional<ExtendedSaveStateInfo> ssi = System::GetExtendedSaveStateInfo(path.c_str());
ListEntry li;