RA_Integration Support & QoL Improvements#2258
RA_Integration Support & QoL Improvements#2258CySlaytor wants to merge 4 commits intoflyinghead:devfrom
Conversation
…ions - Added mappable hotkeys for Pause, Toggle Fast-Forward, and Frame Advance. - Added direct input mappings for Save/Load State Slots 1 through 10. - Implemented `OSDOverlay` in GUI to support sliding notifications and persistent status icons. - Added anti-abuse cooldowns in Hardcore mode to prevent pause-spamming. - Added a "Reset" button to the main pause menu. - Added `rend_present()` to force OSD frame updates even when emulation thread is paused.
- Split RA notifications into visual quadrants for better readability. - Top-Left: Leaderboard Events (Start, Submit, Cancel). - Bottom-Left: Main Overlays (Unlocks, Login, Progress, Mastery) and stacked Leaderboard Trackers. - Bottom-Right: Independent Challenge Indicators. - Updated event handlers in achievements.cpp to map leaderboard events to the new Top-Left queue (`Notification::Leaderboard`).
- Uses `nlohmann::json` to fetch and parse achievement rarity data from the RA servers (or local RACache). - Added `playSound` helper to dispatch `.wav` playback using SDL (Desktop) or Android `SoundPool`. - Tied specific sounds to events: login, leaderboard start/submit/fail, and game load. - Distinguishes standard unlock sounds from rare unlock sounds (< 5% global unlock rate). - Updated CMake configuration to bundle `resources/sounds/` automatically into the build output/assets.
- Added support for the official Windows RAIntegration DLL. - Created `RA_Defs.h` and bound the required function pointers. - Implemented a dummy HWND message pump to handle background HTTP callbacks and menu invocations on Windows. - Added `EnableRAIntegration` toggle to the general settings UI. - Hooked `RA_UpdateFrame()` into the main UI loop to maintain the RA overlay. - Added dynamic syncing of Hardcore Mode state if toggled from the RA DLL. - Added safe deferred emulator resets when triggered by the RA DLL.
Jamiras
left a comment
There was a problem hiding this comment.
Noted a few quick things. Did not do a full review.
| } | ||
|
|
||
| INFO_LOG(COMMON, "RA: Fetching rarity data from server for game %u...", gameId); | ||
| std::string url = "https://retroachievements.org/dorequest.php?r=getgameextended&i=" |
There was a problem hiding this comment.
I'm very confused what this is trying to do. That API doesn't exist.
Rarity data (for the current game) should already be available in the rc_client_achievement_info_t structure returned by https://github.com/RetroAchievements/rcheevos/wiki/rc_client_get_achievement_info
There was a problem hiding this comment.
I had no idea that rarity is already exposed via the rc_client_achievement_info_t struct. I was trying to get the rarity data to determine which audio cue to play (standard vs. rare unlock) and went down a rabbit hole of manually fetching and parsing the JSON. A workaround to temporarily store it in memory for that purpose. I'm glad there's a function for it 👍
| typedef int (*_RA_OnLoadNewRom_Fn)(const unsigned char *pData, unsigned int nDataSize); | ||
| typedef void (*_RA_SetConsoleID_Fn)(unsigned int nConsoleID); | ||
| typedef int (*_RA_OnReset_Fn)(); | ||
| typedef void (*_RA_SetPaused_Fn)(int bIsPaused); |
There was a problem hiding this comment.
I'm confused here too. If the code already supports rc_client, you should be using the rc_client_raintegration functions and callbacks instead of hooking directly into the DLL. Direct integration with the DLL functions should be done using the RAInterface module.
I'm not finding any references to these (_RA_ only appears in this file), so I presume they're leftover from an earlier attempt? If so, they should be cleaned up. RA_Defs.h appears to only be referenced by the CMakeLists.txt and never actually #included.
There was a problem hiding this comment.
RA_Defs.h now is definitely a leftover dead code from an earlier, messier attempt at manually loading the DLL before I discovered that rc_client_begin_load_raintegration already wraps everything nicely.
| if (result == RC_OK) { | ||
| rc_client_raintegration_set_write_memory_function(client, RA_WriteMemory); | ||
| rc_client_raintegration_set_console_id(client, RA_DREAMCAST_ID); | ||
| rc_client_raintegration_set_get_game_name_function(client, RA_GetGameTitle); |
There was a problem hiding this comment.
You don't seem to be providing an rc_client_raintegration_set_event_handler function, which is mostly used when the toolkit wants to pause the emulator.
|
Thank you for the ping and this work! This one unfortunately is out of my wheelhouse and I defer fully to @Jamiras. |
|
Thanks for taking the time to review this, @Jamiras ! Your feedback is incredibly helpful. You are completely right. I missed some of the |
|
this is great! a year and a half ago I was also developing and making chevo sets over at RA... and I had brought up to flying head's attention about bringing in the development tools.So I didn't have to use RAs retroarch like tool set to do dreamcast games.... And it seemed that the thought behind it was since only the windows version of flycast could run it without substantial work to get it to run on the other platforms, flycast runs on, and that every release of flycast must have the same features.... So that is why we never got the memory editor on FC stand alone.... so I was always hoping someone would come along to do a full implementation, and bring the cheevo system more up to par, but I was not willing to port the tool set to all the platforms that flyvast runs on, so great job working on this! |
Hey there! This ended up being a pretty massive changeset, so I wanted to break down exactly what I did and why.
I'm a RetroAchievements developer, and while Flycast already supports
rcheevos(which is great for playing), I noticed it was missing RA_Integration support. By adding this, the Windows build can now load theRA_Integration.dll. This is a huge deal for us achievement devs because it exposes the Memory Inspector, Achievement Editor, and Asset Editor directly inside Flycast. Previously, we had to rely on RALibretro for this, but honestly, RALibretro struggles with the performance overhead of Dreamcast titles. This change makes developing sets for these systems much smoother.To get this working, I had to implement
RA_Defs.hand some window hooking logic to handle the external DLL menu. I also had to call_RA_OnLoadNewRominExports.cppin RA_Integration specifically because without that change, the integration refused to accept game hashes and wouldn't load the achievement data (@Jamiras suggested to callRA_IdentifyHashinstead but unfortunately the implementation results in a lot of race conditions that I couldn't figure out, so calling_RA_OnLoadNewRomis the best approach here). I also pulled in logic to fetch game rarity data, which is a nice touch that was previously mostly unique to RALibretro only.Audio Feedback & Rarity
I've fully implemented audio feedback for achievements. You now get sound cues for logging in, loading a game, and unlocking achievements. I added a rarity check using
RarityHardcore. if an achievement has an unlock rate below 5%, it plays a specialrareunlock.wavinstead of the standard sound.For Android, since it doesn't handle SDL audio quite like the desktop builds, I wrote a JNI bridge (
playRASound) to trigger these effects using Android's nativeSoundPool. I've verified this works reliably on my device.All the sounds are public domain, sourced from http://onj3.andrelouis.com/phonetones/. I picked them specifically to fit the Dreamcast atmosphere.
The set includes:
info.wav,login.wav(System/Auth)unlock.wav,rareunlock.wav(Achievements)lb.wav,lbcancel.wav,lbsubmit.wav(Leaderboards)Input System & QoL
With the dev tools now available, I overhauled the input system to support workflows that developers expect. I added support for button combos and set up default hotkeys for Save/Load States (
Shift+F1/F1), Pause/Play, and Frame Advance. Frame Advance is particularly critical when you are inspecting memory addresses frame-by-frame.I also cleaned up the input mapping UI. I moved System Buttons and Emulator Hotkeys out of the "Dreamcast Controls" view and gave them their own filters to keep things organized.
OSD & Hardcore Logic Improvements
The OSD needed a bit of a refresh to properly support the newer features, so I reworked how everything is laid out and behaves. Status icons like Fast Forward now stack in the top-right with a small sliding animation, while text notifications stay centered at the bottom so things remain readable and don't fight for space.
At the same time, I tightened up Hardcore Mode to better match RA rules. When Hardcore is enabled, Pause and Frame Advance hotkeys are fully blocked, and I added a short cooldown to the Menu button so the emulation can't be manipulated after pausing or resuming. This mainly exists to prevent accidental state abuse and mirrors the behavior seen in emulators like PCSX2.
Most of the work here was structural; the goal was to make the overlay system more stable and predictable rather than just visual polish. The layout logic was reworked to prevent indicators from colliding with each other, and the Trigger indicator was moved to the bottom-right to avoid overlapping with the Measured indicator. Trigger notifications now use symmetrical slide-in/out animations, and achievement unlocks were updated to slide out instead of fading so animations feel consistent across the board.
I also fixed a few race conditions between Trigger/Measured indicators and achievement notifications, and decoupled overlay lifecycles so achievement cards no longer disappear prematurely when other UI elements update.
Leaderboard behavior received similar cleanup. Active leaderboard counters no longer block the Measured indicator, and overlays now dynamically stack with automatic repositioning as items appear or disappear. Multiple leaderboard counters are supported simultaneously, and submission/cancel cards were reworked to sit in the top-left with a simpler fade in/out instead of sliding. Multiple submission cards can now appear at once if they're triggered on the same frame, which avoids UI conflicts.
Hardcore Mode behavior was refined a bit further. Loading savestates is now prevented while still allowing savestate creation for debugging purposes, and the Pause and Frame Advance restrictions remain enforced to avoid unintended exploits.
Building & Cross-Platform
I spent the last few days ensuring this plays nice with other platforms. All the
RA_Integrationlogic is strictly guarded byRC_CLIENT_SUPPORTS_RAINTEGRATIONand_WIN32defines, so it won't bloat the binary or affect runtime on Linux, macOS, or Switch.I also added
#if defined(USE_SDL)guards inachievements.cppto prevent compilation errors on Android/iOS where those headers might be missing. Then, I updatedCMakeLists.txtto make sure the sound assets are copied correctly to the build directory (or bundled intoContents/Resourceson macOS to avoid CodeSign errors).I admit I hesitated a bit before opening this PR since the changes are pretty substantial and touch some sensitive parts of the codebase (like
emulator.cpp). Because of that, I triple-checked everything more times than I'd like to admit before wrapping it up. I've verified it locally on Windows and Android, and everything seems stable.Let me know if you spot any conflicts or weirdness!
Pinging @wescopeland here for discussion, just in case.