> ## 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.

# Installation

> Cloud API zu deinem Minecraft-Plugin oder Standalone-Anwendung hinzufügen

export const DependencySnippet = ({dependencies = [], repositories = [{
  id: "simplecloud",
  url: "https://repo.simplecloud.app/snapshots"
}, {
  id: "buf",
  url: "https://buf.build/gen/maven"
}], language = "en", type = "snapshot"}) => {
  const [versions, setVersions] = useState({});
  const [failed, setFailed] = useState({});
  const dependencyKey = dependencies.map(dep => `${dep.groupId}:${dep.artifactId}:${dep.version || ""}`).join("|");
  const copy = {
    en: {
      loading: "Loading the latest dependency version from the Maven repository...",
      failed: "The latest version could not be loaded. The examples below use dynamic version selectors that resolve the newest available artifact during dependency resolution."
    },
    de: {
      loading: "Die neueste Dependency-Version wird aus dem Maven-Repository geladen...",
      failed: "Die neueste Version konnte nicht geladen werden. Die Beispiele unten verwenden dynamische Versionsselektoren, die beim Auflösen der Dependency das neueste verfügbare Artefakt verwenden."
    }
  };
  const text = copy[language] || copy.en;
  useEffect(() => {
    let cancelled = false;
    dependencies.forEach(dep => {
      if (dep.version) return;
      const key = `${dep.groupId}:${dep.artifactId}`;
      const fetchVersion = async () => {
        try {
          const url = type === "snapshot" ? `https://repo.simplecloud.app/api/maven/latest/version/snapshots/${dep.groupId.replace(/\./g, "/")}/${dep.artifactId}?type=raw` : `https://search.maven.org/solrsearch/select?q=g:${dep.groupId}+AND+a:${dep.artifactId}&rows=1&wt=json`;
          const response = await fetch(url, {
            cache: "no-store"
          });
          if (!response.ok) throw new Error(`Version request failed: ${response.status}`);
          if (type === "snapshot") {
            const version = (await response.text()).trim();
            if (!cancelled && version) {
              setVersions(current => ({
                ...current,
                [key]: version
              }));
            }
            return;
          }
          const data = await response.json();
          const version = data.response?.docs?.[0]?.latestVersion;
          if (!cancelled && version) {
            setVersions(current => ({
              ...current,
              [key]: version
            }));
          }
        } catch (error) {
          if (!cancelled) {
            setFailed(current => ({
              ...current,
              [key]: true
            }));
          }
        }
      };
      fetchVersion();
    });
    return () => {
      cancelled = true;
    };
  }, [dependencyKey, type]);
  const keyFor = dep => `${dep.groupId}:${dep.artifactId}`;
  const hasPendingVersion = dependencies.some(dep => !dep.version && !versions[keyFor(dep)] && !failed[keyFor(dep)]);
  const hasFailedVersion = dependencies.some(dep => failed[keyFor(dep)]);
  const getVersion = (dep, buildTool) => {
    if (dep.version) return dep.version;
    const version = versions[keyFor(dep)];
    if (version) return version;
    return buildTool === "maven" ? "[0,)" : "latest.integration";
  };
  const generateKotlin = () => {
    const repoLines = repositories.map(repo => `    maven("${repo.url}")`).join("\n");
    const depLines = dependencies.map(dep => {
      const depType = dep.type || "implementation";
      return `    ${depType}("${dep.groupId}:${dep.artifactId}:${getVersion(dep, "gradle")}")`;
    }).join("\n");
    return `repositories {\n${repoLines}\n}\n\ndependencies {\n${depLines}\n}`;
  };
  const generateGroovy = () => {
    const repoLines = repositories.map(repo => `    maven { url '${repo.url}' }`).join("\n");
    const depLines = dependencies.map(dep => {
      const depType = dep.type || "implementation";
      return `    ${depType} '${dep.groupId}:${dep.artifactId}:${getVersion(dep, "gradle")}'`;
    }).join("\n");
    return `repositories {\n${repoLines}\n}\n\ndependencies {\n${depLines}\n}`;
  };
  const generateMaven = () => {
    const repoLines = repositories.map(repo => `    <repository>
      <id>${repo.id || "repo"}</id>
      <url>${repo.url}</url>
    </repository>`).join("\n");
    const depLines = dependencies.map(dep => {
      const scope = dep.type === "compileOnly" ? "provided" : "compile";
      return `    <dependency>
      <groupId>${dep.groupId}</groupId>
      <artifactId>${dep.artifactId}</artifactId>
      <version>${getVersion(dep, "maven")}</version>
      <scope>${scope}</scope>
    </dependency>`;
    }).join("\n");
    return `<repositories>\n${repoLines}\n</repositories>\n\n<dependencies>\n${depLines}\n</dependencies>`;
  };
  if (hasPendingVersion) {
    return <Info>{text.loading}</Info>;
  }
  return <>
      {hasFailedVersion && <Warning>
          {text.failed}
        </Warning>}

      <Tabs>
        <Tab title="Gradle (Kotlin)">
          <CodeBlock language="kotlin">{generateKotlin()}</CodeBlock>
        </Tab>
        <Tab title="Gradle (Groovy)">
          <CodeBlock language="groovy">{generateGroovy()}</CodeBlock>
        </Tab>
        <Tab title="Maven">
          <CodeBlock language="xml">{generateMaven()}</CodeBlock>
        </Tab>
      </Tabs>
    </>;
};

## Dependencies hinzufügen

Füge die Cloud API zu deiner Build-Konfiguration hinzu. Die Beispiele unten laden die neueste verfügbare API-Version aus dem SimpleCloud Maven-Repository.

<DependencySnippet
  language="de"
  dependencies={[
{
  groupId: "app.simplecloud.api",
  artifactId: "api",
  type: "compileOnly",
},
]}
/>

<Note>
  Verwende `compileOnly` oder Maven `provided` für Minecraft-Plugins, weil das
  `simplecloud-api` Plugin die API zur Laufzeit bereitstellt. Nutze
  `implementation` nur für Standalone-Anwendungen, die die API selbst mitliefern.
</Note>

<Tip>
  Für reproduzierbare Produktionsbuilds solltest du die angezeigte Version nach
  dem Testen fest pinnen. Aktualisiere diese Seite vor dem Kopieren, wenn du die
  neueste API verwenden möchtest.
</Tip>

## Plugin-Setup

Füge das SimpleCloud API Plugin als Dependency in deinem Plugin-Deskriptor hinzu:

<Tabs>
  <Tab title="Paper/Spigot (plugin.yml)">
    ```yaml theme={null}
    name: mein-plugin
    version: 1.0.0
    main: com.example.MeinPlugin
    depend: [simplecloud-api]
    ```
  </Tab>

  <Tab title="Velocity (velocity-plugin.json)">
    ```json theme={null}
    {
      "id": "mein-plugin",
      "name": "Mein Plugin",
      "version": "1.0.0",
      "main": "com.example.MeinPlugin",
      "dependencies": [{ "id": "simplecloud-api", "optional": false }]
    }
    ```
  </Tab>

  <Tab title="BungeeCord (bungee.yml)">
    ```yaml theme={null}
    name: mein-plugin
    version: 1.0.0
    main: com.example.MeinPlugin
    depends: [simplecloud-api]
    ```
  </Tab>
</Tabs>

<Warning>
  Shade die Cloud API nicht in dein Plugin. Hänge stattdessen vom
  `simplecloud-api` Plugin ab.
</Warning>

## API initialisieren

### Standard-Konfiguration

Wenn du innerhalb eines SimpleCloud-Servers läufst, konfiguriert sich die API automatisch aus Umgebungsvariablen:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    import app.simplecloud.api.CloudApi;

    public class MeinPlugin extends JavaPlugin {
        private CloudApi api;

        @Override
        public void onEnable() {
            api = CloudApi.create();
        }
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    import app.simplecloud.api.CloudApi

    class MeinPlugin : JavaPlugin() {
        private lateinit var api: CloudApi

        override fun onEnable() {
            api = CloudApi.create()
        }
    }
    ```
  </Tab>
</Tabs>

### Eigene Konfiguration

Für Standalone-Anwendungen oder eigene Setups, gib Konfigurationsoptionen an:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CloudApi api = CloudApi.create(CloudApiOptions.builder()
        .networkId("deine-netzwerk-id")
        .networkSecret("dein-secret")
        .controllerUrl("https://controller.simplecloud.app")
        .natsUrl("wss://nats.simplecloud.app:443")
        .component("mein-plugin")
        .build());
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val api = CloudApi.create(CloudApiOptions.builder()
        .networkId("deine-netzwerk-id")
        .networkSecret("dein-secret")
        .controllerUrl("https://controller.simplecloud.app")
        .natsUrl("wss://nats.simplecloud.app:443")
        .component("mein-plugin")
        .build())
    ```
  </Tab>
</Tabs>

## Umgebungsvariablen

Die API liest standardmäßig diese Umgebungsvariablen:

| Variable                                    | Standard                               | Beschreibung                                                          |
| ------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------- |
| `SIMPLECLOUD_NETWORK_ID`                    | `"default"`                            | Deine Netzwerk-Kennung                                                |
| `SIMPLECLOUD_NETWORK_SECRET`                | `""`                                   | Authentifizierungs-Secret                                             |
| `SIMPLECLOUD_CONTROLLER_URL`                | `"https://controller.simplecloud.app"` | Controller API-Endpunkt                                               |
| `SIMPLECLOUD_NATS_URL`                      | `"wss://nats.simplecloud.app:443"`     | NATS-Endpunkt für Events                                              |
| `SIMPLECLOUD_NATS_FAILOVER_RECONNECT_AFTER` | `"30s"`                                | Wartezeit, bevor die API nach einem Failover wieder zu NATS verbindet |
| `SIMPLECLOUD_SERVER_VERSION_MANIFEST_URL`   | SimpleCloud-Server-Manifest auf GitHub | Manifest für Inline-Blueprints ohne `serverUrl`                       |

<Note>
  Innerhalb von SimpleCloud-Servern werden diese Variablen automatisch gesetzt.
  Du musst sie nur für Standalone-Anwendungen oder externe Services
  konfigurieren.
</Note>

## Cache und Timeouts

Die API nutzt standardmäßig einen lokalen Query-Cache. Sie liefert frische Cache-Daten sofort, kann veraltete Daten während einer Hintergrund-Aktualisierung zurückgeben und invalidiert betroffene Einträge automatisch, wenn Cloud-API-Events eintreffen.

```java theme={null}
CloudApi api = CloudApi.create(CloudApiOptions.builder()
    .cache(CacheConfig.builder()
        .defaultStaleTime(Duration.ofSeconds(5))
        .defaultCacheTime(Duration.ofMinutes(2))
        .build())
    .httpConnectTimeout(Duration.ofSeconds(5))
    .httpReadTimeout(Duration.ofSeconds(10))
    .httpWriteTimeout(Duration.ofSeconds(10))
    .build());

// Cache vollständig deaktivieren
CloudApi uncached = CloudApi.create(CloudApiOptions.builder()
    .disableCache()
    .build());
```

Verwende `api.cache()`, um Cache-Statistiken zu prüfen oder Einträge manuell zu invalidieren.

## Best Practices

<AccordionGroup>
  <Accordion title="Eine einzelne API-Instanz verwenden">
    Erstelle eine `CloudApi`-Instanz und verwende sie wieder. Nutze Dependency Injection wenn dein Framework es unterstützt.

    ```java theme={null}
    // Gut - einzelne Instanz
    private final CloudApi api = CloudApi.create();

    // Vermeiden - mehrere Instanzen
    public void doSomething() {
        CloudApi api = CloudApi.create(); // Das nicht tun
    }
    ```
  </Accordion>

  <Accordion title="Async-Operationen richtig behandeln">
    Alle API-Methoden geben `CompletableFuture` zurück. Blockiere nicht auf dem Haupt-Thread.

    ```java theme={null}
    // Gut - async Behandlung
    api.server().getAllServers().thenAccept(servers -> {
        // Server verarbeiten
    });

    // Vermeiden - blockieren
    List<Server> servers = api.server().getAllServers().join(); // Nicht blockieren!
    ```
  </Accordion>

  <Accordion title="Event-Subscriptions aufräumen">
    Subscriptions implementieren `AutoCloseable`. Schließe sie wenn du fertig bist.

    ```java theme={null}
    Subscription sub = api.event().server().onStarted(event -> {
        System.out.println("Gestartet: " + event.getServer().getServerId());
    });

    // Beim Herunterfahren
    sub.close();
    ```
  </Accordion>
</AccordionGroup>
