From 3f8722f0a6789065f709daa3d6a636e2334b3bad Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Mon, 6 May 2024 18:18:42 +0200 Subject: [PATCH] Track online-enable and network-service settings per-account instead of globally --- src/config/ActiveSettings.cpp | 12 ++- src/config/CemuConfig.cpp | 58 +++++++++++++- src/config/CemuConfig.h | 10 ++- src/config/NetworkSettings.cpp | 9 ++- src/config/NetworkSettings.h | 4 +- src/gui/GeneralSettings2.cpp | 137 ++++++++++++++++++++------------- src/gui/GeneralSettings2.h | 4 +- src/gui/MainWindow.cpp | 32 -------- 8 files changed, 164 insertions(+), 102 deletions(-) diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index 81662ab5..07e6f16d 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -131,7 +131,12 @@ uint32 ActiveSettings::GetPersistentId() bool ActiveSettings::IsOnlineEnabled() { - return GetConfig().account.online_enabled && Account::GetAccount(GetPersistentId()).IsValidOnlineAccount() && HasRequiredOnlineFiles(); + if(!Account::GetAccount(GetPersistentId()).IsValidOnlineAccount()) + return false; + if(!HasRequiredOnlineFiles()) + return false; + NetworkService networkService = static_cast(GetConfig().GetAccountNetworkService(GetPersistentId())); + return networkService == NetworkService::Nintendo || networkService == NetworkService::Pretendo || networkService == NetworkService::Custom; } bool ActiveSettings::HasRequiredOnlineFiles() @@ -139,8 +144,9 @@ bool ActiveSettings::HasRequiredOnlineFiles() return s_has_required_online_files; } -NetworkService ActiveSettings::GetNetworkService() { - return static_cast(GetConfig().account.active_service.GetValue()); +NetworkService ActiveSettings::GetNetworkService() +{ + return GetConfig().GetAccountNetworkService(GetPersistentId()); } bool ActiveSettings::DumpShadersEnabled() diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index e4be97a7..4f1736e2 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -328,8 +328,22 @@ void CemuConfig::Load(XMLConfigParser& parser) // account auto acc = parser.get("Account"); account.m_persistent_id = acc.get("PersistentId", account.m_persistent_id); - account.online_enabled = acc.get("OnlineEnabled", account.online_enabled); - account.active_service = acc.get("ActiveService",account.active_service); + // legacy online settings, we only parse these for upgrading purposes + account.legacy_online_enabled = acc.get("OnlineEnabled", account.legacy_online_enabled); + account.legacy_active_service = acc.get("ActiveService",account.legacy_active_service); + // per-account online setting + auto accService = parser.get("AccountService"); + account.service_select.clear(); + for (auto element = accService.get("SelectedService"); element.valid(); element = accService.get("SelectedService", element)) + { + uint32 persistentId = element.get_attribute("PersistentId", 0); + sint32 serviceIndex = element.get_attribute("Service", 0); + NetworkService networkService = static_cast(serviceIndex); + if (persistentId < Account::kMinPersistendId) + continue; + if(networkService == NetworkService::Offline || networkService == NetworkService::Nintendo || networkService == NetworkService::Pretendo || networkService == NetworkService::Custom) + account.service_select.emplace(persistentId, networkService); + } // debug auto debug = parser.get("Debug"); #if BOOST_OS_WINDOWS @@ -512,8 +526,17 @@ void CemuConfig::Save(XMLConfigParser& parser) // account auto acc = config.set("Account"); acc.set("PersistentId", account.m_persistent_id.GetValue()); - acc.set("OnlineEnabled", account.online_enabled.GetValue()); - acc.set("ActiveService",account.active_service.GetValue()); + // legacy online mode setting + acc.set("OnlineEnabled", account.legacy_online_enabled.GetValue()); + acc.set("ActiveService",account.legacy_active_service.GetValue()); + // per-account online setting + auto accService = config.set("AccountService"); + for(auto& it : account.service_select) + { + auto entry = accService.set("SelectedService"); + entry.set_attribute("PersistentId", it.first); + entry.set_attribute("Service", static_cast(it.second)); + } // debug auto debug = config.set("Debug"); #if BOOST_OS_WINDOWS @@ -609,3 +632,30 @@ void CemuConfig::AddRecentNfcFile(std::string_view file) while (recent_nfc_files.size() > kMaxRecentEntries) recent_nfc_files.pop_back(); } + +NetworkService CemuConfig::GetAccountNetworkService(uint32 persistentId) +{ + auto it = account.service_select.find(persistentId); + if (it != account.service_select.end()) + { + NetworkService serviceIndex = it->second; + // make sure the returned service is valid + if (serviceIndex != NetworkService::Offline && + serviceIndex != NetworkService::Nintendo && + serviceIndex != NetworkService::Pretendo && + serviceIndex != NetworkService::Custom) + return NetworkService::Offline; + if( static_cast(serviceIndex) == NetworkService::Custom && !NetworkConfig::XMLExists() ) + return NetworkService::Offline; // custom is selected but no custom config exists + return serviceIndex; + } + // if not found, return the legacy value + if(!account.legacy_online_enabled) + return NetworkService::Offline; + return static_cast(account.legacy_active_service.GetValue() + 1); // +1 because "Offline" now takes index 0 +} + +void CemuConfig::SetAccountSelectedService(uint32 persistentId, NetworkService serviceIndex) +{ + account.service_select[persistentId] = serviceIndex; +} diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index 9f1e7983..cab7a1af 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -8,6 +8,8 @@ #include #include +enum class NetworkService; + struct GameEntry { GameEntry() = default; @@ -483,8 +485,9 @@ struct CemuConfig struct { ConfigValueBounds m_persistent_id{ Account::kMinPersistendId, Account::kMinPersistendId, 0xFFFFFFFF }; - ConfigValue online_enabled{false}; - ConfigValue active_service{0}; + ConfigValue legacy_online_enabled{false}; + ConfigValue legacy_active_service{0}; + std::unordered_map service_select; // per-account service index. Key is persistentId }account{}; // input @@ -509,6 +512,9 @@ struct CemuConfig bool GetGameListCustomName(uint64 titleId, std::string& customName); void SetGameListCustomName(uint64 titleId, std::string customName); + NetworkService GetAccountNetworkService(uint32 persistentId); + void SetAccountSelectedService(uint32 persistentId, NetworkService serviceIndex); + private: GameEntry* GetGameEntryByTitleId(uint64 titleId); GameEntry* CreateGameEntry(uint64 titleId); diff --git a/src/config/NetworkSettings.cpp b/src/config/NetworkSettings.cpp index b086d0ae..42dc9996 100644 --- a/src/config/NetworkSettings.cpp +++ b/src/config/NetworkSettings.cpp @@ -34,14 +34,15 @@ void NetworkConfig::Load(XMLConfigParser& parser) bool NetworkConfig::XMLExists() { + static std::optional s_exists; // caches result of fs::exists + if(s_exists.has_value()) + return *s_exists; std::error_code ec; if (!fs::exists(ActiveSettings::GetConfigPath("network_services.xml"), ec)) { - if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) - { - GetConfig().account.active_service = 0; - } + s_exists = false; return false; } + s_exists = true; return true; } \ No newline at end of file diff --git a/src/config/NetworkSettings.h b/src/config/NetworkSettings.h index be311182..6e114a0e 100644 --- a/src/config/NetworkSettings.h +++ b/src/config/NetworkSettings.h @@ -5,9 +5,11 @@ enum class NetworkService { + Offline, Nintendo, Pretendo, - Custom + Custom, + COUNT = Custom }; struct NetworkConfig diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index dab30981..c0b54949 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -683,18 +683,6 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) content->Add(m_delete_account, 0, wxEXPAND | wxALL | wxALIGN_RIGHT, 5); m_delete_account->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAccountDelete, this); - wxString choices[] = { _("Nintendo"), _("Pretendo"), _("Custom") }; - m_active_service = new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 3, wxRA_SPECIFY_COLS); - if (!NetworkConfig::XMLExists()) - m_active_service->Enable(2, false); - - m_active_service->SetItemToolTip(0, _("Connect to the official Nintendo Network Service")); - m_active_service->SetItemToolTip(1, _("Connect to the Pretendo Network Service")); - m_active_service->SetItemToolTip(2, _("Connect to a custom Network Service (configured via network_services.xml)")); - - m_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this); - content->Add(m_active_service, 0, wxEXPAND | wxALL, 5); - box_sizer->Add(content, 1, wxEXPAND, 5); online_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5); @@ -704,17 +692,33 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) m_active_account->Enable(false); m_create_account->Enable(false); m_delete_account->Enable(false); + } + } + + + { + wxString choices[] = { _("Offline"), _("Nintendo"), _("Pretendo"), _("Custom") }; + m_active_service = new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 4, wxRA_SPECIFY_COLS); + if (!NetworkConfig::XMLExists()) + m_active_service->Enable(3, false); + + m_active_service->SetItemToolTip(0, _("Online functionality disabled for this account")); + m_active_service->SetItemToolTip(1, _("Connect to the official Nintendo Network Service")); + m_active_service->SetItemToolTip(2, _("Connect to the Pretendo Network Service")); + m_active_service->SetItemToolTip(3, _("Connect to a custom Network Service (configured via network_services.xml)")); + + m_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this); + online_panel_sizer->Add(m_active_service, 0, wxEXPAND | wxALL, 5); + + if (CafeSystem::IsTitleRunning()) + { m_active_service->Enable(false); } } - + { - auto* box = new wxStaticBox(online_panel, wxID_ANY, _("Online settings")); + auto* box = new wxStaticBox(online_panel, wxID_ANY, _("Online play requirements")); auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL); - - m_online_enabled = new wxCheckBox(box, wxID_ANY, _("Enable online mode")); - m_online_enabled->Bind(wxEVT_CHECKBOX, &GeneralSettings2::OnOnlineEnable, this); - box_sizer->Add(m_online_enabled, 0, wxEXPAND | wxALL, 5); auto* row = new wxFlexGridSizer(0, 2, 0, 0); row->SetFlexibleDirection(wxBOTH); @@ -873,6 +877,14 @@ GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched) DisableSettings(game_launched); } +uint32 GeneralSettings2::GetSelectedAccountPersistentId() +{ + const auto active_account = m_active_account->GetSelection(); + if (active_account == wxNOT_FOUND) + return GetConfig().account.m_persistent_id.GetInitValue(); + return dynamic_cast(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId(); +} + void GeneralSettings2::StoreConfig() { auto* app = (CemuApp*)wxTheApp; @@ -1038,14 +1050,7 @@ void GeneralSettings2::StoreConfig() config.notification.friends = m_friends_data->GetValue(); // account - const auto active_account = m_active_account->GetSelection(); - if (active_account == wxNOT_FOUND) - config.account.m_persistent_id = config.account.m_persistent_id.GetInitValue(); - else - config.account.m_persistent_id = dynamic_cast(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId(); - - config.account.online_enabled = m_online_enabled->GetValue(); - config.account.active_service = m_active_service->GetSelection(); + config.account.m_persistent_id = GetSelectedAccountPersistentId(); // debug config.crash_dump = (CrashDump)m_crash_dump->GetSelection(); @@ -1371,14 +1376,13 @@ void GeneralSettings2::UpdateAccountInformation() { m_account_grid->SetSplitterPosition(100); - m_online_status->SetLabel(_("At least one issue has been found")); - const auto selection = m_active_account->GetSelection(); if(selection == wxNOT_FOUND) { m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE); ResetAccountInformation(); + m_online_status->SetLabel(_("No account selected")); return; } @@ -1404,11 +1408,26 @@ void GeneralSettings2::UpdateAccountInformation() index = 0; country_property->SetChoiceSelection(index); - const bool online_valid = account.IsValidOnlineAccount() && ActiveSettings::HasRequiredOnlineFiles(); - if (online_valid) + const bool online_fully_valid = account.IsValidOnlineAccount() && ActiveSettings::HasRequiredOnlineFiles(); + if (ActiveSettings::HasRequiredOnlineFiles()) + { + if(account.IsValidOnlineAccount()) + m_online_status->SetLabel(_("Selected account is a valid online account")); + else + m_online_status->SetLabel(_("Selected account is not linked to a NNID or PNID")); + } + else + { + if(NCrypto::OTP_IsPresent() != NCrypto::SEEPROM_IsPresent()) + m_online_status->SetLabel(_("OTP.bin or SEEPROM.bin is missing")); + else if(NCrypto::OTP_IsPresent() && NCrypto::SEEPROM_IsPresent()) + m_online_status->SetLabel(_("OTP and SEEPROM present but no certificate files were found")); + else + m_online_status->SetLabel(_("Online play is not set up. Follow the guide below to get started")); + } + + if(online_fully_valid) { - - m_online_status->SetLabel(_("Your account is a valid online account")); m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_CHECK_YES).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() | wxBORDER_NONE); } @@ -1417,7 +1436,28 @@ void GeneralSettings2::UpdateAccountInformation() m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE); } - + + // enable/disable network service field depending on online requirements + m_active_service->Enable(online_fully_valid && !CafeSystem::IsTitleRunning()); + if(online_fully_valid) + { + NetworkService service = GetConfig().GetAccountNetworkService(account.GetPersistentId()); + m_active_service->SetSelection(static_cast(service)); + // set the config option here for the selected service + // this will guarantee that it's actually written to settings.xml + // allowing us to eventually get rid of the legacy option in the (far) future + GetConfig().SetAccountSelectedService(account.GetPersistentId(), service); + } + else + { + m_active_service->SetSelection(0); // force offline + } + wxString tmp = _("Network service"); + tmp.append(" ("); + tmp.append(wxString::FromUTF8(boost::nowide::narrow(account.GetMiiName()))); + tmp.append(")"); + m_active_service->SetLabel(tmp); + // refresh pane size m_account_grid->InvalidateBestSize(); //m_account_grid->GetParent()->FitInside(); @@ -1663,9 +1703,8 @@ void GeneralSettings2::ApplyConfig() break; } } - - m_online_enabled->SetValue(config.account.online_enabled); - m_active_service->SetSelection(config.account.active_service); + m_active_service->SetSelection((int)config.GetAccountNetworkService(ActiveSettings::GetPersistentId())); + UpdateAccountInformation(); // debug @@ -1673,20 +1712,6 @@ void GeneralSettings2::ApplyConfig() m_gdb_port->SetValue(config.gdb_port.GetValue()); } -void GeneralSettings2::OnOnlineEnable(wxCommandEvent& event) -{ - event.Skip(); - if (!m_online_enabled->GetValue()) - return; - - // show warning if player enables online mode - const auto result = wxMessageBox(_("Please be aware that online mode lets you connect to OFFICIAL servers and therefore there is a risk of getting banned.\nOnly proceed if you are willing to risk losing online access with your Wii U and/or NNID."), - _("Warning"), wxYES_NO | wxCENTRE | wxICON_EXCLAMATION, this); - if (result == wxNO) - m_online_enabled->SetValue(false); -} - - void GeneralSettings2::OnAudioAPISelected(wxCommandEvent& event) { IAudioAPI::AudioAPI api; @@ -1952,6 +1977,9 @@ void GeneralSettings2::OnActiveAccountChanged(wxCommandEvent& event) void GeneralSettings2::OnAccountServiceChanged(wxCommandEvent& event) { + auto& config = GetConfig(); + uint32 peristentId = GetSelectedAccountPersistentId(); + config.SetAccountSelectedService(peristentId, static_cast(m_active_service->GetSelection())); UpdateAccountInformation(); } @@ -2005,12 +2033,12 @@ void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event) err << _("The following error(s) have been found:") << '\n'; if (validator.otp == OnlineValidator::FileState::Missing) - err << _("otp.bin missing in Cemu root directory") << '\n'; + err << _("otp.bin missing in Cemu directory") << '\n'; else if(validator.otp == OnlineValidator::FileState::Corrupted) err << _("otp.bin is invalid") << '\n'; if (validator.seeprom == OnlineValidator::FileState::Missing) - err << _("seeprom.bin missing in Cemu root directory") << '\n'; + err << _("seeprom.bin missing in Cemu directory") << '\n'; else if(validator.seeprom == OnlineValidator::FileState::Corrupted) err << _("seeprom.bin is invalid") << '\n'; @@ -2045,9 +2073,10 @@ void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event) wxString GeneralSettings2::GetOnlineAccountErrorMessage(OnlineAccountError error) { - switch (error) { + switch (error) + { case OnlineAccountError::kNoAccountId: - return _("AccountId missing (The account is not connected to a NNID)"); + return _("AccountId missing (The account is not connected to a NNID/PNID)"); case OnlineAccountError::kNoPasswordCached: return _("IsPasswordCacheEnabled is set to false (The remember password option on your Wii U must be enabled for this account before dumping it)"); case OnlineAccountError::kPasswordCacheEmpty: diff --git a/src/gui/GeneralSettings2.h b/src/gui/GeneralSettings2.h index 2846af38..b34c9222 100644 --- a/src/gui/GeneralSettings2.h +++ b/src/gui/GeneralSettings2.h @@ -71,7 +71,6 @@ private: wxButton* m_create_account, * m_delete_account; wxChoice* m_active_account; wxRadioBox* m_active_service; - wxCheckBox* m_online_enabled; wxCollapsiblePane* m_account_information; wxPropertyGrid* m_account_grid; wxBitmapButton* m_validate_online; @@ -99,10 +98,11 @@ private: void OnMLCPathSelect(wxCommandEvent& event); void OnMLCPathChar(wxKeyEvent& event); void OnShowOnlineValidator(wxCommandEvent& event); - void OnOnlineEnable(wxCommandEvent& event); void OnAccountServiceChanged(wxCommandEvent& event); static wxString GetOnlineAccountErrorMessage(OnlineAccountError error); + uint32 GetSelectedAccountPersistentId(); + // updates cemu audio devices void UpdateAudioDevice(); // refreshes audio device list for dropdown diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index c34c5477..097d506e 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -948,38 +948,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())