diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 086fbe305..d3c5d1b03 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -90,6 +90,7 @@ static struct { const char* DataCustomLocation = "DataCustomLocation"; const char* IgnoreInvalidXbeSig = "IgnoreInvalidXbeSig"; const char *IgnoreInvalidXbeSec = "IgnoreInvalidXbeSec"; + const char* ConsoleTypeToggle = "ConsoleTypeToggle"; } sect_gui_keys; static const char* section_core = "core"; @@ -342,6 +343,8 @@ bool Settings::LoadConfig() m_gui.bIgnoreInvalidXbeSig = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, /*Default=*/false); m_gui.bIgnoreInvalidXbeSec = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, /*Default=*/false); + m_gui.ConsoleTypeToggle = (EMU_CONSOLE_TYPE)m_si.GetLongValue(section_gui, sect_gui_keys.ConsoleTypeToggle, /*Default=*/EMU_CONSOLE_TYPE_AUTO); + // ==== GUI End ============= // ==== Core Begin ========== @@ -588,6 +591,8 @@ bool Settings::Save(std::string file_path) m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, m_gui.bIgnoreInvalidXbeSig, nullptr, true); m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, m_gui.bIgnoreInvalidXbeSec, nullptr, true); + m_si.SetLongValue(section_gui, sect_gui_keys.ConsoleTypeToggle, m_gui.ConsoleTypeToggle, nullptr, true, true); + // ==== GUI End ============= // ==== Core Begin ========== diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index ff8e65994..deebb19f9 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -46,6 +46,14 @@ extern uint16_t g_LibVersion_DSOUND; "Invalid "#type" size, please verify structure is align, not adding new member, or is using placeholder reserves." \ " Otherwise, please perform versioning upgrade and update "#type" sizeof check." +// Toggle emulation console mode. +typedef enum _EMU_CONSOLE_TYPE { + EMU_CONSOLE_TYPE_AUTO = 0, + EMU_CONSOLE_TYPE_RETAIL = 1, + EMU_CONSOLE_TYPE_DEVKIT = 2, + EMU_CONSOLE_TYPE_CHIHIRO = 3, +} EMU_CONSOLE_TYPE; + // Cxbx-Reloaded's data storage location. typedef enum _CXBX_DATA { CXBX_DATA_INVALID = -1, @@ -91,6 +99,7 @@ public: std::string szCustomLocation = ""; bool bIgnoreInvalidXbeSig; bool bIgnoreInvalidXbeSec; + unsigned int ConsoleTypeToggle; } m_gui; // Core settings diff --git a/src/common/util/cliConfig.cpp b/src/common/util/cliConfig.cpp index 96ac94860..261c4dfdf 100644 --- a/src/common/util/cliConfig.cpp +++ b/src/common/util/cliConfig.cpp @@ -60,6 +60,15 @@ bool hasKey(std::string key) return false; } +// Delete the key if it exist +void DeleteKey(std::string key) +{ + auto found = g_cli_configs.find(key); + if (found != g_cli_configs.end()) { + g_cli_configs.erase(found); + } +} + // Generic getter bool GetValue(const std::string key, std::string* value) { @@ -179,4 +188,12 @@ void SetSystemType(const std::string value) } } +void ClearSystemType() +{ + // Clear any system types key existence. + DeleteKey(cli_config::system_retail); + DeleteKey(cli_config::system_devkit); + DeleteKey(cli_config::system_chihiro); +} + } diff --git a/src/common/util/cliConfig.hpp b/src/common/util/cliConfig.hpp index a3409a9ab..23d798c48 100644 --- a/src/common/util/cliConfig.hpp +++ b/src/common/util/cliConfig.hpp @@ -57,5 +57,6 @@ long long GetSessionID(); void SetLoad(const std::string value); void SetSystemType(const std::string value); +void ClearSystemType(); } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 61c93b043..458ddc1d1 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -514,12 +514,84 @@ static bool CxbxrKrnlXbeSystemSelector(int BootFlags, // Load Xbe (this one will reside above WinMain's virtual_memory_placeholder) std::filesystem::path xbeDirectory = std::filesystem::path(xbePath).parent_path(); + CxbxKrnl_Xbe = new Xbe(xbePath.c_str()); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() + + if (CxbxKrnl_Xbe->HasFatalError()) { + CxbxrAbort(CxbxKrnl_Xbe->GetError().c_str()); + return false; + } + + // Check the signature of the xbe + if (CxbxKrnl_Xbe->CheckSignature()) { + EmuLogInit(LOG_LEVEL::INFO, "Valid xbe signature. Xbe is legit"); + } + else { + EmuLogInit(LOG_LEVEL::WARNING, "Invalid xbe signature. Homebrew, tampered or pirated xbe?"); + } + + // Check the integrity of the xbe sections + for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { + if (CxbxKrnl_Xbe->CheckSectionIntegrity(sectionIndex)) { + EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + } + else { + EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, section is corrupted", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + } + } + + // If CLI has given console type, then enforce it. + if (cli_config::hasKey(cli_config::system_chihiro)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as chihiro."); + emulate_system = SYSTEM_CHIHIRO; + } + else if (cli_config::hasKey(cli_config::system_devkit)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as devkit."); + emulate_system = SYSTEM_DEVKIT; + } + else if (cli_config::hasKey(cli_config::system_retail)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as retail."); + emulate_system = SYSTEM_XBOX; + } + // Otherwise, use auto detect method. + else { + // Detect XBE type : + XbeType xbeType = CxbxKrnl_Xbe->GetXbeType(); + EmuLogInit(LOG_LEVEL::INFO, "Auto detect: XbeType = %s", GetXbeTypeToStr(xbeType)); + + // Convert XBE type into corresponding system to emulate. + switch (xbeType) { + case XbeType::xtChihiro: + emulate_system = SYSTEM_CHIHIRO; + break; + case XbeType::xtDebug: + emulate_system = SYSTEM_DEVKIT; + break; + case XbeType::xtRetail: + emulate_system = SYSTEM_XBOX; + break; + DEFAULT_UNREACHABLE; + } + + // If the XBE path contains a boot.id, it must be a Chihiro title + // This is necessary as some Chihiro games use the Debug xor instead of the Chihiro ones + // which means we cannot rely on that alone. + if (std::filesystem::exists(xbeDirectory / "boot.id")) { + emulate_system = SYSTEM_CHIHIRO; + } + } + + EmuLogInit(LOG_LEVEL::INFO, "Host's compatible system types: %2X", reserved_systems); + // If the system to emulate isn't supported on host, enforce failure. + if (!isSystemFlagSupport(reserved_systems, emulate_system)) { + CxbxrAbort("Unable to emulate system type due to host is not able to reserve required memory ranges."); + return false; + } + // Clear emulation system from reserved systems so all unneeded memory ranges can be freed. + reserved_systems &= ~emulate_system; + #ifdef CHIHIRO_WORK // If the Xbe is Chihiro, and we were not launched by SEGABOOT, we need to load SEGABOOT from the Chihiro Media Board rom instead! - // If the XBE path contains a boot.id, it must be a Chihiro title - // This is necessary as some Chihiro games use the Debug xor instead of the Chihiro ones - // which means we cannot rely on that alone. - if (BootFlags == BOOT_NONE && std::filesystem::exists(xbeDirectory / "boot.id")) { + if (BootFlags == BOOT_NONE && emulate_system == SYSTEM_CHIHIRO) { std::string chihiroMediaBoardRom = g_DataFilePath + "/EmuDisk/" + MediaBoardRomFile; if (!std::filesystem::exists(chihiroMediaBoardRom)) { @@ -580,82 +652,9 @@ static bool CxbxrKrnlXbeSystemSelector(int BootFlags, // Launch Segaboot CxbxLaunchNewXbe(chihiroSegaBootNew); CxbxrShutDown(true); - } #endif // Chihiro wip block - CxbxKrnl_Xbe = new Xbe(xbePath.c_str()); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() - - if (CxbxKrnl_Xbe->HasFatalError()) { - CxbxrAbort(CxbxKrnl_Xbe->GetError().c_str()); - return false; - } - - // Check the signature of the xbe - if (CxbxKrnl_Xbe->CheckSignature()) { - EmuLogInit(LOG_LEVEL::INFO, "Valid xbe signature. Xbe is legit"); - } - else { - EmuLogInit(LOG_LEVEL::WARNING, "Invalid xbe signature. Homebrew, tampered or pirated xbe?"); - } - - // Check the integrity of the xbe sections - for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { - if (CxbxKrnl_Xbe->CheckSectionIntegrity(sectionIndex)) { - EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - } - else { - EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, section is corrupted", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - } - } - - // If CLI has given console type, then enforce it. - if (cli_config::hasKey(cli_config::system_chihiro)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as chihiro."); - emulate_system = SYSTEM_CHIHIRO; - } - else if (cli_config::hasKey(cli_config::system_devkit)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as devkit."); - emulate_system = SYSTEM_DEVKIT; - } - else if (cli_config::hasKey(cli_config::system_retail)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as retail."); - emulate_system = SYSTEM_XBOX; - } - // Otherwise, use auto detect method. - else { - // Detect XBE type : - XbeType xbeType = CxbxKrnl_Xbe->GetXbeType(); - EmuLogInit(LOG_LEVEL::INFO, "Auto detect: XbeType = %s", GetXbeTypeToStr(xbeType)); - - // Convert XBE type into corresponding system to emulate. - switch (xbeType) { - case XbeType::xtChihiro: - emulate_system = SYSTEM_CHIHIRO; - break; - case XbeType::xtDebug: - emulate_system = SYSTEM_DEVKIT; - break; - case XbeType::xtRetail: - emulate_system = SYSTEM_XBOX; - break; - DEFAULT_UNREACHABLE; - } - - if (std::filesystem::exists(xbeDirectory / "boot.id")) { - emulate_system = SYSTEM_CHIHIRO; - } - } - - EmuLogInit(LOG_LEVEL::INFO, "Host's compatible system types: %2X", reserved_systems); - // If the system to emulate isn't supported on host, enforce failure. - if (!isSystemFlagSupport(reserved_systems, emulate_system)) { - CxbxrAbort("Unable to emulate system type due to host is not able to reserve required memory ranges."); - return false; - } - // Clear emulation system from reserved systems so all unneeded memory ranges can be freed. - reserved_systems &= ~emulate_system; - // Once we have determine which system type to run as, enforce it in future reboots. if ((BootFlags & BOOT_QUICK_REBOOT) == 0) { const char* system_str = GetSystemTypeToStr(emulate_system); diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 4502c57ec..93bc9c58b 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -70,6 +70,9 @@ #define XBOX_LED_FLASH_PERIOD 176 // if you know a more accurate value, put it here +static const char* popup_force_blank_console_type = "By force using the %s console type may cause side effects and may not be used to report to the game compatibility website."; +static const char* popup_will_not_take_effect_until_the_next_emulation = "This will not take effect until the next time emulation is started."; + static int gameLogoWidth, gameLogoHeight; static int splashLogoWidth, splashLogoHeight; @@ -978,6 +981,49 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } break; + case ID_SETTINGS_CONFIG_CONT_AUTO: + { + g_Settings->m_gui.ConsoleTypeToggle = EMU_CONSOLE_TYPE_AUTO; + if (m_bIsStarted) { + PopupInfo(m_hwnd, popup_will_not_take_effect_until_the_next_emulation); + } + RefreshMenus(); + } + break; + + case ID_SETTINGS_CONFIG_CONT_RETAIL: + { + g_Settings->m_gui.ConsoleTypeToggle = EMU_CONSOLE_TYPE_RETAIL; + PopupWarning(m_hwnd, popup_force_blank_console_type, "retail"); + if (m_bIsStarted) { + PopupInfo(m_hwnd, popup_will_not_take_effect_until_the_next_emulation); + } + RefreshMenus(); + } + break; + + case ID_SETTINGS_CONFIG_CONT_DEVKIT: + { + g_Settings->m_gui.ConsoleTypeToggle = EMU_CONSOLE_TYPE_DEVKIT; + PopupWarning(m_hwnd, popup_force_blank_console_type, "devkit"); + if (m_bIsStarted) { + PopupInfo(m_hwnd, popup_will_not_take_effect_until_the_next_emulation); + } + RefreshMenus(); + } + break; + + case ID_SETTINGS_CONFIG_CONT_CHIHIRO: + { + g_Settings->m_gui.ConsoleTypeToggle = EMU_CONSOLE_TYPE_CHIHIRO; + PopupWarning(m_hwnd, popup_force_blank_console_type, "chihiro"); + if (m_bIsStarted) { + PopupInfo(m_hwnd, popup_will_not_take_effect_until_the_next_emulation); + } + RefreshMenus(); + } + break; + case ID_SETTINGS_CONFIG_DLOCCUSTOM: { char szDir[MAX_PATH]; @@ -1105,7 +1151,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP else { g_Settings->m_core.KrnlDebugMode = DM_NONE; } - PopupInfo(m_hwnd, "This will not take effect until the next time emulation is started."); + PopupInfo(m_hwnd, popup_will_not_take_effect_until_the_next_emulation); RefreshMenus(); @@ -1712,6 +1758,36 @@ void WndMain::RefreshMenus() chk_flag = (g_Settings->m_hacks.SkipRdtscPatching) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_HACKS_SKIPRDTSCPATCHING, chk_flag); + switch (g_Settings->m_gui.ConsoleTypeToggle) { + case EMU_CONSOLE_TYPE_AUTO: + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_AUTO, MF_CHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_RETAIL, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_DEVKIT, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_CHIHIRO, MF_UNCHECKED); + break; + + case EMU_CONSOLE_TYPE_RETAIL: + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_AUTO, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_RETAIL, MF_CHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_DEVKIT, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_CHIHIRO, MF_UNCHECKED); + break; + + case EMU_CONSOLE_TYPE_DEVKIT: + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_AUTO, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_RETAIL, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_DEVKIT, MF_CHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_CHIHIRO, MF_UNCHECKED); + break; + + case EMU_CONSOLE_TYPE_CHIHIRO: + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_AUTO, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_RETAIL, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_DEVKIT, MF_UNCHECKED); + CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_CONT_CHIHIRO, MF_CHECKED); + break; + } + switch (g_Settings->m_gui.DataStorageToggle) { case CXBX_DATA_APPDATA: CheckMenuItem(settings_menu, ID_SETTINGS_CONFIG_DLOCAPPDATA, MF_CHECKED); @@ -2250,6 +2326,20 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / cli_config::SetLoad(m_XbeFilename); cli_config::SetValue(cli_config::hwnd, hwndParent); cli_config::SetValue(cli_config::debug_mode, g_Settings->m_core.KrnlDebugMode); + cli_config::ClearSystemType(); // Require to reset system type in GUI in order to choose the new system option. + if (g_Settings->m_gui.ConsoleTypeToggle > 0) { + switch (g_Settings->m_gui.ConsoleTypeToggle) { + case EMU_CONSOLE_TYPE_RETAIL: + cli_config::SetSystemType(cli_config::system_retail); + break; + case EMU_CONSOLE_TYPE_DEVKIT: + cli_config::SetSystemType(cli_config::system_devkit); + break; + case EMU_CONSOLE_TYPE_CHIHIRO: + cli_config::SetSystemType(cli_config::system_chihiro); + break; + } + } if (g_Settings->m_core.KrnlDebugMode == DM_FILE) { cli_config::SetValue(cli_config::debug_file, g_Settings->m_core.szKrnlDebug); } diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index 56b95e61e..d99adfc1a 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -763,6 +763,13 @@ BEGIN MENUITEM "Config &Network...", ID_SETTINGS_CONFIG_NETWORK,MFT_STRING,MFS_ENABLED MENUITEM "Config &Eeprom...", ID_SETTINGS_CONFIG_EEPROM,MFT_STRING,MFS_ENABLED MENUITEM "Config &Logging...", ID_SETTINGS_CONFIG_LOGGING,MFT_STRING,MFS_ENABLED + POPUP "Config &Console Type..." + BEGIN + MENUITEM "&Auto", ID_SETTINGS_CONFIG_CONT_AUTO + MENUITEM "&Retail", ID_SETTINGS_CONFIG_CONT_RETAIL + MENUITEM "&Devkit", ID_SETTINGS_CONFIG_CONT_DEVKIT + MENUITEM "&Chihiro", ID_SETTINGS_CONFIG_CONT_CHIHIRO + END POPUP "Config &Data Location...", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "Store in AppData", ID_SETTINGS_CONFIG_DLOCAPPDATA,MFT_STRING,MFS_ENABLED diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index eff2e721a..7d062e1e7 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -354,6 +354,10 @@ #define ID_SETTINGS_IGNOREINVALIDXBESIG 40114 #define ID_SETTINGS_IGNOREINVALIDXBESEC 40115 #define ID_SYNC_TIME_CHANGE 40116 +#define ID_SETTINGS_CONFIG_CONT_AUTO 40117 +#define ID_SETTINGS_CONFIG_CONT_RETAIL 40118 +#define ID_SETTINGS_CONFIG_CONT_DEVKIT 40119 +#define ID_SETTINGS_CONFIG_CONT_CHIHIRO 40120 #define IDC_STATIC -1 // Next default values for new objects @@ -361,7 +365,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 139 -#define _APS_NEXT_COMMAND_VALUE 40117 +#define _APS_NEXT_COMMAND_VALUE 40121 #define _APS_NEXT_CONTROL_VALUE 1308 #define _APS_NEXT_SYMED_VALUE 109 #endif