Plugins verwalten
Plugins verwalten
Vollständige Anleitung zum Installiert-Tab — Anzeigen, Filtern, Aktualisieren, Aktivieren/Deaktivieren, Deinstallieren, Upload-Erkennung, ZIP-Export und alle möglichen Fehler.
Installierte Plugins Liste
Zwei Quellen:
- Browser-installiert — Vollständiges Tracking (Anbieter, Version, Plugin-ID, Download-URL, Update-Erkennung)
- Manuell hochgeladen — Vom Scanner automatisch erkannt, als „Manual / Upload" mit eingeschränktem Tracking registriert
Spalten
| Spalte | Beschreibung |
|---|---|
| Icon | Anbieter-Logo (leer bei Uploads) |
| Name | Aus JAR plugin.yml oder Dateiname (Versions-Regex entfernt) |
| Status | Aktiv, Deaktiviert oder Unbekannt |
| Anbieter | SpigotMC, CurseForge, Modrinth, Hangar, GeyserMC oder Upload |
| Version | Installierte Versionsnummer |
| Installiert am | Zeitstempel der Erstinstallation |
| Neueste Version | Neueste verfügbare auf der Plattform (wenn getrackt) |
Upload-Erkennung
scanAndRegisterUploadedPlugins() läuft automatisch:
- Vergleicht JAR-Dateien auf der Festplatte (
/plugins/) mit Datenbankeinträgen - Neue Dateien: Werden mit Anbieter
'upload'registriert. Öffnet JAR zum Extrahieren vonplugin.ymlfür den Namen, oder parst Version aus Dateiname-Regex-(\d+\.\d+(?:\.\d+)?) - Gelöschte Dateien: Werden aus der Datenbank entfernt (Aufräumen)
- Parallelitätsschutz: Atomare Sperre mit 10-Sekunden-TTL
- Einschränkung: Upload-Plugins haben keine automatische Update-Erkennung
Anzeigename-Auflösung
| Anbieter | Namensquelle |
|---|---|
| GeyserMC | Großgeschriebener Projektname |
| PaperMC | Slug-Teil von Owner/Slug |
| CurseForge | Slug wenn versionspräfiziert |
| Andere | JAR plugin.yml → Dateiname-Fallback |
Filtern
| Filter | Zeigt |
|---|---|
| Alle anzeigen | Alle Plugins |
| Aktiv | Nur aktivierte Plugins |
| Deaktiviert | Nur deaktivierte Plugins (mit -bak Suffix) |
| Updates verfügbar | Nur Plugins mit neueren Plattform-Versionen |
Plugins mit Updates werden nach oben sortiert, dann alphabetisch.
Filter-Beibehaltung
Das Plugin nutzt resetTableKeepingFilters() — speichert den Filterzustand bevor Filament zurücksetzt, stellt ihn danach wieder her. Dies verhindert den Verlust des „has_updates"-Filters beim Navigieren.
Plugins aktualisieren
Wie die Update-Erkennung funktioniert
- Plugin fragt die Quellplattform nach gespeicherter plugin_id und Anbieter ab
- Update-Metadaten 24 Stunden gecacht pro Plugin
'upload'Anbieter wird immer übersprungen- Zeichenkettenvergleich für Versions-IDs (kein Semantic Versioning)
Spezial: Update bei deaktiviertem Plugin
Wenn ein Plugin deaktiviert ist (hat -bak Suffix) wenn ein Update installiert wird:
- Der
is_disabledStatus wird vor dem Update gemerkt - Nach dem Update wird das Plugin automatisch erneut deaktiviert
- Dein Deaktiviert-Status bleibt über Updates erhalten
Konsolen-Widget
- Synchronisiert Plugins beim Laden
- Update-Prüfung mit 15-Minuten-Cache
- Warnungs-Badge + Weiterleitungs-URL zum Plugin Browser
- Gleiches Muster wie Game Mods Widget
Plugins aktivieren / deaktivieren
Mechanismus
Datei-Umbenennung über Lesen+Schreiben+Löschen (für Daemon-API-Kompatibilität):
| Aktion | Schritte | Beispiel |
|---|---|---|
| Deaktivieren | 1. Datei lesen 2. Als {name}-bak schreiben 3. Original löschen |
EssentialsX-2.20.jar → EssentialsX-2.20.jar-bak |
| Aktivieren | 1. -bak Datei lesen 2. Als Originalname schreiben 3. -bak löschen |
EssentialsX-2.20.jar-bak → EssentialsX-2.20.jar |
Hinweis: Drei Daemon-API-Aufrufe pro Umschaltung. Der Server muss möglicherweise vorher gestoppt werden.
Benachrichtigungen
| Aktion | Erfolg | Fehler |
|---|---|---|
| Deaktivieren | „Plugin disabled: [Name]" | „Disable failed" + Fehler |
| Aktivieren | „Plugin enabled: [Name]" | „Enable failed" + Fehler |
Plugins deinstallieren
Prozess
- Klicke Deinstallieren → Warnung bestätigen
- JAR-Datei wird aus
/plugins/gelöscht - Datenbankeintrag wird entfernt
- Benachrichtigung: „Plugin uninstalled"
- Server neustarten um vollständig zu entladen
Was NICHT entfernt wird
| Nicht entfernt | Beispiel | Aufräum-Methode |
|---|---|---|
| Konfigurationsdateien | plugins/Essentials/config.yml |
Dateimanager |
| Datendateien | plugins/LuckPerms/luckperms-*.db |
Dateimanager |
| Berechtigungen | Berechtigungsknoten in LuckPerms etc. | Berechtigungs-Plugin-UI |
| Weltdaten | Eigene Strukturen, Blöcke | Nicht umkehrbar |
Plugins-Ordner öffnen
Springt zu /plugins/ im Dateimanager. Nützlich für:
- Tatsächliche Dateien auf der Festplatte prüfen
- Manuelle Uploads
- Aufräumen von Konfigurationsverzeichnissen nach der Deinstallation
- Überprüfen von
-bakErweiterungen bei deaktivierten Plugins
ZIP-Export
Prozess
- Klicke Alle als ZIP herunterladen
- Benachrichtigung: „ZIP download started"
- Server komprimiert alle Dateien in
/plugins/ - JWT-signierte URL wird generiert (läuft nach 30 Minuten ab)
- Download startet automatisch
Enthält: Alle Plugins (aktive + deaktivierte)
Vollständige Fehlerreferenz
„Failed to read installed plugins"
/plugins/-Verzeichnis existiert nicht → Server einmal starten- Verzeichnis nicht lesbar → Daemon-Berechtigungen prüfen
- Festplatte voll
- Daemon-Verbindung verloren
„Failed to disable/enable plugin"
- Berechtigungen: Lesen + Schreiben + Löschen erforderlich auf
/plugins/ - Datei gesperrt: Laufender Server sperrt Dateien → Server zuerst stoppen
- Gleichzeitiger Zugriff: Backup oder Dateimanager greift gleichzeitig zu
- Datei nicht gefunden: Extern umbenannt oder gelöscht
- Daemon-Fehler: Jeder der 3 Schritte (Lesen/Schreiben/Löschen) kann fehlschlagen
„Failed to delete old versions"
- Alte Datei vom laufenden Server gesperrt → Server stoppen
- Dateiberechtigungsproblem
- Datei bereits manuell entfernt
Updates werden nicht angezeigt
- Update-Metadaten 24 Stunden gecacht → Cache leeren
'upload'Plugins werden immer übersprungen- Versionsvergleich ist zeichenkettenbasiert
- Anbieter hat Update möglicherweise noch nicht propagiert
„Uninstall failed"
- Datei bereits manuell gelöscht
- Datei vom Serverprozess gesperrt → Stoppen und erneut versuchen
- Daemon-Verbindungsproblem
Plugin lässt Server nach Installation abstürzen
- Konsolenausgabe / Crash-Report prüfen
- Plugin deaktivieren (nicht löschen!) + neustarten zur Bestätigung
- Sind alle Abhängigkeiten installiert?
- Plugin-Kompatibilität mit MC-Version/Server-Software prüfen
- Eine ältere stabile Version versuchen
- Java-Version prüfen (17 für MC 1.18+, 21 für MC 1.21+)
„Cache clear failed"
- Fehlerbenachrichtigung zeigt
$e->getMessage() - SafeCacheService
flush()konnte Schlüssel nicht entfernen storage/framework/cache/muss existieren und beschreibbar sein (0755)
„Cache health check failed"
- Warnung vom PluginManager geloggt
- Cache-Infrastruktur muss möglicherweise repariert werden
php artisan cache:clearals vollständiger Reset
Interne Provider-Funktionen (Referenz)
Dieser Abschnitt dokumentiert den internen PHP-Code für jede Provider-Integration, einschließlich API-Parameter, Antwort-Schemata, Rate-Limits und Verarbeitungslogik.
SpigotMC / Spiget Provider — Vollständige Referenz
API-Endpunkt-Parameter — GET /v2/search/resources/{query}
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
query |
string (Pfad) | Ja | — | Suchbegriff (URL-kodiert, im Pfad) |
size |
int | Nein | 10 | Ergebnisse pro Seite (max 100) |
page |
int | Nein | 1 | 1-basierte Seitennummer |
sort |
string | Nein | — | Sortierfeld, Präfix - für absteigend (z.B. -downloads) |
fields |
string | Nein | — | Komma-getrennte Feldnamen zur Einschränkung |
API-Endpunkt-Parameter — GET /v2/resources (Durchsuchen ohne Query)
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
size |
int | Nein | 10 | Ergebnisse pro Seite |
page |
int | Nein | 1 | Seitennummer |
sort |
string | Nein | -downloads |
Standard: nach meisten Downloads sortiert |
Antwort-Schema — Suchergebnisse
| Feld | Typ | Beschreibung |
|---|---|---|
[].id |
int | SpigotMC-Ressourcen-ID |
[].name |
string | Ressourcenname |
[].tag |
string | Kurzbeschreibung / Tagline |
[].downloads |
int | Gesamtzahl Downloads |
[].rating.average |
float | Durchschnittliche Bewertung (0–5) |
[].icon.url |
string | Relativer Icon-Pfad (Spiget-CDN voranstellen) |
[].testedVersions |
string[] | Als kompatibel gelistete MC-Versionen |
[].premium |
bool | True bei kostenpflichtiger Ressource |
[].external |
bool | True wenn außerhalb von SpigotMC gehostet |
[].updateDate |
int | Unix-Zeitstempel der letzten Aktualisierung |
[].releaseDate |
int | Unix-Zeitstempel der Erstveröffentlichung |
Header X-Total |
int | Gesamtanzahl passender Ressourcen (für Paginierung) |
Rate-Limits
| Stufe | Limit | Hinweise |
|---|---|---|
| Ohne Authentifizierung | ~600 Anfragen/10 Min pro IP | Spiget nutzt Sliding-Window |
| Bei Überschreitung | HTTP 429 | Kein Retry-After-Header, ~60s warten |
// SpigotMC-Ressourcen durchsuchen — mit Gesamtanzahl aus Header
$response = Http::timeout($timeout)
->get("https://api.spiget.org/v2/search/resources/{$query}", [
'size' => $perPage,
'page' => $page,
'sort' => '-downloads',
]);
// Gesamtanzahl steht im X-Total-Antwort-Header (nicht im JSON-Body!)
$total = (int) $response->header('X-Total');
// Antwortverarbeitung — wie Ressourcen in Plugin-Karten umgewandelt werden
$resources = $response->json();
$plugins = collect($resources)->map(function ($r) {
return [
'id' => $r['id'],
'name' => $r['name'],
'summary' => $r['tag'] ?? '',
'author' => '', // Spiget braucht separaten /resources/{id}/author-Aufruf
'downloads' => $r['downloads'] ?? 0,
'icon_url' => !empty($r['icon']['url'])
? "https://www.spigotmc.org/{$r['icon']['url']}"
: null,
'updated_at' => date('c', $r['updateDate'] ?? 0),
'versions' => $r['testedVersions'] ?? [],
'provider' => 'spiget',
'has_direct_download' => !($r['premium'] ?? false) && !($r['external'] ?? false),
];
});
// Download-Verfügbarkeitsprüfung — HEAD-Anfrage vor dem Download-Versuch
$check = Http::head("https://api.spiget.org/v2/resources/{$id}/download");
if ($check->status() !== 200) {
// Content-Type-Prüfung: JAR = direkter Download, HTML = Premium/extern
$contentType = $check->header('Content-Type');
if (str_contains($contentType, 'text/html')) {
$plugin['has_direct_download'] = false;
// Zeigt „Externe Ressource"- oder „Premium"-Badge
}
}
// Versionsliste abrufen mit Sortierung nach Veröffentlichungsdatum
$versions = Http::timeout($timeout)
->get("https://api.spiget.org/v2/resources/{$id}/versions", [
'size' => 20,
'sort' => '-releaseDate',
])->json();
// Jede Version: { id, uuid, name, releaseDate, downloads, rating }
// Kein Datei-Hash über die Spiget-API verfügbar
Spiget-spezifisches Verhalten:
- Ressourcen mit
premium: truekönnen nicht via API heruntergeladen werden — erfordert SpigotMC-Kauf - Externe Ressourcen (
external: true) liegen außerhalb von SpigotMC — Link manuell folgen - Icons verwenden
data/resource_icons/{id}/{id}.jpg-Format vom Spiget-CDN - Versionsfilterung prüft ob
testedVersionsdie gewünschte MC-Version enthält - Keine Abhängigkeitsauflösung — die Spiget-API liefert keine Abhängigkeitsdaten
- Autoreninfo benötigt separaten
GET /resources/{id}/author-Aufruf — Plugin führt dies verzögert aus
CurseForge Provider (Plugins) — Vollständige Referenz
Verwendet die gleiche CurseForge-API wie Game Mods, aber mit classId=5 (Bukkit Plugins). Die classId ist der entscheidende Unterschied.
API-Endpunkt-Parameter — GET /v1/mods/search
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
gameId |
int | Ja | 432 | Immer Minecraft für Plugins |
classId |
int | Ja | 5 | Bukkit Plugins (NICHT 9137, das sind Mods!) |
searchFilter |
string | Nein | — | Volltextsuche |
sortField |
int | Nein | 2 | 1=Featured (mit Query), 2=Beliebtheit (ohne) |
sortOrder |
string | Nein | desc |
Sortierrichtung |
gameVersion |
string | Nein | — | MC-Versionsfilter |
pageSize |
int | Nein | 20 | Max 50 |
index |
int | Nein | 0 | Paginierungs-Offset |
Antwort-Schema — Gleiche Struktur wie Game Mods CurseForge (siehe Game Mods-Dokumentation), wesentliche Unterschiede:
classId= 5 in allen Ergebnissencategories[].classIdentspricht Plugin-Kategorien, nicht Mod-KategorienlatestFilesIndexes[]kann Bukkit/Spigot/Paper-Kompatibilitätsmarkierungen enthalten
// Plugin-Suche — classId=5 ist der entscheidende Unterschied zu Mods (9137)
$response = Http::withHeaders(['x-api-key' => $apiKey])
->timeout($timeout)
->get('https://api.curseforge.com/v1/mods/search', [
'gameId' => 432, // Minecraft
'classId' => 5, // ⚠ Bukkit Plugins — NICHT 9137 (Mods)!
'searchFilter' => $query,
'sortField' => $query ? 1 : 2, // Dynamische Sortierung
'sortOrder' => 'desc',
'gameVersion' => $mcVersion,
'pageSize' => $perPage,
'index' => ($page - 1) * $perPage,
]);
// Antwortverarbeitung — gleiche Struktur wie Mods, classId unterscheidet sich
$results = $response->json('data', []);
$plugins = collect($results)->map(function ($mod) {
return [
'id' => $mod['id'],
'name' => $mod['name'],
'slug' => $mod['slug'],
'summary' => $mod['summary'],
'author' => $mod['authors'][0]['name'] ?? 'Unbekannt',
'downloads' => $mod['downloadCount'],
'icon_url' => $mod['logo']['url'] ?? null,
'provider' => 'curseforge',
];
});
// Rekursive Abhängigkeitsauflösung — gleiches Muster wie bei Game Mods
foreach ($file['dependencies'] as $dep) {
if ($dep['relationType'] === 3) { // Benötigte Abhängigkeit
$depPlugin = $this->fetchMod($dep['modId']);
$this->installPlugin($depPlugin); // Rekursiv
}
}
// Beschreibungsanreicherung — CurseForge kann leere Zusammenfassung liefern
if (empty($mod['summary'])) {
$html = Http::withHeaders(['x-api-key' => $apiKey])
->get("https://api.curseforge.com/v1/mods/{$mod['id']}/description")
->body();
// HTML wird zu Klartext umgewandelt, max 200 Zeichen
}
CurseForge Plugin Provider-Fehlertabelle
| Fehler / Log-Nachricht | Ursache | Auswirkung | Lösung |
|---|---|---|---|
classId=9137 Ergebnisse |
Code verwendet Mod-classId | Falscher Inhaltstyp | classId=5 für Plugins sicherstellen |
| Leere Beschreibung | Plugin hat keine CurseForge-Zusammenfassung | Fehlende Info | Anreicherungs-API-Aufruf füllt dies |
| Abhängigkeitsschleife | Zirkuläre relationType=3 |
Installation hängt | Auf Plugin-Seite melden |
downloadUrl null |
Autor hat Download eingeschränkt | Manueller Download nötig | Von CurseForge-Website herunterladen |
Modrinth Provider (Plugins) — Vollständige Referenz
API-Endpunkt-Parameter — GET /v2/search
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
query |
string | Nein | — | Suchbegriffe |
facets |
string (JSON) | Ja | siehe unten | Muss project_type:plugin enthalten |
limit |
int | Nein | 20 | Max 100 |
offset |
int | Nein | 0 | Paginierungs-Offset |
Plugin-spezifische Facetten
// Das Plugin baut diese Facetten speziell für Server-Plugins
$facets = [
['project_type:plugin'], // Muss Plugin sein, nicht Mod
['categories:paper', 'categories:spigot', // Serversoftware-Kompatibilität
'categories:bukkit', 'categories:purpur'], // ODER-verknüpft im inneren Array
];
if ($mcVersion) $facets[] = ["versions:$mcVersion"];
if ($loader) $facets[] = ["categories:$loader"]; // z.B. categories:paper
$params['facets'] = json_encode($facets);
Antwort-Schema — Gleiche Struktur wie Game Mods Modrinth (siehe Game Mods-Dokumentation), wesentliche Unterschiede:
hits[].project_type="plugin"(nicht"mod")hits[].categoriesenthält Servertypen wiebukkit,spigot,paper,purpurhits[].loaderslistet unterstützte Serverplattformen
// Antwortverarbeitung — identisch zu Mods, project_type unterscheidet sich
$hits = $response->json('hits', []);
$plugins = collect($hits)->map(function ($hit) {
return [
'id' => $hit['project_id'],
'name' => $hit['title'],
'slug' => $hit['slug'],
'summary' => $hit['description'],
'author' => $hit['author'],
'downloads' => $hit['downloads'],
'icon_url' => $hit['icon_url'] ?? null,
'versions' => $hit['versions'] ?? [],
'provider' => 'modrinth',
];
});
Modrinth Plugin Provider-Fehlertabelle
| Fehler / Log-Nachricht | Ursache | Auswirkung | Lösung |
|---|---|---|---|
Keine Ergebnisse mit project_type:plugin |
Plugin nicht korrekt auf Modrinth getaggt | Fehlende Plugins | Bei anderen Providern suchen |
| SHA-1-Abweichung | Download beschädigt | Integritätsprüfung schlägt fehl | Cache leeren, Download wiederholen |
Falsche project_type-Ergebnisse |
Facetten falsch konfiguriert | Mods mit Plugins vermischt | project_type:plugin-Facette sicherstellen |
PaperMC / Hangar Provider — Vollständige Referenz
API-Endpunkt-Parameter — GET /v1/projects
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
q |
string | Nein | — | Suchanfrage |
limit |
int | Nein | 25 | Ergebnisse pro Seite (max 25) |
offset |
int | Nein | 0 | Paginierungs-Offset |
sort |
string | Nein | -stars |
Sortierung: stars, downloads, views, newest, updated, recent (Präfix - für abst.) |
API-Endpunkt-Parameter — GET /v1/projects/{slug}/versions
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
slug |
string (Pfad) | Ja | — | Projekt-Slug (z.B. ViaVersion) |
limit |
int | Nein | 10 | Versionen pro Seite |
offset |
int | Nein | 0 | Paginierungs-Offset |
platform |
string | Nein | — | Filter: PAPER, VELOCITY, WATERFALL |
Antwort-Schema — Projektsuche
| Feld | Typ | Beschreibung |
|---|---|---|
result[].namespace.owner |
string | Benutzername des Projektbesitzers |
result[].namespace.slug |
string | Projekt-URL-Slug |
result[].name |
string | Anzeigename |
result[].description |
string | Kurzbeschreibung |
result[].stats.downloads |
int | Gesamtdownloads |
result[].stats.stars |
int | Sternebewertungen |
result[].stats.watchers |
int | Beobachter |
result[].avatarUrl |
string | Projekt-Icon-URL |
result[].lastUpdated |
string | ISO 8601 Zeitstempel |
pagination.count |
int | Gesamtergebnisse |
pagination.limit |
int | Seitengröße |
pagination.offset |
int | Aktueller Offset |
Antwort-Schema — Versionen
| Feld | Typ | Beschreibung |
|---|---|---|
result[].name |
string | Versions-Anzeigename |
result[].createdAt |
string | ISO 8601 Veröffentlichungsdatum |
result[].downloads.PAPER[].fileInfo.name |
string | JAR-Dateiname |
result[].downloads.PAPER[].fileInfo.sizeBytes |
int | Dateigröße |
result[].downloads.PAPER[].externalUrl |
string|null | Externer Download-Link (falls extern gehostet) |
result[].platformDependencies.PAPER |
string[] | MC-Versionsbereich (z.B. ["1.8-1.21"]) |
result[].pluginDependencies.PAPER[].name |
string | Namen benötigter Plugins |
// Projektsuche — mit Paginierung
$response = Http::timeout($timeout)
->get('https://hangar.papermc.io/api/v1/projects', [
'q' => $query,
'limit' => $perPage,
'offset' => ($page - 1) * $perPage,
]);
// Antwortverarbeitung
$results = $response->json('result', []);
$plugins = collect($results)->map(function ($project) {
return [
'id' => $project['namespace']['slug'], // owner/slug nicht nötig für Hangar
'name' => $project['name'],
'summary' => $project['description'],
'author' => $project['namespace']['owner'],
'downloads' => $project['stats']['downloads'] ?? 0,
'icon_url' => $project['avatarUrl'] ?? null,
'updated_at' => $project['lastUpdated'],
'provider' => 'hangar',
];
});
// Versionsliste mit Plattform-Priorität
$versions = Http::timeout($timeout)
->get("https://hangar.papermc.io/api/v1/projects/{$slug}/versions", [
'limit' => 20,
])->json('result', []);
// Plattform-Priorität: PAPER → VELOCITY → WATERFALL
// Jede Version hat platformDependencies mit MC-Versionsbereichen
foreach ($versions as $v) {
$mcVersions = $v['platformDependencies']['PAPER'] ?? [];
// Gibt z.B. ["1.8-1.21"] zurück — bedeutet 1.8 bis 1.21 unterstützt
// Prüfung auf externe URL — manche Plugins verlinken zu GitHub/Jenkins
if (!empty($v['downloads']['PAPER'][0]['externalUrl'])) {
$plugin['requires_manual_download'] = true;
}
}
Hangar-spezifisches Verhalten:
- Version-agnostisch: Filtert NICHT nach spezifischer MC-Version — zeigt alle Versionen für alle Plattformen
- Projekte verwenden
namespace.owner/namespace.slug-Format (z.B.ViaVersion/ViaVersion) externalUrlin Downloads → Plugin wird alsrequires_manual_downloadmarkiert- Statistiken umfassen
downloads,stars,watchers— für Sortierungsranking verwendet - Plugin-Abhängigkeiten in
pluginDependencies.PAPER[].name— nur informativ (nicht automatisch aufgelöst) - MC-Versionsfilter ist in der UI ausgeblendet für Hangar, da serverseitige Filterung nicht unterstützt wird
Hangar Provider-Fehlertabelle
| Fehler / Log-Nachricht | Ursache | Auswirkung | Lösung |
|---|---|---|---|
| Keine Ergebnisse | Suchanfrage zu spezifisch oder keine Hangar-Plugins passen | Leere Seite | Kürzere Suchbegriffe verwenden |
| „Version nicht gefunden" | Projekt von Hangar entfernt | Download schlägt fehl | Projekt wurde vom Autor entfernt |
| Falsche Plattform-Version | Version für VELOCITY statt PAPER | Inkompatible JAR | platformDependencies vor Download prüfen |
| Externe URL-Weiterleitung | Plugin auf GitHub/Jenkins gehostet | Automatische Installation nicht möglich | Manuell von externer URL herunterladen |
| CDN-Timeout | Hangar-Download-Server langsam | Download schlägt fehl | Timeout erhöhen, später erneut versuchen |
GeyserMC Provider — Vollständige Referenz
API-Endpunkt-Parameter — GET /v2/projects
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
| (keine) | — | — | — | Gibt alle Projektnamen zurück (immer 6) |
API-Endpunkt-Parameter — GET /v2/projects/{project}/versions/latest/builds/latest
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
project |
string (Pfad) | Ja | — | Einer der 6 Projektnamen |
Die 6 GeyserMC-Projekte
| Projekt | Beschreibung | Primärer Download-Key |
|---|---|---|
geyser |
Bedrock-zu-Java-Brücke | spigot |
floodgate |
Bedrock-Kontoverknüpfung | spigot |
hurricane |
Performance-Verbesserung | spigot |
geyserconnect |
Multi-Server-Verbinder | standalone |
thirdpartycosmetics |
Bedrock-Kosmetik-Unterstützung | spigot |
emoteoffhand |
Emote-Offhand-Fix | spigot |
Antwort-Schema — Neuestes Build
| Feld | Typ | Beschreibung |
|---|---|---|
build |
int | Build-Nummer |
version |
string | Versionsstring (z.B. 2.4.0) |
downloads.{platform}.name |
string | JAR-Dateiname (z.B. Geyser-Spigot.jar) |
downloads.{platform}.sha256 |
string | SHA-256-Hash zur Integritätsprüfung |
changes[].commit |
string | Commit-Hash |
changes[].summary |
string | Commit-Nachricht |
// Alle GeyserMC-Projekte auflisten (gibt immer die gleichen 6 zurück)
$projects = Http::timeout($timeout)
->get('https://download.geysermc.org/v2/projects')
->json();
// ["geyser","floodgate","hurricane","geyserconnect","thirdpartycosmetics","emoteoffhand"]
// Neuestes Build mit plattformspezifischen Downloads abrufen
$build = Http::timeout($timeout)
->get("https://download.geysermc.org/v2/projects/{$project}/versions/latest/builds/latest")
->json();
// Antwortverarbeitung — Versions-ID wird aus Version + Build zusammengesetzt
$versionId = $build['version'] . '-' . $build['build']; // z.B. "2.4.0-670"
// Download-Key-Auflösung — Plattform hängt vom Projekt ab
$downloadKey = match ($project) {
'geyserconnect' => 'standalone',
default => 'spigot', // Paper/Spigot-Server verwenden 'spigot'-Key
};
$jarName = $build['downloads'][$downloadKey]['name']; // "Geyser-Spigot.jar"
$sha256 = $build['downloads'][$downloadKey]['sha256']; // Integritäts-Hash
$url = "https://download.geysermc.org/v2/projects/{$project}/versions/{$build['version']}/builds/{$build['build']}/downloads/{$downloadKey}";
// GeyserMC spezieller Download — umgeht pull(), nutzt cURL direkt
// Dies liegt daran, dass GeyserMC-URLs spezielle User-Agent-Behandlung erfordern
$tmpFile = tempnam(sys_get_temp_dir(), 'geyser_');
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => false,
CURLOPT_FILE => fopen($tmpFile, 'w'),
CURLOPT_TIMEOUT => 60,
CURLOPT_FOLLOWLOCATION => true,
]);
curl_exec($ch);
curl_close($ch);
// Datei wird dann via Daemon putContent() geschrieben
$this->fileRepository->putContent("/plugins/{$jarName}", file_get_contents($tmpFile));
unlink($tmpFile);
GeyserMC-spezifisches Verhalten:
- Keine Suche — zeigt immer alle 6 Projekte in einer festen Liste
- Version-agnostisch — zeigt immer das neueste Build, keine MC-Versionsfilterung
- SHA-256-Prüfsummen für jeden Download verfügbar — zur Integritätsprüfung verwendet
- Download-URLs:
https://download.geysermc.org/v2/projects/{project}/versions/{ver}/builds/{build}/downloads/{platform} - Verfügbare Plattformen variieren je Projekt:
spigot,bungee,standalone,velocity,fabric - 24-Stunden-Metadaten-Cache für Build-Informationen
- Verwendet Base64-SVG-Insel-Icon für alle Projekte (fest kodiert, nicht aus der API)
- Fest kodierte Download-Zahlen angezeigt (nicht live abgefragt)
- MC-Versionsfilter ist in der UI ausgeblendet für GeyserMC (irrelevant)
GeyserMC Provider-Fehlertabelle
| Fehler / Log-Nachricht | Ursache | Auswirkung | Lösung |
|---|---|---|---|
| Nur 6 Projekte angezeigt | Erwartet — GeyserMC hat genau 6 | Kein Fehler | Normaler Betrieb |
| „Build nicht gefunden" | GeyserMC Build-Server-Problem | Neueste Version nicht ermittelbar | Später erneut versuchen, download.geysermc.org prüfen |
| Falsches Platform-JAR | Falscher downloadKey gewählt |
Inkompatible JAR installiert | spigot für Spigot/Paper-Server wählen |
| SHA-256-Abweichung | Download bei Übertragung beschädigt | Integritätsprüfung schlägt fehl | Erneut herunterladen, Netzwerkstabilität prüfen |
| Alte Version installiert | 24-Stunden-Metadaten-Cache | Zeigt veraltetes Build | Cache leeren für sofortige Update-Prüfung |
| cURL-Download fehlgeschlagen | Temp-Datei-Schreibfehler oder Timeout | Keine JAR heruntergeladen | Temp-Verzeichnis-Schreibrechte prüfen, Timeout erhöhen |
GeyserMC download failed: {message} |
Beliebiger Fehler in der Download-Pipeline | Installation schlägt fehl | Server-Logs auf spezifischen Fehler prüfen |
Such-Wiederholungslogik
Wenn die initiale Suche mit Versionsfilter 0 Ergebnisse liefert, wiederholt das Plugin automatisch ohne Versionsfilter. Dies hilft wenn eine bestimmte MC-Version noch nicht beim Provider indiziert ist.
// Automatische Fallback-Suche — gilt für alle durchsuchbaren Provider
$results = $this->search($query, $mcVersion, $loader);
if (empty($results) && $mcVersion) {
// Wiederholung ohne Versionsfilter — Version evtl. noch nicht indiziert
$results = $this->search($query, null, $loader);
// Benutzer sieht alle Versionen, kann Kompatibilität manuell prüfen
}
Providerübergreifende Muster
// Deaktivieren/Aktivieren — in -bak-Namen schreiben, dann Original löschen (Daemon-Kompatibilität)
// Nutzt 3 Schritte: Lesen → neuen Namen schreiben → alten löschen
// KEIN einfaches Umbenennen — Pterodactyl-Daemon unterstützt kein atomares Rename
$content = $this->fileRepository->getContent("/plugins/{$filename}");
$this->fileRepository->putContent("/plugins/{$filename}-bak", $content);
$this->fileRepository->delete("/plugins/{$filename}");
// Update-bei-Deaktivierung — merkt sich deaktivierten Zustand über Updates hinweg
$wasDisabled = $plugin->is_disabled;
$this->updatePlugin($plugin); // Installiert neue Version
if ($wasDisabled) {
$this->disablePlugin($plugin); // Nach Update erneut deaktivieren
}
Vollständige Benachrichtigungs-Referenz
| Ereignis | Typ | Titel | Nachricht |
|---|---|---|---|
| Version erkannt | Erfolg | Erkennung | „Minecraft-Version erkannt: X.X.X" |
| Version nicht erkannt | Warnung | Erkennung | „Minecraft-Version konnte nicht erkannt werden" |
| Installation gestartet | Info | Installation | „Plugin-Installation gestartet" |
| Installation erfolgreich | Erfolg | Installiert | „Plugin erfolgreich installiert" (geloggt) |
| Installation fehlgeschlagen | Fehler | Fehler | „Installation fehlgeschlagen" + Fehlerdetail |
| Abhängigkeiten | Info | Abhängigkeiten | „X zusätzliche Plugins werden installiert…" |
| Plugin deaktiviert | Erfolg | Deaktiviert | „Plugin deaktiviert: [Name]" |
| Plugin aktiviert | Erfolg | Aktiviert | „Plugin aktiviert: [Name]" |
| Deaktivierung fehlgeschlagen | Fehler | Fehler | „Deaktivierung fehlgeschlagen" + Fehler |
| Aktivierung fehlgeschlagen | Fehler | Fehler | „Aktivierung fehlgeschlagen" + Fehler |
| Plugin deinstalliert | Erfolg | Entfernt | „Plugin deinstalliert" |
| Deinstallation fehlgeschlagen | Fehler | Fehler | Fehlerdetail |
| Cache geleert | Erfolg | Cache | „Cache geleert" + Scan-Ergebnisse |
| Cache-Fehler | Fehler | Fehler | „Fehler beim Cache leeren" + $e->getMessage() |
| ZIP gestartet | Info | Export | „ZIP-Download gestartet" |
| ZIP fehlgeschlagen | Fehler | Export | „ZIP-Download fehlgeschlagen" |
| CurseForge-Key fehlt | Warnung | Konfiguration | „CurseForge API-Schlüssel nicht gesetzt" |
| Externe Ressource | Warnung | Download | „Externe Ressource — manuell herunterladen" |
| Premium-Ressource | Warnung | Download | „Premium-Ressource — Kauf erforderlich" |
| Dateiname nicht erkannt | Warnung | Installation | „Dateiname konnte nicht ermittelt werden" (geloggt) |
| JAR-Metadaten-Fehler | Warnung | Installation | „Plugin-Name konnte nicht aus JAR extrahiert werden" (geloggt) |
HTTP-Fehlercode-Referenz (Alle Provider)
| HTTP-Status | Quelle | Bedeutung | Maßnahme |
|---|---|---|---|
| 200 | Alle | Erfolg | — |
| 400 | CurseForge/Spiget | Ungültige Anfrage | Game-ID, Class-ID, Query-Format prüfen |
| 401 | CurseForge | API-Key ungültig | Key auf console.curseforge.com erneuern |
| 403 | CurseForge | Fehlende Berechtigungen | Key neu generieren |
| 403 | Plugin | Feature-Flag plugins fehlt |
["plugins"] zu Egg-Features hinzufügen |
| 404 | Alle Provider | Ressource nicht gefunden | ID/Slug prüfen oder Ressource wurde entfernt |
| 404 | Spiget | Version nicht gefunden | Ressource wurde möglicherweise vom Autor gelöscht |
| 429 | CurseForge | Rate-Limit | 60s warten, Cache-Dauer erhöhen |
| 429 | Spiget | Rate-Limit | Häufigkeit reduzieren, 60s warten |
| 500 | Alle | Serverfehler | Später erneut versuchen |
| 502/503 | Alle | Gateway/Wartung | Provider offline |
| 0 / Timeout | Alle | Verbindungs-Timeout | MODS_REQUEST_TIMEOUT erhöhen, DNS/Firewall prüfen |
Provider-spezifische Fehlertabelle
SpigotMC / Spiget Fehler
| Fehler / Symptom | Ursache | Lösung |
|---|---|---|
| Kein Download-Button | Premium-Ressource | Zuerst auf SpigotMC-Website kaufen |
| „Externe Ressource"-Label | Plugin extern gehostet | Link zur externen Seite folgen |
| Keine Versionen aufgelistet | Sehr alte/inaktive Ressource | Manuellen Upload im Dateimanager nutzen |
| Langsame Suche | Spiget-API unter Last | Timeout erhöhen, erneut versuchen |
| Fehlendes Icon | Kein Icon für Ressource hochgeladen | Kosmetisch — Plugin funktioniert einwandfrei |
| HEAD-Prüfung schlägt fehl | Spiget-CDN-Timeout | Erneut versuchen, Verbindung prüfen |
Hangar Fehler
| Fehler / Symptom | Ursache | Lösung |
|---|---|---|
| Keine Ergebnisse | Suchanfrage zu spezifisch | Kürzere/breitere Begriffe verwenden |
| „Version nicht gefunden" | Hangar-Projekt entfernt | Projekt wurde möglicherweise ausgelistet |
| Falsche Plattform | Version für falschen Servertyp | platformDependencies prüfen (PAPER vs WATERFALL) |
| Download fehlgeschlagen | CDN-Timeout | Erneut versuchen, Timeout erhöhen |
| Leere Statistiken | Neues Projekt | Noch keine Downloads erfasst |
GeyserMC Fehler
| Fehler / Symptom | Ursache | Lösung |
|---|---|---|
| Nur 6 Projekte angezeigt | Erwartet — GeyserMC hat genau 6 | Kein Fehler |
| „Build nicht gefunden" | GeyserMC Build-Server-Problem | Später erneut versuchen |
| Falsches Platform-JAR | Falsche Download-Plattform gewählt | spigot für Spigot/Paper-Server wählen |
| SHA-256-Abweichung | Download beschädigt | Erneut herunterladen, Verbindung prüfen |
| Alte Version installiert | Versions-Cache beträgt 24h | Cache leeren für sofortige Update-Prüfung |