JuByteNexus – Modul-SDK-Referenz

Das Nexus Module SDK (net.jubyte.nexus.sdk) ist der einzige Vertrag zwischen einem Modul und dem Core. Module greifen nie direkt auf fremde Module oder Core-Tabellen zu – nur über Events und die SPI-Schnittstellen Einstieg: Dein erstes eigenes Modul.

Lifecycle

@Component
@NexusModule(id = "mymodule", name = "My Module", version = "1.0.0",
             description = "…", premium = false)
public class MyModule implements NexusModuleLifecycle {
    @Override public void onEnable(NexusModuleContext ctx) {
        ctx.registerPermission("mymodule.view", "Ansehen");
        ctx.declareConfig(ConfigOption.integer("limit", 10, "Max. Einträge"));
        ctx.subscribe("player.join", e -> { /* … */ });
    }
    @Override public void onDisable() { /* Ressourcen freigeben */ }
}

@NexusModule: id (stabil, lowercase – Lizenz-/Routing-Schlüssel), name, version, description, premium (Lizenz-Gate). Premium-Module werden vor dem Aktivieren gegen den License-Gate geprüft.

NexusModuleContext

Das Fenster des Moduls in den Core (in onEnable):

MethodeZweck
registerPermission(key, desc)Feingranulare Permission = zugleich API-Scope (z. B. bansystem.ban.create)
publish(NexusEvent)Event auf den Bus legen
subscribe(typePattern, handler)Events abonnieren (Trailing-* als Wildcard); wird beim Disable entfernt
declareConfig(ConfigOption)Config-Option deklarieren – der Core rendert die ACP-Settings-UI daraus
config(key, default) · configForServer(key, default, server)Wert lesen (Server-Scope: Server → Gruppe → Global → Default)
configBool/Int(...) (+ …ForServer)Typisierte Lesehelfer
logger()System.Logger mit Modul-Namen

Events

NexusEvent ist unveränderlich: type (punktsepariert, z. B. ban.created), data (Map<String,Object>, nur JSON-serialisierbar), at (Instant).

ctx.publish(NexusEvent.of("myevent.fired", Map.of("playerId", id.toString(), "value", 42)));

Abonnieren deklarativ per Methode:

@Subscribe("player.*")           // Trailing-* = Wildcard, "*" = alles
public void onPlayer(NexusEvent e) { … }

EventBus.matches(pattern, type) prüft das Pattern; subscribe(...) liefert eine Subscription zum Abmelden.

Config-Optionen

ConfigOption-Typen: STRING, INT, BOOL, SELECT, SECRET, TEXT, COLOR, DURATION. Factories:

ConfigOption.string(key, default, desc);
ConfigOption.integer(key, default, desc);
ConfigOption.bool(key, default, desc);
ConfigOption.secret(key, default, desc);        // wird in der API nie zurück-geechot
ConfigOption.select(key, default, desc, "A", "B");
ConfigOption.text/color/duration(key, default, desc);

Jeder Default muss produktionssicher sein (leeres Setup muss laufen).

Sicherheit

@RequiresPermission("key") auf Controller-Methoden erzwingt serverseitig die Permission (== API-Scope). Der authentifizierte Aufrufer ist @AuthenticationPrincipal NexusPrincipal mit userId, email, permissions und hasPermission(key) (unterstützt * und Trailing-Wildcards).

SPIs (vom Core implementiert, von Modulen konsumiert)

PlayerDirectory — read-only Spiel-Identitäten

byId · byGameId · byName · byAccount · playtimeSeconds · sessionCount · storedSkinUrl. PlayerInfo{id, game, gameId, name, online, accountId}.

PlayerActions — Live-Aktionen (Fire-and-Forget; false = offline/keine Bridge)

kick(id, reason) · message(id, msg) · broadcast(msg) · executeCommand(id, cmd).

AccountDirectory — read-only Web-Konten

byId · byEmail · withPermission(perm). AccountInfo{id, email, displayName}.

Module nutzen diese SPIs statt direktem Tabellenzugriff – so bleiben die Modul-Grenzen sauber und der Core kann seine Interna ändern.