diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index da907b4477..498cb8e9f2 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -19,6 +19,7 @@ set(SRCS
State.cpp
TitleDatabase.cpp
WiiRoot.cpp
+ WiiUtils.cpp
Boot/Boot_BS2Emu.cpp
Boot/Boot.cpp
Boot/Boot_WiiWAD.cpp
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index 193c73ae98..cee0beb8df 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -290,6 +290,7 @@
+
@@ -524,6 +525,7 @@
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index bd15438132..76c5fcff0d 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -179,6 +179,7 @@
+
ActionReplay
@@ -898,6 +899,7 @@
+
ActionReplay
@@ -1543,4 +1545,4 @@
-
\ No newline at end of file
+
diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp
index 88aa3e28c0..a0f3241e85 100644
--- a/Source/Core/Core/IOS/ES/ES.cpp
+++ b/Source/Core/Core/IOS/ES/ES.cpp
@@ -843,30 +843,21 @@ ReturnCode ES::ReadCertStore(std::vector* buffer) const
ReturnCode ES::WriteNewCertToStore(const IOS::ES::CertReader& cert)
{
- const std::string store_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/sys/cert.sys";
- // The certificate store file may not exist, so we use a+b and not r+b here.
- File::IOFile store_file{store_path, "a+b"};
- if (!store_file)
- return ES_EIO;
-
// Read the current store to determine if the new cert needs to be written.
- const u64 file_size = store_file.GetSize();
- if (file_size != 0)
+ std::vector current_store;
+ const ReturnCode ret = ReadCertStore(¤t_store);
+ if (ret == IPC_SUCCESS)
{
- std::vector certs_bytes(file_size);
- if (!store_file.ReadBytes(certs_bytes.data(), certs_bytes.size()))
- return ES_SHORT_READ;
-
- const std::map certs = IOS::ES::ParseCertChain(certs_bytes);
+ const std::map certs = IOS::ES::ParseCertChain(current_store);
// The cert is already present in the store. Nothing to do.
if (certs.find(cert.GetName()) != certs.end())
return IPC_SUCCESS;
}
// Otherwise, write the new cert at the end of the store.
- // When opening a file in read-write mode, a seek is required before a write.
- store_file.Seek(0, SEEK_END);
- if (!store_file.WriteBytes(cert.GetBytes().data(), cert.GetBytes().size()))
+ const std::string store_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/sys/cert.sys";
+ File::IOFile store_file{store_path, "ab"};
+ if (!store_file || !store_file.WriteBytes(cert.GetBytes().data(), cert.GetBytes().size()))
return ES_EIO;
return IPC_SUCCESS;
}
diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp
new file mode 100644
index 0000000000..0e8a8fd253
--- /dev/null
+++ b/Source/Core/Core/WiiUtils.cpp
@@ -0,0 +1,498 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Core/WiiUtils.h"
+
+#include
+#include
+#include
@@ -185,6 +186,7 @@
+
diff --git a/Source/Core/DolphinQt2/GameList/GameFile.cpp b/Source/Core/DolphinQt2/GameList/GameFile.cpp
index 508265c883..900faab711 100644
--- a/Source/Core/DolphinQt2/GameList/GameFile.cpp
+++ b/Source/Core/DolphinQt2/GameList/GameFile.cpp
@@ -15,6 +15,7 @@
#include "Core/HW/WiiSaveCrypted.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/IOS.h"
+#include "Core/WiiUtils.h"
#include "DiscIO/Blob.h"
#include "DiscIO/Enums.h"
#include "DiscIO/NANDContentLoader.h"
@@ -22,7 +23,6 @@
#include "DolphinQt2/GameList/GameFile.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/Settings.h"
-#include "UICommon/WiiUtils.h"
static const int CACHE_VERSION = 13; // Last changed in PR #3261
static const int DATASTREAM_VERSION = QDataStream::Qt_5_5;
diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp
index b57ac4f134..de38910faa 100644
--- a/Source/Core/DolphinQt2/MainWindow.cpp
+++ b/Source/Core/DolphinQt2/MainWindow.cpp
@@ -30,7 +30,6 @@
#include "DolphinQt2/AboutDialog.h"
#include "DolphinQt2/Config/ControllersWindow.h"
-
#include "DolphinQt2/Config/Mapping/MappingWindow.h"
#include "DolphinQt2/Config/SettingsWindow.h"
#include "DolphinQt2/Host.h"
@@ -39,6 +38,7 @@
#include "DolphinQt2/QtUtils/WindowActivationEventFilter.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/Settings.h"
+#include "DolphinQt2/WiiUpdate.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
@@ -165,6 +165,9 @@ void MainWindow::ConnectMenuBar()
// Options
connect(m_menu_bar, &MenuBar::ConfigureHotkeys, this, &MainWindow::ShowHotkeyDialog);
+ // Tools
+ connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
+
// View
connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView);
connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView);
@@ -530,6 +533,13 @@ void MainWindow::SetStateSlot(int slot)
m_state_slot = slot;
}
+void MainWindow::PerformOnlineUpdate(const std::string& region)
+{
+ WiiUpdate::PerformOnlineUpdate(region, this);
+ // Since the update may have installed a newer system menu, refresh the tools menu.
+ m_menu_bar->UpdateToolsMenu(false);
+}
+
bool MainWindow::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::Close && !Stop())
diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h
index 7a69972ec9..0cd572790d 100644
--- a/Source/Core/DolphinQt2/MainWindow.h
+++ b/Source/Core/DolphinQt2/MainWindow.h
@@ -56,6 +56,8 @@ private slots:
void StateSaveOldest();
void SetStateSlot(int slot);
+ void PerformOnlineUpdate(const std::string& region);
+
void FullScreen();
void ScreenShot();
diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp
index 011649e0e1..888a5d8400 100644
--- a/Source/Core/DolphinQt2/MenuBar.cpp
+++ b/Source/Core/DolphinQt2/MenuBar.cpp
@@ -9,6 +9,9 @@
#include
#include
+#include "Core/CommonTitles.h"
+#include "Core/IOS/ES/ES.h"
+#include "Core/IOS/IOS.h"
#include "Core/State.h"
#include "DolphinQt2/AboutDialog.h"
#include "DolphinQt2/GameList/GameFile.h"
@@ -43,6 +46,7 @@ void MenuBar::EmulationStarted()
m_state_load_menu->setEnabled(true);
m_state_save_menu->setEnabled(true);
UpdateStateSlotMenu();
+ UpdateToolsMenu(true);
}
void MenuBar::EmulationPaused()
{
@@ -66,6 +70,7 @@ void MenuBar::EmulationStopped()
m_state_load_menu->setEnabled(false);
m_state_save_menu->setEnabled(false);
UpdateStateSlotMenu();
+ UpdateToolsMenu(false);
}
void MenuBar::AddFileMenu()
@@ -79,6 +84,17 @@ void MenuBar::AddToolsMenu()
{
QMenu* tools_menu = addMenu(tr("Tools"));
m_wad_install_action = tools_menu->addAction(tr("Install WAD..."), this, SLOT(InstallWAD()));
+
+ m_perform_online_update_menu = tools_menu->addMenu(tr("Perform Online System Update"));
+ m_perform_online_update_for_current_region = m_perform_online_update_menu->addAction(
+ tr("Current Region"), [this] { emit PerformOnlineUpdate(""); });
+ m_perform_online_update_menu->addSeparator();
+ m_perform_online_update_menu->addAction(tr("Europe"),
+ [this] { emit PerformOnlineUpdate("EUR"); });
+ m_perform_online_update_menu->addAction(tr("Japan"), [this] { emit PerformOnlineUpdate("JPN"); });
+ m_perform_online_update_menu->addAction(tr("Korea"), [this] { emit PerformOnlineUpdate("KOR"); });
+ m_perform_online_update_menu->addAction(tr("United States"),
+ [this] { emit PerformOnlineUpdate("USA"); });
}
void MenuBar::AddEmulationMenu()
@@ -248,6 +264,20 @@ void MenuBar::AddTableColumnsMenu(QMenu* view_menu)
}
}
+void MenuBar::UpdateToolsMenu(bool emulation_started)
+{
+ const bool enable_wii_tools = !emulation_started || !Settings::Instance().IsWiiGameRunning();
+ m_perform_online_update_menu->setEnabled(enable_wii_tools);
+ if (enable_wii_tools)
+ {
+ IOS::HLE::Kernel ios;
+ const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
+ for (QAction* action : m_perform_online_update_menu->actions())
+ action->setEnabled(!tmd.IsValid());
+ m_perform_online_update_for_current_region->setEnabled(tmd.IsValid());
+ }
+}
+
void MenuBar::InstallWAD()
{
QString wad_file = QFileDialog::getOpenFileName(this, tr("Select a title to install to NAND"),
diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h
index a0346f4277..426c7748d6 100644
--- a/Source/Core/DolphinQt2/MenuBar.h
+++ b/Source/Core/DolphinQt2/MenuBar.h
@@ -4,6 +4,8 @@
#pragma once
+#include
+
#include
#include
@@ -38,6 +40,8 @@ signals:
void StateSaveOldest();
void SetStateSlot(int slot);
+ void PerformOnlineUpdate(const std::string& region);
+
// Options
void ConfigureHotkeys();
@@ -53,6 +57,7 @@ public slots:
void EmulationPaused();
void EmulationStopped();
void UpdateStateSlotMenu();
+ void UpdateToolsMenu(bool emulation_started);
// Tools
void InstallWAD();
@@ -79,6 +84,8 @@ private:
// Tools
QAction* m_wad_install_action;
+ QMenu* m_perform_online_update_menu;
+ QAction* m_perform_online_update_for_current_region;
// Emulation
QAction* m_play_action;
diff --git a/Source/Core/DolphinQt2/WiiUpdate.cpp b/Source/Core/DolphinQt2/WiiUpdate.cpp
new file mode 100644
index 0000000000..d709e44b50
--- /dev/null
+++ b/Source/Core/DolphinQt2/WiiUpdate.cpp
@@ -0,0 +1,119 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "DolphinQt2/WiiUpdate.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "Common/FileUtil.h"
+#include "Common/Flag.h"
+#include "Core/Core.h"
+#include "Core/WiiUtils.h"
+#include "DiscIO/NANDImporter.h"
+
+namespace WiiUpdate
+{
+void PerformOnlineUpdate(const std::string& region, QWidget* parent)
+{
+ const int confirm = QMessageBox::question(
+ parent, QObject::tr("Confirm"),
+ QObject::tr("Connect to the Internet and perform an online system update?"));
+ if (confirm != QMessageBox::Yes)
+ return;
+
+ // Do not allow the user to close the dialog. Instead, wait until the update is finished
+ // or cancelled.
+ class UpdateProgressDialog final : public QProgressDialog
+ {
+ public:
+ using QProgressDialog::QProgressDialog;
+
+ protected:
+ void reject() override {}
+ };
+
+ UpdateProgressDialog dialog{parent};
+ dialog.setLabelText(QObject::tr("Preparing to update...\nThis can take a while."));
+ dialog.setWindowTitle(QObject::tr("Updating"));
+ // QProgressDialog doesn't set its minimum size correctly.
+ dialog.setMinimumSize(360, 150);
+
+ // QProgressDialog doesn't allow us to disable the cancel button when it's pressed,
+ // so we have to pass it our own push button. Note: the dialog takes ownership of it.
+ auto* cancel_button = new QPushButton(QObject::tr("&Cancel"), parent);
+ dialog.setCancelButton(cancel_button);
+ Common::Flag was_cancelled;
+ QObject::disconnect(&dialog, &QProgressDialog::canceled, &dialog, &QProgressDialog::cancel);
+ QObject::connect(&dialog, &QProgressDialog::canceled, [&] {
+ dialog.setLabelText(QObject::tr("Finishing the update...\nThis can take a while."));
+ cancel_button->setEnabled(false);
+ was_cancelled.Set();
+ });
+
+ std::future result = std::async(std::launch::async, [&] {
+ const WiiUtils::UpdateResult res = WiiUtils::DoOnlineUpdate(
+ [&](size_t processed, size_t total, u64 title_id) {
+ Core::QueueHostJob(
+ [&dialog, &was_cancelled, processed, total, title_id]() {
+ if (was_cancelled.IsSet())
+ return;
+
+ dialog.setRange(0, static_cast(total));
+ dialog.setValue(static_cast(processed));
+ dialog.setLabelText(QObject::tr("Updating title %1...\nThis can take a while.")
+ .arg(title_id, 16, 16, QLatin1Char('0')));
+ },
+ true);
+ return !was_cancelled.IsSet();
+ },
+ region);
+ Core::QueueHostJob([&dialog] { dialog.close(); }, true);
+ return res;
+ });
+
+ dialog.exec();
+
+ switch (result.get())
+ {
+ case WiiUtils::UpdateResult::Succeeded:
+ QMessageBox::information(parent, QObject::tr("Update completed"),
+ QObject::tr("The emulated Wii console has been updated."));
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::AlreadyUpToDate:
+ QMessageBox::information(parent, QObject::tr("Update completed"),
+ QObject::tr("The emulated Wii console is already up-to-date."));
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::ServerFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not download update information from Nintendo. "
+ "Please check your Internet connection and try again."));
+ break;
+ case WiiUtils::UpdateResult::DownloadFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not download update files from Nintendo. "
+ "Please check your Internet connection and try again."));
+ break;
+ case WiiUtils::UpdateResult::ImportFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not install an update to the Wii system memory. "
+ "Please refer to logs for more information."));
+ break;
+ case WiiUtils::UpdateResult::Cancelled:
+ QMessageBox::warning(
+ parent, QObject::tr("Update cancelled"),
+ QObject::tr("The update has been cancelled. It is strongly recommended to "
+ "finish it in order to avoid inconsistent system software versions."));
+ break;
+ }
+}
+}; // namespace WiiUpdate
diff --git a/Source/Core/UICommon/WiiUtils.h b/Source/Core/DolphinQt2/WiiUpdate.h
similarity index 51%
rename from Source/Core/UICommon/WiiUtils.h
rename to Source/Core/DolphinQt2/WiiUpdate.h
index 8419e01b9b..ea7428ebc2 100644
--- a/Source/Core/UICommon/WiiUtils.h
+++ b/Source/Core/DolphinQt2/WiiUpdate.h
@@ -6,9 +6,9 @@
#include
-// Small utility functions for common Wii related tasks.
+class QWidget;
-namespace WiiUtils
+namespace WiiUpdate
{
-bool InstallWAD(const std::string& wad_path);
-}
+void PerformOnlineUpdate(const std::string& region, QWidget* parent = nullptr);
+}; // namespace WiiUpdate
diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h
index 26fdf74455..a4489b83da 100644
--- a/Source/Core/DolphinWX/Frame.h
+++ b/Source/Core/DolphinWX/Frame.h
@@ -345,6 +345,7 @@ private:
void OnUninstallWAD(wxCommandEvent& event);
void OnImportBootMiiBackup(wxCommandEvent& event);
void OnExtractCertificates(wxCommandEvent& event);
+ void OnPerformOnlineWiiUpdate(wxCommandEvent& event);
void OnFifoPlayer(wxCommandEvent& event);
void OnConnectWiimote(wxCommandEvent& event);
void GameListChanged(wxCommandEvent& event);
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index b33ed2cf2f..a403118000 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -3,8 +3,11 @@
// Refer to the license.txt file included.
#include
+#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -18,7 +21,6 @@
#include
#include
#include
-#include
#include
#include
@@ -54,6 +56,7 @@
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/State.h"
+#include "Core/WiiUtils.h"
#include "DiscIO/Enums.h"
#include "DiscIO/NANDContentLoader.h"
@@ -87,7 +90,6 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "UICommon/UICommon.h"
-#include "UICommon/WiiUtils.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoBackendBase.h"
@@ -182,6 +184,12 @@ void CFrame::BindMenuBarEvents()
Bind(wxEVT_MENU, &CFrame::OnLoadWiiMenu, this, IDM_LOAD_WII_MENU);
Bind(wxEVT_MENU, &CFrame::OnImportBootMiiBackup, this, IDM_IMPORT_NAND);
Bind(wxEVT_MENU, &CFrame::OnExtractCertificates, this, IDM_EXTRACT_CERTIFICATES);
+ for (const int idm : {IDM_PERFORM_ONLINE_UPDATE_CURRENT, IDM_PERFORM_ONLINE_UPDATE_EUR,
+ IDM_PERFORM_ONLINE_UPDATE_JPN, IDM_PERFORM_ONLINE_UPDATE_KOR,
+ IDM_PERFORM_ONLINE_UPDATE_USA})
+ {
+ Bind(wxEVT_MENU, &CFrame::OnPerformOnlineWiiUpdate, this, idm);
+ }
Bind(wxEVT_MENU, &CFrame::OnFifoPlayer, this, IDM_FIFOPLAYER);
Bind(wxEVT_MENU, &CFrame::OnConnectWiimote, this, IDM_CONNECT_WIIMOTE1, IDM_CONNECT_BALANCEBOARD);
@@ -1293,6 +1301,93 @@ void CFrame::OnExtractCertificates(wxCommandEvent& WXUNUSED(event))
DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
}
+static std::string GetUpdateRegionFromIdm(int idm)
+{
+ switch (idm)
+ {
+ case IDM_PERFORM_ONLINE_UPDATE_EUR:
+ return "EUR";
+ case IDM_PERFORM_ONLINE_UPDATE_JPN:
+ return "JPN";
+ case IDM_PERFORM_ONLINE_UPDATE_KOR:
+ return "KOR";
+ case IDM_PERFORM_ONLINE_UPDATE_USA:
+ return "USA";
+ case IDM_PERFORM_ONLINE_UPDATE_CURRENT:
+ default:
+ return "";
+ }
+}
+
+void CFrame::OnPerformOnlineWiiUpdate(wxCommandEvent& event)
+{
+ int confirm = wxMessageBox(_("Connect to the Internet and perform an online system update?"),
+ _("System Update"), wxYES_NO, this);
+ if (confirm != wxYES)
+ return;
+
+ wxProgressDialog dialog(_("Updating"), _("Preparing to update...\nThis can take a while."), 1,
+ this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_CAN_ABORT);
+
+ const std::string region = GetUpdateRegionFromIdm(event.GetId());
+ std::future result = std::async(std::launch::async, [&] {
+ const WiiUtils::UpdateResult res = WiiUtils::DoOnlineUpdate(
+ [&](size_t processed, size_t total, u64 title_id) {
+ Core::QueueHostJob(
+ [&dialog, processed, total, title_id] {
+ dialog.SetRange(total);
+ dialog.Update(processed, wxString::Format(_("Updating title %016" PRIx64 "...\n"
+ "This can take a while."),
+ title_id));
+ dialog.Fit();
+ },
+ true);
+ return !dialog.WasCancelled();
+ },
+ region);
+ Core::QueueHostJob([&dialog] { dialog.EndModal(0); }, true);
+ return res;
+ });
+
+ dialog.ShowModal();
+
+ switch (result.get())
+ {
+ case WiiUtils::UpdateResult::Succeeded:
+ wxMessageBox(_("The emulated Wii console has been updated."), _("Update completed"),
+ wxOK | wxICON_INFORMATION);
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::AlreadyUpToDate:
+ wxMessageBox(_("The emulated Wii console is already up-to-date."), _("Update completed"),
+ wxOK | wxICON_INFORMATION);
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::ServerFailed:
+ wxMessageBox(_("Could not download update information from Nintendo. "
+ "Please check your Internet connection and try again."),
+ _("Update failed"), wxOK | wxICON_ERROR);
+ break;
+ case WiiUtils::UpdateResult::DownloadFailed:
+ wxMessageBox(_("Could not download update files from Nintendo. "
+ "Please check your Internet connection and try again."),
+ _("Update failed"), wxOK | wxICON_ERROR);
+ break;
+ case WiiUtils::UpdateResult::ImportFailed:
+ wxMessageBox(_("Could not install an update to the Wii system memory. "
+ "Please refer to logs for more information."),
+ _("Update failed"), wxOK | wxICON_ERROR);
+ break;
+ case WiiUtils::UpdateResult::Cancelled:
+ wxMessageBox(_("The update has been cancelled. It is strongly recommended to "
+ "finish it in order to avoid inconsistent system software versions."),
+ _("Update cancelled"), wxOK | wxICON_WARNING);
+ break;
+ }
+
+ UpdateLoadWiiMenuItem();
+}
+
void CFrame::UpdateLoadWiiMenuItem() const
{
GetMenuBar()->Refresh(true, nullptr);
@@ -1492,10 +1587,6 @@ void CFrame::UpdateGUI()
GetMenuBar()
->FindItem(IDM_LOAD_GC_IPL_EUR)
->Enable(!Initialized && File::Exists(SConfig::GetInstance().GetBootROMPath(EUR_DIR)));
- if (DiscIO::NANDContentManager::Access()
- .GetNANDLoader(Titles::SYSTEM_MENU, Common::FROM_CONFIGURED_ROOT)
- .IsValid())
- GetMenuBar()->FindItem(IDM_LOAD_WII_MENU)->Enable(!Initialized);
// Tools
GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats);
diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h
index ac066872ee..3abcec98f3 100644
--- a/Source/Core/DolphinWX/Globals.h
+++ b/Source/Core/DolphinWX/Globals.h
@@ -104,6 +104,11 @@ enum
IDM_LIST_UNINSTALL_WAD,
IDM_IMPORT_NAND,
IDM_EXTRACT_CERTIFICATES,
+ IDM_PERFORM_ONLINE_UPDATE_CURRENT,
+ IDM_PERFORM_ONLINE_UPDATE_EUR,
+ IDM_PERFORM_ONLINE_UPDATE_JPN,
+ IDM_PERFORM_ONLINE_UPDATE_KOR,
+ IDM_PERFORM_ONLINE_UPDATE_USA,
IDM_FIFOPLAYER,
IDM_LOAD_GC_IPL_JAP,
IDM_LOAD_GC_IPL_USA,
diff --git a/Source/Core/DolphinWX/MainMenuBar.cpp b/Source/Core/DolphinWX/MainMenuBar.cpp
index c9bdb25289..a9324565d1 100644
--- a/Source/Core/DolphinWX/MainMenuBar.cpp
+++ b/Source/Core/DolphinWX/MainMenuBar.cpp
@@ -235,6 +235,16 @@ wxMenu* MainMenuBar::CreateToolsMenu() const
tools_menu->Append(IDM_LOAD_WII_MENU, dummy_string);
tools_menu->Append(IDM_IMPORT_NAND, _("Import BootMii NAND Backup..."));
tools_menu->Append(IDM_EXTRACT_CERTIFICATES, _("Extract Certificates from NAND"));
+ auto* const online_update_menu = new wxMenu;
+ online_update_menu->Append(IDM_PERFORM_ONLINE_UPDATE_CURRENT, _("Current Region"));
+ online_update_menu->AppendSeparator();
+ online_update_menu->Append(IDM_PERFORM_ONLINE_UPDATE_EUR, _("Europe"));
+ online_update_menu->Append(IDM_PERFORM_ONLINE_UPDATE_JPN, _("Japan"));
+ online_update_menu->Append(IDM_PERFORM_ONLINE_UPDATE_KOR, _("Korean"));
+ online_update_menu->Append(IDM_PERFORM_ONLINE_UPDATE_USA, _("United States"));
+ tools_menu->AppendSubMenu(
+ online_update_menu, _("Perform Online System Update"),
+ _("Update the Wii system software to the latest version from Nintendo."));
tools_menu->AppendSeparator();
tools_menu->AppendSubMenu(wiimote_menu, _("Connect Wii Remotes"));
@@ -562,8 +572,6 @@ void MainMenuBar::RefreshSaveStateMenuLabels() const
void MainMenuBar::RefreshWiiToolsLabels() const
{
- RefreshWiiSystemMenuLabel();
-
// The Install WAD option should not be enabled while emulation is running, because
// having unexpected title changes can confuse emulated software; and of course, this is
// not possible on a real Wii and won't be if we have IOS LLE (or simply more accurate IOS HLE).
@@ -571,10 +579,26 @@ void MainMenuBar::RefreshWiiToolsLabels() const
// For similar reasons, it should not be possible to export or import saves, because this can
// result in the emulated software being confused, or even worse, exported saves having
// inconsistent data.
- for (const int index : {IDM_MENU_INSTALL_WAD, IDM_EXPORT_ALL_SAVE, IDM_IMPORT_SAVE,
- IDM_IMPORT_NAND, IDM_EXTRACT_CERTIFICATES})
+ const bool enable_wii_tools = !Core::IsRunning() || !SConfig::GetInstance().bWii;
+ for (const int index :
+ {IDM_MENU_INSTALL_WAD, IDM_EXPORT_ALL_SAVE, IDM_IMPORT_SAVE, IDM_IMPORT_NAND,
+ IDM_EXTRACT_CERTIFICATES, IDM_LOAD_WII_MENU, IDM_PERFORM_ONLINE_UPDATE_CURRENT,
+ IDM_PERFORM_ONLINE_UPDATE_EUR, IDM_PERFORM_ONLINE_UPDATE_JPN, IDM_PERFORM_ONLINE_UPDATE_KOR,
+ IDM_PERFORM_ONLINE_UPDATE_USA})
{
- FindItem(index)->Enable(!Core::IsRunning() || !SConfig::GetInstance().bWii);
+ FindItem(index)->Enable(enable_wii_tools);
+ }
+ if (enable_wii_tools)
+ RefreshWiiSystemMenuLabel();
+}
+
+void MainMenuBar::EnableUpdateMenu(UpdateMenuMode mode) const
+{
+ FindItem(IDM_PERFORM_ONLINE_UPDATE_CURRENT)->Enable(mode == UpdateMenuMode::CurrentRegionOnly);
+ for (const int idm : {IDM_PERFORM_ONLINE_UPDATE_EUR, IDM_PERFORM_ONLINE_UPDATE_JPN,
+ IDM_PERFORM_ONLINE_UPDATE_KOR, IDM_PERFORM_ONLINE_UPDATE_USA})
+ {
+ FindItem(idm)->Enable(mode == UpdateMenuMode::SpecificRegionsOnly);
}
}
@@ -591,11 +615,13 @@ void MainMenuBar::RefreshWiiSystemMenuLabel() const
const wxString version_string = StrToWxStr(DiscIO::GetSysMenuVersionString(version_number));
item->Enable();
item->SetItemLabel(wxString::Format(_("Load Wii System Menu %s"), version_string));
+ EnableUpdateMenu(UpdateMenuMode::CurrentRegionOnly);
}
else
{
item->Enable(false);
item->SetItemLabel(_("Load Wii System Menu"));
+ EnableUpdateMenu(UpdateMenuMode::SpecificRegionsOnly);
}
}
diff --git a/Source/Core/DolphinWX/MainMenuBar.h b/Source/Core/DolphinWX/MainMenuBar.h
index ca005640cb..d7e3d692dc 100644
--- a/Source/Core/DolphinWX/MainMenuBar.h
+++ b/Source/Core/DolphinWX/MainMenuBar.h
@@ -48,6 +48,12 @@ private:
void RefreshSaveStateMenuLabels() const;
void RefreshWiiToolsLabels() const;
void RefreshWiiSystemMenuLabel() const;
+ enum class UpdateMenuMode
+ {
+ CurrentRegionOnly,
+ SpecificRegionsOnly,
+ };
+ void EnableUpdateMenu(UpdateMenuMode mode) const;
void ClearSavedPerspectivesMenu() const;
void PopulateSavedPerspectivesMenu(const std::vector& label_names) const;
diff --git a/Source/Core/UICommon/CMakeLists.txt b/Source/Core/UICommon/CMakeLists.txt
index df1f3fd157..36648bbe7c 100644
--- a/Source/Core/UICommon/CMakeLists.txt
+++ b/Source/Core/UICommon/CMakeLists.txt
@@ -3,7 +3,6 @@ set(SRCS
Disassembler.cpp
UICommon.cpp
USBUtils.cpp
- WiiUtils.cpp
)
if(USE_X11)
diff --git a/Source/Core/UICommon/UICommon.vcxproj b/Source/Core/UICommon/UICommon.vcxproj
index 8b65ab9c25..1b5f3521d4 100644
--- a/Source/Core/UICommon/UICommon.vcxproj
+++ b/Source/Core/UICommon/UICommon.vcxproj
@@ -50,14 +50,12 @@
4200;%(DisableSpecificWarnings)
-
-
@@ -67,4 +65,4 @@
-
\ No newline at end of file
+
diff --git a/Source/Core/UICommon/WiiUtils.cpp b/Source/Core/UICommon/WiiUtils.cpp
deleted file mode 100644
index 994079f623..0000000000
--- a/Source/Core/UICommon/WiiUtils.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include "UICommon/WiiUtils.h"
-#include "Common/CommonTypes.h"
-#include "Common/MsgHandler.h"
-#include "Core/ConfigManager.h"
-#include "Core/IOS/ES/ES.h"
-#include "Core/IOS/ES/Formats.h"
-#include "Core/IOS/IOS.h"
-#include "DiscIO/NANDContentLoader.h"
-#include "DiscIO/WiiWad.h"
-
-namespace WiiUtils
-{
-bool InstallWAD(const std::string& wad_path)
-{
- const DiscIO::WiiWAD wad{wad_path};
- if (!wad.IsValid())
- {
- PanicAlertT("WAD installation failed: The selected file is not a valid WAD.");
- return false;
- }
-
- const auto tmd = wad.GetTMD();
- IOS::HLE::Kernel ios;
- const auto es = ios.GetES();
-
- IOS::HLE::Device::ES::Context context;
- IOS::HLE::ReturnCode ret;
- const bool checks_enabled = SConfig::GetInstance().m_enable_signature_checks;
- while ((ret = es->ImportTicket(wad.GetTicket().GetBytes(), wad.GetCertificateChain())) < 0 ||
- (ret = es->ImportTitleInit(context, tmd.GetBytes(), wad.GetCertificateChain())) < 0)
- {
- if (checks_enabled && ret == IOS::HLE::IOSC_FAIL_CHECKVALUE &&
- AskYesNoT("This WAD has not been signed by Nintendo. Continue to import?"))
- {
- SConfig::GetInstance().m_enable_signature_checks = false;
- continue;
- }
-
- SConfig::GetInstance().m_enable_signature_checks = checks_enabled;
- PanicAlertT("WAD installation failed: Could not initialise title import.");
- return false;
- }
- SConfig::GetInstance().m_enable_signature_checks = checks_enabled;
-
- const bool contents_imported = [&]() {
- const u64 title_id = tmd.GetTitleId();
- for (const IOS::ES::Content& content : tmd.GetContents())
- {
- const std::vector data = wad.GetContent(content.index);
-
- if (es->ImportContentBegin(context, title_id, content.id) < 0 ||
- es->ImportContentData(context, 0, data.data(), static_cast(data.size())) < 0 ||
- es->ImportContentEnd(context, 0) < 0)
- {
- PanicAlertT("WAD installation failed: Could not import content %08x.", content.id);
- return false;
- }
- }
- return true;
- }();
-
- if ((contents_imported && es->ImportTitleDone(context) < 0) ||
- (!contents_imported && es->ImportTitleCancel(context) < 0))
- {
- PanicAlertT("WAD installation failed: Could not finalise title import.");
- return false;
- }
-
- DiscIO::NANDContentManager::Access().ClearCache();
- return true;
-}
-}