Before:
1. In theory there could be multiple, but in practice they were (manually) cleared before creating one
2. (Some of) the conditions to clear one were either to reach it, to create a new one (due to the point above), or to step. This created weird behavior: let's say you Step Over a `bl` (thus creating a temporary breakpoint on `pc+4`), and you reached a regular breakpoint inside the `bl`. The temporary one would still be there: if you resumed, the emulation would still stop there, as a sort of Step Out. But, if before resuming, you made a Step, then it wouldn't do that.
3. The breakpoint widget had no idea concept of them, and will treat them as regular breakpoints. Also, they'll be shown only when the widget is updated in some other way, leading to more confusion.
4. Because only one breakpoint could exist per address, the creation of a temporary breakpoint on a top of a regular one would delete it and inherit its properties (e.g. being log-only). This could happen, for instance, if you Stepped Over a `bl` specifically, and pc+4 had a regular breakpoint.
Now there can only be one temporary breakpoint, which is automatically cleared whenever emulation is paused. So, removing some manual clearing from 1., and removing the weird behavior of 2. As it is stored in a separate variable, it won't be seen at all depending on the function used (fixing 3., and removing some checks in other places), and it won't replace a regular breakpoint, instead simply having priority (fixing 4.).
Now it actually does what it says on the name, instead of creating a breapoint and doing nothing else (not even updating the widget).
Also, it now can't be selected if emulation isn't running.
Closes https://bugs.dolphin-emu.org/issues/13532
Change misleading names.
Fix function usage: Intepreter and Step Out will not check breakpoints in their own wrong way anymore (e.g. breaking on log-only breakpoints).
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.
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.
bugfix: SetQWidgetWindowDecorations(this); not called before show() for Windows darkmode titlebars.
The actual call to (QWidget) show() needed to come sooner. Show() was originally left alone, but with other checks needing to move with (QWidget) show(), this function became less useful. Show() was originally created to fix the render widget appearing behind the main window, but that appears to work fine in this iteration.
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.
Some pieces of code are calling IsRunning because there's some
particular action that only makes sense when emulation is running, for
instance showing the state of the emulated CPU. IsRunning is appropriate
to use for this. Then there are pieces of code that are calling
IsRunning because there's some particular thing they must avoid doing
e.g. when the CPU thread is running or IOS is running. IsRunning isn't
quite appropriate for this. Such code should also be checking for the
states Starting and Stopping. Keep in mind that:
* When the state is Starting, the state can asynchronously change to
Running at any time.
* When we try to stop the core, the state gets set to Stopping before we
take any action to actually stop things.
This commit adds a new method Core::IsUninitialized, and changes all
callers of IsRunning and GetState that look to me like they should be
changed.
Core::GetState reads from four different pieces of state: s_is_stopping,
s_hardware_initialized, s_is_booting, and CPUManager::IsStepping.
I'm keeping that last one as is for now because there's code in Dolphin
that sets it directly, but we can unify the other three to make things
easier to reason about.
This commit also gets rid of s_is_started. This was previously used in
Core::IsRunningAndStarted to ensure true wouldn't be returned until the
CPU thread was started, but it wasn't used in Core::GetState, so
Core::GetState would happily return State::Running after we had
initialized the hardware but before we had initialized the CPU thread.
As far as I know, there are no callers that have any real need to know
whether the boot process is currently initializing the hardware or the
CPU thread. Perhaps once upon a time there was a desire to make the
apploader debuggable, but a long time has passed without anyone stepping
up to implement it, and the way CBoot::RunApploader is implemented makes
it rather difficult. So this commit makes all the functions in Core.cpp
consider the core to still be starting until the CPU thread is started.
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.
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.
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.
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.
rc_client provides basic sorting buckets as a possible option when retrieving the list of achievements or leaderboards; this enables them and labels them in the dialog.
Prior to this change, attempting to decrease the speed limit below 100% in hardmode would display the new attempted speed and then warn that the speed can not be decreased below 100%; this disables that first message under those conditions.
This lets us reduce the number of USE_RETRO_ACHIEVEMENTS ifdefs in the
code base, reducing visual clutter. In particular, needing an ifdef for
each call to IsHardcodeModeActive was annoying to me. This also reduces
the risk that someone writes code that accidentally fails to compile
with USE_RETRO_ACHIEVEMENTS disabled.
We could cut down on ifdefs even further by making HardcodeWarningWidget
always exist, but that would result in non-trivial code ending up in the
binary even with USE_RETRO_ACHIEVEMENTS disabled, so I'm leaving it out
of this PR. It's not a lot of code though, so I might end up revisiting
it at some point.
Enable emulator hotkeys and controller input (when that option is
enabled) when a TAS Input window has focus, as if it was the render
window instead. This allows TASers to use frame advance and the like
without having to switch the focused window or disabling Hotkeys Require
Window Focus which also picks up keypresses while other apps are active.
Cursor updates are disabled when the TAS Input window has focus, as
otherwise the Wii IR widget (and anything else controlled by the mouse)
becomes unusable. The cursor continues to work normally when the render
window has focus.
The names attached to the BadgeStatus object are obsolete and unneeded and are removed from everything that uses them. All BadgeStatus references are updated to just Badge.
Achievement badges/icons are refactored into the type CustomTextureData::ArraySlice::Level as that is the data type images loaded from the filesystem will be. This includes everything that uses the badges in the Qt UI and OnScreenDisplay, and similarly removes the OSD::Icon type because Level already contains that information.
Was informed by the RetroAchievements team that this isn't an option in most emulators, and as the next commits will be to enable default icons, there will always be something to display.
On Windows:
wsi.render_window being set will set/save the initial geometry, which will cause sizing bugs until it's set again by the user resizing/repositioning.
If achievements were disabled but a player token is in settings, prior to this change the Achievement Manager dialog would show a box with no player name and score zero, which is unnecessary.
Previously the Achievements option would only show up if achievements were already enabled, requiring users to manually create a config file in the file system; this now makes it visible no matter what.
Bugfix for hardcore-disabled items being disabled when hardcore was true but achievement integration was false, which should mean hardcore is effectively disabled. Now everything checks the IsHardcoreModeActive method in AchievementManager which processes the setting AND the game state to determine if hardcore mode is actually active.
Spectator Mode is a new mode added by rc_client that allows for achievement and leaderboard functionality, but does not submit this data to the site, partially allowing for offline achievements. It effectively replaces the former settings for disabling achievements, leaderboards, and RP, which are now always active internally as long as the client is active.
The client can take care of itself and handle its own hardcore status when it toggles, so I can tell the settings widget to contact the manager directly to set it.
Also, gradually reorganizing the settings dialog over the next handful of commits.
The client can handle media changes natively so disabling can take place internally. This code uses the same external calls to load data, but will call either BeginLoad or BeginChangeMedia based on whether any media is already loaded.
Due to the client's handling of media changes (it simply disables hardcore if an unknown media is detected) the existing functionality for "disabling" the achievements is no longer necessary and can be deleted.
Two portions of this need updating.
Anything related to points and unlock counts and scoring uses game_summary now instead of the TallyScore method. Unfortunately this comes with the drawback that I cannot easily at this time access the number of points/unlocks from the other hardcore mode, so things like the second progress bar have been deleted.
Rich presence, which no longer needs to be stored, but can be calculated at request. As the AchievementHeader can now update just the Rich Presence, DoFrame can now simply call a header update with .rp=true and the current Rich Presence will be calculated immediately.
As the two items above are the last remaining things to use a number of the components in AchievementManager, this also deletes: Request V1 (V2 is renamed accordingly), ResponseType, PointSpread, TallyScore, UnlockStatus, and the RP generation and ping methods.
UpdateData in AchievementsWindow now only updates the components being requested, massively improving the window's performance. The parameter is UpdatedItems in AchievementManager, which tracks which portions of the system have been updated for every update callback.
Similarly to the Progress widget (though without the separate object for each box, because each Leaderboard unit is just three text fields stacked vertically), AchievementLeaderboardWidget.UpdateData will now accept three options: destroy all and rebuild, update all, or update a set of rows.
As part of this, AchievementManager::GetLeaderboardsInfo has been refactored to GetLeaderboardInfo to return a single leaderboard for the ID passed in.
AchievementProgressWidget maintains in memory a map of AchievementBox pointers so that UpdateData can operate on them individually. UpdateData is overhauled for three options: UpdateData(true) will destroy the entire list and re-create it from scratch as before, to be used if the game or player changes/closes/logs out. UpdateData(false) will loop through the map and call UpdateData on every achievement box, to be used for certain settings changes such as enabling badges or disabling hardcore mode. UpdateData(set<IDs>) will call UpdateData on only the IDs in the set, to be used when achievements are unlocked.
AchievementBox is an extension of QGroupBox that contains the data for a single achievement, initialized with the achievement data and able to reference AchievementManager to update itself.
This change was primarily made to refactor the badge fetching to use the client instead of the runtime, but in the process I also refactored the code to cut down on complexity and duplication. Now the FetchBadge method is passed a function that generates the badge name; this is used to ensure that once the badge is loaded that it is still the desired badge to avoid race conditions.
HashGame has become LoadGame, similar structure with the file loaders but using the client instead. LoadGameCallback has been created to handle the results. The old LoadGameSync has been deleted as have
several hash and load methods that it called.
Deletes AchievementManager::Login, renames LoginAsync to Login, and replaces the one synchronous call in the AchievementSettingsWidget with the async call. There is a minor usability regression in that the UI currently does not notify the user when a login has failed; this will be addressed in a later change (possibly in a different PR).
On Windows 11, when playing windowed in a separate window/widget from the main emulator window, we don't want the window to have rounded corners, as it prevents the corner pixels from being visible
Move CheatManager's child widgets into scroll areas to allow making the
window smaller than the default.
In CheatSearchWidget, enable word wrapping for the label describing the
address space and search type to help it fit better inside a narrower
window.
There were three distinct mechanisms for signaling symbol changes in DolphinQt: `Host::NotifyMapLoaded`, `MenuBar::NotifySymbolsUpdated`, and `CodeViewWidget::SymbolsChanged`. The behavior of these signals has been consolidated into the new `Host::PPCSymbolsUpdated` signal, which can be emitted from anywhere in DolphinQt to properly update symbols everywhere in DolphinQt.
With this, I intend to make it clearer that Auto, Force 4:3, Force 16:9
and Custom are really the same thing, just with the aspect ratio of the
simulated TV being selected in a different way. I also extended the
introduction in a way I feel will clarify things but which you are
welcome to bikeshed :)
I was thinking of this during the review of 41b19e262f, but wanted to
put it in a separate PR as to avoid blocking it on bikeshedding.
I'm a bit unsure what to do about the word "analog" in "analog TV". I
felt that repeating it for each of these options would be too
repetitive. I suppose there's a reason why we used the word originally,
but digital TVs do give you basically the same aspect ratio for GC/Wii
games as analog TVs. (Of course, whether it's 4:3-like or 16:9-like
depends on what aspect ratio you set in the TV's settings, but that's
the case for widescreen CRTs too.)
This implements the GameCube modem adapter. This implementation is stable but not perfect; it drops frames if the receive FIFO length is exceeded. This is probably due to the unimplemented interrupt mentioned in the comments. If the tapserver end of the connection is aware of this limitation, it's easily circumvented by lowering the MTU of the link, but ideally this wouldn't be necessary.
This has been tested with a couple of different versions of Phantasy Star Online, including Episodes 1 & 2 Trial Edition. The Trial Edition is the only version of the game that supports the Modem Adapter and not the Broadband Adapter, which is what made this commit necessary in the first place.
This expands the tapserver BBA interface to be available on all platforms. tapserver itself is still macOS-only, but newserv (the PSO server) is not, and it can directly accept local and remote tapserver connections as well. This makes the tapserver interface potentially useful on all platforms.
Window icon was missing from QDialog lacking a parent.
Giving the QDialog a parent revealed I had failed to make it properly non-modal, necessitating further changes.
Settings save less often, now only upon destruction.
Construction of BranchWatchDialog is now deferred.
* Fix irregularly shaped corners
* Remove extra space for BalloonTips with no message or no title
* When the target tip location is not on a screen, put the tooltip on
the mouse's screen instead of the primary screen
* Fix description getting cut off when the title was too long
* Expose border width as a parameter
* Fix spacing and sizing issues with larger border widths
Most obviously, there is no longer a warning message to the player in the achievement window that achievements are disabled if a game is not currently running.
Adds a setting field under the hood to retain which folder the player last saved/loaded a state to/from, so that the dialog box to select a state to save/load reopens at that folder.
After reading the previous commit, you might think "hold on, what's the
difference between GetProfileName and GetProfileDirectoryName"? These
two are being used for the exact same thing - figuring out where
profiles are stored - yet they return different values for certain
controllers like GC keyboards! As far as I can tell, the existing code
has been broken for GC keyboards since they were introduced a decade
ago. The GUI (and more recently, also InputCycler) would write and read
profiles in one location, and our code for loading profiles specified in
a game INI file would read profiles in another location.
This commit gets rid of the set of values used by the game INI code in
favor of the other set. This does breaking existing setups where a
GCKey profile has been configured in a game INI, but I think the number
of working such setups is vanishingly small. The alternative would make
existing GCKey profiles go missing from the profile dropdown in the GUI,
which I think would be more disruptive. The alternative would also force
new GCKey profiles into the same directory as GCPad profiles.
This commit also fixes a regression from d6c0f8e749. The Android GUI was
using GetProfileName to figure out what key to use in the game INI,
which made it use incorrect game INI entries for GameCube controller
profiles but not Wii Remote profiles. Now the Android GUI uses
GetProfileKey for this, fixing the problem.
Core::RunAsCPUThread is obsoleted by CPUThreadGuard reference already passed into the function. The nonsense lambda in CheatSearchWidget is from changes in fdb7328c73.
This reverts the parts of commit c8c9928eb1 that made translatability
worse rather than better. Changing "Error in column %2" to "%1 in column
%2" not only means that the translators have to check the i18n comments
to know what word hides behind %1, but there's also the problem that
the translator might need to translate "Error" in this context
differently from the standalone string "Error". Having to copy-paste
some HTML tags may be annoying for translators, but it's a far less
serious problem.
This fixes an issue where the game specific graphics backend would be saved as the global setting after playing a game.
This also now displays the currently running graphics backend when looking in the graphics configuration window.
Given how many member functions make use of the system instance,
it's likely just better to pass the system instance in on construction.
Makes the interface a little less noisy to use.
Previously we were always taking the buffer by value, even if it wasn't
being stored anywhere and only read from.
We can use a std::span for the same thing.
The Disabled state sits between Game Closed and completely Shutdown - stronger than the former, as it refuses to let a game be opened again until AchievementManager is restored (which only happens upon a fresh core boot) but it isn't completely shut down and will still allow the player to be logged in and access the achievement settings and their (global) achievement header.
This adds the actual switch to turn on Hardcore Mode to the settings tab of the Achievements dialog. It is accompanied by a large tooltip warning explaining what it does and when it can be enabled.
The switch is only enabled to be turned on when no game is running, so that games are started in hardcore mode and can only be loaded via the console's memory card, as in the original hardware. Hardcore may be turned off while a game is running, but cannot be turned back on until the game is disabled.
The toggle trigger for hardcore mode also automatically disables the settings that are not allowed during hardcore mode.
Finally, the original flag in AchievementSettingsWidget to set whether things are enabled in hardcore mode (primarily Leaderboards) is replaced with the actual Hardcore Mode setting.
Play Input Recording would potentially unlock achievements without any player input and needs to be disabled. If a recording is already playing, hardcore mode cannot be enabled.
The player getting a better view of their surroundings than the game would normally allow could possibly give the player an advantage over the original hardware, so Freelook is disabled in hardcore mode. To do this, I disable the config flag for Freelook when it is accessed, to make sure that it is disabled whether it was enabled before or after hardcore mode was enabled.
Memory patches would be an easy way to manipulate the memory needed to calculate achievement logic, so they must be disabled. Riivolution patches that do not affect memory are allowed, as they will be hashed with the game file.
Debug Mode gives players direct read and write access to memory, which could be used to completely manipulate RetroAchievements logic and therefore is not allowed in hardcore mode.
Frame advancing is easily exploitable for slowing down a game and artificially improving reaction times and is not allowed in RetroAchievements hardcore mode.
While saving states is allowed (especially for the purpose of debugging), RetroAchievements does not allow loading saved states when hardcore mode is on.
This widget will be used in several places to notify the player that a feature has been disabled because hardcore mode is on. It includes a button to open the Achievement Settings so that Hardcore Mode may be turned off. Also included is the framework required to open AchievementsWindow specifically on the Settings tab.
Some state changes are meant to be near instantanoues, before switching to something else. By reporting ithe instant switch, the UI will flicker between states (pause/play button) and the debugger will unnecessarily update. Skipping the callback avoids these issues.
This makes it so that if you just want to reload the current style (eg. on program start, or in response to a system event), you don't need to know the name of the currently selected user style. It's also more consistent with the way the 'userstyle/enabled' flag works.
At the end of each frame automatically update the Current Value for
visible table rows in the selected and visible CheatSearchWidget (if
any). Also update all Current Values in all CheatSearchWidgets when the
State changes to Paused.
Only updating visible table rows serves to minimize the performance cost
of this feature. If the user scrolls to an un-updated cell it will
promptly be updated by either the next VIEndFieldEvent or the State
transitioning to Paused.
The table only needs to be recreated when the displayed addresses might
change. If we're just refreshing the current values then update those
table cells and leave the rest of the table alone.
A new tab is added to the Achievements dialog to chart out the leaderboards in a table. Each row of the table contains the leaderboard information and up to four relevant entries, varying based on how many entries are in the leaderboard, whether or not the player has a submitted score, and where in the leaderboard the player's score is.
The achievement badges will now have a blue or gold border to identify whether they have been unlocked in softcore or hardcore mode. Similarly, the game badge will have a blue border if all achievements have been unlocked in either mode or a gold border if all achievements have been unlocked in hardcore mode.
Provided the badges are turned on in the settings, each achievement will have a badge next to it on the progress tab. There are different badges for locked and unlocked (usually locked is grayscale while unlocked is in color but not necessarily) and the badge chosen depends on the player's current unlock and hardcore status.
Provided badges are turned on, if there's a player logged in their RetroAchievements icon will appear next to their player info in the header of the Achievements dialog. If they're playing a game, so will the icon for the game. Also performed some refactoring and reorganizing to the header as a whole so that it looks consistent whether a game is running or not.
This refactors the Rich Presence generation to store to a member field that can be exposed to the UI to display the Rich Presence in the achievement header. It still updates at its original rate of once per two minutes, but calls an update on the dialog when that ticks.
Moved AchievementManager Init further down in the MainWindow constructor; its original position was because it had an impact on the contents of the menu bar, and this is no longer the case.
Because CPU thread config changed callbacks are no longer instant,
g_Config.iEFBScale doesn't yet contain the new value when the hotkey OSD
code tries to read it.
Should fix https://bugs.dolphin-emu.org/issues/13343.
There's no reason not to allow this now that these settings are
cleanly integrated into the new config system. (Actually, maybe
we could even have done this before the previous commit...)
This fixes a problem where changing the JIT debug settings on
Android while a game was running wouldn't cause the changed settings
to apply to code blocks that already had been compiled.
The previous list had some issues. A lot of variant id's were set to 0x0000. Althought this works for some figures, on a technicallity implemented into the games, they are technically wrong and don't result in exactly the same experience as the real figures. For example, the previous small fry got a "series 1" text in the summon screen. The real small fry does not have this. I also added figure types so I can add seperate generation logic later.
The Kaos element only applies to 3 items. So, I decided to throw it under others since it's not listed as an element in the manual and you can easily search for Kaos
GCAdapter::UseAdapter() reads s_is_adapter_wanted, which gets
initialized by config_guard.~ConfigChangeCallbackGuard(). So we must
wait until after destroying the config guard to know whether we have any
controllers set to GC Adapter.
Expanded the use of the lock mutex already used for loading the player's existing unlock status to guard against races involving the Achievements dialog window reading from data AchievementManager might be in the process of updating. The lock has been exposed publicly and the AchievementsWindow uses it in its UpdateData method, and anywhere else that might modify data used to render that window has also been wrapped with it.
AchievementManager now has a SetUpdateCallback method for providing a single universal callback for anytime something important changes in the achievement state, such as logging in/out, game load/close, or events such as achievement unlocks. AchievementsWindow sets this callback in its own init to its UpdateData method so that the AchievementsWindow gets updated when one of these changes takes place.
This widget is a tab in the AchievementsWindow that displays the player's current achievement progress: which achievements are locked or unlocked, and the progress of achievements that have progress metrics.
This widget displays a header on the AchievementsWindow dialog above the tabs that shows the currently logged in user (if there is one) and the game they are playing (if there is one).
1 ) When first opened, the (user selected) post process shader config widget would print the wrong values on the text label next to int range sliders. For example if the range was from 1 to 6, and the value loaded from the config was 1, the label would print 0 when first opened, to then start showing the correct value once the slider was first moved.
This mirrors the behaviour of the float slider code below:
```auto* const value_box = new QLineEdit(QString::asprintf("%f", m_config_option->m_float_values[i]));```
2 ) The defautl int slider value would also be set wrong on first load, as it was being divided by the slider max instead of the slider step amount (again, just like for the float implementation). This is a mistake I had made with my previous submission.