RetroAchievements - On Screen Challenge/Progress Indicators - #155
Open
sunlollyking wants to merge 1 commit into
Open
RetroAchievements - On Screen Challenge/Progress Indicators#155sunlollyking wants to merge 1 commit into
sunlollyking wants to merge 1 commit into
Conversation
8 tasks
sunlollyking
force-pushed
the
achievement-progress-indicator
branch
from
September 1, 2026 12:42
f50cbad to
d52af20
Compare
sunlollyking
force-pushed
the
achievement-progress-indicator
branch
from
September 1, 2026 13:10
d52af20 to
d1055b3
Compare
Two things are worth a corner of the screen while a game is running: the achievement the player is inside an attempt at, and how far along a counted one is -- "collect 180 rings" is no use as a number you have to open a dialog to read. The achievement runtime already decides both, and says when to take them away again. The add-on receives those decisions and, until now, used them only as a hint to republish the whole measured set, so the choice was thrown away. It now forwards them as RCOnChallengeIndicator and RCOnProgressIndicator, with a null payload meaning nothing should be shown. Kodi could choose an achievement itself, since the measured set is already here and the one closest to completion is a fair guess. What it cannot know is when to stop: nothing in the set says the player has moved on, so a guess would leave the last thing it chose on screen for the rest of the session. The set keeps its own callback and its own job -- every measured achievement, so their progress can be listed -- while these two are one achievement each, and only while it should be seen. Both are held as sets rather than single slots. A game counting two things at once announces each separately, a few milliseconds apart, so one slot would be handed back and forth between them faster than either could be read. The measured indicator shows whichever is closest to being earned. They are drawn by a modeless dialog rather than by controls in the fullscreen window. Where the game has its own plane, CGameWindowFullScreen stops marking itself dirty each frame and CApplication skips compositing the GUI layer while nothing else dirties it, so a control there becoming visible never reaches the screen. A dialog does, and marks itself dirty while it is up; it is only up while there is something to show, so the rest of the session keeps the saving that optimisation exists for. Modeless because the player is still playing and must keep their input. It closes itself from Process(), on the thread that can act at once rather than posting a close and then testing whether the post has been served. A setting under RetroAchievements turns them off. Answered at display time rather than never recorded, so switching it off during an attempt clears the screen at once and the achievements dialog still knows what is being attempted. The Game API goes to 8.1.0, and the minimum with it. Both callbacks are ones the add-on calls rather than ones it answers, so appending them buys nothing in the direction the minimum governs: an add-on built against 8.1.0 reads two entries past the end of the table an 8.0.0 frontend hands it, and calls whatever follows. Every earlier bump that changed the table moved the minimum alongside it. Ending an attempt is the one thing the C API cannot say precisely: a null payload is the hide signal, so it carries no achievement and the runtime can only clear every attempt it holds. The measured path already did this; the challenge path did not, and left the indicator on screen for the rest of the game. The dialog answers the setting too, not just the labels. Otherwise turning the feature off still opened it and still marked it dirty every frame, for a feature drawing nothing -- the exact cost it exists to avoid. An indicator arriving during the close animation cannot reopen the dialog from the game thread, because the window manager will not activate one that is still running; it would finish closing with something to show, and a challenge that produces no further event would stay hidden for the rest of the attempt. Process() runs on the GUI thread and reopens it there.
sunlollyking
force-pushed
the
achievement-progress-indicator
branch
from
September 2, 2026 09:29
d1055b3 to
046efd4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two things are worth a corner of the screen while a game is running: the achievement the player is inside an attempt at, and how far along a counted one is. "Collect 180 rings" is no use as a number you have to open a dialog to read.
The achievement runtime already decides both, and says when to take them away again. The add-on receives those decisions and until now used them only as a hint to republish the whole measured set, so the choice was discarded. It now forwards them, and Estuary draws them in the corner.
Pairs with kodi-game/game.libretro#177, which is the add-on half.
Motivation and context
Kodi could pick an achievement itself — the measured set already arrives, and the one closest to completion is a fair guess. What it cannot know is when to stop: nothing in that set says the player has moved on, so a guess would leave the last thing it chose on screen for the rest of the session. The set keeps its own callback and its own job, every measured achievement so their progress can be listed, while these two are one achievement each and only while it should be seen.
Both are held as sets rather than single slots. A game counting two things at once announces each separately, a few milliseconds apart, so a single slot is handed back and forth between them faster than either can be read — visible as a flicker in the corner. The measured indicator shows whichever is closest to being earned.
They are drawn by a modeless dialog rather than by controls in the fullscreen window. Where the game has its own plane,
CGameWindowFullScreenstops marking itself dirty each frame andCApplicationskips compositing the GUI layer while nothing else dirties it, so a control there becoming visible never reaches the screen — which is why notifications have always shown over games and controls beside them have not. A dialog does reach it, and marks itself dirty while up; it is only up while there is something to show, so the rest of the session keeps the saving that optimisation exists for. Modeless because the player is still playing and must keep their input.Game API
Goes to 8.1.0. Both callbacks are appended, so the minimum stays at 8.0.0: add-ons built against it keep loading, and one that sends neither indicator simply shows nothing.
How has this been tested?
On GBM/Wayland GLES with Balloon Fight (fceumm) and Sonic the Hedgehog 2 (genplus), logged into RetroAchievements.
11 unit tests in
TestGamesGUIInfo, including one that announces two achievements in the order that would show the wrong one if the latest simply replaced the last, then stops the leading one and checks the other takes over.What is the effect on users?
A game client that sends the indicators shows them in the corner while playing, and the setting under RetroAchievements turns them off. Nothing changes for a client that does not send them.
Types of change
Checklist