Skip to content

feat(proxy): expose network-wide player counts per backend server - #15

Merged
hbrombeer merged 1 commit into
mainfrom
feat/network-player-counts
Jul 24, 2026
Merged

hbrombeer merged 1 commit into
mainfrom
feat/network-player-counts

Conversation

@hbrombeer

Copy link
Copy Markdown
Member

Why

ProxyService is the seam every plugin uses to reason about players on other proxies — resolve a name, send a message, transfer them. The one thing it could not do was count them, so /agones fell back to Velocity's playersConnected, which is proxy-local by definition and reported "1 player" in a lobby holding two.

What

  • PlayerSessionQuery.countPlayersByServer() — implemented by plugin-player, backed by service-player's session table.
  • ProxyService.getNetworkPlayerCounts() — what consumers call.
  • NetworkPlayerCounts(byServer, total). A server nobody is on is absent rather than zero; total includes players not yet on a backend server, so it can exceed the sum.

Returns null, not a local fallback. Every other ProxyService method degrades to a local answer when no PlayerSessionQuery is registered, and that is right for them — a local player is a correct answer to "where is this player". It is wrong for a count: a proxy-local number looks exactly like a network number once rendered, and quietly showing it is the bug. Callers should say the figure is proxy-local instead.

Merge order

2 of 5. Depends on nothing; blocks the consumer.

  1. feat(player): count online players per backend server library-grpc-contracts#71 → release library-grpc-contracts-player 0.4.0
  2. this PR → release plugin-proxy-api (0.2.0)
  3. service-player — implement the RPC
  4. plugin-player — implement countPlayersByServer()
  5. plugin-agones — /agones reads the network numbers

Verified

./gradlew build green. Published locally as gg.grounds:plugin-proxy-api:0.2.0 and compiled plugin-player and plugin-agones against it.

A proxy can only count the players connected to itself, so with two proxies in
front of one lobby each of them reports half of it. ProxyService now answers for
the whole network, via the registered PlayerSessionQuery.

Returns null when the network cannot be asked, rather than falling back to this
proxy's own numbers: a local count is indistinguishable from a network count once
it is rendered, and silently showing the wrong one is the bug being fixed.
@hbrombeer

Copy link
Copy Markdown
Member Author

Zwei Sachen, bevor das gemerged wird — CI ist grün, die Doku im Diff ist gut (besonders "null statt proxy-lokalem Fallback", genau richtig).

1. Abstrakte Methode auf einer publizierten Schnittstelle. countPlayersByServer() kommt ohne Default in PlayerSessionQuery, und plugin-player implementiert die (presence/PlayerSessionQueryImpl.kt). Sobald plugin-player auf die neue plugin-proxy-api hebt, kompiliert es nicht mehr. Ein = null als Default hält es nicht-brechend und passt sogar zur Semantik: "das Netz kann gerade nicht gefragt werden".

2. Die Zahl kann heute niemand beantworten. getNetworkPlayerCounts() reicht auf sessionQuery()?.countPlayersByServer() durch, aber:

  • plugin-player implementiert countPlayersByServer nicht (kein Treffer im Repo), und
  • service-player hat gar keinen passenden RPC — player.proto kennt UpdatePlayerServer, aber nichts, das pro Server zählt.

So gemerged liefert der neue Call überall null. Für ein echtes Feature braucht es die Kette: RPC in library-grpc-contracts → Implementierung in service-player → PlayerSessionQueryImpl in plugin-player. Als reine API-Vorbereitung ist der PR fein, aber der Consumer-seitige Nutzen (u.a. die netzwerkweite Zahl in plugin-chat's /proxy, die ich dort gerade entfernt habe) kommt erst mit den drei Folgeschritten.

Deshalb bewusst als Draft gelassen statt auf ready gesetzt.

@hbrombeer

Copy link
Copy Markdown
Member Author

Nachtrag: mein erster Einwand hat sich erledigt, der zweite nicht ganz.

Erledigt — der fehlende = null-Default ist kein Bruch mehr: plugin-player#24 ist inzwischen auf main und implementiert countPlayersByServer() in PlayerSessionQueryImpl. Der einzige Implementierer der Schnittstelle kennt die Methode also, sobald er auf die neue plugin-proxy-api hebt. Ein Default wäre weiterhin freundlicher gegenüber künftigen Implementierern, aber nichts bricht mehr daran.

Offen — beantworten kann die Zahl trotzdem noch niemand: der Pfad endet in service-player, und dort hängt es an der Reihenfolge. CountPlayersByServer ist nicht auf library-grpc-contracts/main, nur im Draft #71 (dessen Konflikt ich aufgelöst und gepusht habe). Solange der nicht gemergt und released ist, liefert getNetworkPlayerCounts() überall null — und plugin-player main ist deswegen aktuell rot (Could not find gg.grounds:library-grpc-contracts-player:0.4.0).

Reihenfolge: contracts#71 → Contracts-Release → service-player#77 → dieser PR.

@hbrombeer
hbrombeer marked this pull request as ready for review July 24, 2026 13:24
@hbrombeer
hbrombeer merged commit a2ccb9f into main Jul 24, 2026
3 checks passed
@hbrombeer
hbrombeer deleted the feat/network-player-counts branch July 24, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant