diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 1c97e21cdb..21e8efaec5 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -142,6 +142,7 @@ const Info MAIN_FS_PATH{{System::Main, "General", "NANDRootPath"}, const Info MAIN_SD_PATH{{System::Main, "General", "WiiSDCardPath"}, ""}; // Main.Network + const Info MAIN_NETWORK_SSL_DUMP_READ{{System::Main, "Network", "SSLDumpRead"}, false}; const Info MAIN_NETWORK_SSL_DUMP_WRITE{{System::Main, "Network", "SSLDumpWrite"}, false}; const Info MAIN_NETWORK_SSL_VERIFY_CERTIFICATES{ @@ -149,4 +150,8 @@ const Info MAIN_NETWORK_SSL_VERIFY_CERTIFICATES{ const Info MAIN_NETWORK_SSL_DUMP_ROOT_CA{{System::Main, "Network", "SSLDumpRootCA"}, false}; const Info MAIN_NETWORK_SSL_DUMP_PEER_CERT{{System::Main, "Network", "SSLDumpPeerCert"}, false}; + +// Main.Interface + +const Info MAIN_SKIP_NKIT_WARNING{{System::Main, "Interface", "SkipNKitWarning"}, false}; } // namespace Config diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 61f59069ec..086e18419a 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -126,4 +126,8 @@ extern const Info MAIN_NETWORK_SSL_DUMP_WRITE; extern const Info MAIN_NETWORK_SSL_VERIFY_CERTIFICATES; extern const Info MAIN_NETWORK_SSL_DUMP_ROOT_CA; extern const Info MAIN_NETWORK_SSL_DUMP_PEER_CERT; + +// Main.Interface + +extern const Info MAIN_SKIP_NKIT_WARNING; } // namespace Config diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index dff293772c..dcf608ac61 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -32,7 +32,7 @@ bool IsSettingSaveable(const Config::Location& config_location) } } - static constexpr std::array s_setting_saveable = { + static constexpr std::array s_setting_saveable = { // Main.Core &Config::MAIN_DEFAULT_ISO.location, @@ -47,6 +47,10 @@ bool IsSettingSaveable(const Config::Location& config_location) &Config::MAIN_MEM2_SIZE.location, &Config::MAIN_GFX_BACKEND.location, + // Main.Interface + + &Config::MAIN_SKIP_NKIT_WARNING.location, + // UI.General &Config::MAIN_USE_DISCORD_PRESENCE.location, diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index a5c4e6be14..e176c5d72a 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -116,6 +116,7 @@ public: } virtual Platform GetVolumeType() const = 0; virtual bool IsDatelDisc() const = 0; + virtual bool IsNKit() const = 0; virtual bool SupportsIntegrityCheck() const { return false; } virtual bool CheckH3TableIntegrity(const Partition& partition) const { return false; } virtual bool CheckBlockIntegrity(u64 block_index, const std::vector& encrypted_data, diff --git a/Source/Core/DiscIO/VolumeDisc.cpp b/Source/Core/DiscIO/VolumeDisc.cpp index bf622bb8fb..fed82a8067 100644 --- a/Source/Core/DiscIO/VolumeDisc.cpp +++ b/Source/Core/DiscIO/VolumeDisc.cpp @@ -84,4 +84,10 @@ std::optional VolumeDisc::GetDiscNumber(const Partition& partition) const return ReadSwapped(6, partition); } +bool VolumeDisc::IsNKit() const +{ + constexpr u32 NKIT_MAGIC = 0x4E4B4954; // "NKIT" + return ReadSwapped(0x200, PARTITION_NONE) == NKIT_MAGIC; +} + } // namespace DiscIO diff --git a/Source/Core/DiscIO/VolumeDisc.h b/Source/Core/DiscIO/VolumeDisc.h index 333ea7d4aa..680bbf83b0 100644 --- a/Source/Core/DiscIO/VolumeDisc.h +++ b/Source/Core/DiscIO/VolumeDisc.h @@ -22,6 +22,7 @@ public: std::string GetInternalName(const Partition& partition = PARTITION_NONE) const override; std::string GetApploaderDate(const Partition& partition) const override; std::optional GetDiscNumber(const Partition& partition = PARTITION_NONE) const override; + bool IsNKit() const override; protected: Region RegionCodeToRegion(std::optional region_code) const; diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp index 00e850071a..c1a2bcbd90 100644 --- a/Source/Core/DiscIO/VolumeVerifier.cpp +++ b/Source/Core/DiscIO/VolumeVerifier.cpp @@ -988,22 +988,18 @@ void VolumeVerifier::CheckMisc() } } - if (IsDisc(m_volume.GetVolumeType())) + if (m_volume.IsNKit()) { - constexpr u32 NKIT_MAGIC = 0x4E4B4954; // "NKIT" - if (m_volume.ReadSwapped(0x200, PARTITION_NONE) == NKIT_MAGIC) - { - AddProblem( - Severity::Low, - Common::GetStringT("This disc image is in the NKit format. It is not a good dump in its " - "current form, but it might become a good dump if converted back. " - "The CRC32 of this file might match the CRC32 of a good dump even " - "though the files are not identical.")); - } - - if (StringBeginsWith(game_id_unencrypted, "R8P")) - CheckSuperPaperMario(); + AddProblem( + Severity::Low, + Common::GetStringT("This disc image is in the NKit format. It is not a good dump in its " + "current form, but it might become a good dump if converted back. " + "The CRC32 of this file might match the CRC32 of a good dump even " + "though the files are not identical.")); } + + if (IsDisc(m_volume.GetVolumeType()) && StringBeginsWith(game_id_unencrypted, "R8P")) + CheckSuperPaperMario(); } void VolumeVerifier::CheckSuperPaperMario() diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index 61b772ec31..b7b8fa35cd 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -289,6 +289,11 @@ bool VolumeWAD::IsDatelDisc() const return false; } +bool VolumeWAD::IsNKit() const +{ + return false; +} + std::map VolumeWAD::GetLongNames() const { if (!m_tmd.IsValid() || !IOS::ES::IsChannel(m_tmd.GetTitleId())) diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index d76b8853ec..a4c311da78 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -60,6 +60,7 @@ public: } Platform GetVolumeType() const override; bool IsDatelDisc() const override; + bool IsNKit() const override; Region GetRegion() const override; Country GetCountry(const Partition& partition = PARTITION_NONE) const override; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 269083c4dc..8388f7bb6d 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -37,6 +37,8 @@ add_executable(dolphin-emu MainWindow.h MenuBar.cpp MenuBar.h + NKitWarningDialog.cpp + NKitWarningDialog.h RenderWidget.cpp RenderWidget.h Resources.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 1e4fd3b0b2..6fe7dfb10b 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -178,6 +178,7 @@ + @@ -290,6 +291,7 @@ + @@ -394,6 +396,7 @@ + diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 1ecb875986..bff3a6422c 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -18,6 +18,7 @@ #include #include +#include #if defined(__unix__) || defined(__unix) || defined(__APPLE__) #include @@ -83,6 +84,7 @@ #include "DolphinQt/HotkeyScheduler.h" #include "DolphinQt/MainWindow.h" #include "DolphinQt/MenuBar.h" +#include "DolphinQt/NKitWarningDialog.h" #include "DolphinQt/NetPlay/NetPlayBrowser.h" #include "DolphinQt/NetPlay/NetPlayDialog.h" #include "DolphinQt/NetPlay/NetPlaySetupDialog.h" @@ -952,6 +954,15 @@ void MainWindow::StartGame(const std::vector& paths, void MainWindow::StartGame(std::unique_ptr&& parameters) { + if (std::holds_alternative(parameters->parameters)) + { + if (std::get(parameters->parameters).volume->IsNKit()) + { + if (!NKitWarningDialog::ShowUnlessDisabled()) + return; + } + } + // If we're running, only start a new game once we've stopped the last. if (Core::GetState() != Core::State::Uninitialized) { diff --git a/Source/Core/DolphinQt/NKitWarningDialog.cpp b/Source/Core/DolphinQt/NKitWarningDialog.cpp new file mode 100644 index 0000000000..3b8a821b8a --- /dev/null +++ b/Source/Core/DolphinQt/NKitWarningDialog.cpp @@ -0,0 +1,87 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt/NKitWarningDialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/Config/Config.h" +#include "Core/Config/MainSettings.h" +#include "DolphinQt/Resources.h" + +bool NKitWarningDialog::ShowUnlessDisabled(QWidget* parent) +{ + if (Config::Get(Config::MAIN_SKIP_NKIT_WARNING)) + return true; + else + return NKitWarningDialog(parent).exec() == QDialog::Accepted; +} + +NKitWarningDialog::NKitWarningDialog(QWidget* parent) : QDialog(parent) +{ + setWindowTitle(tr("NKit Warning")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowIcon(Resources::GetAppIcon()); + + QVBoxLayout* main_layout = new QVBoxLayout; + + QLabel* warning = new QLabel( + tr("You are about to run an NKit disc image. NKit disc images cause problems that don't " + "happen with normal disc images. These problems include:\n" + "\n" + "• The emulated loading times are longer\n" + "• You can't use NetPlay with people who have normal disc images\n" + "• Input recordings are not compatible between NKit disc images and normal disc images\n" + "• Savestates are not compatible between NKit disc images and normal disc images\n" + "• Some games crash, such as Super Paper Mario\n" + "• Wii games don't work at all in older versions of Dolphin and in many other programs\n" + "\n" + "Are you sure you want to continue anyway?\n")); + warning->setWordWrap(true); + main_layout->addWidget(warning); + + QCheckBox* checkbox_accept = new QCheckBox(tr("I am aware of the risks and want to continue")); + main_layout->addWidget(checkbox_accept); + + QCheckBox* checkbox_skip = new QCheckBox(tr("Don't show this again")); + main_layout->addWidget(checkbox_skip); + + QHBoxLayout* button_layout = new QHBoxLayout; + QPushButton* ok = new QPushButton(tr("OK")); + button_layout->addWidget(ok); + QPushButton* cancel = new QPushButton(tr("Cancel")); + button_layout->addWidget(cancel); + main_layout->addLayout(button_layout); + + QHBoxLayout* top_layout = new QHBoxLayout; + + QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning); + QLabel* icon_label = new QLabel; + icon_label->setPixmap(icon.pixmap(100)); + icon_label->setAlignment(Qt::AlignTop); + top_layout->addWidget(icon_label); + top_layout->addSpacing(10); + + top_layout->addLayout(main_layout); + + setLayout(top_layout); + + connect(ok, &QPushButton::clicked, this, &QDialog::accept); + connect(cancel, &QPushButton::clicked, this, &QDialog::reject); + + ok->setEnabled(false); + connect(checkbox_accept, &QCheckBox::stateChanged, + [&ok](int state) { ok->setEnabled(state == Qt::Checked); }); + + connect(this, &QDialog::accepted, [checkbox_skip] { + Config::SetBase(Config::MAIN_SKIP_NKIT_WARNING, checkbox_skip->isChecked()); + }); +} diff --git a/Source/Core/DolphinQt/NKitWarningDialog.h b/Source/Core/DolphinQt/NKitWarningDialog.h new file mode 100644 index 0000000000..df82ab5332 --- /dev/null +++ b/Source/Core/DolphinQt/NKitWarningDialog.h @@ -0,0 +1,19 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +class NKitWarningDialog final : public QDialog +{ + Q_OBJECT + +public: + static bool ShowUnlessDisabled(QWidget* parent = nullptr); + +private: + explicit NKitWarningDialog(QWidget* parent = nullptr); +};