Atlas Developers
Dashboard

Java API · 1.0

The SDK for modern Minecraft infrastructure

The Atlas Java SDK gives every Minecraft server and proxy one view of the whole network. Read projected state from memory, make authoritative claims asynchronously, and keep running when the control plane is far away.

Local queriesHeap reads, safe on the tick thread
Async claimsFutures for authoritative placement
Resilient by defaultReconnects without killing the server
JavaAtlasClient.java
try (AtlasClient atlas = AtlasClient.connect()) {
    atlas.awaitReady(Duration.ofSeconds(5));

    // Local: no network call.
    int online = atlas.playerCount("squidgame");

    // Central: returns immediately.
    atlas.reserveSlot("squidgame", playerId)
        .thenAccept(slot -> connect(slot.serverId()));
}

Get started

Installation

Atlas requires Java 17 or newer. Add the SDK artifact supplied with your Atlas installation to your plugin build. Platform adapters for Paper, Velocity, and BungeeCord are shipped separately.

Runtime identity is injected for you.

An Atlas-managed process receives ATLAS_SDK_SOCKET and ATLAS_SERVER_ID from its local agent. Do not put server IDs or control-plane credentials in your plugin.

Artifact

Group
com.atlasgg
Artifact
atlas-sdk
Current build
0.1.0
Java
17+
Maven
<dependency>
  <groupId>com.atlasgg</groupId>
  <artifactId>atlas-sdk</artifactId>
  <version>0.1.0</version>
</dependency>

Use the Atlas artifact repository or SDK bundle provided with your account.

Get started

Connect to the local agent

Call AtlasClient.connect() during plugin startup. It opens the local Unix socket and identifies the current Atlas server using agent-provided environment values.

The client initially has an empty registry. If “not loaded yet” must be different from “the network is empty,” wait for the first projection with awaitReady.

Only Atlas-managed processes can connect.

A process started outside the agent will fail clearly because its socket path and server identity are absent.

Java
private AtlasClient atlas;

public void start() throws IOException {
    atlas = AtlasClient.connect();
    atlas.awaitReady(Duration.ofSeconds(5));
}

public void stop() throws IOException {
    if (atlas != null) atlas.close();
}

Get started

The execution model is part of the API

Method shape tells you what the call costs. Synchronous query methods read the SDK’s in-process projection. Methods that need authoritative agreement return CompletableFuture. Fire-and-forget mutations can throw IOException if they cannot reach the local agent.

KindShapeExamplesUse it for
QueryT method()servers(), playerCount()Advisory state on hot paths
ClaimCompletableFuture<T>reserveSlot(), locate()Placement and central truth
Mutationvoid … throws IOExceptionsetStatus(), send()Reports and best-effort delivery

Core API

Read network state locally

Every query below is thread-safe and reads memory in the current process. Values describe the whole Atlas network, not just the current node, and are normally about one second behind.

  • playerCount(group)Players across every server in a group.
  • availableSlots(group)Advisory free slots across joinable servers.
  • networkPlayerCount()True total from proxy groups, without double-counting backends.
  • servers(group)All projected servers in one group.
  • servers()All projected servers in the network.
  • routableServers(group)Ready, accepting, addressable servers.
  • self()This server’s view, or null before the projection.
Availability is advisory.

Seeing one available slot does not make it yours. Call reserveSlot before moving a player.

Java
int players = atlas.playerCount("lobby");
int capacity = atlas.availableSlots("lobby");

List<ServerView> targets =
    atlas.routableServers("lobby");

for (ServerView server : targets) {
    logger.info("%s — %d/%d".formatted(
        server.getServerId(),
        server.getPlayerCount(),
        server.getSlotCapacity()));
}

Core API

Report what this server is doing

Atlas does not inspect your game. Report the facts that drive placement and lifecycle decisions: current occupancy, successful arrivals, and your game status.

Status names are yours. Your group configuration decides whether a value such as INGAME stops new placements and starts replacement capacity.

Consume reservations on arrival.

playerArrived releases the short-lived hold and reports the authoritative backend count in one operation.

Paper
// Match begins: remain healthy, stop taking players.
atlas.setStatus("INGAME");

// A reserved player reaches the backend.
int count = Bukkit.getOnlinePlayers().size();
atlas.playerArrived(player.getUniqueId(), count);

// Match ends: restore ordinary joinability.
atlas.clearStatus();

Core API

React to network changes

onEvent derives events from the same projection queries read. Delivery is at-most-once, not durable, and updates may be coalesced. Treat events as a prompt to inspect state—not as a ledger.

Server events

ServerStarting, ServerReady, ServerStopping, ServerStopped, ServerStatusChanged, and ServerJoinabilityChanged.

Player events

PlayerJoinedNetwork, PlayerLeftNetwork, and PlayerSwitchedServer.

Never attach irreversible work to an event.

Payments, punishments, and inventory writes need durable application state. Atlas lifecycle events can be missed during a disconnect.

Paper
atlas.onEvent(event -> {
    // Callback runs on the SDK reader thread.
    Bukkit.getScheduler().runTask(plugin, () -> {
        if (event instanceof
                AtlasEvent.ServerReady ready) {
            announce("Ready: "
                + ready.server().getServerId());
        }
    });
});

Core API

Reach a player anywhere

atlas.player(uuid) returns a handle whether the player is online or not. Presence stays central, so location and transfer methods are asynchronous.

  • locate()Returns proxy, server, group, node, and placement time.
  • isOnline()Checks for a live presence record.
  • transfer(group)Reserves capacity, then asks the holding proxy to move.
  • transferTo(server)Moves to an exact server without creating a reservation.
  • send(payload)Fire-and-forget delivery to the current holder.

Messages perform no location lookup. The server holding the player owns a live subscription; when that connection disappears, the route disappears with it.

Java
AtlasPlayer player = atlas.player(playerId);

player.locate().thenCompose(presence -> {
    if (!presence.online()) {
        return CompletableFuture.failedFuture(
            new IllegalStateException("offline"));
    }
    return player.transfer("squidgame");
}).exceptionally(error -> {
    logger.warning(error.getMessage());
    return null;
});

player.send("The next match is ready.");

Core API

Place groups atomically

Use atlas.players(…) instead of looping over individual players. A party request considers everyone in one central operation, so separate reservations cannot scatter the group by accident.

ALL_OR_NOTHINGOne server fits everyone, or the request fails.
PREFER_TOGETHERTry one server first, then split across the best options.
SPLITPlace each member using the group strategy.

A completed party transfer may still contain unplaced players. Always inspect isComplete(), placed(), and unplaced().

Java
AtlasParty party = atlas.players(memberIds);

party.transfer("squidgame",
        PartyPolicy.PREFER_TOGETHER)
    .thenAccept(result -> {
        if (!result.isComplete()) {
            result.unplaced().forEach((id, reason) ->
                logger.warning(id + ": " + reason));
        }
    });

Reliability

Survive an agent restart

The client reconnects indefinitely with capped exponential backoff and jitter. After reconnecting, it identifies itself again and replays held players, player count, and status.

Requests already in flight fail with a retryable AtlasConnectionException. Issue a fresh request after the connection-state callback reports true.

Backend safety

The Paper adapter can shut down a backend safely after a sustained agent outage. The default grace is five minutes, followed by a 30-second player warning and save. Set ATLAS_ORPHAN_SHUTDOWN_GRACE_SECONDS to at least 120 seconds, or use 0/off to disable it.

Java
atlas.onConnectionStateChanged(connected -> {
    logger.info("Atlas agent: "
        + (connected ? "connected" : "reconnecting"));
});

atlas.onDisconnectedFor(Duration.ofMinutes(2),
    () -> scheduler.execute(this::enterSafeMode));

if (atlas.isConnected()) {
    submitPlacement();
}

Reliability

Handle rejection and transport failure separately

AtlasException means the agent or control plane rejected an operation. Inspect code() and retryable(). AtlasConnectionException is an I/O failure on the local agent connection and is always safe to retry after reconnection.

Async failures normally arrive wrapped by CompletionException. Unwrap the cause before classifying it.

INVALID_ARGUMENTNOT_FOUNDCONFLICTUNAVAILABLETIMEOUTSEQUENCE_GAPINTERNAL
Java
atlas.reserveSlot(group, playerId)
    .whenComplete((slot, failure) -> {
        if (failure == null) {
            connect(slot.serverId());
            return;
        }

        Throwable cause = failure.getCause() == null
            ? failure : failure.getCause();
        if (cause instanceof AtlasException e
                && e.retryable()) {
            enqueueForLater(playerId);
        }
    });

Reliability

Callbacks run off the platform thread

Event, message, connection, and transfer callbacks run on the SDK reader/reconnect thread. Hand platform work to Bukkit, Velocity, or BungeeCord’s scheduler before touching their APIs.

Do not block a callback. It shares the connection path that delivers events and completes claim replies.

Paper
atlas.onPlayerMessage((playerId, payload) ->
    Bukkit.getScheduler().runTask(plugin, () -> {
        Player player = Bukkit.getPlayer(playerId);
        if (player != null) {
            player.sendMessage(new String(payload,
                StandardCharsets.UTF_8));
        }
    })
);

Reference

Platform adapters

The packaged adapters implement the platform-specific bridge around the same Java client.

Backend

Paper / Spigot

Reports player counts and arrivals, exposes atlas() and setStatus(), delivers messages on the Bukkit scheduler, and owns orphan safety shutdown.

Proxy

Velocity

Synchronizes projected backends, resolves initial placement, reports presence, executes cross-network transfers, and publishes the Atlas player count in pings.

Proxy

BungeeCord

Provides the same placement, presence, transfer, messaging, and ping behavior through BungeeCord’s scheduler and event model.

Reference

Core types

ServerView

Projected protobuf view: IDs, group and node, lifecycle state, players, capacity, status, joinability, address, port, kind, and observation time.

Slot

reservationId, serverId, expiresAtUnixMs, plus expiresAt() and isExpired().

PlayerPresence

online, proxyId, serverId, groupId, nodeId, and sinceUnixMs.

JoinPlacement

The selected groupId, a live slot, and whether the player’s remembered group was used.

PartyPlacement

Primary server, expiry, per-player slots, and per-player failure reasons. Helpers report completeness and togetherness.

TransferRequest

The player, target server, and optional reservation that a proxy adapter must execute on its platform thread.

Reference

Method index

AtlasClient

  • static connect()
  • awaitReady(Duration)
  • static connect(Path, String)
  • playerCount(String)
  • availableSlots(String)
  • networkPlayerCount()
  • servers(String)
  • servers()
  • routableServers(String)
  • self()
  • setStatus(String)
  • clearStatus()
  • setPlayerCount(int)
  • playerArrived(UUID[, int])
  • player(UUID)
  • players(Collection|UUID…)
  • holdPlayer(UUID)
  • releasePlayer(UUID)
  • onPlayerMessage(BiConsumer)
  • onPlayerTransfer(Function)
  • reportPresence(…)
  • reportPlayerLeft(UUID, String)
  • reserveSlot(String, UUID)
  • reserveParty(…)
  • resolveJoin(UUID)
  • onEvent(Consumer)
  • isConnected()
  • onConnectionStateChanged(Consumer)
  • onDisconnectedFor(Duration, Runnable)
  • close()

AtlasPlayer

  • uuid()
  • locate()
  • isOnline()
  • transfer(String)
  • transferTo(ServerView)
  • send(byte[])
  • send(String)

AtlasParty

  • members()
  • reserve(String[, PartyPolicy])
  • transfer(String[, PartyPolicy])

Generated protocol types live under com.atlasgg.protocol.v1. Application-facing helpers live under com.atlasgg.sdk.