feat(metrics): publish which platform Bedrock players are on - #44
Merged
Conversation
Nothing in the estate could answer "are these players on a phone or a
console". The device travels in a Bedrock client's login chain, Geyser hands
it to Floodgate, and by the time Velocity sees the player they are an ordinary
Java-protocol connection with the platform stripped off — the game servers
cannot tell a Switch from a phone, and the Bedrock proxy was the last place
that still knew.
On a proxy that also runs Floodgate — only velocity-bedrock does — the
endpoint now publishes:
velocity_bedrock_players{device_os="ANDROID"} by Floodgate's DeviceOs enum
name: ANDROID, IOS, OSX,
XBOX, NX, PS4, UWP, …
Floodgate is read reflectively rather than depended on. This plugin loads on
every proxy and only one of them has Floodgate, so the dependency would be
compileOnly anyway — and GeyserMC publishes the API as a SNAPSHOT only, so the
only thing it would buy is type safety against a moving artifact that could
break the build of a plugin which has nothing to do with Bedrock. Three calls
do not justify that. The shape was checked against the published API jar
rather than assumed.
Four decisions worth arguing with:
- The class is probed on every read, not once at startup. Velocity's plugin
classloaders can see each other but load order is not guaranteed, and this
declares no dependency on Floodgate — probing once would let a proxy that
happened to start this plugin first conclude "no Floodgate" and stay wrong
for the life of the pod.
- The platform is the enum's `name`, not its `toString`. Floodgate renders
NX as "Nintendo Switch"; a label that changes case and spacing between
releases splits one series into two.
- A proxy without Floodgate publishes no series at all rather than zero.
"No Bedrock players" and "cannot see Bedrock players" are different
states, and only one of them belongs on a graph.
- A platform that empties keeps its row and reports 0. Dropping it would
make the series stale, which Grafana draws as a gap — indistinguishable
from the endpoint being down.
Rows are refreshed inside the HTTP handler rather than on a timer: the
endpoint is the only reader, so a scrape sees the count as it is at that
moment and an unscraped proxy pays nothing.
94 tests, 12 of them new. The reflection runs against a Floodgate stand-in
handed in through the class lookup, so what is tested is the code that ships
rather than a copy of it; the not-installed path runs against Floodgate's real
absence from the test classpath.
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.
Nothing in the estate could answer "are these players on a phone or a console". The device travels in a Bedrock client's login chain, Geyser hands it to Floodgate, and by the time Velocity sees the player they are an ordinary Java-protocol connection with the platform stripped off — the game servers cannot tell a Switch from a phone, and the Bedrock proxy is the last place that still knows.
What
On a proxy that also runs Floodgate — only
velocity-bedrockdoes — the endpoint now publishes:by Floodgate's
DeviceOsenum name:ANDROID,IOS,OSX,XBOX,NX,PS4,UWP, … Low cardinality, one series per platform per proxy.Floodgate is read reflectively, not depended on
This plugin loads on every proxy and only one of them has Floodgate, so the dependency would be
compileOnlyanyway. And GeyserMC publishes the API as a SNAPSHOT only (2.2.5-SNAPSHOT, no releases) — the only thing a build dependency would buy is type safety against a moving artifact that could break the build of a plugin which has nothing to do with Bedrock.Three calls do not justify that. The shape was checked against the published API jar, not assumed:
The enum itself lives in yet another artifact, so it is read as a name and never resolved.
Four decisions worth arguing with
name, not itstoString. Floodgate rendersNXas"Nintendo Switch". A label that changes case and spacing between releases silently splits one series into two, and neither half is the whole truth afterwards.Rows are refreshed inside the HTTP handler rather than on a timer: the endpoint is the only reader, so a scrape sees the count as it is at that moment and an unscraped proxy pays nothing.
Verification
./gradlew buildgreen — spotless + 94 tests, 12 new.The reflection runs against a Floodgate stand-in handed in through the class lookup, so what is tested is the code that ships rather than a copy of it written twice. Covered: counting by platform, a player whose device Floodgate does not know being skipped rather than labelled, the enum-name-not-display-string rule, the empty-map cases (no players / Floodgate loaded but not started), a Floodgate that changed shape degrading instead of throwing — a
NoSuchMethodErrorescaping here would take the whole scrape with it — the class being resolved once, and at the endpoint level: the series appearing with the right values, re-read on every scrape, going to 0 rather than vanishing, and being absent entirely on a proxy without Floodgate (which is the real absence, since Floodgate is not on the test classpath).Follow-ups
deploy— bump theplugin-floodgate… no: bump theplugin-proxyimage tag once this releases, sovelocity-bedrockfetches the new jar. Same jar-fetch ordering caveat as last time: the proxy pulls the plugin at startup from the sibling Service, so the jar server has to be new before the proxy restarts.grounds-pulumi— a platform breakdown panel on the Bedrock dashboard.