Merge with latest.

This commit is contained in:
Chris Spegal 2025-04-06 00:33:16 -04:00
commit 345098c37a
484 changed files with 30773 additions and 15076 deletions

View file

@ -12,10 +12,8 @@
#include "audio/audioDebuggerWindow.h"
#include "gui/canvas/OpenGLCanvas.h"
#include "gui/canvas/VulkanCanvas.h"
#include "Cafe/OS/libs/nn_nfp/nn_nfp.h"
#include "Cafe/OS/libs/nfc/nfc.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
#include "Cafe/IOSU/legacy/iosu_crypto.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "gui/debugger/DebuggerWindow2.h"
#include "util/helpers/helpers.h"
#include "config/CemuConfig.h"
@ -23,10 +21,8 @@
#include "util/ScreenSaver/ScreenSaver.h"
#include "gui/GeneralSettings2.h"
#include "gui/GraphicPacksWindow2.h"
#include "gui/GameProfileWindow.h"
#include "gui/CemuApp.h"
#include "gui/CemuUpdateWindow.h"
#include "gui/helpers/wxCustomData.h"
#include "gui/LoggingWindow.h"
#include "config/ActiveSettings.h"
#include "config/LaunchSettings.h"
@ -34,11 +30,10 @@
#include "Cafe/Filesystem/FST/FST.h"
#include "gui/TitleManager.h"
#include "gui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h"
#include "Cafe/CafeSystem.h"
#include "Cafe/TitleList/GameInfo.h"
#include <boost/algorithm/string.hpp>
#include "util/helpers/SystemException.h"
#include "gui/DownloadGraphicPacksWindow.h"
#include "gui/GettingStartedDialog.h"
@ -81,6 +76,8 @@ enum
MAINFRAME_MENU_ID_FILE_LOAD = 20100,
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER,
MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER,
MAINFRAME_MENU_ID_FILE_SAVESTATE,
MAINFRAME_MENU_ID_FILE_LOADSTATE,
MAINFRAME_MENU_ID_FILE_EXIT,
@ -117,6 +114,7 @@ enum
MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER = 20600,
MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER,
MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER,
MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES,
// cpu
// cpu->timer speed
MAINFRAME_MENU_ID_TIMER_SPEED_1X = 20700,
@ -159,11 +157,8 @@ enum
MAINFRAME_MENU_ID_DEBUG_DUMP_FST,
MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS,
// help
MAINFRAME_MENU_ID_HELP_WEB = 21700,
MAINFRAME_MENU_ID_HELP_ABOUT,
MAINFRAME_MENU_ID_HELP_ABOUT = 21700,
MAINFRAME_MENU_ID_HELP_UPDATE,
MAINFRAME_MENU_ID_HELP_GETTING_STARTED,
// custom
MAINFRAME_ID_TIMER1 = 21800,
};
@ -182,8 +177,9 @@ EVT_MOVE(MainWindow::OnMove)
// file menu
EVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenCemuFolder)
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenFolder)
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MainWindow::OnOpenFolder)
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, MainWindow::OnOpenFolder)
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
@ -203,6 +199,7 @@ EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_INPUT, MainWindow::OnOptionsInput)
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, MainWindow::OnToolsInput)
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, MainWindow::OnToolsInput)
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, MainWindow::OnToolsInput)
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES, MainWindow::OnToolsInput)
// cpu menu
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_8X, MainWindow::OnDebugSetting)
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_4X, MainWindow::OnDebugSetting)
@ -240,10 +237,8 @@ EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, MainWindow::OnDebugViewPPCDe
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER, MainWindow::OnDebugViewAudioDebugger)
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, MainWindow::OnDebugViewTextureRelations)
// help menu
EVT_MENU(MAINFRAME_MENU_ID_HELP_WEB, MainWindow::OnHelpVistWebpage)
EVT_MENU(MAINFRAME_MENU_ID_HELP_ABOUT, MainWindow::OnHelpAbout)
EVT_MENU(MAINFRAME_MENU_ID_HELP_UPDATE, MainWindow::OnHelpUpdate)
EVT_MENU(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, MainWindow::OnHelpGettingStarted)
// misc
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAMELIST_REFRESH, MainWindow::OnRequestGameListRefresh)
@ -263,7 +258,7 @@ public:
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override
{
if(!m_window->IsGameLaunched() && filenames.GetCount() == 1)
return m_window->FileLoad(filenames[0].wc_str(), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);
return m_window->FileLoad(_utf8ToPath(filenames[0].utf8_string()), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);
return false;
}
@ -280,20 +275,20 @@ public:
{
if (!m_window->IsGameLaunched() || filenames.GetCount() != 1)
return false;
uint32 nfcError;
if (nnNfp_touchNfcTagFromFile(filenames[0].wc_str(), &nfcError))
std::string path = filenames[0].utf8_string();
if (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError))
{
GetConfig().AddRecentNfcFile((wchar_t*)filenames[0].wc_str());
GetConfig().AddRecentNfcFile(path);
m_window->UpdateNFCMenu();
return true;
}
else
{
if (nfcError == NFC_ERROR_NO_ACCESS)
if (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)
wxMessageBox(_("Cannot open file"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC NTAG215 file"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
else if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC file"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
}
@ -436,25 +431,6 @@ wxString MainWindow::GetInitialWindowTitle()
return BUILD_VERSION_WITH_NAME_STRING;
}
void MainWindow::ShowGettingStartedDialog()
{
GettingStartedDialog dia(this);
dia.ShowModal();
if (dia.HasGamePathChanged() || dia.HasMLCChanged())
m_game_list->ReloadGameEntries();
TogglePadView();
auto& config = GetConfig();
m_padViewMenuItem->Check(config.pad_open.GetValue());
m_fullscreenMenuItem->Check(config.fullscreen.GetValue());
}
namespace coreinit
{
void OSSchedulerEnd();
};
void MainWindow::OnClose(wxCloseEvent& event)
{
wxTheClipboard->Flush();
@ -508,9 +484,8 @@ bool MainWindow::InstallUpdate(const fs::path& metaFilePath)
return false;
}
bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY initiatedBy)
bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATED_BY initiatedBy)
{
const fs::path launchPath = fs::path(fileName);
TitleInfo launchTitle{ launchPath };
if (launchTitle.IsValid())
{
@ -524,40 +499,40 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
CafeSystem::STATUS_CODE r = CafeSystem::PrepareForegroundTitle(baseTitleId);
if (r == CafeSystem::STATUS_CODE::INVALID_RPX)
CafeSystem::PREPARE_STATUS_CODE r = CafeSystem::PrepareForegroundTitle(baseTitleId);
if (r == CafeSystem::PREPARE_STATUS_CODE::INVALID_RPX)
{
cemu_assert_debug(false);
return false;
}
else if (r == CafeSystem::STATUS_CODE::UNABLE_TO_MOUNT)
else if (r == CafeSystem::PREPARE_STATUS_CODE::UNABLE_TO_MOUNT)
{
wxString t = _("Unable to mount title.\nMake sure the configured game paths are still valid and refresh the game list.\n\nFile which failed to load:\n");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
else if (r != CafeSystem::STATUS_CODE::SUCCESS)
else if (r != CafeSystem::PREPARE_STATUS_CODE::SUCCESS)
{
wxString t = _("Failed to launch game.");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
}
else //if (launchTitle.GetFormat() == TitleInfo::TitleDataFormat::INVALID_STRUCTURE )
{
// title is invalid, if its an RPX/ELF we can launch it directly
// otherwise its an error
// title is invalid, if it's an RPX/ELF we can launch it directly
// otherwise it's an error
CafeTitleFileType fileType = DetermineCafeSystemFileType(launchPath);
if (fileType == CafeTitleFileType::RPX || fileType == CafeTitleFileType::ELF)
{
CafeSystem::STATUS_CODE r = CafeSystem::PrepareForegroundTitleFromStandaloneRPX(launchPath);
if (r != CafeSystem::STATUS_CODE::SUCCESS)
CafeSystem::PREPARE_STATUS_CODE r = CafeSystem::PrepareForegroundTitleFromStandaloneRPX(launchPath);
if (r != CafeSystem::PREPARE_STATUS_CODE::SUCCESS)
{
cemu_assert_debug(false); // todo
wxString t = _("Failed to launch executable. Path: ");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
@ -565,7 +540,7 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY
else if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::GAME_LIST)
{
wxString t = _("Unable to launch title.\nMake sure the configured game paths are still valid and refresh the game list.\n\nPath which failed to load:\n");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
@ -573,23 +548,33 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY
initiatedBy == wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE)
{
wxString t = _("Unable to launch game\nPath:\n");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
if(launchTitle.GetInvalidReason() == TitleInfo::InvalidReason::NO_DISC_KEY)
{
t.append("\n\n");
t.append(_("Could not decrypt title. Make sure that keys.txt contains the correct disc key for this title."));
}
if(launchTitle.GetInvalidReason() == TitleInfo::InvalidReason::NO_TITLE_TIK)
{
t.append("\n\n");
t.append(_("Could not decrypt title because title.tik is missing."));
}
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
else
{
wxString t = _("Unable to launch game\nPath:\n");
t.append(fileName);
t.append(_pathToUtf8(launchPath));
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return false;
}
}
if(launchTitle.IsValid())
GetConfig().AddRecentlyLaunchedFile(launchTitle.GetPath().generic_wstring());
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));
else
GetConfig().AddRecentlyLaunchedFile(fileName);
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));
wxWindowUpdateLocker lock(this);
@ -637,6 +622,7 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY
CreateCanvas();
CafeSystem::LaunchForegroundTitle();
RecreateMenu();
UpdateChildWindowTitleRunningState();
return true;
}
@ -645,7 +631,7 @@ void MainWindow::OnLaunchFromFile(wxLaunchGameEvent& event)
{
if (event.GetPath().empty())
return;
FileLoad(event.GetPath().generic_wstring(), event.GetInitiatedBy());
FileLoad(event.GetPath(), event.GetInitiatedBy());
}
void MainWindow::OnFileMenu(wxCommandEvent& event)
@ -653,17 +639,21 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
const auto menuId = event.GetId();
if (menuId == MAINFRAME_MENU_ID_FILE_LOAD)
{
const auto wildcard = wxStringFormat2(
"{}|*.wud;*.wux;*.wua;*.iso;*.rpx;*.elf"
const auto wildcard = formatWxString(
"{}|*.wud;*.wux;*.wua;*.wuhb;*.iso;*.rpx;*.elf;title.tmd"
"|{}|*.wud;*.wux;*.iso"
"|{}|title.tmd"
"|{}|*.wua"
"|{}|*.wuhb"
"|{}|*.rpx;*.elf"
"|{}|*",
_("All Wii U files (*.wud, *.wux, *.wua, *.iso, *.rpx, *.elf)"),
_("All Wii U files (*.wud, *.wux, *.wua, *.wuhb, *.iso, *.rpx, *.elf)"),
_("Wii U image (*.wud, *.wux, *.iso, *.wad)"),
_("Wii U NUS content"),
_("Wii U archive (*.wua)"),
_("Wii U homebrew bundle (*.wuhb)"),
_("Wii U executable (*.rpx, *.elf)"),
_("All files (*.*)")
_("All files (*.*)")
);
wxFileDialog openFileDialog(this, _("Open file to launch"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
@ -672,7 +662,7 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
return;
const wxString wxStrFilePath = openFileDialog.GetPath();
FileLoad(wxStrFilePath.wc_str(), wxLaunchGameEvent::INITIATED_BY::MENU);
FileLoad(_utf8ToPath(wxStrFilePath.utf8_string()), wxLaunchGameEvent::INITIATED_BY::MENU);
}
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
{
@ -680,7 +670,7 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
const size_t index = menuId - MAINFRAME_MENU_ID_FILE_RECENT_0;
if (index < config.recent_launch_files.size())
{
const auto& path = config.recent_launch_files[index];
fs::path path = _utf8ToPath(config.recent_launch_files[index]);
if (!path.empty())
FileLoad(path, wxLaunchGameEvent::INITIATED_BY::MENU);
}
@ -693,12 +683,21 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
RecreateMenu();
CreateGameListAndStatusBar();
DoLayout();
UpdateChildWindowTitleRunningState();
}
}
void MainWindow::OnOpenCemuFolder(wxCommandEvent& event)
void MainWindow::OnOpenFolder(wxCommandEvent& event)
{
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetUserDataPath()));
const auto id = event.GetId();
if(id == MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER)
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetUserDataPath()));
else if(id == MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER)
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetMlcPath()));
else if (id == MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER)
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetCachePath("shaderCache")));
}
void MainWindow::OnInstallUpdate(wxCommandEvent& event)
@ -721,7 +720,7 @@ void MainWindow::OnInstallUpdate(wxCommandEvent& event)
{
if (!fs::exists(dirPath.parent_path() / "code") || !fs::exists(dirPath.parent_path() / "content") || !fs::exists(dirPath.parent_path() / "meta"))
{
wxMessageBox(wxStringFormat2(_("The (parent) folder of the title you selected is missing at least one of the required subfolders (\"code\", \"content\" and \"meta\")\nMake sure that the files are complete."), dirPath.filename().string()));
wxMessageBox(formatWxString(_("The (parent) folder of the title you selected is missing at least one of the required subfolders (\"code\", \"content\" and \"meta\")\nMake sure that the files are complete."), dirPath.filename().string()));
continue;
}
else
@ -752,16 +751,16 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event)
return;
wxString wxStrFilePath = openFileDialog.GetPath();
uint32 nfcError;
if (nnNfp_touchNfcTagFromFile(wxStrFilePath.wc_str(), &nfcError) == false)
if (nfc::TouchTagFromFile(_utf8ToPath(wxStrFilePath.utf8_string()), &nfcError) == false)
{
if (nfcError == NFC_ERROR_NO_ACCESS)
if (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)
wxMessageBox(_("Cannot open file"));
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC NTAG215 file"));
else if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC file"));
}
else
{
GetConfig().AddRecentNfcFile((wchar_t*)wxStrFilePath.wc_str());
GetConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());
UpdateNFCMenu();
}
}
@ -775,12 +774,12 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event)
if (!path.empty())
{
uint32 nfcError = 0;
if (nnNfp_touchNfcTagFromFile(path.c_str(), &nfcError) == false)
if (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError) == false)
{
if (nfcError == NFC_ERROR_NO_ACCESS)
if (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)
wxMessageBox(_("Cannot open file"));
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC NTAG215 file"));
else if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)
wxMessageBox(_("Not a valid NFC file"));
}
else
{
@ -972,38 +971,6 @@ void MainWindow::OnAccountSelect(wxCommandEvent& event)
g_config.Save();
}
//void MainWindow::OnConsoleRegion(wxCommandEvent& event)
//{
// switch (event.GetId())
// {
// case MAINFRAME_MENU_ID_OPTIONS_REGION_AUTO:
// GetConfig().console_region = ConsoleRegion::Auto;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_JPN:
// GetConfig().console_region = ConsoleRegion::JPN;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_USA:
// GetConfig().console_region = ConsoleRegion::USA;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_EUR:
// GetConfig().console_region = ConsoleRegion::EUR;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_CHN:
// GetConfig().console_region = ConsoleRegion::CHN;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_KOR:
// GetConfig().console_region = ConsoleRegion::KOR;
// break;
// case MAINFRAME_MENU_ID_OPTIONS_REGION_TWN:
// GetConfig().console_region = ConsoleRegion::TWN;
// break;
// default:
// cemu_assert_debug(false);
// }
//
// g_config.Save();
//}
void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
{
switch (event.GetId())
@ -1047,8 +1014,11 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
default:
cemu_assert_debug(false);
}
m_game_list->DeleteCachedStrings();
m_game_list->ReloadGameEntries(false);
if (m_game_list)
{
m_game_list->DeleteCachedStrings();
m_game_list->ReloadGameEntries(false);
}
g_config.Save();
}
@ -1139,7 +1109,14 @@ void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
sint32 id = event.GetId();
if (id >= loggingIdBase && id < (MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 64))
{
cemuLog_setFlag(static_cast<LogType>(id - loggingIdBase), event.IsChecked());
bool isEnable = event.IsChecked();
LogType loggingType = static_cast<LogType>(id - loggingIdBase);
if (isEnable)
GetConfig().log_flag = GetConfig().log_flag.GetValue() | cemuLog_getFlag(loggingType);
else
GetConfig().log_flag = GetConfig().log_flag.GetValue() & ~cemuLog_getFlag(loggingType);
cemuLog_setActiveLoggingFlags(GetConfig().log_flag.GetValue());
g_config.Save();
}
}
@ -1178,9 +1155,7 @@ void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event)
{
try
{
// create directory
const fs::path path(ActiveSettings::GetUserDataPath());
fs::create_directories(path / "dump" / "shaders");
fs::create_directories(ActiveSettings::GetUserDataPath("dump/shaders"));
}
catch (const std::exception & ex)
{
@ -1506,6 +1481,19 @@ void MainWindow::OnKeyUp(wxKeyEvent& event)
g_window_info.has_screenshot_request = true; // async screenshot request
}
void MainWindow::OnKeyDown(wxKeyEvent& event)
{
if ((event.AltDown() && event.GetKeyCode() == WXK_F4) ||
(event.CmdDown() && event.GetKeyCode() == 'Q'))
{
Close(true);
}
else
{
event.Skip();
}
}
void MainWindow::OnChar(wxKeyEvent& event)
{
if (swkbd_hasKeyboardInputHook())
@ -1548,6 +1536,29 @@ void MainWindow::OnToolsInput(wxCommandEvent& event)
});
m_title_manager->Show();
}
break;
}
case MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES:
{
if (m_usb_devices)
{
m_usb_devices->Show(true);
m_usb_devices->Raise();
m_usb_devices->SetFocus();
}
else
{
m_usb_devices = new EmulatedUSBDeviceFrame(this);
m_usb_devices->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event)
{
if (event.CanVeto()) {
m_usb_devices->Show(false);
event.Veto();
}
});
m_usb_devices->Show(true);
}
break;
}
break;
}
@ -1611,6 +1622,7 @@ void MainWindow::CreateCanvas()
// key events
m_render_canvas->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);
m_render_canvas->Bind(wxEVT_KEY_DOWN, &MainWindow::OnKeyDown, this);
m_render_canvas->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);
m_render_canvas->SetDropTarget(new wxAmiiboDropTarget(this));
@ -1777,13 +1789,13 @@ void MainWindow::UpdateNFCMenu()
if (entry.empty())
continue;
if (!fs::exists(entry))
if (!fs::exists(_utf8ToPath(entry)))
continue;
if (recentFileIndex == 0)
m_nfcMenuSeparator0 = m_nfcMenu->AppendSeparator();
m_nfcMenu->Append(MAINFRAME_MENU_ID_NFC_RECENT_0 + i, fmt::format(L"{}. {}", recentFileIndex, entry ));
m_nfcMenu->Append(MAINFRAME_MENU_ID_NFC_RECENT_0 + i, to_wxString(fmt::format("{}. {}", recentFileIndex, entry)));
recentFileIndex++;
if (recentFileIndex >= 12)
@ -1833,8 +1845,6 @@ void MainWindow::OnTimer(wxTimerEvent& event)
}
void MainWindow::OnHelpVistWebpage(wxCommandEvent& event) {}
#define BUILD_DATE __DATE__ " " __TIME__
class CemuAboutDialog : public wxDialog
@ -1873,7 +1883,7 @@ public:
void AddHeaderInfo(wxWindow* parent, wxSizer* sizer)
{
auto versionString = fmt::format(fmt::runtime(_("Cemu\nVersion {0}\nCompiled on {1}\nOriginal authors: {2}").ToStdString()), BUILD_VERSION_STRING, BUILD_DATE, "Exzap, Petergov");
auto versionString = formatWxString(_("Cemu\nVersion {0}\nCompiled on {1}\nOriginal authors: {2}"), BUILD_VERSION_STRING, BUILD_DATE, "Exzap, Petergov");
sizer->Add(new wxStaticText(parent, wxID_ANY, versionString), wxSizerFlags().Border(wxALL, 3).Border(wxTOP, 10));
sizer->Add(new wxHyperlinkCtrl(parent, -1, "https://cemu.info", "https://cemu.info"), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 3));
@ -1897,7 +1907,7 @@ public:
{
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
lineSizer->Add(new wxStaticText(parent, -1, "zLib ("), 0);
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "http://www.zlib.net", "http://www.zlib.net"), 0);
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://www.zlib.net", "https://www.zlib.net"), 0);
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
sizer->Add(lineSizer);
}
@ -2043,7 +2053,7 @@ public:
, "Faris Leonhart", "MahvZero", "PlaguedGuardian", "Stuffie", "CaptainLester", "Qtech", "Zaurexus", "Leonidas", "Artifesto"
, "Alca259", "SirWestofAsh", "Loli Co.", "The Technical Revolutionary", "MegaYama", "mitori", "Seymordius", "Adrian Josh Cruz", "Manuel Hoenings", "Just A Jabb"
, "pgantonio", "CannonXIII", "Lonewolf00708", "AlexsDesign.com", "NoskLo", "MrSirHaku", "xElite_V AKA William H. Johnson", "Zalnor", "Pig", "James \"SE4LS\"", "DairyOrange", "Horoko Lawrence", "bloodmc", "Officer Jenny", "Quasar", "Postposterous", "Jake Jackson", "Kaydax", "CthePredatorG"
, "Hengi", "Pyrochaser"};
, "Hengi", "Pyrochaser", "luma.x3"};
wxString nameListLeft, nameListRight;
for (size_t i = 0; i < patreonSupporterNames.size(); i++)
@ -2083,11 +2093,6 @@ void MainWindow::OnHelpUpdate(wxCommandEvent& event)
test.ShowModal();
}
void MainWindow::OnHelpGettingStarted(wxCommandEvent& event)
{
ShowGettingStartedDialog();
}
void MainWindow::RecreateMenu()
{
if (m_menuBar)
@ -2113,17 +2118,12 @@ void MainWindow::RecreateMenu()
m_fileMenuSeparator1 = nullptr;
for (size_t i = 0; i < config.recent_launch_files.size(); i++)
{
const auto& entry = config.recent_launch_files[i];
if (entry.empty())
const std::string& pathStr = config.recent_launch_files[i];
if (pathStr.empty())
continue;
if (!fs::exists(entry))
continue;
if (recentFileIndex == 0)
m_fileMenuSeparator0 = m_fileMenu->AppendSeparator();
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, fmt::format(L"{}. {}", recentFileIndex, entry));
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, to_wxString(fmt::format("{}. {}", recentFileIndex, pathStr)));
recentFileIndex++;
if (recentFileIndex >= 8)
@ -2140,6 +2140,8 @@ void MainWindow::RecreateMenu()
}
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("&Open Cemu folder"));
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _("&Open MLC folder"));
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, _("Open &shader cache folder"));
m_fileMenu->AppendSeparator();
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit"));
@ -2172,6 +2174,14 @@ void MainWindow::RecreateMenu()
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE, _("&Portuguese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::PT);
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN, _("&Russian"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::RU);
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, _("&Taiwanese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::TW);
if(IsGameLaunched())
{
auto items = optionsConsoleLanguageMenu->GetMenuItems();
for (auto& item : items)
{
item->Enable(false);
}
}
// options submenu
wxMenu* optionsMenu = new wxMenu();
@ -2196,6 +2206,8 @@ void MainWindow::RecreateMenu()
m_memorySearcherMenuItem->Enable(false);
toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, _("&Title Manager"));
toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, _("&Download Manager"));
toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES, _("&Emulated USB Devices"));
m_menuBar->Append(toolsMenu, _("&Tools"));
// cpu timer speed menu
@ -2230,22 +2242,35 @@ void MainWindow::RecreateMenu()
m_menuBar->Append(savestatesMenu, _("&Savestates"));
// debug->logging submenu
wxMenu* debugLoggingMenu = new wxMenu;
wxMenu* debugLoggingMenu = new wxMenu();
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::UnsupportedAPI), _("&Unsupported API calls"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::UnsupportedAPI));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::APIErrors), _("&Invalid API usage"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::APIErrors));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitLogging), _("&Coreinit Logging (OSReport/OSConsole)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitLogging));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitFile), _("&Coreinit File-Access API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitFile));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::ThreadSync), _("&Coreinit Thread-Synchronization API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::ThreadSync));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMem), _("&Coreinit Memory API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMem));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("&Coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("&Coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::nn_nfp), _("&NN NFP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::nn_nfp));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("&GX2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("&Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("&Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Socket), _("&Socket API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Socket));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Save), _("&Save API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Save));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::H264), _("&H264 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::H264));
debugLoggingMenu->AppendSeparator();
wxMenu* logCosModulesMenu = new wxMenu();
logCosModulesMenu->AppendCheckItem(0, _("&Options below are for experts. Leave off if unsure"), wxEmptyString)->Enable(false);
logCosModulesMenu->AppendSeparator();
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitFile), _("coreinit File-Access API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitFile));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThreadSync), _("coreinit Thread-Synchronization API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThreadSync));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMem), _("coreinit Memory API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMem));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Save), _("nn_save API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Save));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_NFP), _("nn_nfp API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_NFP));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_FP), _("nn_fp API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_FP));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::PRUDP), _("nn_fp PRUDP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::PRUDP));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_BOSS), _("nn_boss API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_BOSS));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NFC), _("nfc API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NFC));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NTAG), _("ntag API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NTAG));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Socket), _("nsysnet API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Socket));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::H264), _("h264 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::H264));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("gx2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));
logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));
debugLoggingMenu->AppendSubMenu(logCosModulesMenu, _("&CafeOS modules logging"));
debugLoggingMenu->AppendSeparator();
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Patches), _("&Graphic pack patches"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Patches));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureCache), _("&Texture cache warnings"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::TextureCache));
@ -2298,10 +2323,12 @@ void MainWindow::RecreateMenu()
m_menuBar->Append(debugMenu, _("&Debug"));
// help menu
wxMenu* helpMenu = new wxMenu();
//helpMenu->Append(MAINFRAME_MENU_ID_HELP_WEB, wxT("&Visit website"));
//helpMenu->AppendSeparator();
m_check_update_menu = helpMenu->Append(MAINFRAME_MENU_ID_HELP_UPDATE, _("&Check for updates"));
helpMenu->Append(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, _("&Getting started"));
#if BOOST_OS_LINUX
if (!std::getenv("APPIMAGE")) {
m_check_update_menu->Enable(false);
}
#endif
helpMenu->AppendSeparator();
helpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _("&About Cemu"));
@ -2330,55 +2357,12 @@ void MainWindow::RecreateMenu()
SetMenuVisible(false);
}
void MainWindow::OnAfterCallShowErrorDialog()
void MainWindow::UpdateChildWindowTitleRunningState()
{
//wxMessageBox((const wxString&)dialogText, (const wxString&)dialogTitle, wxICON_INFORMATION);
//wxDialog* dialog = new wxDialog(NULL,wxID_ANY,(const wxString&)dialogTitle,wxDefaultPosition,wxSize(310,170));
//dialog->ShowModal();
//dialogState = 1;
}
const bool running = CafeSystem::IsTitleRunning();
bool MainWindow::EnableOnlineMode() const
{
// TODO: not used anymore
//
// if enabling online mode, check if all requirements are met
std::wstring additionalErrorInfo;
const sint32 onlineReqError = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo);
bool enableOnline = false;
if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OTP_MISSING)
{
wxMessageBox(_("otp.bin could not be found"), _("Error"), wxICON_ERROR);
}
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED)
{
wxMessageBox(_("otp.bin is corrupted or has invalid size"), _("Error"), wxICON_ERROR);
}
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING)
{
wxMessageBox(_("seeprom.bin could not be found"), _("Error"), wxICON_ERROR);
}
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_SEEPROM_CORRUPTED)
{
wxMessageBox(_("seeprom.bin is corrupted or has invalid size"), _("Error"), wxICON_ERROR);
}
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_MISSING_FILE)
{
std::wstring errorMessage = fmt::format(L"Unable to load a necessary file:\n{}", additionalErrorInfo);
wxMessageBox(errorMessage.c_str(), _("Error"), wxICON_ERROR);
}
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OK)
{
enableOnline = true;
}
else
{
wxMessageBox(_("Unknown error occured"), _("Error"), wxICON_ERROR);
}
//config_get()->enableOnlineMode = enableOnline;
return enableOnline;
if(m_graphic_pack_window)
m_graphic_pack_window->UpdateTitleRunning(running);
}
void MainWindow::RestoreSettingsAfterGameExited()