This was causing the achievement runtime to shutdown in the middle
of a disc change even if the resulting disc was valid, which was
causing achievements like the ones in Resident Evil for completing
the entire game in a single session to break midway through.
Also adds a log to notify the user when the disc change is invalid
(e.g. different game inserted).
Mistakenly thought the change media call would close the current
game if the new media failed to hash. This wasn't the case so
instead I'll close the current game myself. This fixes an issue
where a default ISO would immediately load achievements when
starting up the Wii menu.
It turns out that it is possible to create a login alias in RetroAchievements
such that you can log in with a username that doesn't match your display name.
AchievementManager was treating this as a synchronization error, but this is
desired behavior, so this removes the check.
Re-added a line of code from a cancelled PR (that I thought was in
main already) that RetroAchievements uses to properly synchronize
memory reads and writes with the emulator frames. This appears to
fix some pretty major freezing and deadlocks in the RA dev tools.
If the build is an Android build, identify it as such in the AchievementManager user agent so that android builds can be tracked separately for debug purposes.
Displays a different message at game launch if RetroAchievements fails specifically due to an invalid or expired API token, instructing the player to log back in with the game closed.
Previous changes to the patch allowlist format were not reflected in AchievementManager; this corrects that and re-enables patches and codes in hardcore mode.
Prior to this change, any game unrecognized by RetroAchievements would ultimately result in the game being "Closed" by AchievementManager. As a result, if any game was run while in this state without any other closing being done, AchievementManager would simply load it like a new game, despite memory already being accessed.
However, testing and documentation determined that the rcheevos client doesn't actually complain when it fails to hash a game; it just runs this as "Unidentified Game" with RA ID = 0. As such, this change utilizes that in AchievementManager to differentiate between no software running and unidentified software running.
As a result of this, now LoadGame needs to be called for every piece of runnable software, supported format or otherwise. If a supported format is not available, LoadGame can now be called with a nullptr to ensure that rcheevos still properly sets up an unidentified game.
The memory copy algorithm (only needed for RetroAchievements devs) was broken for Gamecube as it assumed EXRAM size was zero when in reality it's using ARAM. For the time being, we do not need to use or access ARAM so instead this sets that value to zero for Gamecube titles.
Refactors the PatchAllowlistTest to streamline the experience for developers. Instead of a textual description of what needs to change in ApprovedInis.json for RetroAchievements compatibility, the test will now generate a replacement file and instruct the coder where to copy it in their local branch, and what to update APPROVED_LIST_HASH to. The result should be easier and more instructive for developers to make changes, while still maintaining that allowed codes cannot be added or modified without recompiling Dolphin.
As ApprovedInis.json no longer needs to be user-readable for this process, it no longer contains titles or pretty formatting and as such is updated in this commit, hash included.
This was causing deadlocks when a game didn't load (including if RetroAchievements does not yet support it) because it was attempting to close the queue the the callback was currently running on, forcing LoadGameCallback to wait for LoadGameCallback to finish. However, it appears that recent changes to the queue have independently resolved the reason CloseGame was being called here in the first place.
The clone of system memory used by AchievementManager during achievement development for the sake of thread decoupling was only copying MEM1; this grabs MEM2 as well if it exists.
Within AchievementManager, CloseGame being called when LoadGame fails was causing m_queue.Cancel to be called within a lock when Cancel itself locks until it is empty, causing a deadlock. This is resolved by cancelling the queues outside of the lock when they are safe to wait for resolutions.
Add a method to detect console ID from an input file and instruct rcheevos to load as Gamecube or Wii accordingly. Also, hash .wads upon loading, to support achievements on WiiWare titles.
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.