Skip to content

Introduce new version of spectator API with explicit score token passing#523

Draft
bdach wants to merge 9 commits into
ppy:masterfrom
bdach:non-serialising-end-play-session
Draft

Introduce new version of spectator API with explicit score token passing#523
bdach wants to merge 9 commits into
ppy:masterfrom
bdach:non-serialising-end-play-session

Conversation

@bdach

@bdach bdach commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

RFC.

Related:

Compatibility matrix:

old client new client
old server 🟢1 🔴2
new server 🟢1 🟢3

One continuing sticking point in attempts to make online flows more reliable is the serialising factor of spectator server in one part of submission, namely replay saving.

Up until now, the active score token ID was part of SpectatorClientState, and relied on as ambient server-side state to make SendFrameData() and EndPlaying() calls work.

However, only being able to store one token ID means that the client cannot move on to start a new play without concluding the last one, which is a problem, as the user essentially cannot start a new play until they're sure the old one concluded. This is a large pain point for users with unreliable network connections.

This PR attempts to improve this bottleneck by allowing clients to send spectator data out-of-order. The general rules are as follows:

  • The user can have up to MAX_STARTED_SCORES = 5 scores started at any given time; their tokens are stored to the state. (Value of constant up for negotiation.)
  • All methods now explicitly accept a score token. null score tokens are generally ignored for the replay code paths, instead only updating the SpectatorClientState.
  • The BeginPlayingV2() call will always overwrite properties on SpectatorClientState that are not ScoreTokens.
  • Clients are now allowed to interleave SendFrameDataV2() and EndPlayingV2() calls from multiple scores. In cases of those calls, the ambient SpectatorClientState is only updated if the score token supplied is null or equal to the latest non-null score token stored to the state.

Listening to suggestions with respect to collection of metrics (should the total number of scores started be tracked to a counter?)

Footnotes

  1. Old client continues to use the old version of the API which did not functionally change and is not aware of the existence of the new API. Spectating and replay upload operational. 2

  2. New client will attempt to use the new version of the API which does not exist on old server. Complete failure of spectator and replay upload flows for all users affected.

  3. New client uses the new version of the API which exists on new server. Spectating and replay upload operational.

bdach added 9 commits July 6, 2026 12:12
One continuing sticking point in attempts to make online flows more
reliable is the serialising factor of spectator server in one part of
submission, namely replay saving.

Up until now, the active score token ID was part of
`SpectatorClientState`, and relied on as ambient server-side state to
make `SendFrameData()` and `EndPlaying()` calls work.

However, only being able to store *one* token ID means that the client
cannot move on to start a new play without concluding the last one,
which is a problem, as the user essentially cannot start a new play
until they're sure the old one concluded.

This PR attempts to improve this bottleneck by allowing clients to send
spectator data out-of-order. The general rules are as follows:

- The user can have up to `MAX_STARTED_SCORES = 5` scores started at any
  given time; their tokens are stored to the state.

- All methods now explicitly accept a score token. `null` score tokens
  are generally ignored for the replay pathways, instead only updating
  the `SpectatorClientState`.

- Clients are now allowed to interleave `SendFrameDataV2()` and
  `EndPlayingV2()` calls from multiple scores. In cases of those calls,
  the ambient `SpectatorClientState` is only updated if the score token
  supplied is `null` or equal to the latest non-`null` score token
  stored to the state.
Most of the data that was sent was redundant; the only real thing that
needs to be sent across is `SpectatedUserState`.

This helps client-side as there is no longer any need to keep around
full states from non-latest started scores.
@bdach bdach requested review from peppy and smoogipoo July 6, 2026 10:55
@bdach bdach self-assigned this Jul 6, 2026
@bdach bdach moved this from Inbox to Pending Review in osu! team task tracker Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Pending Review

Development

Successfully merging this pull request may close these issues.

1 participant