Split the "welcome" messages letting players know achievements are active into a separate method that gets called (currently) after a number of frames to ensure that the emulator has started properly and has somewhere to display the messages.
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.
FetchBoardInfo is called (via the work queue asynchronously) on a leaderboard every time it is activated or submitted to. It makes two calls to the RetroAchievements API for fetching leaderboard info, one that requests the top four entries in the leaderboard and another that requests the player's entry, the two entries above the player and the two entries below. All of these are inserted into a single map (resolving any overlaps) so the result can be exposed to the UI.
The leaderboard map created here contains information useful to displaying leaderboard stats in the Achievement dialog, including each leaderboard's name and description and a partial list of entries for display. The entire map is exposed to the UI in a single call for simplicity.
Both of these functions access `m_game_data` and don't lock themselves, so they must be called in a way that guarantees that `m_game_data` is not modified during the call.
Scope issue in the event callback from `rc_runtime_do_frame()`. The pointer points to a variable on the stack from inside `rc_runtime_do_frame()`, so that's a race condition between the thread calling `rc_runtime_do_frame()` and the event queue thread.
Added handling to Achievement Progress Events, which are generated when an achievement with a Measured field updates in value. For example, an achievement for collecting 120 stars will throw this event when the player collects each star, and with this handling, the player will get a message on screen informing them of this progress. This message will only appear if the newly added RA_PROGRESS_ENABLED setting is true.
A deep-copy method CopyReader has been added to BlobReader (virtual) and all of its subclasses (override). This should create a second BlobReader to open the same set of data but with an independent read pointer so that it doesn't interfere with any reads done on the original Reader.
As part of this, IOFile has added code to create a deep copy IOFile pointer onto the same file, with code based on the platform in question to find the file ID from the file pointer and open a new one. There has also been a small piece added to FileInfo to enable a deep copy, but its only subclass at this time already had a copy constructor so this was relatively minor.
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.