Namespaces
A private JSON store for each game, keyed by (gameMode, namespace). Invisible to every other game, versioned for safe updates.
Stats and currencies cover numbers. For everything else - kit selections, cosmetics, quest progress, per-player settings - each game gets a namespace: an arbitrary JSON blob that is yours and yours alone.
{
"selectedKit": "archer",
"unlockedKits": ["soldier", "archer", "tank"],
"cosmetics": { "cage": "heart", "trail": "flames" },
"settings": { "autoTeam": true }
} Store whatever shape you want. It rides back on every profile load:
hive.player()
.fetchPlayerData(player.uuid(), player.name(), "skywars", GameType.HYTALE)
.thenAccept(data -> {
Namespace mine = data.getNamespace("skywars"); // only ever your data
String kit = mine != null ? mine.getString("selectedKit") : "default";
giveKit(player, kit);
}); Yours alone
A namespace is keyed by (gameMode, namespace), and a game can only read its own.
Your SkyWars store is invisible to and untouchable by every other game on the
network - no shared schema to coordinate, no other team’s bug that can corrupt
your data, no naming collisions. It’s a private database per game, with none of
the setup.
Versioned for safe updates
Every namespace carries a version. Concurrent writes from two servers can’t
silently clobber each other - the stale write is rejected, not lost in a
last-writer-wins race. You get a private store and correctness under
concurrency, for free.
Namespace or stat? Structured state that’s just yours → namespace. Anything you want ranked or counted over time → statistics. Don’t build a leaderboard inside a JSON blob.
Next
- Statistics - per-game counters and leaderboards.
- Currencies - network-wide balances on the player.