> ## Documentation Index
> Fetch the complete documentation index at: https://simplecloud.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Servers API

> Laufende Server-Instanzen abfragen und verwalten

Die Servers API verwaltet laufende Server-Instanzen. Verwende `api.server()`, um Server abzufragen, zu stoppen und zu aktualisieren.

<Info>
  Neue Gruppen-Server startest du über die Groups API mit `api.group().requestServerStart(...)`. Die Servers API arbeitet nur mit Server-Instanzen, die bereits existieren.
</Info>

## Server abrufen

```java theme={null}
// Alle Server
api.server().getAllServers()
    .thenAccept(servers -> System.out.println("Total: " + servers.size()));

// Server mit Filtern
ServerQuery query = ServerQuery.create()
    .filterByServerGroupName("lobby")
    .filterByState(ServerState.AVAILABLE, ServerState.INGAME)
    .sortBy("numerical_id")
    .sortOrder("asc");

api.server().getAllServers(query)
    .thenAccept(servers -> servers.forEach(server ->
        System.out.println(server.getServerId() + ": " + server.getState())));

// Server nach ID
api.server().getServerById("server-uuid")
    .thenAccept(server -> System.out.println(server.getState()));

// Server in einer Gruppe
api.server().getServersByGroup("lobby")
    .thenAccept(servers -> servers.forEach(server ->
        System.out.println(server.getServerId() + ": " + server.getState())));

// Server nach Gruppe und numerischer ID, zum Beispiel Lobby-1
api.server().getServerByNumericalId("lobby", 1)
    .thenAccept(server -> System.out.println(server.getServerId()));

// Aktuellen Server innerhalb einer laufenden Instanz abrufen
api.server().getCurrentServer()
    .thenAccept(server -> System.out.println("Läuft auf: " + server.getServerId()));
```

## Gruppen-Server anfordern

Reihe einen neuen Server-Start für eine Gruppe mit `api.group()` ein. Der Reconciler verarbeitet die Anfrage beim nächsten Tick und erstellt den Server, wenn die Gruppenlimits es erlauben.

```java theme={null}
api.group().getGroupByName("lobby")
    .thenCompose(group -> {
        if (group == null) {
            return CompletableFuture.failedFuture(
                new IllegalArgumentException("Gruppe nicht gefunden: lobby"));
        }
        return api.group().requestServerStart(group);
    })
    .thenRun(() -> System.out.println("Start-Anfrage für lobby angenommen"));
```

<Note>
  `requestServerStart` ist abgeschlossen, sobald die Anfrage angenommen wurde, nicht sobald der Server bereit ist. Nutze `api.event().server().onStateChanged(...)` oder frage die Gruppe ab, um den neuen Server zu finden, sobald er `AVAILABLE` erreicht.
</Note>

## Server stoppen

```java theme={null}
api.server().stopServer("server-uuid")
    .thenRun(() -> System.out.println("Stop angefragt"));
```

### Server stoppen (REST)

Nutze `DELETE /v0/servers`, wenn der Controller den Server normal stoppen und den Server-Lifecycle ausführen soll.

<RequestExample>
  ```bash cURL theme={null}
  curl -X DELETE "https://your-controller/v0/servers?server_id=123e4567-e89b-12d3-a456-426614174000" \
    -H "X-Network-ID: your-network-id" \
    -H "X-Network-Credential: your-network-password"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "message": "Server stop request sent successfully",
    "server_id": "123e4567-e89b-12d3-a456-426614174000",
    "state": "STOPPING"
  }
  ```
</ResponseExample>

<ParamField query="server_id" type="string" required>
  ID der Serverinstanz, die gestoppt werden soll.
</ParamField>

## Server aktualisieren

```java theme={null}
UpdateServerRequest update = UpdateServerRequest.builder()
    .maxPlayers(64)
    .build();

api.server().updateServer("server-uuid", update)
    .thenAccept(server -> System.out.println("Aktualisiert: " + server.getMaxPlayers()));
```

## Server-Properties

Server erben Properties von ihrer Gruppe oder ihrem persistenten Server. Pro Instanz kannst du sie überschreiben:

```java theme={null}
// Properties hinzufügen oder aktualisieren (merged mit bestehenden)
Map<String, Object> props = Map.of("map", "castle", "mode", "competitive");
api.server().updateServerProperties("server-uuid", props)
    .thenAccept(updated -> System.out.println("Properties: " + updated));

// Bestimmte Properties entfernen
api.server().deleteServerProperties("server-uuid", List.of("mode"));
```

## Server auflisten (REST)

Um Server in einem Netzwerk mit optionalen Filtern aufzulisten, verwende `GET /v0/servers`. Die Antwort enthält Server-Details, Gruppen- oder Persistent-Server-Metadaten, Blueprint-Informationen und Workflow-Konfigurationen.

<RequestExample>
  ```bash cURL theme={null}
  curl "https://your-controller/v0/servers?state=AVAILABLE&type=lobby" \
    -H "X-Network-ID: your-network-id" \
    -H "X-Network-Credential: your-network-password"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "count": 1,
    "servers": [
      {
        "server_id": "123e4567-e89b-12d3-a456-426614174000",
        "network_id": "production",
        "server_group_id": "lobby",
        "persistent_server_id": null,
        "serverhost_id": "host-eu-1",
        "numerical_id": 1,
        "ip": "127.0.0.1",
        "port": 25565,
        "state": "AVAILABLE",
        "player_count": 12,
        "max_players": 100,
        "min_memory": 512,
        "max_memory": 1024,
        "properties": {
          "map": "castle"
        }
      }
    ]
  }
  ```
</ResponseExample>

<ParamField header="X-Network-ID" type="string" required>
  Deine Netzwerk-ID.
</ParamField>

<ParamField header="X-Network-Credential" type="string" required>
  Dein Netzwerk-Passwort oder ein für das Zielnetzwerk gültiges App-JWT. Der ältere Header-Name `X-Network-Secret` wird aus Rückwärtskompatibilität weiterhin akzeptiert, ist aber deprecated.
</ParamField>

<ParamField header="X-SC-Component" type="string">
  Optionaler Name der aufrufenden Komponente für das Controller-Request-Event.
</ParamField>

<ParamField query="server_group_id" type="string">
  Nach einer oder mehreren Server-Gruppen-IDs filtern. Trenne mehrere IDs mit Kommas.
</ParamField>

<ParamField query="state" type="string">
  Nach einem oder mehreren Statuswerten filtern, zum Beispiel `AVAILABLE,STARTING`.
</ParamField>

<ParamField query="serverhost_id" type="string">
  Nach Serverhost-ID filtern.
</ParamField>

<ParamField query="persistent_server_id" type="string">
  Nach Persistent-Server-ID filtern.
</ParamField>

<ParamField query="type" type="string">
  Nach Gruppen- oder Persistent-Server-Typ filtern.
</ParamField>

<ParamField query="name" type="string">
  Nach Gruppen- oder Persistent-Server-Name filtern.
</ParamField>

<ParamField query="tags" type="string">
  Nach Gruppen- oder Persistent-Server-Tags filtern.
</ParamField>

<ParamField query="numerical_id" type="string">
  Nach einer oder mehreren numerischen IDs filtern. Trenne mehrere IDs mit Kommas.
</ParamField>

<ParamField query="sort_by" type="string">
  Sortierfeld. Unterstützte Werte sind `created_at`, `updated_at`, `numerical_id` und `state`.
</ParamField>

<ParamField query="sort_order" type="string">
  Sortierreihenfolge. Nutze `asc` oder `desc`.
</ParamField>

### Response-Cache

Der Controller kann Datenbankzeilen für `GET /v0/servers` für 2 Sekunden cachen, um Dashboards und Polling-Clients zu entlasten. Wenn der Cache aktiv ist, enthält die Antwort `X-DB-Cache: HIT` oder `X-DB-Cache: MISS`. Anfragen mit Benutzer-Berechtigungsfilter umgehen diesen Cache immer.

## Server-Datensatz löschen

Um einen verwaisten Server-Datensatz direkt aus der Datenbank zu entfernen, ohne einen Prozess zu stoppen oder Lifecycle-Events zu senden, verwende `DELETE /v0/servers/database`.

<Warning>
  Diese Operation entfernt nur den Datenbankeintrag. Sie stoppt keinen Serverprozess, löst keine Cleanup-Workflows aus und sendet keine Lifecycle-Events. Verwende `stopServer` für normales Herunterfahren.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl -X DELETE "https://your-controller/v0/servers/database?server_id=123e4567-e89b-12d3-a456-426614174000" \
    -H "X-Network-ID: your-network-id" \
    -H "X-Network-Credential: your-network-password"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "message": "Server row deleted successfully",
    "server_id": "123e4567-e89b-12d3-a456-426614174000"
  }
  ```
</ResponseExample>

<ParamField query="server_id" type="string" required>
  ID der Serverzeile, die aus der Datenbank entfernt werden soll.
</ParamField>

## Server Model

<ResponseField name="serverId" type="string" required>
  Eindeutige Server-Instanz-ID.
</ResponseField>

<ResponseField name="persistentServerId" type="string | null">
  Persistent-Server-ID, falls die Instanz von einem persistenten Server gestartet wurde.
</ResponseField>

<ResponseField name="numericalId" type="integer" required>
  Numerische ID innerhalb der Gruppe oder des persistenten Servers.
</ResponseField>

<ResponseField name="serverGroupId" type="string | null">
  Server-Gruppen-ID, falls die Instanz von einer Gruppe gestartet wurde.
</ResponseField>

<ResponseField name="serverhostId" type="string" required>
  Host, auf dem der Server läuft.
</ResponseField>

<ResponseField name="networkId" type="string" required>
  Netzwerk-Kennung.
</ResponseField>

<ResponseField name="ip" type="string | null">
  Zugewiesene IP-Adresse.
</ResponseField>

<ResponseField name="port" type="integer | null">
  Zugewiesener Port.
</ResponseField>

<ResponseField name="minMemory" type="integer" required>
  Minimaler Speicher in MB.
</ResponseField>

<ResponseField name="maxMemory" type="integer" required>
  Maximaler Speicher in MB.
</ResponseField>

<ResponseField name="cpuUsage" type="number | null">
  Aktuelle CPU-Nutzung in Prozent.
</ResponseField>

<ResponseField name="memoryUsage" type="number | null">
  Aktuelle Speichernutzung in MB.
</ResponseField>

<ResponseField name="playerCount" type="integer | null">
  Aktuelle Spielerzahl.
</ResponseField>

<ResponseField name="maxPlayers" type="integer" required>
  Spielerlimit.
</ResponseField>

<ResponseField name="state" type="ServerState" required>
  Aktueller Lifecycle-Status.
</ResponseField>

<ResponseField name="createdAt" type="string" required>
  Erstellungszeitpunkt im ISO-8601-Format.
</ResponseField>

<ResponseField name="updatedAt" type="string" required>
  Letzter Aktualisierungszeitpunkt im ISO-8601-Format.
</ResponseField>

<ResponseField name="lastActivity" type="string | null">
  Zeitpunkt der letzten Aktivität.
</ResponseField>

<ResponseField name="properties" type="object | null">
  Instanz-spezifische Metadaten.
</ResponseField>

<ResponseField name="blueprint" type="Blueprint | null">
  Blueprint, aus dem der Server erstellt wurde.
</ResponseField>

<ResponseField name="serverBase" type="ServerBase" required>
  Gemeinsame Gruppen- oder Persistent-Server-Konfiguration.
</ResponseField>

<ResponseField name="group" type="Group | null">
  Quellgruppe, wenn dies ein Gruppen-Server ist.
</ResponseField>

<ResponseField name="persistentServer" type="PersistentServer | null">
  Quellserver, wenn dies ein persistenter Server ist.
</ResponseField>

## ServerState

| Status          | Beschreibung                                 |
| --------------- | -------------------------------------------- |
| `UNKNOWN_STATE` | Unbekannter oder nicht gesetzter Status      |
| `PREPARING`     | Dateien und Laufzeitdaten werden vorbereitet |
| `STARTING`      | Serverprozess startet                        |
| `AVAILABLE`     | Bereit für Spieler                           |
| `INGAME`        | Im Spiel mit aktiven Spielern                |
| `STOPPING`      | Shutdown läuft                               |
| `CLEANUP`       | Server ist gestoppt und Cleanup läuft        |

## Umgebungsvariablen

Innerhalb eines laufenden Servers kannst du Server-Info ohne API abrufen:

```java theme={null}
String group = System.getenv("SIMPLECLOUD_GROUP");
String uniqueId = System.getenv("SIMPLECLOUD_UNIQUE_ID");
String numericalId = System.getenv("SIMPLECLOUD_NUMERICAL_ID");
String host = System.getenv("SIMPLECLOUD_HOST");
String ip = System.getenv("SIMPLECLOUD_IP");
String port = System.getenv("SIMPLECLOUD_PORT");
String maxPlayers = System.getenv("SIMPLECLOUD_MAX_PLAYERS");
String maxMemory = System.getenv("SIMPLECLOUD_MAX_MEMORY");
```

Eigene Gruppen-Properties sind ebenfalls mit dem Präfix `SIMPLECLOUD_` verfügbar. Property-Namen werden großgeschrieben und Bindestriche werden zu Unterstrichen.
