diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 2017afa5d..292d2780d 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -127,7 +127,7 @@ std::string GameList::GetGameCodeForImage(CDImage* cdi) return code; } -std::optional GameList::GetRegionForCode(std::string_view code) +DiscRegion GameList::GetRegionForCode(std::string_view code) { std::string prefix; for (size_t pos = 0; pos < code.length(); pos++) @@ -140,21 +140,21 @@ std::optional GameList::GetRegionForCode(std::string_view code) } if (prefix == "sces" || prefix == "sced" || prefix == "sles" || prefix == "sled") - return ConsoleRegion::PAL; + return DiscRegion::PAL; else if (prefix == "scps" || prefix == "slps" || prefix == "slpm") - return ConsoleRegion::NTSC_J; + return DiscRegion::NTSC_J; else if (prefix == "scus" || prefix == "slus" || prefix == "papx") - return ConsoleRegion::NTSC_U; + return DiscRegion::NTSC_U; else - return std::nullopt; + return DiscRegion::Other; } -std::optional GameList::GetRegionFromSystemArea(CDImage* cdi) +DiscRegion GameList::GetRegionFromSystemArea(CDImage* cdi) { // The license code is on sector 4 of the disc. u8 sector[CDImage::DATA_SECTOR_SIZE]; if (!cdi->Seek(1, 4) || cdi->Read(CDImage::ReadMode::DataOnly, 1, sector) != 1) - return std::nullopt; + return DiscRegion::Other; static constexpr char ntsc_u_string[] = " Licensed by Sony Computer Entertainment Amer ica "; static constexpr char ntsc_j_string[] = " Licensed by Sony Computer Entertainment Inc."; @@ -162,29 +162,29 @@ std::optional GameList::GetRegionFromSystemArea(CDImage* cdi) // subtract one for the terminating null if (std::equal(ntsc_u_string, ntsc_u_string + countof(ntsc_u_string) - 1, sector)) - return ConsoleRegion::NTSC_U; + return DiscRegion::NTSC_U; else if (std::equal(ntsc_j_string, ntsc_j_string + countof(ntsc_j_string) - 1, sector)) - return ConsoleRegion::NTSC_J; + return DiscRegion::NTSC_J; else if (std::equal(pal_string, pal_string + countof(pal_string) - 1, sector)) - return ConsoleRegion::PAL; - - return std::nullopt; + return DiscRegion::PAL; + else + return DiscRegion::Other; } -std::optional GameList::GetRegionForImage(CDImage* cdi) +DiscRegion GameList::GetRegionForImage(CDImage* cdi) { - std::optional system_area_region = GetRegionFromSystemArea(cdi); - if (system_area_region) + DiscRegion system_area_region = GetRegionFromSystemArea(cdi); + if (system_area_region != DiscRegion::Other) return system_area_region; std::string code = GetGameCodeForImage(cdi); if (code.empty()) - return std::nullopt; + return DiscRegion::Other; return GetRegionForCode(code); } -std::optional GameList::GetRegionForPath(const char* image_path) +std::optional GameList::GetRegionForPath(const char* image_path) { std::unique_ptr cdi = CDImage::Open(image_path); if (!cdi) @@ -263,7 +263,7 @@ bool GameList::GetExeListEntry(const char* path, GameListEntry* entry) // no way to detect region... entry->path = path; - entry->region = ConsoleRegion::NTSC_U; + entry->region = DiscRegion::Other; entry->total_size = ZeroExtend64(file_size); entry->last_modified_time = ffd.ModificationTime.AsUnixTimestamp(); entry->type = GameListEntryType::PSExe; @@ -280,10 +280,14 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry) if (!cdi) return false; + std::string code = GetGameCodeForImage(cdi.get()); + DiscRegion region = GetRegionFromSystemArea(cdi.get()); + if (region == DiscRegion::Other) + region = GetRegionForCode(code); + entry->path = path; - entry->code = GetGameCodeForImage(cdi.get()); - entry->region = - GetRegionFromSystemArea(cdi.get()).value_or(GetRegionForCode(entry->code).value_or(ConsoleRegion::NTSC_U)); + entry->code = std::move(code); + entry->region = region; entry->total_size = static_cast(CDImage::RAW_SECTOR_SIZE) * static_cast(cdi->GetLBACount()); entry->type = GameListEntryType::Disc; cdi.reset(); @@ -299,7 +303,9 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry) if (database_entry) { entry->title = database_entry->title; - entry->region = database_entry->region; + + if (entry->region != database_entry->region) + Log_WarningPrintf("Region mismatch between disc and database for '%s'", entry->code.c_str()); } else { @@ -418,7 +424,7 @@ bool GameList::LoadEntriesFromCache(ByteStream* stream) if (!ReadString(stream, &path) || !ReadString(stream, &code) || !ReadString(stream, &title) || !ReadU64(stream, &total_size) || !ReadU64(stream, &last_modified_time) || !ReadU8(stream, ®ion) || - region >= static_cast(ConsoleRegion::Count) || !ReadU8(stream, &type) || + region >= static_cast(DiscRegion::Count) || !ReadU8(stream, &type) || type > static_cast(GameListEntryType::PSExe)) { Log_WarningPrintf("Game list cache entry is corrupted"); @@ -431,7 +437,7 @@ bool GameList::LoadEntriesFromCache(ByteStream* stream) ge.title = std::move(title); ge.total_size = total_size; ge.last_modified_time = last_modified_time; - ge.region = static_cast(region); + ge.region = static_cast(region); ge.type = static_cast(type); auto iter = m_cache_map.find(ge.path); @@ -620,7 +626,7 @@ public: { GameListDatabaseEntry gde; gde.code = std::move(code); - gde.region = GameList::GetRegionForCode(gde.code).value_or(ConsoleRegion::NTSC_U); + gde.region = GameList::GetRegionForCode(gde.code); gde.title = name; m_database.emplace(gde.code, std::move(gde)); } diff --git a/src/core/game_list.h b/src/core/game_list.h index 0b51d1fea..afb797530 100644 --- a/src/core/game_list.h +++ b/src/core/game_list.h @@ -22,7 +22,7 @@ struct GameListDatabaseEntry { std::string code; std::string title; - ConsoleRegion region; + DiscRegion region; }; struct GameListEntry @@ -32,7 +32,7 @@ struct GameListEntry std::string title; u64 total_size; u64 last_modified_time; - ConsoleRegion region; + DiscRegion region; GameListEntryType type; }; @@ -51,10 +51,10 @@ public: static std::string GetGameCodeForImage(CDImage* cdi); static std::string GetGameCodeForPath(const char* image_path); - static std::optional GetRegionForCode(std::string_view code); - static std::optional GetRegionFromSystemArea(CDImage* cdi); - static std::optional GetRegionForImage(CDImage* cdi); - static std::optional GetRegionForPath(const char* image_path); + static DiscRegion GetRegionForCode(std::string_view code); + static DiscRegion GetRegionFromSystemArea(CDImage* cdi); + static DiscRegion GetRegionForImage(CDImage* cdi); + static std::optional GetRegionForPath(const char* image_path); static std::string_view GetTitleForPath(const char* path); const EntryList& GetEntries() const { return m_entries; } @@ -79,7 +79,7 @@ private: enum : u32 { GAME_LIST_CACHE_SIGNATURE = 0x45434C47, - GAME_LIST_CACHE_VERSION = 2 + GAME_LIST_CACHE_VERSION = 3 }; using DatabaseMap = std::unordered_map; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2c570c49f..7cd0c898e 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -155,6 +155,34 @@ const char* Settings::GetConsoleRegionDisplayName(ConsoleRegion region) return s_console_region_display_names[static_cast(region)]; } +static std::array s_disc_region_names = {{"NTSC-J", "NTSC-U", "PAL", "Other"}}; +static std::array s_disc_region_display_names = { + {"NTSC-J (Japan)", "NTSC-U (US)", "PAL (Europe, Australia)", "Other"}}; + +std::optional Settings::ParseDiscRegionName(const char* str) +{ + int index = 0; + for (const char* name : s_console_region_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetDiscRegionName(DiscRegion region) +{ + return s_disc_region_names[static_cast(region)]; +} + +const char* Settings::GetDiscRegionDisplayName(DiscRegion region) +{ + return s_disc_region_display_names[static_cast(region)]; +} + static std::array s_cpu_execution_mode_names = {{"Interpreter", "CachedInterpreter", "Recompiler"}}; static std::array s_cpu_execution_mode_display_names = { {"Intepreter (Slowest)", "Cached Interpreter (Faster)", "Recompiler (Fastest)"}}; diff --git a/src/core/settings.h b/src/core/settings.h index 62b7358e1..bc7af795c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -91,6 +91,10 @@ struct Settings static const char* GetConsoleRegionName(ConsoleRegion region); static const char* GetConsoleRegionDisplayName(ConsoleRegion region); + static std::optional ParseDiscRegionName(const char* str); + static const char* GetDiscRegionName(DiscRegion region); + static const char* GetDiscRegionDisplayName(DiscRegion region); + static std::optional ParseCPUExecutionMode(const char* str); static const char* GetCPUExecutionModeName(CPUExecutionMode mode); static const char* GetCPUExecutionModeDisplayName(CPUExecutionMode mode); diff --git a/src/core/system.cpp b/src/core/system.cpp index 6c8702706..6555d556f 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -59,6 +59,23 @@ System::~System() DestroyComponents(); } +ConsoleRegion System::GetConsoleRegionForDiscRegion(DiscRegion region) +{ + switch (region) + { + case DiscRegion::NTSC_J: + return ConsoleRegion::NTSC_J; + + case DiscRegion::NTSC_U: + case DiscRegion::Other: + default: + return ConsoleRegion::NTSC_U; + + case DiscRegion::PAL: + return ConsoleRegion::PAL; + } +} + std::unique_ptr System::Create(HostInterface* host_interface) { std::unique_ptr system(new System(host_interface)); @@ -136,18 +153,19 @@ bool System::Boot(const SystemBootParameters& params) if (m_region == ConsoleRegion::Auto) { - std::optional detected_region = GameList::GetRegionForImage(media.get()); - if (detected_region) + const DiscRegion disc_region = GameList::GetRegionForImage(media.get()); + if (disc_region != DiscRegion::Other) { - m_region = detected_region.value(); - Log_InfoPrintf("Auto-detected %s region for '%s'", Settings::GetConsoleRegionName(m_region), - params.filename.c_str()); + m_region = GetConsoleRegionForDiscRegion(disc_region); + Log_InfoPrintf("Auto-detected console %s region for '%s' (region %s)", + Settings::GetConsoleRegionName(m_region), params.filename.c_str(), + Settings::GetDiscRegionName(disc_region)); } else { m_region = ConsoleRegion::NTSC_U; - Log_WarningPrintf("Could not determine region for CD. Defaulting to %s.", - Settings::GetConsoleRegionName(m_region)); + Log_WarningPrintf("Could not determine console region for disc region %s. Defaulting to %s.", + Settings::GetDiscRegionName(disc_region), Settings::GetConsoleRegionName(m_region)); } } } diff --git a/src/core/system.h b/src/core/system.h index 476f8ca41..f6988b715 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -45,6 +45,9 @@ public: ~System(); + /// Returns the preferred console type for a disc. + static ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region); + /// Creates a new System. static std::unique_ptr Create(HostInterface* host_interface); diff --git a/src/core/types.h b/src/core/types.h index 1645ac883..f551457d5 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -31,6 +31,15 @@ enum class ConsoleRegion Count }; +enum class DiscRegion : u8 +{ + NTSC_J, // SCEI + NTSC_U, // SCEA + PAL, // SCEE + Other, + Count +}; + enum class CPUExecutionMode : u8 { Interpreter, @@ -78,7 +87,6 @@ enum : u32 NUM_CONTROLLER_AND_CARD_PORTS = 2 }; - enum : u32 { CPU_CODE_CACHE_PAGE_SIZE = 1024, diff --git a/src/duckstation-qt/gamelistwidget.cpp b/src/duckstation-qt/gamelistwidget.cpp index 34d68c016..583e19a62 100644 --- a/src/duckstation-qt/gamelistwidget.cpp +++ b/src/duckstation-qt/gamelistwidget.cpp @@ -147,11 +147,11 @@ public: { switch (ge.region) { - case ConsoleRegion::NTSC_J: + case DiscRegion::NTSC_J: return m_region_jp_pixmap; - case ConsoleRegion::NTSC_U: + case DiscRegion::NTSC_U: return m_region_us_pixmap; - case ConsoleRegion::PAL: + case DiscRegion::PAL: default: return m_region_eu_pixmap; }