PAR-108
Bedrock: @Arg OfflinePlayer resolver does a Mojang name lookup → ghost UUIDs
Found in the cross-plugin Bedrock/Floodgate audit. Highest-leverage remaining fix — it's the binding resolver for every @Arg(...) OfflinePlayer command across Treasury and Business.
Bug: commander/resolvers/OfflinePlayerResolver.resolve tries Bukkit.getOfflinePlayerIfCached(token) then falls back to Bukkit.getOfflinePlayer(token) (deprecated). On an online-mode server (DC) that String overload does a blocking Mojang lookup, which FAILS for Bedrock players (their .-prefixed names aren't in Mojang's DB) — returning a fabricated/offline UUID, never the real Floodgate UUID. A cached Bedrock player (joined before, in usercache under .name) resolves fine; a not-yet-cached one resolves to a ghost.
Consumer impact:
- Treasury
/eco,/fine,/transactions audit,/tax trigger— mostly safe: each guards withhasPlayedBefore()right after, so a synthetic is rejected (just a worse error path + a needless Mojang call on the async thread). - Business
RequestCommands(HIGH):offer/hireand thetransfer begin/confirm/cancel/complete/rejectfamily take@Arg("user") OfflinePlayerwith NO guard — hiring/transferring to a never-seen player by name writes the fabricated UUID intofirm_staff/proprietor records, so the real (Bedrock) player is never actually employed/granted. Ghost rows.
Recommended fix (one change, fixes all consumers): drop the Mojang fallback. Either (a) return the cache-only result and Optional.empty() when uncached — the framework then rejects with "unknown target" and no command acts on a ghost (cleanest; minor message regression vs the current synthetic-so-the-handler-can-message design), or (b) build the synthetic from a locally-computed offline UUID (UUID.nameUUIDFromBytes("OfflinePlayer:"+name)) instead of the Mojang call, preserving the "handler decides" contract but removing the network hit — then add hasPlayedBefore() guards to Business RequestCommands.offer/beginTransfer to stop ghost rows. Realty uses its own cache-only resolver and is unaffected.
Note: framework change → needs publishToMavenLocal + treasury/business rebuilds to take effect.
Resources
- commit0b6cf8b Bump hibernia-framework to 1.0.2 for the Bedrock OfflinePlayer resolver fix (PAR-108)MCCitiesNetwork/Business
- commit889594c Bedrock: resolve @Arg OfflinePlayer from cache only, no Mojang (PAR-108)ParadauxIO/hibernia-framework
- PR · merged#6 Release: develop → main (v1.0.2)ParadauxIO/hibernia-framework
Comments
tesks · Jun 6, 2026, 1:03 PM
Fixed on hibernia-framework develop (889594c). Resolver is now cache-only — uncached names return empty so the framework rejects them; no Mojang call, no fabricated UUID. Verified treasury + business rebuild green against the new framework (published to mavenLocal).
Deploy chain: this is a framework change, so for release/CI builds the new hibernia jar must be published to repo.paradaux.io (./gradlew :treasury-api… — i.e. hibernia publish), and treasury + business rebuilt to bundle it. Until then their shaded jars carry the old resolver. (Local mavenLocal is updated for dev builds.)
Behavioural note: a never-seen name now fails with the framework's generic "invalid target" instead of a plugin-specific message — acceptable, and the data-integrity win (no ghost employment/proprietor rows from /firm hire/transfer) is the point. Cached players, including Bedrock under their .-prefixed name, resolve as before.
tesks · Jun 6, 2026, 11:49 PM
Released and rolled out to consumers.
- hibernia-framework PR #6 merged →
1.0.2published (main tipdef658c). Version bumped from the already-released v1.0.1 so no collision. - Bumped
io.paradaux:hibernia-framework→ 1.0.2 in the command plugins that carry@Arg OfflinePlayercommands and rebuilt clean against it:- treasury (
a674fb2) - business-rian (
0b6cf8b) - treasury-api-plugin (
4e17430)
- treasury (
Not bumped: treasury-ingest (1.0.1) — no command surface, doesn't use the resolver; and business-api (compileOnly 0.1.2) — the API jar doesn't bundle the resolver and the SPI types it references are unchanged. Both fine to leave; can align later if desired.
Verified locally against 1.0.2 from mavenLocal (treasury + business unit suites green; treasury-api-plugin compiles). Their CI/release builds will resolve 1.0.2 from repo.paradaux.io.
Activity
- ParadauxIO linked a commit — Commit 0b6cf8b — Bump hibernia-framework to 1.0.2 for the Bedrock OfflinePlayer resolver fix (PAR-108)
- tesks commented
- ParadauxIO linked a commit — Commit 0b6cf8b — Bump hibernia-framework to 1.0.2 for the Bedrock OfflinePlayer resolver fix (PAR-108)
- ParadauxIO linked a commit — Commit 889594c — Bedrock: resolve @Arg OfflinePlayer from cache only, no Mojang (PAR-108)
- ParadauxIO changed status to Status → Done
- ParadauxIO linked a pull request — PR #6 merged — Release: develop → main (v1.0.2)
- ParadauxIO linked a pull request — PR #6 open — Release: develop → main (v1.0.2)
- tesks commented
- tesks changed status to Status → Pending Release
- ParadauxIO linked a commit — Commit 889594c — Bedrock: resolve @Arg OfflinePlayer from cache only, no Mojang (PAR-108)
- tesks created the issue