mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
System: Store game hash as well as serial
This commit is contained in:
parent
7681551544
commit
9aa6c24620
|
@ -296,7 +296,6 @@ static Command s_command = Command::None;
|
||||||
static Command s_command_second_response = Command::None;
|
static Command s_command_second_response = Command::None;
|
||||||
static DriveState s_drive_state = DriveState::Idle;
|
static DriveState s_drive_state = DriveState::Idle;
|
||||||
static DiscRegion s_disc_region = DiscRegion::Other;
|
static DiscRegion s_disc_region = DiscRegion::Other;
|
||||||
static bool s_ps1_disc = false;
|
|
||||||
|
|
||||||
static StatusRegister s_status = {};
|
static StatusRegister s_status = {};
|
||||||
static SecondaryStatusRegister s_secondary_status = {};
|
static SecondaryStatusRegister s_secondary_status = {};
|
||||||
|
@ -666,7 +665,7 @@ DiscRegion CDROM::GetDiscRegion()
|
||||||
|
|
||||||
bool CDROM::IsMediaPS1Disc()
|
bool CDROM::IsMediaPS1Disc()
|
||||||
{
|
{
|
||||||
return s_ps1_disc;
|
return (s_disc_region != DiscRegion::NonPS1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDROM::IsMediaAudioCD()
|
bool CDROM::IsMediaAudioCD()
|
||||||
|
@ -715,35 +714,21 @@ bool CDROM::CanReadMedia()
|
||||||
return (s_drive_state != DriveState::ShellOpening && m_reader.HasMedia());
|
return (s_drive_state != DriveState::ShellOpening && m_reader.HasMedia());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::InsertMedia(std::unique_ptr<CDImage> media)
|
void CDROM::InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region)
|
||||||
{
|
{
|
||||||
if (CanReadMedia())
|
if (CanReadMedia())
|
||||||
RemoveMedia(true);
|
RemoveMedia(true);
|
||||||
|
|
||||||
// check if it's a valid PS1 disc
|
|
||||||
std::string exe_name;
|
|
||||||
std::vector<u8> exe_buffer;
|
|
||||||
s_ps1_disc = System::ReadExecutableFromImage(media.get(), &exe_name, &exe_buffer);
|
|
||||||
|
|
||||||
if (s_ps1_disc)
|
|
||||||
{
|
|
||||||
// set the region from the system area of the disc
|
|
||||||
s_disc_region = System::GetRegionForImage(media.get());
|
|
||||||
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s",
|
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s",
|
||||||
Settings::GetDiscRegionName(s_disc_region), Settings::GetConsoleRegionName(System::GetRegion()));
|
Settings::GetDiscRegionName(region), Settings::GetConsoleRegionName(System::GetRegion()));
|
||||||
}
|
|
||||||
else
|
s_disc_region = region;
|
||||||
{
|
m_reader.SetMedia(std::move(media));
|
||||||
s_disc_region = DiscRegion::Other;
|
SetHoldPosition(0, true);
|
||||||
Log_InfoPrint("Inserting new media, non-PS1 disc");
|
|
||||||
}
|
|
||||||
|
|
||||||
// motor automatically spins up
|
// motor automatically spins up
|
||||||
if (s_drive_state != DriveState::ShellOpening)
|
if (s_drive_state != DriveState::ShellOpening)
|
||||||
StartMotor();
|
StartMotor();
|
||||||
|
|
||||||
m_reader.SetMedia(std::move(media));
|
|
||||||
SetHoldPosition(0, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
|
std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
|
||||||
|
@ -764,8 +749,7 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
|
||||||
s_secondary_status.motor_on = false;
|
s_secondary_status.motor_on = false;
|
||||||
s_secondary_status.shell_open = true;
|
s_secondary_status.shell_open = true;
|
||||||
s_secondary_status.ClearActiveBits();
|
s_secondary_status.ClearActiveBits();
|
||||||
s_disc_region = DiscRegion::Other;
|
s_disc_region = DiscRegion::NonPS1;
|
||||||
s_ps1_disc = false;
|
|
||||||
|
|
||||||
// If the drive was doing anything, we need to abort the command.
|
// If the drive was doing anything, we need to abort the command.
|
||||||
ClearDriveState();
|
ClearDriveState();
|
||||||
|
@ -2683,7 +2667,7 @@ void CDROM::DoIDRead()
|
||||||
|
|
||||||
static constexpr u32 REGION_STRING_LENGTH = 4;
|
static constexpr u32 REGION_STRING_LENGTH = 4;
|
||||||
static constexpr std::array<std::array<u8, REGION_STRING_LENGTH>, static_cast<size_t>(DiscRegion::Count)>
|
static constexpr std::array<std::array<u8, REGION_STRING_LENGTH>, static_cast<size_t>(DiscRegion::Count)>
|
||||||
region_strings = {{{'S', 'C', 'E', 'I'}, {'S', 'C', 'E', 'A'}, {'S', 'C', 'E', 'E'}, {0, 0, 0, 0}}};
|
region_strings = {{{'S', 'C', 'E', 'I'}, {'S', 'C', 'E', 'A'}, {'S', 'C', 'E', 'E'}, {0, 0, 0, 0}, {0, 0, 0, 0}}};
|
||||||
s_async_response_fifo.PushRange(region_strings[static_cast<u8>(s_disc_region)].data(), REGION_STRING_LENGTH);
|
s_async_response_fifo.PushRange(region_strings[static_cast<u8>(s_disc_region)].data(), REGION_STRING_LENGTH);
|
||||||
|
|
||||||
SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete);
|
SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete);
|
||||||
|
|
|
@ -25,7 +25,7 @@ bool IsMediaPS1Disc();
|
||||||
bool IsMediaAudioCD();
|
bool IsMediaAudioCD();
|
||||||
bool DoesMediaRegionMatchConsole();
|
bool DoesMediaRegionMatchConsole();
|
||||||
|
|
||||||
void InsertMedia(std::unique_ptr<CDImage> media);
|
void InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region);
|
||||||
std::unique_ptr<CDImage> RemoveMedia(bool for_disc_swap);
|
std::unique_ptr<CDImage> RemoveMedia(bool for_disc_swap);
|
||||||
bool PrecacheMedia();
|
bool PrecacheMedia();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "game_database.h"
|
#include "game_database.h"
|
||||||
|
@ -35,7 +35,6 @@ enum : u32
|
||||||
};
|
};
|
||||||
|
|
||||||
static Entry* GetMutableEntry(const std::string_view& serial);
|
static Entry* GetMutableEntry(const std::string_view& serial);
|
||||||
static const Entry* GetEntryForId(const std::string_view& code);
|
|
||||||
|
|
||||||
static bool LoadFromCache();
|
static bool LoadFromCache();
|
||||||
static bool SaveToCache();
|
static bool SaveToCache();
|
||||||
|
@ -111,6 +110,9 @@ void GameDatabase::Unload()
|
||||||
|
|
||||||
const GameDatabase::Entry* GameDatabase::GetEntryForId(const std::string_view& code)
|
const GameDatabase::Entry* GameDatabase::GetEntryForId(const std::string_view& code)
|
||||||
{
|
{
|
||||||
|
if (code.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
EnsureLoaded();
|
EnsureLoaded();
|
||||||
|
|
||||||
auto iter = UnorderedStringMapFind(s_code_lookup, code);
|
auto iter = UnorderedStringMapFind(s_code_lookup, code);
|
||||||
|
@ -144,7 +146,8 @@ std::string GameDatabase::GetSerialForPath(const char* path)
|
||||||
|
|
||||||
const GameDatabase::Entry* GameDatabase::GetEntryForDisc(CDImage* image)
|
const GameDatabase::Entry* GameDatabase::GetEntryForDisc(CDImage* image)
|
||||||
{
|
{
|
||||||
std::string id(System::GetGameIdFromImage(image, false));
|
std::string id;
|
||||||
|
System::GetGameDetailsFromImage(image, &id, nullptr);
|
||||||
if (!id.empty())
|
if (!id.empty())
|
||||||
{
|
{
|
||||||
const Entry* entry = GetEntryForId(id);
|
const Entry* entry = GetEntryForId(id);
|
||||||
|
@ -152,15 +155,7 @@ const GameDatabase::Entry* GameDatabase::GetEntryForDisc(CDImage* image)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string hash_id(System::GetGameHashIdFromImage(image));
|
Log_WarningPrintf("No entry found for disc '%s'", id.c_str());
|
||||||
if (!hash_id.empty())
|
|
||||||
{
|
|
||||||
const Entry* entry = GetEntryForId(hash_id);
|
|
||||||
if (entry)
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log_WarningPrintf("No entry found for disc (exe code: '%s', hash code: '%s')", id.c_str(), hash_id.c_str());
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +493,7 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
|
||||||
"Controller in port %u (%s) is not supported for %s.\nSupported controllers: "
|
"Controller in port %u (%s) is not supported for %s.\nSupported controllers: "
|
||||||
"%s\nPlease configure a supported controller from the list above."),
|
"%s\nPlease configure a supported controller from the list above."),
|
||||||
i + 1u, Host::TranslateString("ControllerType", Settings::GetControllerTypeDisplayName(ctype)).GetCharArray(),
|
i + 1u, Host::TranslateString("ControllerType", Settings::GetControllerTypeDisplayName(ctype)).GetCharArray(),
|
||||||
System::GetRunningTitle().c_str(), supported_controller_string.GetCharArray());
|
System::GetGameTitle().c_str(), supported_controller_string.GetCharArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ void EnsureLoaded();
|
||||||
void Unload();
|
void Unload();
|
||||||
|
|
||||||
const Entry* GetEntryForDisc(CDImage* image);
|
const Entry* GetEntryForDisc(CDImage* image);
|
||||||
|
const Entry* GetEntryForId(const std::string_view& code);
|
||||||
const Entry* GetEntryForSerial(const std::string_view& serial);
|
const Entry* GetEntryForSerial(const std::string_view& serial);
|
||||||
std::string GetSerialForDisc(CDImage* image);
|
std::string GetSerialForDisc(CDImage* image);
|
||||||
std::string GetSerialForPath(const char* path);
|
std::string GetSerialForPath(const char* path);
|
||||||
|
|
|
@ -788,10 +788,11 @@ const char* Settings::GetConsoleRegionDisplayName(ConsoleRegion region)
|
||||||
return s_console_region_display_names[static_cast<int>(region)];
|
return s_console_region_display_names[static_cast<int>(region)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<const char*, 4> s_disc_region_names = {{"NTSC-J", "NTSC-U", "PAL", "Other"}};
|
static std::array<const char*, 5> s_disc_region_names = {{"NTSC-J", "NTSC-U", "PAL", "Other", "Non-PS1"}};
|
||||||
static std::array<const char*, 4> s_disc_region_display_names = {
|
static std::array<const char*, 5> s_disc_region_display_names = {
|
||||||
{TRANSLATABLE("DiscRegion", "NTSC-J (Japan)"), TRANSLATABLE("DiscRegion", "NTSC-U/C (US, Canada)"),
|
{TRANSLATABLE("DiscRegion", "NTSC-J (Japan)"), TRANSLATABLE("DiscRegion", "NTSC-U/C (US, Canada)"),
|
||||||
TRANSLATABLE("DiscRegion", "PAL (Europe, Australia)"), TRANSLATABLE("DiscRegion", "Other")}};
|
TRANSLATABLE("DiscRegion", "PAL (Europe, Australia)"), TRANSLATABLE("DiscRegion", "Other"),
|
||||||
|
TRANSLATABLE("DiscRegion", "Non-PS1")}};
|
||||||
|
|
||||||
std::optional<DiscRegion> Settings::ParseDiscRegionName(const char* str)
|
std::optional<DiscRegion> Settings::ParseDiscRegionName(const char* str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
@ -91,7 +91,6 @@ static bool LoadMemoryState(const MemorySaveState& mss);
|
||||||
static bool LoadEXE(const char* filename);
|
static bool LoadEXE(const char* filename);
|
||||||
|
|
||||||
static std::string GetExecutableNameForImage(ISOReader& iso, bool strip_subdirectories);
|
static std::string GetExecutableNameForImage(ISOReader& iso, bool strip_subdirectories);
|
||||||
|
|
||||||
static bool ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name,
|
static bool ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name,
|
||||||
std::vector<u8>* out_executable_data);
|
std::vector<u8>* out_executable_data);
|
||||||
|
|
||||||
|
@ -128,6 +127,7 @@ static void SetTimerResolutionIncreased(bool enabled);
|
||||||
} // namespace System
|
} // namespace System
|
||||||
|
|
||||||
static constexpr const float PERFORMANCE_COUNTER_UPDATE_INTERVAL = 1.0f;
|
static constexpr const float PERFORMANCE_COUNTER_UPDATE_INTERVAL = 1.0f;
|
||||||
|
static constexpr const char FALLBACK_EXE_NAME[] = "PSX.EXE";
|
||||||
|
|
||||||
static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
|
||||||
static std::unique_ptr<INISettingsInterface> s_input_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_input_settings_interface;
|
||||||
|
@ -147,6 +147,7 @@ static BIOS::Hash s_bios_hash = {};
|
||||||
static std::string s_running_game_path;
|
static std::string s_running_game_path;
|
||||||
static std::string s_running_game_serial;
|
static std::string s_running_game_serial;
|
||||||
static std::string s_running_game_title;
|
static std::string s_running_game_title;
|
||||||
|
static System::GameHash s_running_game_hash;
|
||||||
static bool s_running_unknown_game;
|
static bool s_running_unknown_game;
|
||||||
|
|
||||||
static float s_throttle_frequency = 60.0f;
|
static float s_throttle_frequency = 60.0f;
|
||||||
|
@ -315,20 +316,25 @@ void System::IncrementInternalFrameNumber()
|
||||||
s_internal_frame_number++;
|
s_internal_frame_number++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& System::GetRunningPath()
|
const std::string& System::GetDiscPath()
|
||||||
{
|
{
|
||||||
return s_running_game_path;
|
return s_running_game_path;
|
||||||
}
|
}
|
||||||
const std::string& System::GetRunningSerial()
|
const std::string& System::GetGameSerial()
|
||||||
{
|
{
|
||||||
return s_running_game_serial;
|
return s_running_game_serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& System::GetRunningTitle()
|
const std::string& System::GetGameTitle()
|
||||||
{
|
{
|
||||||
return s_running_game_title;
|
return s_running_game_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System::GameHash System::GetGameHash()
|
||||||
|
{
|
||||||
|
return s_running_game_hash;
|
||||||
|
}
|
||||||
|
|
||||||
bool System::IsRunningUnknownGame()
|
bool System::IsRunningUnknownGame()
|
||||||
{
|
{
|
||||||
return s_running_unknown_game;
|
return s_running_unknown_game;
|
||||||
|
@ -447,6 +453,7 @@ ConsoleRegion System::GetConsoleRegionForDiscRegion(DiscRegion region)
|
||||||
|
|
||||||
case DiscRegion::NTSC_U:
|
case DiscRegion::NTSC_U:
|
||||||
case DiscRegion::Other:
|
case DiscRegion::Other:
|
||||||
|
case DiscRegion::NonPS1:
|
||||||
default:
|
default:
|
||||||
return ConsoleRegion::NTSC_U;
|
return ConsoleRegion::NTSC_U;
|
||||||
|
|
||||||
|
@ -455,70 +462,86 @@ ConsoleRegion System::GetConsoleRegionForDiscRegion(DiscRegion region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string System::GetGameSerialForPath(const char* image_path, bool fallback_to_hash)
|
std::string System::GetGameHashId(GameHash hash)
|
||||||
{
|
{
|
||||||
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path, false, nullptr);
|
return StringUtil::StdStringFromFormat("HASH-%" PRIX64, hash);
|
||||||
if (!cdi)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return GetGameIdFromImage(cdi.get(), fallback_to_hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string System::GetGameIdFromImage(CDImage* cdi, bool fallback_to_hash)
|
bool System::GetGameDetailsFromImage(CDImage* cdi, std::string* out_id, GameHash* out_hash)
|
||||||
{
|
|
||||||
std::string code(GetExecutableNameForImage(cdi));
|
|
||||||
if (!code.empty())
|
|
||||||
{
|
|
||||||
// SCES_123.45 -> SCES-12345
|
|
||||||
for (std::string::size_type pos = 0; pos < code.size();)
|
|
||||||
{
|
|
||||||
if (code[pos] == '.')
|
|
||||||
{
|
|
||||||
code.erase(pos, 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code[pos] == '_')
|
|
||||||
code[pos] = '-';
|
|
||||||
else
|
|
||||||
code[pos] = static_cast<char>(std::toupper(code[pos]));
|
|
||||||
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fallback_to_hash)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return GetGameHashIdFromImage(cdi);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string System::GetGameHashIdFromImage(CDImage* cdi)
|
|
||||||
{
|
{
|
||||||
ISOReader iso;
|
ISOReader iso;
|
||||||
if (!iso.Open(cdi, 1))
|
if (!iso.Open(cdi, 1))
|
||||||
return {};
|
{
|
||||||
|
if (out_id)
|
||||||
|
out_id->clear();
|
||||||
|
if (out_hash)
|
||||||
|
*out_hash = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string id;
|
||||||
std::string exe_name;
|
std::string exe_name;
|
||||||
std::vector<u8> exe_buffer;
|
std::vector<u8> exe_buffer;
|
||||||
if (!ReadExecutableFromImage(cdi, &exe_name, &exe_buffer))
|
if (!ReadExecutableFromImage(iso, &exe_name, &exe_buffer))
|
||||||
return {};
|
{
|
||||||
|
if (out_id)
|
||||||
|
out_id->clear();
|
||||||
|
if (out_hash)
|
||||||
|
*out_hash = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always compute the hash.
|
||||||
const u32 track_1_length = cdi->GetTrackLength(1);
|
const u32 track_1_length = cdi->GetTrackLength(1);
|
||||||
|
|
||||||
XXH64_state_t* state = XXH64_createState();
|
XXH64_state_t* state = XXH64_createState();
|
||||||
XXH64_reset(state, 0x4242D00C);
|
XXH64_reset(state, 0x4242D00C);
|
||||||
XXH64_update(state, exe_name.c_str(), exe_name.size());
|
XXH64_update(state, exe_name.c_str(), exe_name.size());
|
||||||
XXH64_update(state, exe_buffer.data(), exe_buffer.size());
|
XXH64_update(state, exe_buffer.data(), exe_buffer.size());
|
||||||
XXH64_update(state, &iso.GetPVD(), sizeof(ISOReader::ISOPrimaryVolumeDescriptor));
|
XXH64_update(state, &iso.GetPVD(), sizeof(ISOReader::ISOPrimaryVolumeDescriptor));
|
||||||
XXH64_update(state, &track_1_length, sizeof(track_1_length));
|
XXH64_update(state, &track_1_length, sizeof(track_1_length));
|
||||||
const u64 hash = XXH64_digest(state);
|
const GameHash hash = XXH64_digest(state);
|
||||||
XXH64_freeState(state);
|
XXH64_freeState(state);
|
||||||
|
Log_DevPrintf("Hash for '%s' - %" PRIX64, exe_name.c_str(), hash);
|
||||||
|
|
||||||
Log_InfoPrintf("Hash for '%s' - %" PRIX64, exe_name.c_str(), hash);
|
if (exe_name != FALLBACK_EXE_NAME)
|
||||||
return StringUtil::StdStringFromFormat("HASH-%" PRIX64, hash);
|
{
|
||||||
|
// Strip off any subdirectories.
|
||||||
|
const std::string::size_type slash = exe_name.rfind('\\');
|
||||||
|
if (slash != std::string::npos)
|
||||||
|
id = std::string_view(exe_name).substr(slash + 1);
|
||||||
|
else
|
||||||
|
id = exe_name;
|
||||||
|
|
||||||
|
// SCES_123.45 -> SCES-12345
|
||||||
|
for (std::string::size_type pos = 0; pos < id.size();)
|
||||||
|
{
|
||||||
|
if (id[pos] == '.')
|
||||||
|
{
|
||||||
|
id.erase(pos, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id[pos] == '_')
|
||||||
|
id[pos] = '-';
|
||||||
|
else
|
||||||
|
id[pos] = static_cast<char>(std::toupper(id[pos]));
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_id)
|
||||||
|
{
|
||||||
|
if (id.empty())
|
||||||
|
*out_id = GetGameHashId(hash);
|
||||||
|
else
|
||||||
|
*out_id = std::move(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_hash)
|
||||||
|
*out_hash = hash;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string System::GetExecutableNameForImage(ISOReader& iso, bool strip_subdirectories)
|
std::string System::GetExecutableNameForImage(ISOReader& iso, bool strip_subdirectories)
|
||||||
|
@ -526,7 +549,7 @@ std::string System::GetExecutableNameForImage(ISOReader& iso, bool strip_subdire
|
||||||
// Read SYSTEM.CNF
|
// Read SYSTEM.CNF
|
||||||
std::vector<u8> system_cnf_data;
|
std::vector<u8> system_cnf_data;
|
||||||
if (!iso.ReadFile("SYSTEM.CNF", &system_cnf_data))
|
if (!iso.ReadFile("SYSTEM.CNF", &system_cnf_data))
|
||||||
return {};
|
return FALLBACK_EXE_NAME;
|
||||||
|
|
||||||
// Parse lines
|
// Parse lines
|
||||||
std::vector<std::pair<std::string, std::string>> lines;
|
std::vector<std::pair<std::string, std::string>> lines;
|
||||||
|
@ -568,7 +591,10 @@ std::string System::GetExecutableNameForImage(ISOReader& iso, bool strip_subdire
|
||||||
auto iter = std::find_if(lines.begin(), lines.end(),
|
auto iter = std::find_if(lines.begin(), lines.end(),
|
||||||
[](const auto& it) { return StringUtil::Strcasecmp(it.first.c_str(), "boot") == 0; });
|
[](const auto& it) { return StringUtil::Strcasecmp(it.first.c_str(), "boot") == 0; });
|
||||||
if (iter == lines.end())
|
if (iter == lines.end())
|
||||||
return {};
|
{
|
||||||
|
// Fallback to PSX.EXE
|
||||||
|
return FALLBACK_EXE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
std::string code = iter->second;
|
std::string code = iter->second;
|
||||||
std::string::size_type pos;
|
std::string::size_type pos;
|
||||||
|
@ -608,45 +634,13 @@ std::string System::GetExecutableNameForImage(ISOReader& iso, bool strip_subdire
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string System::GetExecutableNameForImage(CDImage* cdi)
|
std::string System::GetExecutableNameForImage(CDImage* cdi, bool strip_subdirectories)
|
||||||
{
|
{
|
||||||
ISOReader iso;
|
ISOReader iso;
|
||||||
if (!iso.Open(cdi, 1))
|
if (!iso.Open(cdi, 1))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return GetExecutableNameForImage(iso, true);
|
return GetExecutableNameForImage(iso, strip_subdirectories);
|
||||||
}
|
|
||||||
|
|
||||||
bool System::ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name,
|
|
||||||
std::vector<u8>* out_executable_data)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
std::string executable_path(GetExecutableNameForImage(iso, false));
|
|
||||||
Log_DevPrintf("Executable path: '%s'", executable_path.c_str());
|
|
||||||
if (!executable_path.empty())
|
|
||||||
{
|
|
||||||
result = iso.ReadFile(executable_path.c_str(), out_executable_data);
|
|
||||||
if (!result)
|
|
||||||
Log_ErrorPrintf("Failed to read executable '%s' from disc", executable_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
// fallback to PSX.EXE
|
|
||||||
executable_path = "PSX.EXE";
|
|
||||||
result = iso.ReadFile(executable_path.c_str(), out_executable_data);
|
|
||||||
if (!result)
|
|
||||||
Log_ErrorPrint("Failed to read fallback PSX.EXE from disc");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (out_executable_name)
|
|
||||||
*out_executable_name = std::move(executable_path);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name,
|
bool System::ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name,
|
||||||
|
@ -659,6 +653,25 @@ bool System::ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_n
|
||||||
return ReadExecutableFromImage(iso, out_executable_name, out_executable_data);
|
return ReadExecutableFromImage(iso, out_executable_name, out_executable_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool System::ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name, std::vector<u8>* out_executable_data)
|
||||||
|
{
|
||||||
|
const std::string executable_path = GetExecutableNameForImage(iso, false);
|
||||||
|
Log_DevPrintf("Executable path: '%s'", executable_path.c_str());
|
||||||
|
if (!executable_path.empty() && out_executable_data)
|
||||||
|
{
|
||||||
|
if (!iso.ReadFile(executable_path.c_str(), out_executable_data))
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to read executable '%s' from disc", executable_path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_executable_name)
|
||||||
|
*out_executable_name = std::move(executable_path);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DiscRegion System::GetRegionForSerial(std::string_view serial)
|
DiscRegion System::GetRegionForSerial(std::string_view serial)
|
||||||
{
|
{
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
|
@ -705,15 +718,25 @@ DiscRegion System::GetRegionFromSystemArea(CDImage* cdi)
|
||||||
|
|
||||||
DiscRegion System::GetRegionForImage(CDImage* cdi)
|
DiscRegion System::GetRegionForImage(CDImage* cdi)
|
||||||
{
|
{
|
||||||
DiscRegion system_area_region = GetRegionFromSystemArea(cdi);
|
const DiscRegion system_area_region = GetRegionFromSystemArea(cdi);
|
||||||
if (system_area_region != DiscRegion::Other)
|
if (system_area_region != DiscRegion::Other)
|
||||||
return system_area_region;
|
return system_area_region;
|
||||||
|
|
||||||
std::string serial = GetGameIdFromImage(cdi, false);
|
ISOReader iso;
|
||||||
if (serial.empty())
|
if (!iso.Open(cdi, 1))
|
||||||
return DiscRegion::Other;
|
return DiscRegion::NonPS1;
|
||||||
|
|
||||||
return GetRegionForSerial(serial);
|
// The executable must exist, because this just returns PSX.EXE if it doesn't.
|
||||||
|
const std::string exename = GetExecutableNameForImage(iso, false);
|
||||||
|
if (exename.empty() || !iso.FileExists(exename.c_str()))
|
||||||
|
return DiscRegion::NonPS1;
|
||||||
|
|
||||||
|
// Strip off any subdirectories.
|
||||||
|
const std::string::size_type slash = exename.rfind('\\');
|
||||||
|
if (slash != std::string::npos)
|
||||||
|
return GetRegionForSerial(std::string_view(exename).substr(slash + 1));
|
||||||
|
else
|
||||||
|
return GetRegionForSerial(exename);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscRegion System::GetRegionForExe(const char* path)
|
DiscRegion System::GetRegionForExe(const char* path)
|
||||||
|
@ -1115,7 +1138,8 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
|
|
||||||
// Load CD image up and detect region.
|
// Load CD image up and detect region.
|
||||||
Common::Error error;
|
Common::Error error;
|
||||||
std::unique_ptr<CDImage> media;
|
std::unique_ptr<CDImage> disc;
|
||||||
|
DiscRegion disc_region = DiscRegion::NonPS1;
|
||||||
std::string exe_boot;
|
std::string exe_boot;
|
||||||
std::string psf_boot;
|
std::string psf_boot;
|
||||||
if (!parameters.filename.empty())
|
if (!parameters.filename.empty())
|
||||||
|
@ -1139,8 +1163,8 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log_InfoPrintf("Loading CD image '%s'...", parameters.filename.c_str());
|
Log_InfoPrintf("Loading CD image '%s'...", parameters.filename.c_str());
|
||||||
media = CDImage::Open(parameters.filename.c_str(), g_settings.cdrom_load_image_patches, &error);
|
disc = CDImage::Open(parameters.filename.c_str(), g_settings.cdrom_load_image_patches, &error);
|
||||||
if (!media)
|
if (!disc)
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("Error", fmt::format("Failed to load CD image '{}': {}",
|
Host::ReportErrorAsync("Error", fmt::format("Failed to load CD image '{}': {}",
|
||||||
Path::GetFileName(parameters.filename), error.GetCodeAndMessage()));
|
Path::GetFileName(parameters.filename), error.GetCodeAndMessage()));
|
||||||
|
@ -1151,7 +1175,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
|
|
||||||
if (s_region == ConsoleRegion::Auto)
|
if (s_region == ConsoleRegion::Auto)
|
||||||
{
|
{
|
||||||
const DiscRegion disc_region = GetRegionForImage(media.get());
|
disc_region = GetRegionForImage(disc.get());
|
||||||
if (disc_region != DiscRegion::Other)
|
if (disc_region != DiscRegion::Other)
|
||||||
{
|
{
|
||||||
s_region = GetConsoleRegionForDiscRegion(disc_region);
|
s_region = GetConsoleRegionForDiscRegion(disc_region);
|
||||||
|
@ -1178,7 +1202,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
Log_InfoPrintf("Console Region: %s", Settings::GetConsoleRegionDisplayName(s_region));
|
Log_InfoPrintf("Console Region: %s", Settings::GetConsoleRegionDisplayName(s_region));
|
||||||
|
|
||||||
// Switch subimage.
|
// Switch subimage.
|
||||||
if (media && parameters.media_playlist_index != 0 && !media->SwitchSubImage(parameters.media_playlist_index, &error))
|
if (disc && parameters.media_playlist_index != 0 && !disc->SwitchSubImage(parameters.media_playlist_index, &error))
|
||||||
{
|
{
|
||||||
Host::ReportFormattedErrorAsync("Error", "Failed to switch to subimage %u in '%s': %s",
|
Host::ReportFormattedErrorAsync("Error", "Failed to switch to subimage %u in '%s': %s",
|
||||||
parameters.media_playlist_index, parameters.filename.c_str(),
|
parameters.media_playlist_index, parameters.filename.c_str(),
|
||||||
|
@ -1189,7 +1213,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update running game, this will apply settings as well.
|
// Update running game, this will apply settings as well.
|
||||||
UpdateRunningGame(media ? media->GetFileName().c_str() : parameters.filename.c_str(), media.get(), true);
|
UpdateRunningGame(disc ? disc->GetFileName().c_str() : parameters.filename.c_str(), disc.get(), true);
|
||||||
|
|
||||||
if (!parameters.override_exe.empty())
|
if (!parameters.override_exe.empty())
|
||||||
{
|
{
|
||||||
|
@ -1207,7 +1231,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for SBI.
|
// Check for SBI.
|
||||||
if (!CheckForSBIFile(media.get()))
|
if (!CheckForSBIFile(disc.get()))
|
||||||
{
|
{
|
||||||
s_state = State::Shutdown;
|
s_state = State::Shutdown;
|
||||||
ClearRunningGame();
|
ClearRunningGame();
|
||||||
|
@ -1274,8 +1298,8 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert CD, and apply fastboot patch if enabled.
|
// Insert CD, and apply fastboot patch if enabled.
|
||||||
if (media)
|
if (disc)
|
||||||
CDROM::InsertMedia(std::move(media));
|
CDROM::InsertMedia(std::move(disc), disc_region);
|
||||||
if (CDROM::HasMedia() && (parameters.override_fast_boot.has_value() ? parameters.override_fast_boot.value() :
|
if (CDROM::HasMedia() && (parameters.override_fast_boot.has_value() ? parameters.override_fast_boot.value() :
|
||||||
g_settings.bios_patch_fast_boot))
|
g_settings.bios_patch_fast_boot))
|
||||||
{
|
{
|
||||||
|
@ -1513,6 +1537,7 @@ void System::ClearRunningGame()
|
||||||
s_running_game_serial.clear();
|
s_running_game_serial.clear();
|
||||||
s_running_game_path.clear();
|
s_running_game_path.clear();
|
||||||
s_running_game_title.clear();
|
s_running_game_title.clear();
|
||||||
|
s_running_game_hash = 0;
|
||||||
s_running_unknown_game = false;
|
s_running_unknown_game = false;
|
||||||
s_cheat_list.reset();
|
s_cheat_list.reset();
|
||||||
s_state = State::Shutdown;
|
s_state = State::Shutdown;
|
||||||
|
@ -1967,7 +1992,8 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
||||||
CDROM::Reset();
|
CDROM::Reset();
|
||||||
if (media)
|
if (media)
|
||||||
{
|
{
|
||||||
CDROM::InsertMedia(std::move(media));
|
const DiscRegion region = GetRegionForImage(media.get());
|
||||||
|
CDROM::InsertMedia(std::move(media), region);
|
||||||
if (g_settings.cdrom_load_image_to_ram)
|
if (g_settings.cdrom_load_image_to_ram)
|
||||||
CDROM::PrecacheMedia();
|
CDROM::PrecacheMedia();
|
||||||
}
|
}
|
||||||
|
@ -2997,8 +3023,9 @@ bool System::InsertMedia(const char* path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DiscRegion region = GetRegionForImage(image.get());
|
||||||
UpdateRunningGame(path, image.get(), false);
|
UpdateRunningGame(path, image.get(), false);
|
||||||
CDROM::InsertMedia(std::move(image));
|
CDROM::InsertMedia(std::move(image), region);
|
||||||
Log_InfoPrintf("Inserted media from %s (%s, %s)", s_running_game_path.c_str(), s_running_game_serial.c_str(),
|
Log_InfoPrintf("Inserted media from %s (%s, %s)", s_running_game_path.c_str(), s_running_game_serial.c_str(),
|
||||||
s_running_game_title.c_str());
|
s_running_game_title.c_str());
|
||||||
if (g_settings.cdrom_load_image_to_ram)
|
if (g_settings.cdrom_load_image_to_ram)
|
||||||
|
@ -3031,6 +3058,7 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
|
||||||
s_running_game_path.clear();
|
s_running_game_path.clear();
|
||||||
s_running_game_serial.clear();
|
s_running_game_serial.clear();
|
||||||
s_running_game_title.clear();
|
s_running_game_title.clear();
|
||||||
|
s_running_game_hash = 0;
|
||||||
s_running_unknown_game = true;
|
s_running_unknown_game = true;
|
||||||
|
|
||||||
if (path && std::strlen(path) > 0)
|
if (path && std::strlen(path) > 0)
|
||||||
|
@ -3044,7 +3072,10 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
|
||||||
}
|
}
|
||||||
else if (image)
|
else if (image)
|
||||||
{
|
{
|
||||||
const GameDatabase::Entry* entry = GameDatabase::GetEntryForDisc(image);
|
std::string id;
|
||||||
|
GetGameDetailsFromImage(image, &id, &s_running_game_hash);
|
||||||
|
|
||||||
|
const GameDatabase::Entry* entry = GameDatabase::GetEntryForId(id);
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
s_running_game_serial = entry->serial;
|
s_running_game_serial = entry->serial;
|
||||||
|
@ -3053,9 +3084,8 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string display_name(FileSystem::GetDisplayNameFromPath(path));
|
s_running_game_serial = std::move(id);
|
||||||
s_running_game_serial = GetGameIdFromImage(image, true);
|
s_running_game_title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path));
|
||||||
s_running_game_title = Path::GetFileTitle(display_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image->HasSubImages() && g_settings.memory_card_use_playlist_title)
|
if (image->HasSubImages() && g_settings.memory_card_use_playlist_title)
|
||||||
|
@ -3182,14 +3212,17 @@ bool System::SwitchMediaSubImage(u32 index)
|
||||||
Host::AddFormattedOSDMessage(10.0f,
|
Host::AddFormattedOSDMessage(10.0f,
|
||||||
Host::TranslateString("OSDMessage", "Failed to switch to subimage %u in '%s': %s."),
|
Host::TranslateString("OSDMessage", "Failed to switch to subimage %u in '%s': %s."),
|
||||||
index + 1u, image->GetFileName().c_str(), error.GetCodeAndMessage().GetCharArray());
|
index + 1u, image->GetFileName().c_str(), error.GetCodeAndMessage().GetCharArray());
|
||||||
CDROM::InsertMedia(std::move(image));
|
|
||||||
|
const DiscRegion region = GetRegionForImage(image.get());
|
||||||
|
CDROM::InsertMedia(std::move(image), region);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Host::AddFormattedOSDMessage(20.0f, Host::TranslateString("OSDMessage", "Switched to sub-image %s (%u) in '%s'."),
|
Host::AddFormattedOSDMessage(20.0f, Host::TranslateString("OSDMessage", "Switched to sub-image %s (%u) in '%s'."),
|
||||||
image->GetSubImageMetadata(index, "title").c_str(), index + 1u,
|
image->GetSubImageMetadata(index, "title").c_str(), index + 1u,
|
||||||
image->GetMetadata("title").c_str());
|
image->GetMetadata("title").c_str());
|
||||||
CDROM::InsertMedia(std::move(image));
|
const DiscRegion region = GetRegionForImage(image.get());
|
||||||
|
CDROM::InsertMedia(std::move(image), region);
|
||||||
|
|
||||||
ClearMemorySaveStates();
|
ClearMemorySaveStates();
|
||||||
return true;
|
return true;
|
||||||
|
@ -3840,7 +3873,7 @@ bool System::StartDumpingAudio(const char* filename)
|
||||||
std::string auto_filename;
|
std::string auto_filename;
|
||||||
if (!filename)
|
if (!filename)
|
||||||
{
|
{
|
||||||
const auto& serial = System::GetRunningSerial();
|
const auto& serial = System::GetGameSerial();
|
||||||
if (serial.empty())
|
if (serial.empty())
|
||||||
{
|
{
|
||||||
auto_filename = Path::Combine(
|
auto_filename = Path::Combine(
|
||||||
|
@ -3885,7 +3918,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
|
||||||
std::string auto_filename;
|
std::string auto_filename;
|
||||||
if (!filename)
|
if (!filename)
|
||||||
{
|
{
|
||||||
const auto& code = System::GetRunningSerial();
|
const auto& code = System::GetGameSerial();
|
||||||
const char* extension = "png";
|
const char* extension = "png";
|
||||||
if (code.empty())
|
if (code.empty())
|
||||||
{
|
{
|
||||||
|
@ -4079,7 +4112,7 @@ std::string System::GetCheatFileName()
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
const std::string& title = System::GetRunningTitle();
|
const std::string& title = System::GetGameTitle();
|
||||||
if (!title.empty())
|
if (!title.empty())
|
||||||
ret = Path::Combine(EmuFolders::Cheats, fmt::format("{}.cht", title.c_str()));
|
ret = Path::Combine(EmuFolders::Cheats, fmt::format("{}.cht", title.c_str()));
|
||||||
|
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -88,6 +88,8 @@ enum class State
|
||||||
Paused
|
Paused
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using GameHash = u64;
|
||||||
|
|
||||||
extern TickCount g_ticks_per_second;
|
extern TickCount g_ticks_per_second;
|
||||||
|
|
||||||
/// Returns true if the filename is a PlayStation executable we can inject.
|
/// Returns true if the filename is a PlayStation executable we can inject.
|
||||||
|
@ -105,12 +107,12 @@ bool IsSaveStateFilename(const std::string_view& path);
|
||||||
/// Returns the preferred console type for a disc.
|
/// Returns the preferred console type for a disc.
|
||||||
ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region);
|
ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region);
|
||||||
|
|
||||||
std::string GetExecutableNameForImage(CDImage* cdi);
|
std::string GetExecutableNameForImage(CDImage* cdi, bool strip_subdirectories);
|
||||||
bool ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name, std::vector<u8>* out_executable_data);
|
bool ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name, std::vector<u8>* out_executable_data);
|
||||||
|
|
||||||
std::string GetGameHashIdFromImage(CDImage* cdi);
|
bool IsValidGameImage(CDImage* cdi);
|
||||||
std::string GetGameIdFromImage(CDImage* cdi, bool fallback_to_hash);
|
std::string GetGameHashId(GameHash hash);
|
||||||
std::string GetGameSerialForPath(const char* image_path, bool fallback_to_hash);
|
bool GetGameDetailsFromImage(CDImage* cdi, std::string* out_id, GameHash* out_hash);
|
||||||
DiscRegion GetRegionForSerial(std::string_view serial);
|
DiscRegion GetRegionForSerial(std::string_view serial);
|
||||||
DiscRegion GetRegionFromSystemArea(CDImage* cdi);
|
DiscRegion GetRegionFromSystemArea(CDImage* cdi);
|
||||||
DiscRegion GetRegionForImage(CDImage* cdi);
|
DiscRegion GetRegionForImage(CDImage* cdi);
|
||||||
|
@ -177,11 +179,12 @@ u32 GetInternalFrameNumber();
|
||||||
void FrameDone();
|
void FrameDone();
|
||||||
void IncrementInternalFrameNumber();
|
void IncrementInternalFrameNumber();
|
||||||
|
|
||||||
const std::string& GetRunningPath();
|
const std::string& GetDiscPath();
|
||||||
const std::string& GetRunningSerial();
|
const std::string& GetGameSerial();
|
||||||
const std::string& GetRunningTitle();
|
const std::string& GetGameTitle();
|
||||||
|
GameHash GetGameHash();
|
||||||
bool IsRunningUnknownGame();
|
bool IsRunningUnknownGame();
|
||||||
|
|
||||||
const BIOS::ImageInfo* GetBIOSImageInfo();
|
const BIOS::ImageInfo* GetBIOSImageInfo();
|
||||||
const BIOS::Hash& GetBIOSHash();
|
const BIOS::Hash& GetBIOSHash();
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum class DiscRegion : u8
|
||||||
NTSC_U, // SCEA
|
NTSC_U, // SCEA
|
||||||
PAL, // SCEE
|
PAL, // SCEE
|
||||||
Other,
|
Other,
|
||||||
|
NonPS1,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -657,7 +657,7 @@ bool NoGUIHost::AcquireHostDisplay(RenderAPI api)
|
||||||
Assert(!g_host_display);
|
Assert(!g_host_display);
|
||||||
|
|
||||||
g_nogui_window->ExecuteInMessageLoop([api]() {
|
g_nogui_window->ExecuteInMessageLoop([api]() {
|
||||||
if (g_nogui_window->CreatePlatformWindow(GetWindowTitle(System::GetRunningTitle())))
|
if (g_nogui_window->CreatePlatformWindow(GetWindowTitle(System::GetGameTitle())))
|
||||||
{
|
{
|
||||||
const std::optional<WindowInfo> wi(g_nogui_window->GetPlatformWindowInfo());
|
const std::optional<WindowInfo> wi(g_nogui_window->GetPlatformWindowInfo());
|
||||||
if (wi.has_value())
|
if (wi.has_value())
|
||||||
|
|
|
@ -1284,8 +1284,8 @@ void MainWindow::onViewGamePropertiesActionTriggered()
|
||||||
if (!s_system_valid)
|
if (!s_system_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string& path = System::GetRunningPath();
|
const std::string& path = System::GetDiscPath();
|
||||||
const std::string& serial = System::GetRunningSerial();
|
const std::string& serial = System::GetGameSerial();
|
||||||
if (path.empty() || serial.empty())
|
if (path.empty() || serial.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1116,11 +1116,11 @@ void EmuThread::loadState(bool global, qint32 slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldn't even get here if we don't have a running game
|
// shouldn't even get here if we don't have a running game
|
||||||
if (!global && System::GetRunningSerial().empty())
|
if (!global && System::GetGameSerial().empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bootOrLoadState(global ? System::GetGlobalSaveStateFileName(slot) :
|
bootOrLoadState(global ? System::GetGlobalSaveStateFileName(slot) :
|
||||||
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot));
|
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::saveState(const QString& filename, bool block_until_done /* = false */)
|
void EmuThread::saveState(const QString& filename, bool block_until_done /* = false */)
|
||||||
|
@ -1147,11 +1147,11 @@ void EmuThread::saveState(bool global, qint32 slot, bool block_until_done /* = f
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global && System::GetRunningSerial().empty())
|
if (!global && System::GetGameSerial().empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
System::SaveState((global ? System::GetGlobalSaveStateFileName(slot) :
|
System::SaveState((global ? System::GetGlobalSaveStateFileName(slot) :
|
||||||
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot))
|
System::GetGameSaveStateFileName(System::GetGameSerial(), slot))
|
||||||
.c_str(),
|
.c_str(),
|
||||||
g_settings.create_save_state_backups);
|
g_settings.create_save_state_backups);
|
||||||
}
|
}
|
||||||
|
|
|
@ -848,6 +848,7 @@ QIcon GetIconForRegion(DiscRegion region)
|
||||||
case DiscRegion::NTSC_U:
|
case DiscRegion::NTSC_U:
|
||||||
return QIcon(QStringLiteral(":/icons/flag-uc.svg"));
|
return QIcon(QStringLiteral(":/icons/flag-uc.svg"));
|
||||||
case DiscRegion::Other:
|
case DiscRegion::Other:
|
||||||
|
case DiscRegion::NonPS1:
|
||||||
default:
|
default:
|
||||||
return QIcon::fromTheme(QStringLiteral("file-unknow-line"));
|
return QIcon::fromTheme(QStringLiteral("file-unknow-line"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,7 +470,7 @@ void Achievements::Initialize()
|
||||||
s_logged_in = (!s_username.empty() && !s_api_token.empty());
|
s_logged_in = (!s_username.empty() && !s_api_token.empty());
|
||||||
|
|
||||||
if (System::IsValid())
|
if (System::IsValid())
|
||||||
GameChanged(System::GetRunningPath(), nullptr);
|
GameChanged(System::GetDiscPath(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Achievements::UpdateSettings(const Settings& old_config)
|
void Achievements::UpdateSettings(const Settings& old_config)
|
||||||
|
@ -2142,7 +2142,7 @@ void Achievements::RAIntegration::RACallbackRebuildMenu()
|
||||||
|
|
||||||
void Achievements::RAIntegration::RACallbackEstimateTitle(char* buf)
|
void Achievements::RAIntegration::RACallbackEstimateTitle(char* buf)
|
||||||
{
|
{
|
||||||
StringUtil::Strlcpy(buf, System::GetRunningTitle(), 256);
|
StringUtil::Strlcpy(buf, System::GetGameTitle(), 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Achievements::RAIntegration::RACallbackResetEmulator()
|
void Achievements::RAIntegration::RACallbackResetEmulator()
|
||||||
|
|
|
@ -570,8 +570,8 @@ void CommonHost::UpdateDiscordPresence(bool rich_presence_only)
|
||||||
SmallString details_string;
|
SmallString details_string;
|
||||||
if (!System::IsShutdown())
|
if (!System::IsShutdown())
|
||||||
{
|
{
|
||||||
details_string.AppendFormattedString("%s (%s)", System::GetRunningTitle().c_str(),
|
details_string.AppendFormattedString("%s (%s)", System::GetGameTitle().c_str(),
|
||||||
System::GetRunningSerial().c_str());
|
System::GetGameSerial().c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -635,7 +635,7 @@ static void HotkeyLoadStateSlot(bool global, s32 slot)
|
||||||
if (!System::IsValid())
|
if (!System::IsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!global && System::GetRunningSerial().empty())
|
if (!global && System::GetGameSerial().empty())
|
||||||
{
|
{
|
||||||
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot load state for game without serial."),
|
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot load state for game without serial."),
|
||||||
5.0f);
|
5.0f);
|
||||||
|
@ -643,7 +643,7 @@ static void HotkeyLoadStateSlot(bool global, s32 slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
|
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
|
||||||
System::GetGameSaveStateFileName(System::GetRunningSerial(), slot));
|
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
|
||||||
if (!FileSystem::FileExists(path.c_str()))
|
if (!FileSystem::FileExists(path.c_str()))
|
||||||
{
|
{
|
||||||
Host::AddKeyedOSDMessage("LoadState",
|
Host::AddKeyedOSDMessage("LoadState",
|
||||||
|
@ -659,7 +659,7 @@ static void HotkeySaveStateSlot(bool global, s32 slot)
|
||||||
if (!System::IsValid())
|
if (!System::IsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!global && System::GetRunningSerial().empty())
|
if (!global && System::GetGameSerial().empty())
|
||||||
{
|
{
|
||||||
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot save state for game without serial."),
|
Host::AddKeyedOSDMessage("LoadState", TRANSLATABLE("OSDMessage", "Cannot save state for game without serial."),
|
||||||
5.0f);
|
5.0f);
|
||||||
|
@ -667,7 +667,7 @@ static void HotkeySaveStateSlot(bool global, s32 slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path(global ? System::GetGlobalSaveStateFileName(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);
|
System::SaveState(path.c_str(), g_settings.create_save_state_backups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -654,8 +654,8 @@ void FullscreenUI::OnRunningGameChanged()
|
||||||
if (!IsInitialized())
|
if (!IsInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string& path = System::GetRunningPath();
|
const std::string& path = System::GetDiscPath();
|
||||||
const std::string& serial = System::GetRunningSerial();
|
const std::string& serial = System::GetGameSerial();
|
||||||
if (!serial.empty())
|
if (!serial.empty())
|
||||||
s_current_game_subtitle = fmt::format("{0} - {1}", serial, Path::GetFileName(path));
|
s_current_game_subtitle = fmt::format("{0} - {1}", serial, Path::GetFileName(path));
|
||||||
else
|
else
|
||||||
|
@ -963,7 +963,7 @@ void FullscreenUI::DoChangeDiscFromFile()
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenFileSelector(ICON_FA_COMPACT_DISC " Select Disc Image", false, std::move(callback), GetDiscImageFilters(),
|
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()
|
void FullscreenUI::DoChangeDisc()
|
||||||
|
@ -1010,7 +1010,7 @@ void FullscreenUI::DoCheatsMenu()
|
||||||
{
|
{
|
||||||
if (!System::LoadCheatListFromDatabase() || ((cl = System::GetCheatList()) == nullptr))
|
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);
|
10.0f);
|
||||||
ReturnToMainWindow();
|
ReturnToMainWindow();
|
||||||
return;
|
return;
|
||||||
|
@ -2325,14 +2325,14 @@ void FullscreenUI::SwitchToGameSettingsForSerial(const std::string_view& serial)
|
||||||
|
|
||||||
void FullscreenUI::SwitchToGameSettings()
|
void FullscreenUI::SwitchToGameSettings()
|
||||||
{
|
{
|
||||||
if (System::GetRunningSerial().empty())
|
if (System::GetGameSerial().empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto lock = GameList::GetLock();
|
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)
|
if (!entry)
|
||||||
{
|
{
|
||||||
SwitchToGameSettingsForSerial(System::GetRunningSerial());
|
SwitchToGameSettingsForSerial(System::GetGameSerial());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4561,12 +4561,12 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
|
||||||
|
|
||||||
// title info
|
// title info
|
||||||
{
|
{
|
||||||
const std::string& title = System::GetRunningTitle();
|
const std::string& title = System::GetGameTitle();
|
||||||
const std::string& serial = System::GetRunningSerial();
|
const std::string& serial = System::GetGameSerial();
|
||||||
|
|
||||||
if (!serial.empty())
|
if (!serial.empty())
|
||||||
buffer.Format("%s - ", serial.c_str());
|
buffer.Format("%s - ", serial.c_str());
|
||||||
buffer.AppendString(Path::GetFileName(System::GetRunningPath()));
|
buffer.AppendString(Path::GetFileName(System::GetDiscPath()));
|
||||||
|
|
||||||
const ImVec2 title_size(
|
const ImVec2 title_size(
|
||||||
g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f, title.c_str()));
|
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(),
|
DrawShadowedText(dl, g_large_font, time_pos, IM_COL32(255, 255, 255, 255), buffer.GetCharArray(),
|
||||||
buffer.GetCharArray() + buffer.GetLength());
|
buffer.GetCharArray() + buffer.GetLength());
|
||||||
|
|
||||||
const std::string& serial = System::GetRunningSerial();
|
const std::string& serial = System::GetGameSerial();
|
||||||
if (!serial.empty())
|
if (!serial.empty())
|
||||||
{
|
{
|
||||||
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
|
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
|
||||||
|
@ -4674,7 +4674,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
|
||||||
case PauseSubMenu::None:
|
case PauseSubMenu::None:
|
||||||
{
|
{
|
||||||
// NOTE: Menu close must come first, because otherwise VM destruction options will race.
|
// 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())
|
if (ActiveButton(ICON_FA_PLAY " Resume Game", false) || WantsToCloseMenu())
|
||||||
ClosePauseMenu();
|
ClosePauseMenu();
|
||||||
|
@ -4698,7 +4698,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ActiveButton(ICON_FA_FROWN_OPEN " Cheat List", false,
|
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;
|
s_current_main_window = MainWindowType::None;
|
||||||
DoCheatsMenu();
|
DoCheatsMenu();
|
||||||
|
@ -4944,7 +4944,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
|
||||||
s_save_state_selector_game_path = {};
|
s_save_state_selector_game_path = {};
|
||||||
s_save_state_selector_loading = is_loading;
|
s_save_state_selector_loading = is_loading;
|
||||||
s_save_state_selector_resuming = false;
|
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;
|
s_save_state_selector_open = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -5380,7 +5380,7 @@ void FullscreenUI::DoSaveState(s32 slot, bool global)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string filename(global ? System::GetGlobalSaveStateFileName(slot) :
|
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);
|
System::SaveState(filename.c_str(), g_settings.create_save_state_backups);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6172,7 +6172,7 @@ GPUTexture* FullscreenUI::GetCoverForCurrentGame()
|
||||||
{
|
{
|
||||||
auto lock = GameList::GetLock();
|
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)
|
if (!entry)
|
||||||
return s_fallback_disc_texture.get();
|
return s_fallback_disc_texture.get();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "game_list.h"
|
#include "game_list.h"
|
||||||
|
@ -18,13 +18,14 @@
|
||||||
#include "core/psf_loader.h"
|
#include "core/psf_loader.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
|
#include "tinyxml2.h"
|
||||||
#include "util/cd_image.h"
|
#include "util/cd_image.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <tinyxml2.h>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
Log_SetChannel(GameList);
|
Log_SetChannel(GameList);
|
||||||
|
@ -37,7 +38,7 @@ namespace GameList {
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
|
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
|
||||||
GAME_LIST_CACHE_VERSION = 32,
|
GAME_LIST_CACHE_VERSION = 33,
|
||||||
|
|
||||||
PLAYED_TIME_SERIAL_LENGTH = 32,
|
PLAYED_TIME_SERIAL_LENGTH = 32,
|
||||||
PLAYED_TIME_LAST_TIME_LENGTH = 20, // uint64
|
PLAYED_TIME_LAST_TIME_LENGTH = 20, // uint64
|
||||||
|
@ -55,6 +56,8 @@ struct PlayedTimeEntry
|
||||||
using CacheMap = UnorderedStringMap<Entry>;
|
using CacheMap = UnorderedStringMap<Entry>;
|
||||||
using PlayedTimeMap = UnorderedStringMap<PlayedTimeEntry>;
|
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 GetExeListEntry(const std::string& path, Entry* entry);
|
||||||
static bool GetPsfListEntry(const std::string& path, Entry* entry);
|
static bool GetPsfListEntry(const std::string& path, Entry* entry);
|
||||||
static bool GetDiscListEntry(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->type = EntryType::Disc;
|
||||||
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
|
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
System::GetGameDetailsFromImage(cdi.get(), &id, &entry->hash);
|
||||||
|
|
||||||
// try the database first
|
// try the database first
|
||||||
const GameDatabase::Entry* dentry = GameDatabase::GetEntryForDisc(cdi.get());
|
const GameDatabase::Entry* dentry = GameDatabase::GetEntryForId(id);
|
||||||
if (dentry)
|
if (dentry)
|
||||||
{
|
{
|
||||||
// pull from database
|
// pull from database
|
||||||
|
@ -227,7 +233,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
|
||||||
const std::string display_name(FileSystem::GetDisplayNameFromPath(path));
|
const std::string display_name(FileSystem::GetDisplayNameFromPath(path));
|
||||||
|
|
||||||
// no game code, so use the filename title
|
// 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->title = Path::GetFileTitle(display_name);
|
||||||
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
|
entry->compatibility = GameDatabase::CompatibilityRating::Unknown;
|
||||||
entry->release_date = 0;
|
entry->release_date = 0;
|
||||||
|
@ -239,9 +245,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// region detection
|
// region detection
|
||||||
entry->region = System::GetRegionFromSystemArea(cdi.get());
|
entry->region = System::GetRegionForImage(cdi.get());
|
||||||
if (entry->region == DiscRegion::Other)
|
|
||||||
entry->region = System::GetRegionForSerial(entry->serial);
|
|
||||||
|
|
||||||
if (cdi->HasSubImages())
|
if (cdi->HasSubImages())
|
||||||
{
|
{
|
||||||
|
@ -310,12 +314,12 @@ bool GameList::LoadEntriesFromCache(ByteStream* stream)
|
||||||
if (!stream->ReadU8(&type) || !stream->ReadU8(®ion) || !stream->ReadSizePrefixedString(&path) ||
|
if (!stream->ReadU8(&type) || !stream->ReadU8(®ion) || !stream->ReadSizePrefixedString(&path) ||
|
||||||
!stream->ReadSizePrefixedString(&ge.serial) || !stream->ReadSizePrefixedString(&ge.title) ||
|
!stream->ReadSizePrefixedString(&ge.serial) || !stream->ReadSizePrefixedString(&ge.title) ||
|
||||||
!stream->ReadSizePrefixedString(&ge.genre) || !stream->ReadSizePrefixedString(&ge.publisher) ||
|
!stream->ReadSizePrefixedString(&ge.genre) || !stream->ReadSizePrefixedString(&ge.publisher) ||
|
||||||
!stream->ReadSizePrefixedString(&ge.developer) || !stream->ReadU64(&ge.total_size) ||
|
!stream->ReadSizePrefixedString(&ge.developer) || !stream->ReadU64(&ge.hash) ||
|
||||||
!stream->ReadU64(reinterpret_cast<u64*>(&ge.last_modified_time)) || !stream->ReadU64(&ge.release_date) ||
|
!stream->ReadU64(&ge.total_size) || !stream->ReadU64(reinterpret_cast<u64*>(&ge.last_modified_time)) ||
|
||||||
!stream->ReadU32(&ge.supported_controllers) || !stream->ReadU8(&ge.min_players) ||
|
!stream->ReadU64(&ge.release_date) || !stream->ReadU32(&ge.supported_controllers) ||
|
||||||
!stream->ReadU8(&ge.max_players) || !stream->ReadU8(&ge.min_blocks) || !stream->ReadU8(&ge.max_blocks) ||
|
!stream->ReadU8(&ge.min_players) || !stream->ReadU8(&ge.max_players) || !stream->ReadU8(&ge.min_blocks) ||
|
||||||
!stream->ReadU8(&compatibility_rating) || region >= static_cast<u8>(DiscRegion::Count) ||
|
!stream->ReadU8(&ge.max_blocks) || !stream->ReadU8(&compatibility_rating) ||
|
||||||
type >= static_cast<u8>(EntryType::Count) ||
|
region >= static_cast<u8>(DiscRegion::Count) || type >= static_cast<u8>(EntryType::Count) ||
|
||||||
compatibility_rating >= static_cast<u8>(GameDatabase::CompatibilityRating::Count))
|
compatibility_rating >= static_cast<u8>(GameDatabase::CompatibilityRating::Count))
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Game list cache entry is corrupted");
|
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->genre);
|
||||||
result &= s_cache_write_stream->WriteSizePrefixedString(entry->publisher);
|
result &= s_cache_write_stream->WriteSizePrefixedString(entry->publisher);
|
||||||
result &= s_cache_write_stream->WriteSizePrefixedString(entry->developer);
|
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->total_size);
|
||||||
result &= s_cache_write_stream->WriteU64(entry->last_modified_time);
|
result &= s_cache_write_stream->WriteU64(entry->last_modified_time);
|
||||||
result &= s_cache_write_stream->WriteU64(entry->release_date);
|
result &= s_cache_write_stream->WriteU64(entry->release_date);
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -37,6 +37,7 @@ struct Entry
|
||||||
std::string genre;
|
std::string genre;
|
||||||
std::string publisher;
|
std::string publisher;
|
||||||
std::string developer;
|
std::string developer;
|
||||||
|
u64 hash = 0;
|
||||||
u64 total_size = 0;
|
u64 total_size = 0;
|
||||||
std::time_t last_modified_time = 0;
|
std::time_t last_modified_time = 0;
|
||||||
std::time_t last_played_time = 0;
|
std::time_t last_played_time = 0;
|
||||||
|
|
|
@ -621,11 +621,11 @@ void SaveStateSelectorUI::RefreshList()
|
||||||
if (System::IsShutdown())
|
if (System::IsShutdown())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!System::GetRunningSerial().empty())
|
if (!System::GetGameSerial().empty())
|
||||||
{
|
{
|
||||||
for (s32 i = 1; i <= System::PER_GAME_SAVE_STATE_SLOTS; i++)
|
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());
|
std::optional<ExtendedSaveStateInfo> ssi = System::GetExtendedSaveStateInfo(path.c_str());
|
||||||
|
|
||||||
ListEntry li;
|
ListEntry li;
|
||||||
|
|
|
@ -293,3 +293,9 @@ bool ISOReader::ReadFile(const char* path, std::vector<u8>* data)
|
||||||
data->resize(de->length_le);
|
data->resize(de->length_le);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ISOReader::FileExists(const char* path)
|
||||||
|
{
|
||||||
|
auto de = LocateFile(path);
|
||||||
|
return de.has_value();
|
||||||
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ public:
|
||||||
std::vector<std::string> GetFilesInDirectory(const char* path);
|
std::vector<std::string> GetFilesInDirectory(const char* path);
|
||||||
|
|
||||||
bool ReadFile(const char* path, std::vector<u8>* data);
|
bool ReadFile(const char* path, std::vector<u8>* data);
|
||||||
|
bool FileExists(const char* path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadPVD();
|
bool ReadPVD();
|
||||||
|
|
Loading…
Reference in a new issue