Fixing an oversight: this was causing the debugger to be disabled if achievements were disabled but hardcore mode was still enabled in the .ini. This fix properly checks for hardcore state via AchievementManager which takes both settings into account.
RetroAchievements disables pausing too frequently when running but there's no sense of doing this if RetroAchievements does not currently have a game running.
We have identified that a failed RetroAchievements game load (most easily done when closing a game before the server can finish responding) can leave data behind that causes problems. As such, refactored CloseGame to always delete data even if there wasn't a game loaded when it was called, and call it on the failure paths of LoadGameCallback.
Due to requests from RA Devs, updating the AchievementManager LoadGameCallback to still set MemoryPeeker (and set m_system) if the load game response is NO_GAME_LOADED, so that the memory inspector et al continue function properly on unidentified hashes. Without this, no memory is loaded and the memory inspector will show all zeroes.
If the development system is started for a game with an unrecognized hash, RA_Integration opens a dialog for connecting the hash with a title. That dialog is prepopulated by the results of GameTitleEstimateHandler.
Displays an additional message when an achievement unlocks that isn't on the site yet (either hasn't yet been uploaded or modified from remote) i.e. achievements the "player" is actively developing.
Refactors the AR/Gecko/Patch code approval process to verify from every possible game ini, not just the base game ID. This fixes codes on specific revisions or codes general to any region.
Adding a community-requested list of Gecko and Action Replay codes to the allowlist. Many of these codes were from the wiki and are being added to Dolphin's repo for the first time.
New code adds a test failure if there's a Patches/Gecko/AR_Retroachievements_Verified code that doesn't appear to actually exist in the file. This will catch if the allowed patch is formatted wrong, which I found happening several times already due to not realizing that the patch author's name would need to be omitted.
Now that patches and codes are enabled on a case by case basis, remove patcher code blocking codes entirely in hardcore mode, and reword the warning to be more accurate.
If the host is in hardcore mode, all joining players will be set to hardcore mode; if not, all joining players will be set to softcore. This ensures all players have the same settings and remain synchroized.
The primary focus of this PR is the Eternal Darkness patch which fixes hanging at startup, which prior to this fix makes Eternal Darkness unplayable in hardcore. The MHTri patch was added as well simply because it could be.
Found this bug while testing; if I manually edit the config files while Dolphin is closed I was able to get debug and hardcore on at the same time, this resolves that.
AchievementManager::SetHardcoreMode now handles the (non-Qt) settings disabled by hardcore mode, instead of doing this on the Qt layer. Also ensured Init/Enable Achievements paths run this code, fixing the bug wherein the player can manipulate things when achievements are disabled that persist when turned back on.
With this change, a different message is displayed if starting a game with RetroAchievements fails due to the Dolphin version being blocked as opposed to failing because the game hash is unsupported.
The player_index field in question is ultimately what gets used to determine which ranks get displayed in the leaderboards chart, and because this was missing the chart was simply displaying the top four results no matter what.
The cause of the leaderboard spam was primarily this call where if there was an attempt to get leaderboard info and there wasn't already, there would be a fetch request. This is bad for many reasons: some games have hundreds of boards that will be fetched at startup, if there's simply no data to populate that board, this will just continue to fetch every time the dialog needs to update. To mitigate this, I simply don't load leaderboard information until there are events for that leaderboard - less information for the player, sadly, but heavily cuts down on the number of leaderboard fetches.
Now that we have some test data, it wasn't showing up in the leaderboards tab; this fixes it to ensure (1) that the right ID is being passed to UpdateRow and (2) the map of leaderboard entries is being populated correctly.
This unit test compares ApprovedInis.json with the contents of the GameSettings folder to verify that every patch marked allowed for use with RetroAchievements has a hash in ApprovedInis.json. If not, that hash is reported in the test logs so that the hash may be updated more easily.
Prototype of a system to whitelist known game patches that are allowed to be used while RetroAchievements Hardcore mode is active. ApprovedInis.txt contains known hashes for the ini files as they appear in the repo, and can be compared to the local versions of these files to ensure they have not been edited locally by the player. ApprovedInis.txt is hashed and verified similarly first, with its hash residing as a const string within AchievementManager.h, ensuring ApprovedInis and the hashes within cannot be modified without editing Dolphin's source code and recompiling completely.
The challenge popups have proven to be excessive and are no longer useful thanks to the achievements hotkey. Instead, those events will ask for an immediate RP-level update to the achievements dialog, which will among other things re-sort the dialog to show challenges on top faster.
There are two pieces of functionality to be added here. One, we want to disallow pausing too frequently, as it may be used as an artificial slowdown. This is handled within the client, which can tell us if a pause is allowed. Two, we want to call rc_client_idle on a periodic basis so the connection with the server can be maintained even while the emulator is paused.
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.
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.
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.
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.
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.
If an icon is displayed on screen before it downloads, it was displaying a default icon but it would fail to load the actual icon even after it was downloaded. This fixes that.
Add a two second timer to Achievement Progress Indicators to wait until two seconds after the previous message (when it should have decayed out automatically) before posting any new ones.
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.
AchievementManager maintains a unique pointer to a copy of the current volume so it can asynchronously hash that volume. It is not needed otherwise, so I can release that pointer when hashing is complete. This change fixes a bug whereby changing discs in a game and then changing to a different game would result in the loaded volume pointer still being loaded with and hashing to the previous game.
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.
The defaults get loaded in by Dolphin at emulator start, and are used if the badge that would normally be displayed has not for whatever reason been downloaded yet. Badges attached to this PR are placeholders (MayIMilae is designing permanent badges) and reside in Sys\Load\RetroAchievements.
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.
If Rich Presence and Discord Presence are enabled in Achievement Settings, the string generated by rcheevos as the player's current Rich Presence will be sent to the Status field in the Discord Presence object. This will be updated whenever Rich Presence updates.
The "welcome message" that shows up to players when a game starts up and Achievements are active will now either tell the player upon load that there's no support for achievements, or will wait until the first attempt to load the game's badge either succeeds or fails and then display a full message with title and progress and status. This is in part facilitated by a boolean field for when to display a welcome message, set to true upon loading and to false upon a message being displayed.
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.