Merge pull request #2490 from RadWolfie/toggle-console-mode

GUI: Add ability to choose console type
This commit is contained in:
Luke Usher 2025-04-13 18:35:10 +01:00 committed by GitHub
commit ce15f50848
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 211 additions and 79 deletions

View File

@ -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 ==========

View File

@ -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

View File

@ -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);
}
}

View File

@ -57,5 +57,6 @@ long long GetSessionID();
void SetLoad(const std::string value);
void SetSystemType(const std::string value);
void ClearSystemType();
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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