Skip to main content
Alpha features require the PlayerTracking feature gate to be enabled in your Agones installation. These APIs may change in future releases.

Overview

The Alpha SDK provides player tracking capabilities, allowing game servers to manage connected players through the Agones API. The SDK maintains player counts and IDs, syncing them to the GameServer status resource. Package: agones.dev.sdk.alpha

Key Features

  • Automatic Capacity Tracking: Maintain player count and capacity automatically
  • Player ID Management: Track individual player connections by ID
  • Batched Updates: Player updates are batched for efficiency (1-second intervals)
  • Capacity Enforcement: Prevents exceeding configured player capacity
  • SDK-Managed State: SDK maintains accurate state even before Kubernetes updates

Important Considerations

Do not use Alpha SDK player tracking methods if you’re manually managing GameServer.Status.Players.IDs and GameServer.Status.Players.Count through the Kubernetes API. This will cause indeterminate results.

Update Batching

Player tracking updates are batched to reduce Kubernetes API load:
  • Updates are sent approximately 1 second after the first change
  • Multiple changes within the 1-second window are combined
  • The SDK maintains accurate state immediately, even before the batch update
  • Use SDK methods (not Kubernetes API) to query current state for accuracy

PlayerConnect

Increases the player count by one and adds the player ID to the connected players list.
rpc PlayerConnect (PlayerID) returns (Bool);

Behavior

  • Increments GameServer.Status.Players.Count by 1
  • Appends the player ID to GameServer.Status.Players.IDs
  • Updates are batched and sent ~1 second later
  • Returns true if the player ID was added successfully
  • Returns false if the player ID already exists
  • Returns an error if capacity is reached

Request

playerID
string
required
The unique identifier for the player connecting to the game server.

Response

bool
bool
  • true: Player ID was added successfully
  • false: Player ID already exists in the connected players list
  • Error: Player capacity has been reached

Example Usage

import (
    "log"
    alphaSdk "agones.dev/agones/sdks/go/alpha"
)

func onPlayerJoin(alpha *alphaSdk.Alpha, playerID string) error {
    connected, err := alpha.PlayerConnect(playerID)
    if err != nil {
        return fmt.Errorf("could not connect player: %v", err)
    }
    
    if connected {
        log.Printf("Player %s connected successfully", playerID)
    } else {
        log.Printf("Player %s was already connected", playerID)
    }
    
    return nil
}

// Usage
if err := onPlayerJoin(alpha, "player-12345"); err != nil {
    if strings.Contains(err.Error(), "capacity") {
        log.Println("Server is full")
        // Reject connection
    }
}

PlayerDisconnect

Decreases the player count by one and removes the player ID from the connected players list.
rpc PlayerDisconnect (PlayerID) returns (Bool);

Behavior

  • Decrements GameServer.Status.Players.Count by 1
  • Removes the player ID from GameServer.Status.Players.IDs
  • Updates are batched and sent ~1 second later
  • Returns true if the player ID was removed successfully
  • Returns false if the player ID was not in the list

Request

playerID
string
required
The unique identifier for the player disconnecting from the game server.

Response

bool
bool
  • true: Player ID was removed successfully
  • false: Player ID was not in the connected players list

Example Usage

func onPlayerLeave(alpha *alphaSdk.Alpha, playerID string) {
    disconnected, err := alpha.PlayerDisconnect(playerID)
    if err != nil {
        log.Printf("Error disconnecting player: %v", err)
        return
    }
    
    if disconnected {
        log.Printf("Player %s disconnected successfully", playerID)
    } else {
        log.Printf("Player %s was not connected", playerID)
    }
}

SetPlayerCapacity

Updates the maximum player capacity for the game server.
rpc SetPlayerCapacity (Count) returns (Empty);

Behavior

  • Updates GameServer.Status.Players.Capacity to the specified value
  • Can increase or decrease capacity dynamically
  • Cannot set capacity below current player count

Request

count
int64
required
The new player capacity. Must be a non-negative integer and greater than or equal to the current player count.

Response

-
Empty
Returns empty on success.

Example Usage

// Increase capacity for a large match
func setLargeMatchCapacity(alpha *alphaSdk.Alpha) error {
    count := &alpha.Count{Count: 64}
    if err := alpha.SetPlayerCapacity(count); err != nil {
        return fmt.Errorf("could not set capacity: %v", err)
    }
    log.Println("Set player capacity to 64")
    return nil
}

// Reduce capacity for a small match
func setSmallMatchCapacity(alpha *alphaSdk.Alpha) error {
    count := &alpha.Count{Count: 8}
    if err := alpha.SetPlayerCapacity(count); err != nil {
        return fmt.Errorf("could not set capacity: %v", err)
    }
    log.Println("Set player capacity to 8")
    return nil
}

GetPlayerCapacity

Retrieves the current player capacity. This is always accurate from the SDK’s perspective, even before Kubernetes updates.
rpc GetPlayerCapacity (Empty) returns (Count);

Behavior

  • Returns the current capacity maintained by the SDK
  • Accurate even if the value hasn’t been written to Kubernetes yet
  • For manually-set capacity via Kubernetes API, use SDK.GameServer() instead

Request

-
Empty
No parameters required.

Response

count
int64
The current player capacity.

Example Usage

func checkCapacity(alpha *alphaSdk.Alpha) (int64, error) {
    capacity, err := alpha.GetPlayerCapacity()
    if err != nil {
        return 0, err
    }
    
    log.Printf("Current capacity: %d", capacity.Count)
    return capacity.Count, nil
}

GetPlayerCount

Retrieves the current player count. This is always accurate from the SDK’s perspective, even before Kubernetes updates.
rpc GetPlayerCount (Empty) returns (Count);

Behavior

  • Returns the current count maintained by the SDK
  • Accurate even if the value hasn’t been written to Kubernetes yet
  • For manually-set counts via Kubernetes API, use SDK.GameServer() instead

Request

-
Empty
No parameters required.

Response

count
int64
The current number of connected players.

Example Usage

func logPlayerCount(alpha *alphaSdk.Alpha) error {
    count, err := alpha.GetPlayerCount()
    if err != nil {
        return err
    }
    
    log.Printf("Current player count: %d", count.Count)
    return nil
}

// Check if server is full
func isServerFull(alpha *alphaSdk.Alpha) (bool, error) {
    count, err := alpha.GetPlayerCount()
    if err != nil {
        return false, err
    }
    
    capacity, err := alpha.GetPlayerCapacity()
    if err != nil {
        return false, err
    }
    
    return count.Count >= capacity.Count, nil
}

IsPlayerConnected

Checks if a specific player ID is currently connected.
rpc IsPlayerConnected (PlayerID) returns (Bool);

Behavior

  • Returns true if the player ID is in the connected players list
  • Returns false if the player ID is not in the list
  • Accurate even if the value hasn’t been written to Kubernetes yet
  • For manually-managed player IDs via Kubernetes API, use SDK.GameServer() instead

Request

playerID
string
required
The player ID to check.

Response

bool
bool
  • true: Player is connected
  • false: Player is not connected

Example Usage

func checkPlayerConnection(alpha *alphaSdk.Alpha, playerID string) (bool, error) {
    result, err := alpha.IsPlayerConnected(playerID)
    if err != nil {
        return false, err
    }
    
    if result.Bool {
        log.Printf("Player %s is connected", playerID)
    } else {
        log.Printf("Player %s is not connected", playerID)
    }
    
    return result.Bool, nil
}

// Prevent duplicate connections
func connectPlayerIfNew(alpha *alphaSdk.Alpha, playerID string) error {
    connected, err := alpha.IsPlayerConnected(playerID)
    if err != nil {
        return err
    }
    
    if connected.Bool {
        return fmt.Errorf("player %s is already connected", playerID)
    }
    
    _, err = alpha.PlayerConnect(playerID)
    return err
}

GetConnectedPlayers

Retrieves the list of all currently connected player IDs.
rpc GetConnectedPlayers(Empty) returns (PlayerIDList);

Behavior

  • Returns all player IDs in the connected players list
  • Accurate even if the value hasn’t been written to Kubernetes yet
  • For manually-managed player IDs via Kubernetes API, use SDK.GameServer() instead

Request

-
Empty
No parameters required.

Response

list
string[]
Array of connected player IDs.

Example Usage

func listConnectedPlayers(alpha *alphaSdk.Alpha) ([]string, error) {
    players, err := alpha.GetConnectedPlayers()
    if err != nil {
        return nil, err
    }
    
    log.Printf("Connected players: %v", players.List)
    return players.List, nil
}

// Send message to all connected players
func broadcastToAllPlayers(alpha *alphaSdk.Alpha, message string) error {
    players, err := alpha.GetConnectedPlayers()
    if err != nil {
        return err
    }
    
    for _, playerID := range players.List {
        sendMessage(playerID, message)
    }
    
    return nil
}

Message Types

PlayerID

message PlayerID {
    string playerID = 1;
}
Represents a unique player identifier.

Count

message Count {
    int64 count = 1;
}
Represents a count value (player count or capacity).

Bool

message Bool {
    bool bool = 1;
}
Represents a boolean result.

PlayerIDList

message PlayerIDList {
    repeated string list = 1;
}
Represents a list of player IDs.

HTTP Gateway

Alpha SDK methods are available via HTTP/JSON:
curl -X POST http://localhost:9357/alpha/player/connect \
  -H "Content-Type: application/json" \
  -d '{"playerID": "player-12345"}'

Complete Integration Example

package main

import (
    "context"
    "log"
    "time"
    
    "agones.dev/agones/sdks/go"
    alphaSdk "agones.dev/agones/sdks/go/alpha"
)

type GameServer struct {
    sdk   *sdk.SDK
    alpha *alphaSdk.Alpha
}

func NewGameServer() (*GameServer, error) {
    s, err := sdk.NewSDK()
    if err != nil {
        return nil, err
    }
    
    a := alphaSdk.NewAlpha(s)
    
    return &GameServer{sdk: s, alpha: a}, nil
}

func (gs *GameServer) Start() error {
    // Set player capacity
    capacity := &alphaSdk.Count{Count: 32}
    if err := gs.alpha.SetPlayerCapacity(capacity); err != nil {
        return err
    }
    
    // Signal ready
    if err := gs.sdk.Ready(); err != nil {
        return err
    }
    
    log.Println("Game server ready with capacity for 32 players")
    return nil
}

func (gs *GameServer) OnPlayerJoin(playerID string) error {
    connected, err := gs.alpha.PlayerConnect(playerID)
    if err != nil {
        return err
    }
    
    if !connected {
        return fmt.Errorf("player already connected")
    }
    
    count, _ := gs.alpha.GetPlayerCount()
    log.Printf("Player %s joined. Total: %d", playerID, count.Count)
    
    return nil
}

func (gs *GameServer) OnPlayerLeave(playerID string) error {
    disconnected, err := gs.alpha.PlayerDisconnect(playerID)
    if err != nil {
        return err
    }
    
    if !disconnected {
        return fmt.Errorf("player not connected")
    }
    
    count, _ := gs.alpha.GetPlayerCount()
    log.Printf("Player %s left. Total: %d", playerID, count.Count)
    
    // Shutdown if no players left
    if count.Count == 0 {
        log.Println("No players remaining, shutting down...")
        time.Sleep(30 * time.Second) // Grace period
        gs.sdk.Shutdown()
    }
    
    return nil
}

Build docs developers (and LLMs) love