1
0
mirror of https://github.com/dolphin-emu/dolphin synced 2024-07-01 07:54:33 +00:00

Compare commits

...

33 Commits

Author SHA1 Message Date
JosJuice
ad5d6fcce1
Merge e0d588e375 into f49659fbfc 2024-06-28 19:04:38 +02:00
OatmealDome
f49659fbfc
Merge pull request #12897 from Dentomologist/achievementmanager_fix_ignored_qualifiers_warning
AchievementManager: Fix -Wignored-qualifiers warning
2024-06-28 01:23:04 -04:00
Dentomologist
c46c010ae3 AchievementManager: Fix -Wignored-qualifiers warning
Fix warning on Android builder by returning bool instead of const bool.
2024-06-27 14:36:14 -07:00
Admiral H. Curtiss
233ea58446
Merge pull request #12877 from LillyJadeKatrin/retroachievements-auto-update
Update Achievement List when Rich Presence Updates
2024-06-27 20:30:01 +02:00
Admiral H. Curtiss
2f30ff6970
Merge pull request #12892 from JMC47/geistini
Disable Dualcore in Geist
2024-06-27 19:17:42 +02:00
OatmealDome
134c079ad2
Merge pull request #12893 from JosJuice/revert-audit-get-state
Revert "Audit uses of IsRunning and GetState"
2024-06-26 18:40:56 -04:00
JosJuice
bc67fc97c3 Revert "Audit uses of IsRunning and GetState"
This reverts commit 72cf2bdb87.

SYSCONF settings are getting cleared when they shouldn't be. Let's
revert the change until I get proper time to figure out why it's broken.
2024-06-26 20:36:46 +02:00
JosJuice
3dbaf38eae Translation resources sync with Transifex 2024-06-26 20:22:36 +02:00
JMC47
e58d6f4f1f Disable Dualcore in Geist
Fixes random crashes and unknown opcode errors.
2024-06-26 01:53:47 -04:00
LillyJadeKatrin
1a33e28452 Update Achievement Sort and Progress on RP
Whenever a request to update the Rich Presence comes in, typically every ten seconds, the Achievement Progress Widget will update the sort order of the achievements and all of their measured values.
2024-06-25 23:05:56 -04:00
OatmealDome
10a95a4d5b
Merge pull request #12890 from OatmealDome/release-stuff
Miscellaneous release string updates
2024-06-25 01:25:08 -04:00
OatmealDome
04b0ceedcd Android: Update copyright year in About dialog to 2024 2024-06-24 15:08:12 -04:00
OatmealDome
9c432e960b AboutDialog: Update copyright year to 2024 2024-06-24 15:06:54 -04:00
OatmealDome
f8f117e599 GeneralPane: Update "Beta" auto update track to "Releases" 2024-06-24 15:06:37 -04:00
JMC47
c536754ffe
Merge pull request #12878 from LillyJadeKatrin/retroachievements-hardcore-state-changed
Decouple Hardcore from EmulationStateChanged
2024-06-23 18:13:56 -04:00
Admiral H. Curtiss
e9e29daca4
Merge pull request #12872 from LillyJadeKatrin/retroachievements-start-session-bug
Add MemoryVerifier to AchievementManager Startup
2024-06-23 21:18:34 +02:00
Admiral H. Curtiss
2aec195ec8
Merge pull request #12876 from dreamsyntax/advanced-cpu-clock-override-step-adjustment
DolphinQt: Adjust CPU Clock Override slider
2024-06-23 15:28:29 +02:00
Admiral H. Curtiss
c337ab6473
Merge pull request #12884 from Tilka/qt_this
DolphinQt: fix some warnings
2024-06-23 15:08:13 +02:00
Admiral H. Curtiss
a75c65bde2
Merge pull request #12879 from LillyJadeKatrin/retroachievements-1200-shines
Trim extra characters from measured progress
2024-06-23 15:05:09 +02:00
Admiral H. Curtiss
28692681ad
Merge pull request #12883 from LillyJadeKatrin/retroachievements-cutoff-text
Fix cut off text in Achievements dialog
2024-06-23 14:59:54 +02:00
LillyJadeKatrin
bf230a9909 Trim extra characters from measured progress
The measured_progress C string for achievements to display potentially contains junk data after the null terminator, which was rendering in the QString in the dialog. This trims those junk characters.
2024-06-22 23:36:06 -04:00
OatmealDome
883195f171
Merge pull request #12886 from AdmiralCurtiss/dual-core-lockup
Core/VideoCommon: Revert change from #12828
2024-06-22 22:22:52 -04:00
Admiral H. Curtiss
ce2f4101f3
Core/VideoCommon: Revert change from #12828
This causes Dual Core to lock up during the boot sequence, because it tries to wait for a not-yet-running GPU thread.

Fixes https://bugs.dolphin-emu.org/issues/13559
2024-06-23 03:44:05 +02:00
Tillmann Karras
8e7d11d1a1 DolphinQt: fix -Wunused-const-variable warning 2024-06-23 02:38:04 +01:00
Tillmann Karras
5c46716d28 DolphinQt: fix two -Wshadow-uncaptured-local warnings 2024-06-23 02:38:00 +01:00
Tillmann Karras
0f659508ea DolphinQt: fix two -Wunused-lambda-capture warnings
Also clean up signals a bit.
2024-06-23 00:13:58 +01:00
LillyJadeKatrin
aa393dfb6e Add MemoryVerifier to AchievementManager Startup
rc_client calls the provided memory peeker asynchronously in the callback for starting a session, to validate/invalidate the memory used for achievements. Dolphin cannot access memory from any thread but host or CPU so this access has a small chance of being invalid. This commit adds a MemoryVerifier that the AchievementManager will use to perform this, before changing the peek method back to the original MemoryPeeker for normal operation.
2024-06-22 09:31:00 -04:00
LillyJadeKatrin
e1a8dc65ce Fix cut off text in Achievements dialog 2024-06-22 00:26:52 -04:00
LillyJadeKatrin
9b9e6c4582 Refactored AchievementProgress UpdateData to Re-Sort
When AchievementProgress::UpdateData(false) is called, it will now empty itself and reinsert all existing boxes, re-sorted into their current buckets, and call UpdateProgress on them all.
2024-06-20 09:03:30 -04:00
LillyJadeKatrin
29f1b82f5e Decouple Hardcore from EmulationStateChanged
Rerendering the entire Achievements dialog every EmulationStateChanged signal is far too often when it turns out that signal fires multiple times to confirm game close, for example. This change results in only the settings changing on EmulationStateChanged, and having the Hardcore mode toggle (which DOES require redrawing the entire dialog) emit its own signal alongside EmulationStateChanged.
2024-06-20 07:59:59 -04:00
LillyJadeKatrin
75c2360aea Split AchievementBox UpdateData
AchievementBox now has UpdateData and UpdateProgress, which is called from UpdateData, but may be called elsewhere to update just the progress measurement of the achievement.
2024-06-19 22:12:30 -04:00
dreamsyntax
55ba014fed DolphinQt: Adjust CPU Clock Override slider
CPU Clock Override slider now increments 1% in the UI, with the new lower limit
being 1% instead of 6%.

Prior implementation made it impossible to set exactly 150% in the GUI.
147% -> 152%. Now users can set exact clock % without needing to edit INIs.
2024-06-18 18:52:35 -07:00
JosJuice
e0d588e375 DolphinQt: Split Config > Advanced into Misc and Advanced
It has gotten too tall.
2024-01-08 14:14:05 +01:00
84 changed files with 46617 additions and 43215 deletions

View File

@ -0,0 +1,16 @@
# GITP01, GITE01 - Geist
[Core]
# Values set here will override the main Dolphin settings.
# The game has random crashes and tons of unknown opcodes
# when using Dualcore.
CPUThread = False
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -381,15 +381,9 @@ public final class NativeLibrary
*/
public static native boolean IsRunning();
/**
* Returns true if emulation is running and not paused.
*/
public static native boolean IsRunningAndUnpaused();
public static native boolean IsRunningAndStarted();
/**
* Returns true if emulation is fully shut down.
*/
public static native boolean IsUninitialized();
public static native boolean IsRunningAndUnpaused();
/**
* Writes out the JitBlock Cache log dump

View File

@ -36,7 +36,7 @@ class Settings : Closeable {
if (isGameSpecific) {
// Loading game INIs while the core is running will mess with the game INIs loaded by the core
check(NativeLibrary.IsUninitialized()) { "Attempted to load game INI while emulating" }
check(!NativeLibrary.IsRunning()) { "Attempted to load game INI while emulating" }
NativeConfig.loadGameInis(gameId, revision)
}
}

View File

@ -20,5 +20,5 @@ class RunRunnable(
override val setting: AbstractSetting? = null
override val isEditable: Boolean
get() = worksDuringEmulation || NativeLibrary.IsUninitialized()
get() = worksDuringEmulation || !NativeLibrary.IsRunning()
}

View File

@ -54,7 +54,7 @@ abstract class SettingsItem {
open val isEditable: Boolean
get() {
if (NativeLibrary.IsUninitialized()) return true
if (!NativeLibrary.IsRunning()) return true
val setting = setting
return setting != null && setting.isRuntimeEditable
}

View File

@ -69,7 +69,7 @@ class SettingsFragmentPresenter(
} else if (
menuTag == MenuTag.GRAPHICS
&& this.gameId.isNullOrEmpty()
&& NativeLibrary.IsUninitialized()
&& !NativeLibrary.IsRunning()
&& GpuDriverHelper.supportsCustomDriverLoading()
) {
this.gpuDriver =
@ -1303,7 +1303,7 @@ class SettingsFragmentPresenter(
if (
this.gpuDriver != null && this.gameId.isNullOrEmpty()
&& NativeLibrary.IsUninitialized()
&& !NativeLibrary.IsRunning()
&& GpuDriverHelper.supportsCustomDriverLoading()
) {
sl.add(

View File

@ -180,11 +180,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private fun run(isActivityRecreated: Boolean) {
if (isActivityRecreated) {
if (NativeLibrary.IsUninitialized()) {
loadPreviousTemporaryState = true
} else {
if (NativeLibrary.IsRunning()) {
loadPreviousTemporaryState = false
deleteFile(temporaryStateFilePath)
} else {
loadPreviousTemporaryState = true
}
} else {
Log.debug("[EmulationFragment] activity resumed or fresh start")
@ -203,7 +203,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private fun runWithValidSurface() {
runWhenSurfaceIsValid = false
if (NativeLibrary.IsUninitialized()) {
if (!NativeLibrary.IsRunning()) {
NativeLibrary.SetIsBooting()
val emulationThread = Thread({
if (loadPreviousTemporaryState) {

View File

@ -83,7 +83,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
fun initTouchPointer() {
// Check if we have all the data we need yet
val aspectRatioAvailable = NativeLibrary.IsRunning()
val aspectRatioAvailable = NativeLibrary.IsRunningAndStarted()
if (!aspectRatioAvailable || surfacePosition == null)
return

View File

@ -874,7 +874,7 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="about_website"><a href="https://dolphin-emu.org/">Website</a></string>
<string name="about_github"><a href="https://github.com/dolphin-emu/dolphin">GitHub</a></string>
<string name="about_support"><a href="https://forums.dolphin-emu.org/">Support</a></string>
<string name="about_copyright_warning">\u00A9 20032015+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.</string>
<string name="about_copyright_warning">\u00A9 20032024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.</string>
<string name="system_driver">System driver</string>
<string name="system_driver_desc">The GPU driver that is part of the OS.</string>

View File

@ -118,7 +118,8 @@ void Host_Message(HostMessageID id)
}
else if (id == HostMessageID::WMUserStop)
{
Core::QueueHostJob(&Core::Stop);
if (Core::IsRunning(Core::System::GetInstance()))
Core::QueueHostJob(&Core::Stop);
}
}
@ -275,6 +276,13 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetIsBooting
}
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv*, jclass)
{
return s_is_booting.IsSet() ||
static_cast<jboolean>(Core::IsRunning(Core::System::GetInstance()));
}
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndStarted(JNIEnv*,
jclass)
{
return static_cast<jboolean>(Core::IsRunning(Core::System::GetInstance()));
}
@ -285,13 +293,6 @@ Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndUnpaused(JNIEnv*, jclas
return static_cast<jboolean>(Core::GetState(Core::System::GetInstance()) == Core::State::Running);
}
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsUninitialized(JNIEnv*,
jclass)
{
return static_cast<jboolean>(Core::IsUninitialized(Core::System::GetInstance()) &&
!s_is_booting.IsSet());
}
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env,
jclass)
{

View File

@ -13,6 +13,7 @@
#include <rcheevos/include/rc_api_info.h>
#include <rcheevos/include/rc_hash.h>
#include "Common/Assert.h"
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/Image.h"
@ -22,6 +23,7 @@
#include "Common/WorkQueueThread.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/MMU.h"
#include "Core/System.h"
#include "DiscIO/Blob.h"
@ -44,7 +46,7 @@ void AchievementManager::Init()
LoadDefaultBadges();
if (!m_client && Config::Get(Config::RA_ENABLED))
{
m_client = rc_client_create(MemoryPeeker, Request);
m_client = rc_client_create(MemoryVerifier, Request);
std::string host_url = Config::Get(Config::RA_HOST_URL);
if (!host_url.empty())
rc_client_set_host(m_client, host_url.c_str());
@ -120,6 +122,7 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo
rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED));
rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED));
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
rc_client_set_read_memory_function(m_client, MemoryVerifier);
if (volume)
{
std::lock_guard lg{m_lock};
@ -338,7 +341,7 @@ AchievementManager::RichPresence AchievementManager::GetRichPresence() const
return m_rich_presence;
}
const bool AchievementManager::AreChallengesUpdated() const
bool AchievementManager::AreChallengesUpdated() const
{
return m_challenges_updated;
}
@ -679,13 +682,14 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
}
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
AchievementManager::GetInstance().m_display_welcome_message = true;
AchievementManager::GetInstance().FetchGameBadges();
AchievementManager::GetInstance().m_system = &Core::System::GetInstance();
AchievementManager::GetInstance().m_update_callback({.all = true});
auto& instance = AchievementManager::GetInstance();
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
instance.m_display_welcome_message = true;
instance.FetchGameBadges();
instance.m_system = &Core::System::GetInstance();
instance.m_update_callback({.all = true});
// Set this to a value that will immediately trigger RP
AchievementManager::GetInstance().m_last_rp_time =
std::chrono::steady_clock::now() - std::chrono::minutes{2};
instance.m_last_rp_time = std::chrono::steady_clock::now() - std::chrono::minutes{2};
}
void AchievementManager::ChangeMediaCallback(int result, const char* error_message,
@ -706,6 +710,7 @@ void AchievementManager::ChangeMediaCallback(int result, const char* error_messa
ERROR_LOG_FMT(ACHIEVEMENTS, "RetroAchievements media change failed: {}", error_message);
}
rc_client_set_read_memory_function(AchievementManager::GetInstance().m_client, MemoryPeeker);
}
void AchievementManager::DisplayWelcomeMessage()
@ -914,11 +919,36 @@ void AchievementManager::Request(const rc_api_request_t* request,
});
}
// Currently, when rc_client calls the memory peek method provided in its constructor (or in
// rc_client_set_read_memory_function) it will do so on the thread that calls DoFrame, which is
// currently the host thread, with one exception: an asynchronous callback in the load game process.
// This is done to validate/invalidate each memory reference in the downloaded assets, mark assets
// as unsupported, and notify the player upon startup that there are unsupported assets and how
// many. As such, all that call needs to do is return the number of bytes that can be read with this
// call. As only the CPU and host threads are allowed to read from memory, I provide a separate
// method for this verification. In lieu of a more convenient set of steps, I provide MemoryVerifier
// to rc_client at construction, and in the Load Game callback, after the verification has been
// complete, I call rc_client_set_read_memory_function to switch to the usual MemoryPeeker for all
// future synchronous calls.
u32 AchievementManager::MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
{
auto& system = Core::System::GetInstance();
u32 ram_size = system.GetMemory().GetRamSizeReal();
if (address >= ram_size)
return 0;
return std::min(ram_size - address, num_bytes);
}
u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
{
if (buffer == nullptr)
return 0u;
auto& system = Core::System::GetInstance();
if (!(Core::IsHostThread() || Core::IsCPUThread()))
{
ASSERT_MSG(ACHIEVEMENTS, false, "MemoryPeeker called from wrong thread");
return 0;
}
Core::CPUThreadGuard threadguard(system);
for (u32 num_read = 0; num_read < num_bytes; num_read++)
{

View File

@ -116,7 +116,7 @@ public:
const Badge& GetAchievementBadge(AchievementId id, bool locked) const;
const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id);
RichPresence GetRichPresence() const;
const bool AreChallengesUpdated() const;
bool AreChallengesUpdated() const;
void ResetChallengesUpdated();
const std::unordered_set<AchievementId>& GetActiveChallenges() const;
std::vector<std::string> GetActiveLeaderboards() const;
@ -177,6 +177,7 @@ private:
static void Request(const rc_api_request_t* request, rc_client_server_callback_t callback,
void* callback_data, rc_client_t* client);
static u32 MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
void FetchBadge(Badge* badge, u32 badge_type, const BadgeNameFunction function,
const UpdatedItems callback_data);

View File

@ -33,7 +33,7 @@ namespace ConfigLoaders
{
void SaveToSYSCONF(Config::LayerType layer, std::function<bool(const Config::Location&)> predicate)
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (Core::IsRunning(Core::System::GetInstance()))
return;
IOS::HLE::Kernel ios;
@ -183,7 +183,7 @@ public:
private:
void LoadFromSYSCONF(Config::Layer* layer)
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (Core::IsRunning(Core::System::GetInstance()))
return;
IOS::HLE::Kernel ios;

View File

@ -211,11 +211,6 @@ bool IsRunningOrStarting(Core::System& system)
return state == State::Running || state == State::Starting;
}
bool IsUninitialized(Core::System& system)
{
return s_state.load() == State::Uninitialized;
}
bool IsCPUThread()
{
return tls_is_cpu_thread;
@ -242,7 +237,7 @@ bool Init(Core::System& system, std::unique_ptr<BootParameters> boot, const Wind
{
if (s_emu_thread.joinable())
{
if (!IsUninitialized(system))
if (IsRunning(system))
{
PanicAlertFmtT("Emu Thread already running");
return false;

View File

@ -134,13 +134,8 @@ void UndeclareAsHostThread();
std::string StopMessage(bool main_thread, std::string_view message);
// Returns true when GetState returns Running or Paused.
bool IsRunning(Core::System& system);
// Returns true when GetState returns Starting, Running or Paused.
bool IsRunningOrStarting(Core::System& system);
// Returns true when GetState returns Uninitialized.
bool IsUninitialized(Core::System& system);
bool IsCPUThread(); // this tells us whether we are the CPU thread.
bool IsGPUThread();
bool IsHostThread();

View File

@ -89,7 +89,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
// in your translation, please use the type of curly quotes that's appropriate for
// your language. If you aren't sure which type is appropriate, see
// https://en.wikipedia.org/wiki/Quotation_mark#Specific_language_features
tr("\u00A9 2003-2015+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
tr("\u00A9 2003-2024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
"trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.")));
QLabel* logo = new QLabel();

View File

@ -4,10 +4,12 @@
#ifdef USE_RETRO_ACHIEVEMENTS
#include "DolphinQt/Achievements/AchievementBox.h"
#include <QByteArray>
#include <QDateTime>
#include <QHBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QSizePolicy>
#include <QVBoxLayout>
#include <QWidget>
@ -30,9 +32,11 @@ AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achieve
m_badge = new QLabel();
QLabel* title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title)));
title->setWordWrap(true);
title->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QLabel* description =
new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description)));
description->setWordWrap(true);
description->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QLabel* points = new QLabel(tr("%1 points").arg(achievement->points));
m_status = new QLabel();
m_progress_bar = new QProgressBar();
@ -61,39 +65,57 @@ AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achieve
}
void AchievementBox::UpdateData()
{
{
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
// rc_client guarantees m_achievement will be valid as long as the game is loaded
if (!AchievementManager::GetInstance().IsGameLoaded())
return;
const auto& badge = AchievementManager::GetInstance().GetAchievementBadge(
m_achievement->id, m_achievement->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
std::string_view color = AchievementManager::GRAY;
if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE)
color = AchievementManager::GOLD;
else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE)
color = AchievementManager::BLUE;
QImage i_badge(&badge.data.front(), badge.width, badge.height, QImage::Format_RGBA8888);
m_badge->setPixmap(
QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
m_badge->adjustSize();
m_badge->setStyleSheet(
QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color)));
if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED)
{
m_status->setText(
tr("Unlocked at %1")
.arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString()));
}
else
{
m_status->setText(tr("Locked"));
}
}
UpdateProgress();
}
void AchievementBox::UpdateProgress()
{
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
const auto& badge = AchievementManager::GetInstance().GetAchievementBadge(
m_achievement->id, m_achievement->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
std::string_view color = AchievementManager::GRAY;
if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE)
color = AchievementManager::GOLD;
else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE)
color = AchievementManager::BLUE;
QImage i_badge(&badge.data.front(), badge.width, badge.height, QImage::Format_RGBA8888);
m_badge->setPixmap(
QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
m_badge->adjustSize();
m_badge->setStyleSheet(QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color)));
if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED)
{
m_status->setText(
tr("Unlocked at %1")
.arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString()));
}
else
{
m_status->setText(tr("Locked"));
}
// rc_client guarantees m_achievement will be valid as long as the game is loaded
if (!AchievementManager::GetInstance().IsGameLoaded())
return;
if (m_achievement->measured_percent > 0.000)
{
m_progress_bar->setRange(0, 100);
m_progress_bar->setValue(m_achievement->measured_percent);
m_progress_bar->setTextVisible(false);
m_progress_label->setText(QString::fromUtf8(m_achievement->measured_progress, PROGRESS_LENGTH));
m_progress_label->setText(
QString::fromUtf8(m_achievement->measured_progress,
qstrnlen(m_achievement->measured_progress, PROGRESS_LENGTH)));
m_progress_bar->setVisible(true);
}
else

View File

@ -20,6 +20,7 @@ class AchievementBox final : public QGroupBox
public:
explicit AchievementBox(QWidget* parent, rc_client_achievement_t* achievement);
void UpdateData();
void UpdateProgress();
private:
QLabel* m_badge;

View File

@ -57,8 +57,10 @@ void AchievementLeaderboardWidget::UpdateData(bool clean_all)
m_leaderboard_order[leaderboard->id] = row;
QLabel* a_title = new QLabel(QString::fromUtf8(leaderboard->title));
a_title->setWordWrap(true);
a_title->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QLabel* a_description = new QLabel(QString::fromUtf8(leaderboard->description));
a_description->setWordWrap(true);
a_description->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QVBoxLayout* a_col_left = new QVBoxLayout();
a_col_left->addWidget(a_title);
a_col_left->addWidget(a_description);

View File

@ -42,33 +42,51 @@ void AchievementProgressWidget::UpdateData(bool clean_all)
{
m_achievement_boxes.clear();
ClearLayoutRecursively(m_common_layout);
auto& instance = AchievementManager::GetInstance();
if (!instance.IsGameLoaded())
return;
auto* client = instance.GetClient();
auto* achievement_list = rc_client_create_achievement_list(
client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS);
for (u32 ix = 0; ix < achievement_list->num_buckets; ix++)
{
m_common_layout->addWidget(new QLabel(tr(achievement_list->buckets[ix].label)));
for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++)
{
auto* achievement = achievement_list->buckets[ix].achievements[jx];
m_achievement_boxes[achievement->id] = std::make_shared<AchievementBox>(this, achievement);
m_common_layout->addWidget(m_achievement_boxes[achievement->id].get());
}
}
rc_client_destroy_achievement_list(achievement_list);
}
else
{
for (auto box : m_achievement_boxes)
while (auto* item = m_common_layout->takeAt(0))
{
box.second->UpdateData();
auto* widget = item->widget();
m_common_layout->removeWidget(widget);
if (std::strcmp(widget->metaObject()->className(), "QLabel") == 0)
{
widget->deleteLater();
delete item;
}
}
}
auto& instance = AchievementManager::GetInstance();
if (!instance.IsGameLoaded())
return;
auto* client = instance.GetClient();
auto* achievement_list =
rc_client_create_achievement_list(client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS);
if (!achievement_list)
return;
for (u32 ix = 0; ix < achievement_list->num_buckets; ix++)
{
m_common_layout->addWidget(new QLabel(tr(achievement_list->buckets[ix].label)));
for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++)
{
auto* achievement = achievement_list->buckets[ix].achievements[jx];
auto box_itr = m_achievement_boxes.lower_bound(achievement->id);
if (box_itr != m_achievement_boxes.end() && box_itr->first == achievement->id)
{
box_itr->second->UpdateProgress();
m_common_layout->addWidget(box_itr->second.get());
}
else
{
const auto new_box_itr = m_achievement_boxes.try_emplace(
box_itr, achievement->id, std::make_shared<AchievementBox>(this, achievement));
m_common_layout->addWidget(new_box_itr->second.get());
}
}
}
rc_client_destroy_achievement_list(achievement_list);
}
void AchievementProgressWidget::UpdateData(

View File

@ -159,8 +159,6 @@ void AchievementSettingsWidget::OnControllerInterfaceConfigure()
void AchievementSettingsWidget::LoadSettings()
{
Core::System& system = Core::System::GetInstance();
bool enabled = Config::Get(Config::RA_ENABLED);
bool hardcore_enabled = Config::Get(Config::RA_HARDCORE_ENABLED);
bool logged_out = Config::Get(Config::RA_API_TOKEN).empty();
@ -176,15 +174,18 @@ void AchievementSettingsWidget::LoadSettings()
SignalBlocking(m_common_password_input)->setVisible(logged_out);
SignalBlocking(m_common_password_input)->setEnabled(enabled);
SignalBlocking(m_common_login_button)->setVisible(logged_out);
SignalBlocking(m_common_login_button)->setEnabled(enabled && Core::IsUninitialized(system));
SignalBlocking(m_common_login_button)
->setEnabled(enabled && !Core::IsRunning(Core::System::GetInstance()));
SignalBlocking(m_common_logout_button)->setVisible(!logged_out);
SignalBlocking(m_common_logout_button)->setEnabled(enabled);
SignalBlocking(m_common_hardcore_enabled_input)
->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED));
auto& system = Core::System::GetInstance();
SignalBlocking(m_common_hardcore_enabled_input)
->setEnabled(enabled && (hardcore_enabled || (Core::IsUninitialized(system) &&
!system.GetMovie().IsPlayingInput())));
->setEnabled(enabled &&
(hardcore_enabled || (Core::GetState(system) == Core::State::Uninitialized &&
!system.GetMovie().IsPlayingInput())));
SignalBlocking(m_common_unofficial_enabled_input)
->setChecked(Config::Get(Config::RA_UNOFFICIAL_ENABLED));
@ -236,7 +237,10 @@ void AchievementSettingsWidget::ToggleRAIntegration()
else
instance.Shutdown();
if (Config::Get(Config::RA_HARDCORE_ENABLED))
{
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
emit Settings::Instance().HardcoreStateChanged();
}
}
void AchievementSettingsWidget::Login()
@ -266,6 +270,7 @@ void AchievementSettingsWidget::ToggleHardcore()
Settings::Instance().SetDebugModeEnabled(false);
}
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
emit Settings::Instance().HardcoreStateChanged();
}
void AchievementSettingsWidget::ToggleUnofficial()

View File

@ -34,6 +34,8 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent)
});
});
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[this] { m_settings_widget->UpdateData(); });
connect(&Settings::Instance(), &Settings::HardcoreStateChanged, this,
[this] { AchievementsWindow::UpdateData({.all = true}); });
}
@ -89,7 +91,7 @@ void AchievementsWindow::UpdateData(AchievementManager::UpdatedItems updated_ite
{
m_header_widget->UpdateData();
}
if (updated_items.all_achievements)
if (updated_items.all_achievements || updated_items.rich_presence)
m_progress_widget->UpdateData(false);
else if (updated_items.achievements.size() > 0)
m_progress_widget->UpdateData(updated_items.achievements);

View File

@ -348,6 +348,8 @@ add_executable(dolphin-emu
Settings/GeneralPane.h
Settings/InterfacePane.cpp
Settings/InterfacePane.h
Settings/MiscPane.cpp
Settings/MiscPane.h
Settings/PathPane.cpp
Settings/PathPane.h
Settings/USBDeviceAddToWhitelistDialog.cpp

View File

@ -159,7 +159,8 @@ void CheatSearchFactoryWidget::OnNewSearchClicked()
if (m_standard_address_space->isChecked())
{
auto& system = Core::System::GetInstance();
if (!Core::IsRunning(system))
const Core::State core_state = Core::GetState(system);
if (core_state != Core::State::Running && core_state != Core::State::Paused)
{
ModalMessageBox::warning(
this, tr("No game running."),

View File

@ -104,9 +104,8 @@ void CheatsManager::RefreshCodeTabs(Core::State state, bool force)
if (!force && (state == Core::State::Starting || state == Core::State::Stopping))
return;
const auto& game_id = state == Core::State::Running || state == Core::State::Paused ?
SConfig::GetInstance().GetGameID() :
std::string();
const auto& game_id =
state != Core::State::Uninitialized ? SConfig::GetInstance().GetGameID() : std::string();
const auto& game_tdb_id = SConfig::GetInstance().GetGameTDBID();
const u16 revision = SConfig::GetInstance().GetRevision();

View File

@ -24,9 +24,8 @@ CheatWarningWidget::CheatWarningWidget(const std::string& game_id, bool restart_
connect(&Settings::Instance(), &Settings::EnableCheatsChanged, this,
[this] { Update(Core::IsRunning(Core::System::GetInstance())); });
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
Update(state == Core::State::Running || state == Core::State::Paused);
});
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[this](Core::State state) { Update(state == Core::State::Running); });
Update(Core::IsRunning(Core::System::GetInstance()));
}

View File

@ -43,7 +43,8 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent)
});
OnBackendChanged();
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
Core::State::Uninitialized);
}
void AdvancedWidget::CreateWidgets()

View File

@ -44,7 +44,8 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent)
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
Core::State::Uninitialized);
}
void GeneralWidget::CreateWidgets()
@ -360,8 +361,7 @@ void GeneralWidget::OnBackendChanged(const QString& backend_name)
const bool supports_adapters = !adapters.empty();
m_adapter_combo->setCurrentIndex(g_Config.iAdapter);
m_adapter_combo->setEnabled(supports_adapters &&
Core::IsUninitialized(Core::System::GetInstance()));
m_adapter_combo->setEnabled(supports_adapters && !Core::IsRunning(Core::System::GetInstance()));
static constexpr char TR_ADAPTER_AVAILABLE_DESCRIPTION[] =
QT_TR_NOOP("Selects a hardware adapter to use.<br><br>"

View File

@ -59,8 +59,6 @@
#include "InputCommon/ControllerInterface/CoreDevice.h"
#include "InputCommon/InputConfig.h"
constexpr const char* PROFILES_DIR = "Profiles/";
MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
: QDialog(parent), m_port(port_num)
{

View File

@ -16,6 +16,7 @@
#include "DolphinQt/Settings/GameCubePane.h"
#include "DolphinQt/Settings/GeneralPane.h"
#include "DolphinQt/Settings/InterfacePane.h"
#include "DolphinQt/Settings/MiscPane.h"
#include "DolphinQt/Settings/PathPane.h"
#include "DolphinQt/Settings/WiiPane.h"
@ -40,6 +41,7 @@ SettingsWindow::SettingsWindow(QWidget* parent) : QDialog(parent)
m_tab_widget->addTab(GetWrappedWidget(new PathPane, this, 125, 100), tr("Paths"));
m_tab_widget->addTab(GetWrappedWidget(new GameCubePane, this, 125, 100), tr("GameCube"));
m_tab_widget->addTab(GetWrappedWidget(new WiiPane, this, 125, 100), tr("Wii"));
m_tab_widget->addTab(GetWrappedWidget(new MiscPane, this, 125, 200), tr("Misc"));
m_tab_widget->addTab(GetWrappedWidget(new AdvancedPane, this, 125, 200), tr("Advanced"));
// Dialog box buttons

View File

@ -791,7 +791,7 @@ bool AssemblerWidget::SaveEditor(AsmEditor* editor)
void AssemblerWidget::OnEmulationStateChanged(Core::State state)
{
m_inject->setEnabled(state == Core::State::Running || state == Core::State::Paused);
m_inject->setEnabled(state != Core::State::Uninitialized);
}
void AssemblerWidget::OnTabClose(int index)

View File

@ -251,7 +251,7 @@ void BreakpointWidget::UpdateButtonsEnabled()
if (!isVisible())
return;
const bool is_initialised = Core::IsRunning(m_system);
const bool is_initialised = Core::GetState(m_system) != Core::State::Uninitialized;
m_new->setEnabled(is_initialised);
m_load->setEnabled(is_initialised);
m_save->setEnabled(is_initialised);

View File

@ -560,7 +560,7 @@ void CodeViewWidget::OnContextMenu()
QMenu* menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose, true);
const bool running = Core::IsRunning(m_system);
const bool running = Core::GetState(m_system) != Core::State::Uninitialized;
const bool paused = Core::GetState(m_system) == Core::State::Paused;
const u32 addr = GetContextAddress();

View File

@ -258,7 +258,7 @@ void ThreadWidget::Update()
auto& system = Core::System::GetInstance();
const auto emu_state = Core::GetState(system);
if (emu_state == Core::State::Stopping || emu_state == Core::State::Uninitialized)
if (emu_state == Core::State::Stopping)
{
m_thread_table->setRowCount(0);
UpdateThreadContext({});

View File

@ -195,11 +195,10 @@ void WatchWidget::Update()
QBrush brush = QPalette().brush(QPalette::Text);
const bool core_is_running = Core::IsRunning(m_system);
if (!core_is_running || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
if (!Core::IsRunning(m_system) || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
brush.setColor(Qt::red);
if (core_is_running)
if (Core::IsRunning(m_system))
{
if (PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
{

View File

@ -212,6 +212,7 @@
<ClCompile Include="Settings\GameCubePane.cpp" />
<ClCompile Include="Settings\GeneralPane.cpp" />
<ClCompile Include="Settings\InterfacePane.cpp" />
<ClCompile Include="Settings\MiscPane.cpp" />
<ClCompile Include="Settings\PathPane.cpp" />
<ClCompile Include="Settings\USBDeviceAddToWhitelistDialog.cpp" />
<ClCompile Include="Settings\WiiPane.cpp" />
@ -414,6 +415,7 @@
<QtMoc Include="Settings\GameCubePane.h" />
<QtMoc Include="Settings\GeneralPane.h" />
<QtMoc Include="Settings\InterfacePane.h" />
<QtMoc Include="Settings\MiscPane.h" />
<QtMoc Include="Settings\PathPane.h" />
<QtMoc Include="Settings\USBDeviceAddToWhitelistDialog.h" />
<QtMoc Include="Settings\WiiPane.h" />

View File

@ -59,14 +59,11 @@ FIFOPlayerWindow::FIFOPlayerWindow(FifoPlayer& fifo_player, FifoRecorder& fifo_r
});
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (state != m_emu_state)
{
if (state == Core::State::Running && m_emu_state != Core::State::Paused)
OnEmulationStarted();
else if (state == Core::State::Uninitialized)
OnEmulationStopped();
m_emu_state = state;
}
if (state == Core::State::Running && m_emu_state != Core::State::Paused)
OnEmulationStarted();
else if (state == Core::State::Uninitialized)
OnEmulationStopped();
m_emu_state = state;
});
installEventFilter(this);
@ -379,11 +376,9 @@ void FIFOPlayerWindow::UpdateLimits()
void FIFOPlayerWindow::UpdateControls()
{
Core::System& system = Core::System::GetInstance();
const bool core_is_uninitialized = Core::IsUninitialized(system);
const bool core_is_running = Core::IsRunning(system);
const bool is_recording = m_fifo_recorder.IsRecording();
const bool is_playing = m_fifo_player.IsPlaying();
bool running = Core::IsRunning(Core::System::GetInstance());
bool is_recording = m_fifo_recorder.IsRecording();
bool is_playing = m_fifo_player.IsPlaying();
m_frame_range_from->setEnabled(is_playing);
m_frame_range_from_label->setEnabled(is_playing);
@ -399,10 +394,10 @@ void FIFOPlayerWindow::UpdateControls()
m_frame_record_count_label->setEnabled(enable_frame_record_count);
m_frame_record_count->setEnabled(enable_frame_record_count);
m_load->setEnabled(core_is_uninitialized);
m_record->setEnabled(core_is_running && !is_playing);
m_load->setEnabled(!running);
m_record->setEnabled(running && !is_playing);
m_stop->setVisible(core_is_running && is_recording);
m_stop->setVisible(running && is_recording);
m_record->setVisible(!m_stop->isVisible());
m_save->setEnabled(m_fifo_recorder.IsRecordingDone());

View File

@ -299,16 +299,14 @@ void GameList::MakeEmptyView()
size_policy.setRetainSizeWhenHidden(true);
m_empty->setSizePolicy(size_policy);
connect(&Settings::Instance(), &Settings::GameListRefreshRequested, this,
[this, refreshing_msg = refreshing_msg] {
m_empty->setText(refreshing_msg);
m_empty->setEnabled(false);
});
connect(&Settings::Instance(), &Settings::GameListRefreshCompleted, this,
[this, empty_msg = empty_msg] {
m_empty->setText(empty_msg);
m_empty->setEnabled(true);
});
connect(&Settings::Instance(), &Settings::GameListRefreshRequested, this, [this, refreshing_msg] {
m_empty->setText(refreshing_msg);
m_empty->setEnabled(false);
});
connect(&Settings::Instance(), &Settings::GameListRefreshCompleted, this, [this, empty_msg] {
m_empty->setText(empty_msg);
m_empty->setEnabled(true);
});
}
void GameList::resizeEvent(QResizeEvent* event)
@ -438,7 +436,7 @@ void GameList::ShowContextMenu(const QPoint&)
// system menu, trigger a refresh.
Settings::Instance().NANDRefresh();
});
perform_disc_update->setEnabled(Core::IsUninitialized(system) || !system.IsWii());
perform_disc_update->setEnabled(!Core::IsRunning(system) || !system.IsWii());
}
if (!is_mod_descriptor && platform == DiscIO::Platform::WiiWAD)
@ -451,10 +449,10 @@ void GameList::ShowContextMenu(const QPoint&)
for (QAction* a : {wad_install_action, wad_uninstall_action})
{
a->setEnabled(Core::IsUninitialized(system));
a->setEnabled(!Core::IsRunning(system));
menu->addAction(a);
}
if (Core::IsUninitialized(system))
if (!Core::IsRunning(system))
wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu,
@ -475,8 +473,8 @@ void GameList::ShowContextMenu(const QPoint&)
QAction* export_wii_save =
menu->addAction(tr("Export Wii Save"), this, &GameList::ExportWiiSave);
open_wii_save_folder->setEnabled(Core::IsUninitialized(system));
export_wii_save->setEnabled(Core::IsUninitialized(system));
open_wii_save_folder->setEnabled(!Core::IsRunning(system));
export_wii_save->setEnabled(!Core::IsRunning(system));
menu->addSeparator();
}
@ -533,7 +531,7 @@ void GameList::ShowContextMenu(const QPoint&)
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
netplay_host->setEnabled(state == Core::State::Uninitialized);
});
netplay_host->setEnabled(Core::IsUninitialized(system));
netplay_host->setEnabled(!Core::IsRunning(system));
menu->addAction(netplay_host);
}

View File

@ -188,7 +188,7 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_EXIT))
emit ExitHotkey();
if (Core::IsUninitialized(system))
if (!Core::IsRunning(system))
{
// Only check for Play Recording hotkey when no game is running
if (IsHotkey(HK_PLAY_RECORDING))

View File

@ -905,7 +905,7 @@ void MainWindow::OnStopComplete()
bool MainWindow::RequestStop()
{
if (Core::IsUninitialized(Core::System::GetInstance()))
if (!Core::IsRunning(Core::System::GetInstance()))
{
Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true);
return true;
@ -1112,7 +1112,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
}
// If we're running, only start a new game once we've stopped the last.
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized)
{
if (!RequestStop())
return;
@ -1536,7 +1536,7 @@ void MainWindow::NetPlayInit()
bool MainWindow::NetPlayJoin()
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (Core::IsRunning(Core::System::GetInstance()))
{
ModalMessageBox::critical(nullptr, tr("Error"),
tr("Can't start a NetPlay Session while a game is still running!"));
@ -1603,7 +1603,7 @@ bool MainWindow::NetPlayJoin()
bool MainWindow::NetPlayHost(const UICommon::GameFile& game)
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (Core::IsRunning(Core::System::GetInstance()))
{
ModalMessageBox::critical(nullptr, tr("Error"),
tr("Can't start a NetPlay Session while a game is still running!"));
@ -1850,7 +1850,7 @@ void MainWindow::OnImportNANDBackup()
result.wait();
m_menu_bar->UpdateToolsMenu(Core::State::Uninitialized);
m_menu_bar->UpdateToolsMenu(Core::IsRunning(Core::System::GetInstance()));
}
void MainWindow::OnPlayRecording()
@ -1882,8 +1882,7 @@ void MainWindow::OnStartRecording()
{
auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
if (Core::GetState(system) == Core::State::Starting ||
Core::GetState(system) == Core::State::Stopping || movie.IsRecordingInput() ||
if (Core::GetState(system) == Core::State::Starting || movie.IsRecordingInput() ||
movie.IsPlayingInput())
{
return;
@ -1915,7 +1914,7 @@ void MainWindow::OnStartRecording()
{
emit RecordingStatusChanged(true);
if (Core::IsUninitialized(system))
if (!Core::IsRunning(system))
Play();
}
}

View File

@ -138,11 +138,9 @@ void MenuBar::OnEmulationStateChanged(Core::State state)
m_recording_stop->setEnabled(false);
m_recording_export->setEnabled(false);
}
const bool can_start_from_boot = m_game_selected && state == Core::State::Uninitialized;
const bool can_start_from_savestate =
state == Core::State::Running || state == Core::State::Paused;
m_recording_play->setEnabled(can_start_from_boot && !hardcore);
m_recording_start->setEnabled((can_start_from_boot || can_start_from_savestate) &&
m_recording_play->setEnabled(m_game_selected && !running);
m_recording_play->setEnabled(m_game_selected && !running && !hardcore);
m_recording_start->setEnabled((m_game_selected || running) &&
!Core::System::GetInstance().GetMovie().IsPlayingInput());
// JIT
@ -161,7 +159,7 @@ void MenuBar::OnEmulationStateChanged(Core::State state)
m_symbols->setEnabled(running);
UpdateStateSlotMenu();
UpdateToolsMenu(state);
UpdateToolsMenu(running);
OnDebugModeToggled(Settings::Instance().IsDebugModeEnabled());
}
@ -302,8 +300,7 @@ void MenuBar::AddToolsMenu()
m_boot_sysmenu->setEnabled(false);
connect(&Settings::Instance(), &Settings::NANDRefresh, this,
[this] { UpdateToolsMenu(Core::State::Uninitialized); });
connect(&Settings::Instance(), &Settings::NANDRefresh, this, [this] { UpdateToolsMenu(false); });
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(
@ -1053,23 +1050,20 @@ void MenuBar::AddSymbolsMenu()
m_symbols->addAction(tr("&Patch HLE Functions"), this, &MenuBar::PatchHLEFunctions);
}
void MenuBar::UpdateToolsMenu(Core::State state)
void MenuBar::UpdateToolsMenu(bool emulation_started)
{
const bool is_uninitialized = state == Core::State::Uninitialized;
const bool is_running = state == Core::State::Running || state == Core::State::Paused;
m_boot_sysmenu->setEnabled(!emulation_started);
m_perform_online_update_menu->setEnabled(!emulation_started);
m_ntscj_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(JAP_DIR)));
m_ntscu_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(USA_DIR)));
m_pal_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(EUR_DIR)));
m_wad_install_action->setEnabled(!emulation_started);
m_import_backup->setEnabled(!emulation_started);
m_check_nand->setEnabled(!emulation_started);
m_import_wii_save->setEnabled(!emulation_started);
m_export_wii_saves->setEnabled(!emulation_started);
m_boot_sysmenu->setEnabled(is_uninitialized);
m_perform_online_update_menu->setEnabled(is_uninitialized);
m_ntscj_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(JAP_DIR)));
m_ntscu_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(USA_DIR)));
m_pal_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(EUR_DIR)));
m_wad_install_action->setEnabled(is_uninitialized);
m_import_backup->setEnabled(is_uninitialized);
m_check_nand->setEnabled(is_uninitialized);
m_import_wii_save->setEnabled(is_uninitialized);
m_export_wii_saves->setEnabled(is_uninitialized);
if (is_uninitialized)
if (!emulation_started)
{
IOS::HLE::Kernel ios;
const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
@ -1092,7 +1086,7 @@ void MenuBar::UpdateToolsMenu(Core::State state)
}
const auto bt = WiiUtils::GetBluetoothEmuDevice();
const bool enable_wiimotes = is_running && bt != nullptr;
const bool enable_wiimotes = emulation_started && bt != nullptr;
for (std::size_t i = 0; i < m_wii_remotes.size(); i++)
{
@ -1263,20 +1257,16 @@ void MenuBar::OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_
m_game_selected = !!game_file;
auto& system = Core::System::GetInstance();
const bool can_start_from_boot = m_game_selected && Core::IsUninitialized(system);
const bool can_start_from_savestate = Core::IsRunning(system);
m_recording_play->setEnabled(can_start_from_boot);
m_recording_start->setEnabled((can_start_from_boot || can_start_from_savestate) &&
const bool core_is_running = Core::IsRunning(system);
m_recording_play->setEnabled(m_game_selected && !core_is_running);
m_recording_start->setEnabled((m_game_selected || core_is_running) &&
!system.GetMovie().IsPlayingInput());
}
void MenuBar::OnRecordingStatusChanged(bool recording)
{
auto& system = Core::System::GetInstance();
const bool can_start_from_boot = m_game_selected && Core::IsUninitialized(system);
const bool can_start_from_savestate = Core::IsRunning(system);
m_recording_start->setEnabled(!recording && (can_start_from_boot || can_start_from_savestate));
m_recording_start->setEnabled(!recording && (m_game_selected || Core::IsRunning(system)));
m_recording_stop->setEnabled(recording);
m_recording_export->setEnabled(recording);
}

View File

@ -43,7 +43,7 @@ public:
explicit MenuBar(QWidget* parent = nullptr);
void UpdateToolsMenu(Core::State state);
void UpdateToolsMenu(bool emulation_started);
QMenu* GetListColumnsMenu() const { return m_cols_menu; }

View File

@ -804,11 +804,9 @@ void NetPlayDialog::DisplayMessage(const QString& msg, const std::string& color,
QColor c(color.empty() ? QStringLiteral("white") : QString::fromStdString(color));
if (g_ActiveConfig.bShowNetPlayMessages && Core::IsRunning(Core::System::GetInstance()))
{
g_netplay_chat_ui->AppendChat(msg.toStdString(),
{static_cast<float>(c.redF()), static_cast<float>(c.greenF()),
static_cast<float>(c.blueF())});
}
}
void NetPlayDialog::AppendChat(const std::string& msg)

View File

@ -354,11 +354,6 @@ void Settings::NotifyRefreshGameListComplete()
emit GameListRefreshCompleted();
}
void Settings::RefreshMetadata()
{
emit MetadataRefreshRequested();
}
void Settings::NotifyMetadataRefreshComplete()
{
emit MetadataRefreshCompleted();

View File

@ -104,7 +104,6 @@ public:
void RefreshGameList();
void NotifyRefreshGameListStarted();
void NotifyRefreshGameListComplete();
void RefreshMetadata();
void NotifyMetadataRefreshComplete();
void ReloadTitleDB();
bool IsAutoRefreshEnabled() const;
@ -224,6 +223,7 @@ signals:
void SDCardInsertionChanged(bool inserted);
void USBKeyboardConnectionChanged(bool connected);
void EnableGfxModsChanged(bool enabled);
void HardcoreStateChanged();
private:
Settings();

View File

@ -4,9 +4,6 @@
#include "DolphinQt/Settings/AdvancedPane.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
@ -17,23 +14,14 @@
#include <cmath>
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/SystemTimers.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
static const std::map<PowerPC::CPUCore, const char*> CPU_CORE_NAMES = {
{PowerPC::CPUCore::Interpreter, QT_TR_NOOP("Interpreter (slowest)")},
{PowerPC::CPUCore::CachedInterpreter, QT_TR_NOOP("Cached Interpreter (slower)")},
{PowerPC::CPUCore::JIT64, QT_TR_NOOP("JIT Recompiler for x86-64 (recommended)")},
{PowerPC::CPUCore::JITARM64, QT_TR_NOOP("JIT Recompiler for ARM64 (recommended)")},
};
AdvancedPane::AdvancedPane(QWidget* parent) : QWidget(parent)
{
CreateLayout();
@ -49,44 +37,6 @@ void AdvancedPane::CreateLayout()
auto* main_layout = new QVBoxLayout();
setLayout(main_layout);
auto* cpu_options_group = new QGroupBox(tr("CPU Options"));
auto* cpu_options_group_layout = new QVBoxLayout();
cpu_options_group->setLayout(cpu_options_group_layout);
main_layout->addWidget(cpu_options_group);
auto* cpu_emulation_engine_layout = new QFormLayout;
cpu_emulation_engine_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
cpu_emulation_engine_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
cpu_options_group_layout->addLayout(cpu_emulation_engine_layout);
m_cpu_emulation_engine_combobox = new QComboBox(this);
cpu_emulation_engine_layout->addRow(tr("CPU Emulation Engine:"), m_cpu_emulation_engine_combobox);
for (PowerPC::CPUCore cpu_core : PowerPC::AvailableCPUCores())
{
m_cpu_emulation_engine_combobox->addItem(tr(CPU_CORE_NAMES.at(cpu_core)));
}
m_enable_mmu_checkbox = new ConfigBool(tr("Enable MMU"), Config::MAIN_MMU);
m_enable_mmu_checkbox->SetDescription(
tr("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = "
"Fast)<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_enable_mmu_checkbox);
m_pause_on_panic_checkbox = new ConfigBool(tr("Pause on Panic"), Config::MAIN_PAUSE_ON_PANIC);
m_pause_on_panic_checkbox->SetDescription(
tr("Pauses the emulation if a Read/Write or Unknown Instruction panic occurs.<br>Enabling "
"will affect performance.<br>The performance impact is the same as having Enable MMU "
"on.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_pause_on_panic_checkbox);
m_accurate_cpu_cache_checkbox =
new ConfigBool(tr("Enable Write-Back Cache (slow)"), Config::MAIN_ACCURATE_CPU_CACHE);
m_accurate_cpu_cache_checkbox->SetDescription(
tr("Enables emulation of the CPU write-back cache.<br>Enabling will have a significant "
"impact on performance.<br>This should be left disabled unless absolutely "
"needed.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_accurate_cpu_cache_checkbox);
auto* clock_override = new QGroupBox(tr("Clock Override"));
auto* clock_override_layout = new QVBoxLayout();
clock_override->setLayout(clock_override_layout);
@ -100,7 +50,7 @@ void AdvancedPane::CreateLayout()
clock_override_layout->addLayout(cpu_clock_override_slider_layout);
m_cpu_clock_override_slider = new QSlider(Qt::Horizontal);
m_cpu_clock_override_slider->setRange(0, 150);
m_cpu_clock_override_slider->setRange(1, 400);
cpu_clock_override_slider_layout->addWidget(m_cpu_clock_override_slider);
m_cpu_clock_override_slider_label = new QLabel();
@ -155,56 +105,18 @@ void AdvancedPane::CreateLayout()
ram_override_description->setWordWrap(true);
ram_override_layout->addWidget(ram_override_description);
auto* rtc_options = new QGroupBox(tr("Custom RTC Options"));
rtc_options->setLayout(new QVBoxLayout());
main_layout->addWidget(rtc_options);
m_custom_rtc_checkbox = new QCheckBox(tr("Enable Custom RTC"));
rtc_options->layout()->addWidget(m_custom_rtc_checkbox);
m_custom_rtc_datetime = new QDateTimeEdit();
// Show seconds
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("mm"), QStringLiteral("mm:ss")));
if (!m_custom_rtc_datetime->displayFormat().contains(QStringLiteral("yyyy")))
{
// Always show the full year, no matter what the locale specifies. Otherwise, two-digit years
// will always be interpreted as in the 21st century.
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("yy"), QStringLiteral("yyyy")));
}
m_custom_rtc_datetime->setDateTimeRange(QDateTime({2000, 1, 1}, {0, 0, 0}, Qt::UTC),
QDateTime({2099, 12, 31}, {23, 59, 59}, Qt::UTC));
m_custom_rtc_datetime->setTimeSpec(Qt::UTC);
rtc_options->layout()->addWidget(m_custom_rtc_datetime);
auto* custom_rtc_description =
new QLabel(tr("This setting allows you to set a custom real time clock (RTC) separate from "
"your current system time.\n\nIf unsure, leave this unchecked."));
custom_rtc_description->setWordWrap(true);
rtc_options->layout()->addWidget(custom_rtc_description);
main_layout->addStretch(1);
}
void AdvancedPane::ConnectLayout()
{
connect(m_cpu_emulation_engine_combobox, &QComboBox::currentIndexChanged, [](int index) {
const auto cpu_cores = PowerPC::AvailableCPUCores();
if (index >= 0 && static_cast<size_t>(index) < cpu_cores.size())
Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, cpu_cores[index]);
});
connect(m_cpu_clock_override_checkbox, &QCheckBox::toggled, [this](bool enable_clock_override) {
Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK_ENABLE, enable_clock_override);
Update();
});
connect(m_cpu_clock_override_slider, &QSlider::valueChanged, [this](int oc_factor) {
// Vaguely exponential scaling?
const float factor = std::exp2f((m_cpu_clock_override_slider->value() - 100.f) / 25.f);
const float factor = m_cpu_clock_override_slider->value() / 100.f;
Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK, factor);
Update();
});
@ -225,36 +137,13 @@ void AdvancedPane::ConnectLayout()
Config::SetBaseOrCurrent(Config::MAIN_MEM2_SIZE, mem2_size);
Update();
});
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_ENABLE, enable_custom_rtc);
Update();
});
connect(m_custom_rtc_datetime, &QDateTimeEdit::dateTimeChanged, [this](QDateTime date_time) {
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_VALUE,
static_cast<u32>(date_time.toSecsSinceEpoch()));
Update();
});
}
void AdvancedPane::Update()
{
const bool running = !Core::IsUninitialized(Core::System::GetInstance());
const bool running = Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized;
const bool enable_cpu_clock_override_widgets = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running;
const auto available_cpu_cores = PowerPC::AvailableCPUCores();
const auto cpu_core = Config::Get(Config::MAIN_CPU_CORE);
for (size_t i = 0; i < available_cpu_cores.size(); ++i)
{
if (available_cpu_cores[i] == cpu_core)
m_cpu_emulation_engine_combobox->setCurrentIndex(int(i));
}
m_cpu_emulation_engine_combobox->setEnabled(!running);
m_enable_mmu_checkbox->setEnabled(!running);
m_pause_on_panic_checkbox->setEnabled(!running);
{
QFont bf = font();
@ -271,8 +160,8 @@ void AdvancedPane::Update()
{
const QSignalBlocker blocker(m_cpu_clock_override_slider);
m_cpu_clock_override_slider->setValue(static_cast<int>(
std::round(std::log2f(Config::Get(Config::MAIN_OVERCLOCK)) * 25.f + 100.f)));
m_cpu_clock_override_slider->setValue(
static_cast<int>(std::round(Config::Get(Config::MAIN_OVERCLOCK) * 100.f)));
}
m_cpu_clock_override_slider_label->setText([] {
@ -313,12 +202,4 @@ void AdvancedPane::Update()
const u32 mem2_size = Config::Get(Config::MAIN_MEM2_SIZE) / 0x100000;
return tr("%1 MB (MEM2)").arg(QString::number(mem2_size));
}());
m_custom_rtc_checkbox->setEnabled(!running);
SignalBlocking(m_custom_rtc_checkbox)->setChecked(Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE));
QDateTime initial_date_time;
initial_date_time.setSecsSinceEpoch(Config::Get(Config::MAIN_CUSTOM_RTC_VALUE));
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
SignalBlocking(m_custom_rtc_datetime)->setDateTime(initial_date_time);
}

View File

@ -3,22 +3,13 @@
#pragma once
#include <vector>
#include <QWidget>
class ConfigBool;
class QCheckBox;
class QComboBox;
class QLabel;
class QRadioButton;
class QSlider;
class QDateTimeEdit;
namespace Core
{
enum class State;
}
class AdvancedPane final : public QWidget
{
@ -31,18 +22,11 @@ private:
void ConnectLayout();
void Update();
QComboBox* m_cpu_emulation_engine_combobox;
ConfigBool* m_enable_mmu_checkbox;
ConfigBool* m_pause_on_panic_checkbox;
ConfigBool* m_accurate_cpu_cache_checkbox;
QCheckBox* m_cpu_clock_override_checkbox;
QSlider* m_cpu_clock_override_slider;
QLabel* m_cpu_clock_override_slider_label;
QLabel* m_cpu_clock_override_description;
QCheckBox* m_custom_rtc_checkbox;
QDateTimeEdit* m_custom_rtc_datetime;
QCheckBox* m_ram_override_checkbox;
QSlider* m_mem1_override_slider;
QLabel* m_mem1_override_slider_label;

View File

@ -40,7 +40,8 @@ AudioPane::AudioPane()
OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
Core::State::Uninitialized);
}
void AudioPane::CreateWidgets()

View File

@ -194,7 +194,7 @@ void GeneralPane::CreateAutoUpdate()
auto_update_group_layout->addRow(tr("&Auto Update:"), m_combobox_update_track);
for (const QString& option :
{tr("Don't Update"), tr("Beta (once a month)"), tr("Dev (multiple times a day)")})
{tr("Don't Update"), tr("Releases (every few months)"), tr("Dev (multiple times a day)")})
m_combobox_update_track->addItem(option);
}

View File

@ -235,15 +235,15 @@ void InterfacePane::ConnectLayout()
connect(m_checkbox_use_builtin_title_database, &QCheckBox::toggled, &Settings::Instance(),
&Settings::GameListRefreshRequested);
connect(m_checkbox_use_covers, &QCheckBox::toggled, &Settings::Instance(),
&Settings::RefreshMetadata);
&Settings::MetadataRefreshRequested);
connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, &Settings::Instance(),
&Settings::SetDebugModeEnabled);
connect(m_combobox_theme, &QComboBox::currentIndexChanged, this,
[this](int index) { Settings::Instance().TriggerThemeChanged(); });
connect(m_combobox_theme, &QComboBox::currentIndexChanged, &Settings::Instance(),
&Settings::ThemeChanged);
connect(m_combobox_userstyle, &QComboBox::currentIndexChanged, this,
&InterfacePane::OnUserStyleChanged);
connect(m_combobox_language, &QComboBox::currentIndexChanged, this,
[this]() { OnLanguageChanged(); });
&InterfacePane::OnLanguageChanged);
connect(m_checkbox_top_window, &QCheckBox::toggled, &Settings::Instance(),
&Settings::KeepWindowOnTopChanged);
connect(m_radio_cursor_visible_movement, &ConfigRadioInt::OnSelected, &Settings::Instance(),
@ -253,7 +253,7 @@ void InterfacePane::ConnectLayout()
connect(m_radio_cursor_visible_always, &ConfigRadioInt::OnSelected, &Settings::Instance(),
&Settings::CursorVisibilityChanged);
connect(m_checkbox_lock_mouse, &QCheckBox::toggled, &Settings::Instance(),
[this]() { Settings::Instance().LockCursorChanged(); });
&Settings::LockCursorChanged);
}
void InterfacePane::UpdateShowDebuggingCheckbox()

View File

@ -0,0 +1,159 @@
// Copyright 2020 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DolphinQt/Settings/MiscPane.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QVBoxLayout>
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
static const std::map<PowerPC::CPUCore, const char*> CPU_CORE_NAMES = {
{PowerPC::CPUCore::Interpreter, QT_TR_NOOP("Interpreter (slowest)")},
{PowerPC::CPUCore::CachedInterpreter, QT_TR_NOOP("Cached Interpreter (slower)")},
{PowerPC::CPUCore::JIT64, QT_TR_NOOP("JIT Recompiler for x86-64 (recommended)")},
{PowerPC::CPUCore::JITARM64, QT_TR_NOOP("JIT Recompiler for ARM64 (recommended)")},
};
MiscPane::MiscPane(QWidget* parent) : QWidget(parent)
{
CreateLayout();
Update();
ConnectLayout();
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, &MiscPane::Update);
}
void MiscPane::CreateLayout()
{
auto* main_layout = new QVBoxLayout();
setLayout(main_layout);
auto* cpu_options_group = new QGroupBox(tr("CPU Options"));
auto* cpu_options_group_layout = new QVBoxLayout();
cpu_options_group->setLayout(cpu_options_group_layout);
main_layout->addWidget(cpu_options_group);
auto* cpu_emulation_engine_layout = new QFormLayout;
cpu_emulation_engine_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
cpu_emulation_engine_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
cpu_options_group_layout->addLayout(cpu_emulation_engine_layout);
m_cpu_emulation_engine_combobox = new QComboBox(this);
cpu_emulation_engine_layout->addRow(tr("CPU Emulation Engine:"), m_cpu_emulation_engine_combobox);
for (PowerPC::CPUCore cpu_core : PowerPC::AvailableCPUCores())
{
m_cpu_emulation_engine_combobox->addItem(tr(CPU_CORE_NAMES.at(cpu_core)));
}
m_enable_mmu_checkbox = new ConfigBool(tr("Enable MMU"), Config::MAIN_MMU);
m_enable_mmu_checkbox->SetDescription(
tr("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = "
"Fast)<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_enable_mmu_checkbox);
m_pause_on_panic_checkbox = new ConfigBool(tr("Pause on Panic"), Config::MAIN_PAUSE_ON_PANIC);
m_pause_on_panic_checkbox->SetDescription(
tr("Pauses the emulation if a Read/Write or Unknown Instruction panic occurs.<br>Enabling "
"will affect performance.<br>The performance impact is the same as having Enable MMU "
"on.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_pause_on_panic_checkbox);
m_accurate_cpu_cache_checkbox =
new ConfigBool(tr("Enable Write-Back Cache (slow)"), Config::MAIN_ACCURATE_CPU_CACHE);
m_accurate_cpu_cache_checkbox->SetDescription(
tr("Enables emulation of the CPU write-back cache.<br>Enabling will have a significant "
"impact on performance.<br>This should be left disabled unless absolutely "
"needed.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
cpu_options_group_layout->addWidget(m_accurate_cpu_cache_checkbox);
auto* rtc_options = new QGroupBox(tr("Custom RTC Options"));
rtc_options->setLayout(new QVBoxLayout());
main_layout->addWidget(rtc_options);
m_custom_rtc_checkbox = new QCheckBox(tr("Enable Custom RTC"));
rtc_options->layout()->addWidget(m_custom_rtc_checkbox);
m_custom_rtc_datetime = new QDateTimeEdit();
// Show seconds
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("mm"), QStringLiteral("mm:ss")));
if (!m_custom_rtc_datetime->displayFormat().contains(QStringLiteral("yyyy")))
{
// Always show the full year, no matter what the locale specifies. Otherwise, two-digit years
// will always be interpreted as in the 21st century.
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("yy"), QStringLiteral("yyyy")));
}
m_custom_rtc_datetime->setDateTimeRange(QDateTime({2000, 1, 1}, {0, 0, 0}, Qt::UTC),
QDateTime({2099, 12, 31}, {23, 59, 59}, Qt::UTC));
m_custom_rtc_datetime->setTimeSpec(Qt::UTC);
rtc_options->layout()->addWidget(m_custom_rtc_datetime);
auto* custom_rtc_description =
new QLabel(tr("This setting allows you to set a custom real time clock (RTC) separate from "
"your current system time.\n\nIf unsure, leave this unchecked."));
custom_rtc_description->setWordWrap(true);
rtc_options->layout()->addWidget(custom_rtc_description);
main_layout->addStretch(1);
}
void MiscPane::ConnectLayout()
{
connect(m_cpu_emulation_engine_combobox, &QComboBox::currentIndexChanged, [](int index) {
const auto cpu_cores = PowerPC::AvailableCPUCores();
if (index >= 0 && static_cast<size_t>(index) < cpu_cores.size())
Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, cpu_cores[index]);
});
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_ENABLE, enable_custom_rtc);
Update();
});
connect(m_custom_rtc_datetime, &QDateTimeEdit::dateTimeChanged, [this](QDateTime date_time) {
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_VALUE,
static_cast<u32>(date_time.toSecsSinceEpoch()));
Update();
});
}
void MiscPane::Update()
{
const bool running = Core::GetState() != Core::State::Uninitialized;
const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running;
const auto available_cpu_cores = PowerPC::AvailableCPUCores();
const auto cpu_core = Config::Get(Config::MAIN_CPU_CORE);
for (size_t i = 0; i < available_cpu_cores.size(); ++i)
{
if (available_cpu_cores[i] == cpu_core)
m_cpu_emulation_engine_combobox->setCurrentIndex(int(i));
}
m_cpu_emulation_engine_combobox->setEnabled(!running);
m_enable_mmu_checkbox->setEnabled(!running);
m_pause_on_panic_checkbox->setEnabled(!running);
m_custom_rtc_checkbox->setEnabled(!running);
SignalBlocking(m_custom_rtc_checkbox)->setChecked(Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE));
QDateTime initial_date_time;
initial_date_time.setSecsSinceEpoch(Config::Get(Config::MAIN_CUSTOM_RTC_VALUE));
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
SignalBlocking(m_custom_rtc_datetime)->setDateTime(initial_date_time);
}

View File

@ -0,0 +1,33 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QWidget>
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
class QCheckBox;
class QComboBox;
class QDateTimeEdit;
class MiscPane final : public QWidget
{
Q_OBJECT
public:
explicit MiscPane(QWidget* parent = nullptr);
private:
void CreateLayout();
void ConnectLayout();
void Update();
QComboBox* m_cpu_emulation_engine_combobox;
ConfigBool* m_enable_mmu_checkbox;
ConfigBool* m_pause_on_panic_checkbox;
ConfigBool* m_accurate_cpu_cache_checkbox;
QCheckBox* m_custom_rtc_checkbox;
QDateTimeEdit* m_custom_rtc_datetime;
};

View File

@ -93,7 +93,8 @@ WiiPane::WiiPane(QWidget* parent) : QWidget(parent)
LoadConfig();
ConnectLayout();
ValidateSelectionState();
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
Core::State::Uninitialized);
}
void WiiPane::CreateLayout()

View File

@ -66,12 +66,15 @@ void VideoConfig::Refresh()
CPUThreadConfigCallback::AddConfigChangedCallback([]() {
auto& system = Core::System::GetInstance();
system.GetFifo().PauseAndLock(true, false);
const bool lock_gpu_thread = Core::IsRunning(system);
if (lock_gpu_thread)
system.GetFifo().PauseAndLock(true, false);
g_Config.Refresh();
g_Config.VerifyValidity();
system.GetFifo().PauseAndLock(false, true);
if (lock_gpu_thread)
system.GetFifo().PauseAndLock(false, true);
});
s_has_registered_callback = true;
}