Zum Hauptinhalt springen

MySQL

Gemeinsamer MySQL- oder PostgreSQL-Speicher für Fakten und Artefakte, mit Redis-Synchronisierung, Präsenz und Server-Register.

Privatv0.0.1Hilfsmittel
BenötigtTypeWriter0.9.0-beta-177 (BTC build)MySQL 8+ or PostgreSQLRedis or Valkeyoptional

Für das BornToCraft-Netzwerk entwickelt. Diese Erweiterung ist zu Referenzzwecken dokumentiert und wird nicht verteilt.

Überblick​

Die MySQL-Erweiterung ist die Brücke, über die mehrere TypeWriter-Server dieselben Daten teilen. Wenn du sie aktivierst, werden die Facts (Spielerfortschritt) und die Artifacts (von anderen Erweiterungen erstellte Datendateien) nicht mehr in Dateien unter plugins/Typewriter/ gehalten. Sie werden in einer MySQL- oder PostgreSQL-Datenbank gespeichert, die jeder Server deines Netzwerks liest und beschreibt.

Sie besitzt außerdem die optionale Redis-Verbindung (oder Valkey). Redis transportiert sofortige Änderungsbenachrichtigungen, das Register „auf welchem Server ist dieser Spieler“ und die Nachrichten der sozialen Erweiterungen (Friend, Party, Guild) und von Ghost. Mehrere andere BTC-Erweiterungen lesen ihre Einstellungen, ihren Spielmodus und ihren Servernamen aus dieser Erweiterung.

Diese Erweiterung hat keine Entries: Du konfigurierst sie mit einer Datei und optional über das BTC-Web-Panel.

Funktionen​

  • Datenbankspeicherung — Facts und Artifacts in MySQL 8 oder PostgreSQL, mit automatischer Tabellenerstellung und einem Verbindungspool.
  • Standardmäßig sicher — wenn gemeinsamer Speicher angefordert wird und nicht erreichbar ist, stoppt der Server, statt stillschweigend auf lokalen Dateien weiterzuspielen.
  • Spielmodi — getrennte Daten pro Spielmodus (Survival, Skyblock, Minispiele) in derselben Datenbank.
  • Serverübergreifende Synchronisierung — Änderungen werden von anderen Servern innerhalb von Sekunden übernommen, mit Redis sofort.
  • Redis und Valkey — Pub/Sub-Messaging, netzwerkweite Spielerpräsenz und Spielertransfers über den Proxy.
  • Speicherregeln pro Erweiterung — wähle, welche Erweiterungen die Datenbank nutzen und ob ihre Daten pro Profil gelten und über Spielmodi hinweg geteilt werden.
  • Migration beim ersten Start — vorhandene Facts und Asset-Dateien werden in die Datenbank kopiert, wenn sie leer ist.
  • Server-Register — jeder Server meldet seinen Status (TPS, Spieler, Speicher, Erweiterungen) alle 30 Sekunden.
  • Geheimnisse aus der Umgebung — jede Einstellung kann aus einer Umgebungsvariablen gelesen werden.
  • Unterstützung des Administrationspanels — Serverzustand, Spielmodi, Datenexport und Tabellenansicht für das BTC-Web-Panel.

Installation​

  1. Erstelle auf MySQL 8 oder neuer oder auf PostgreSQL eine leere Datenbank und einen Benutzer dafür. Der Benutzer benötigt das Recht, Tabellen zu erstellen und zu ändern.
  2. Optional, für mehrere Server: Betreibe einen Redis- oder Valkey-Server, den jedes Backend erreichen kann.
  3. Lege die MySQL-JAR in plugins/Typewriter/extensions/ ab und starte einmal neu. Die Datei plugins/Typewriter/mysql/config.yml wird erstellt.
  4. Bearbeite die Datei wie unter Erste Schritte beschrieben und starte dann neu. Die Datenbanktreiber, der Verbindungspool und der Redis-Client sind in der Erweiterung enthalten.

Erste Schritte​

So stellst du einen Server auf eine gemeinsame Datenbank um:

  1. Stoppe den Server und öffne plugins/Typewriter/mysql/config.yml.
  2. Fülle unter mysql host, port, database, username und password. Füge für PostgreSQL außerdem database-type: "POSTGRESQL" hinzu und verwende Port 5432.
  3. Setze mysql.game-mode.current auf den Spielmodus dieses Servers, zum Beispiel survival. Server, die Facts teilen sollen, benötigen denselben Wert.
  4. Setze mysql.enabled: true.
  5. Aktiviere für ein Netzwerk Redis: redis.enabled: true, mit host, port und password, einem eindeutigen redis.server-name pro Server und derselben redis.group-id auf allen Servern, die zusammengehören.
  6. Starte den Server. Das Log zeigt „Database storage initialized“. Vorhandene Facts und Dateien werden in die Datenbank kopiert, wenn sie noch leer ist (siehe Migration).
  7. Wiederhole das auf den anderen Servern mit ihrem eigenen server-name.
Wähle enabled bewusst

Bei mysql.enabled: false speichert ein Server alles in seinen eigenen Dateien. Das ist für einen dauerhaften Server in Ordnung, aber wird sein Verzeichnis beim Start aus einer Vorlage neu erstellt, werden die Daten in einen Ordner geschrieben, den es beim nächsten Mal nicht mehr gibt, und nichts warnt dich. Bei mysql.enabled: true fährt ein Server, der die Datenbank nicht erreichen kann, herunter, statt Spieler auf lokalen Dateien zu bedienen.

So funktioniert es​

Beim Start ersetzt die Erweiterung die Dateispeicherung von TypeWriter durch die Datenbankspeicherung, bevor eine andere Erweiterung ihre Daten liest. TypeWriter hält Facts im Speicher und schreibt die Änderungen in kleinen Stapeln in die Datenbank. Andere Server lesen die Änderungen, die sie noch nicht gesehen haben, durch Abfragen der Datenbank, und Redis teilt ihnen sofort mit, wenn sich etwas geändert hat. Wenn ein Spieler den Server verlässt oder gekickt wird, werden seine ausstehenden Facts sofort geschrieben.

Die Datenbank speichert nur, was sich geändert hat. Ein gelöschter Fact wird als Zeile mit dem Wert 0 gespeichert (ein Tombstone), damit andere Server von der Löschung erfahren, statt den alten Wert erneut zu speichern. Tombstones, die älter als fact-tombstone-retention-days sind, werden beim Start bereinigt.

Konfiguration​

Die Datei ist plugins/Typewriter/mysql/config.yml. Die meisten Abschnitte sind optional: Jeder fehlende Key übernimmt seinen Standardwert.

Datenbank​

KeyStandardBedeutung
mysql.enabledfalseDie Datenbank verwenden. Bei true stoppt der Server, wenn die Datenbank nicht erreichbar ist oder eine Einstellung unvollständig ist.
mysql.database-typeMYSQLMYSQL oder POSTGRESQL. Nicht in der generierten Datei, füge es bei Bedarf hinzu.
mysql.host, mysql.portlocalhost, 3306Datenbankadresse. Verwende 5432 für PostgreSQL.
mysql.databasetypewriterDatenbankname.
mysql.username, mysql.passwordtypewriter, leerZugangsdaten.
mysql.use-sslfalseSSL verwenden (require bei PostgreSQL).
mysql.allow-public-key-retrievaltrueNur MySQL.
mysql.table-prefixbtc_Präfix der von dieser Erweiterung erstellten Tabellen. Zeichen außer Buchstaben, Ziffern und _ werden zu _, und das Präfix wird kleingeschrieben.
mysql.migrate-from-filestrueVorhandene Asset-Dateien in die Datenbank kopieren, wenn die Asset-Tabelle leer ist.
mysql.fact-tombstone-retention-days30Tage, bevor Löschzeilen bereinigt werden. Muss länger sein als die Zeit, die ein Server offline bleibt.
mysql.sync-interval-seconds30Wird gelesen, in dieser Version aber nicht verwendet: Das Abfrageintervall legt TypeWriter selbst fest.
mysql.pool.*siehe untenVerbindungspool.
mysql.game-mode.currentdefaultSpielmodus dieses Servers.

Die Pool-Keys sind maximum-pool-size (10), minimum-idle (2), connection-timeout (30000 ms), max-lifetime (1800000 ms), validation-timeout (5000 ms) und keepalive-time (0, deaktiviert).

Umgebungsvariablen​

Jeder Wert, der genau ${env:NAME} lautet, wird beim Laden der Datei aus der Umgebungsvariablen NAME gelesen:

mysql:
password: ${env:BTC_TYPEWRITER_DB_PASSWORD}

Ein numerischer oder boolescher Wert (zum Beispiel ein Port) wird mit dem richtigen Typ gelesen. Eine nicht gesetzte oder leere Variable stoppt den Server mit einer Meldung, die die Variable nennt. Es werden nur ganze Werte unterstützt, nicht Text, der lediglich ${env:...} enthält.

Redis und Valkey​

KeyStandardBedeutung
redis.enabledfalseMit Redis oder Valkey verbinden. Funktioniert auch, wenn mysql.enabled false ist.
redis.typeredisredis oder valkey. Beide verwenden dasselbe Protokoll.
redis.host, redis.portlocalhost, 6379Serveradresse.
redis.username, redis.passwordleerZugangsdaten. Der Benutzername default oder ein leerer gilt als kein Benutzername.
redis.channeltypewriter:eventsVon allen Servern gemeinsam genutzter Pub/Sub-Kanal.
redis.server-namesurvival im Code, server1 in der generierten DateiEindeutiger Name dieses Servers. Er ist auch der für Transfers verwendete Proxy-Servername.
redis.group-idleerNetzwerkgruppe dieses Servers. Buchstaben, Ziffern, ., _, -, bis zu 64 Zeichen. Leer bedeutet isoliert.

Die group-id begrenzt jede Funktion, die zwischen Servern kommuniziert: Soziale Nachrichten, Ghosts und Netzwerklisten wandern nur zwischen Servern mit derselben, nicht leeren Gruppen-ID. Server mit einer anderen Gruppe sehen sich nicht.

Speicherung pro Erweiterung​

Unter mysql.extensions.<name> hat jeder Eintrag drei Keys:

  • enabled — ob die Erweiterung ihre eigenen Daten in der Datenbank speichert.
  • profile-mode — shared (ein Datensatz für alle Profile) oder per-profile.
  • network-mode — shared (dieselben Daten in jedem Spielmodus) oder isolated (ein Satz pro Spielmodus).

Die generierte Datei listet Standardwerte für Profiles, Cosmetics, Party, BattlePass, Translate und weitere auf. Diese Einstellungen werden von den Erweiterungen gelesen, die sie unterstützen, zum Beispiel Profiles. Sie wirken sich nicht auf die eigenen Facts und Artifacts von TypeWriter aus, die immer in die Datenbank gehen, wenn mysql.enabled true ist.

Einstellungen werden in dieser Reihenfolge aufgelöst: der Eintrag in config.yml, dann die Zeile der Tabelle <prefix>game_mode_extensions für den aktuellen Spielmodus. Beim Start erhält jede geladene Erweiterung dort eine Zeile, deaktiviert, die darauf wartet, dass ein Administrator sie aktiviert. Key-Namen werden normalisiert: TypeWriter-ProfilesExtension und profiles sind dasselbe, und friends ist ein Alias für party.

Abschnitt profiles​

Der Abschnitt profiles derselben Datei konfiguriert die Profiles-Erweiterung: enabled, max-profiles, default-profile-name, save-statistics, save-inventory, save-ender-chest, require-permission, auto-create-default, force-profile-selection, switch-cooldown-seconds, coop-supported und creation-menu-entry-id. Ihre Bedeutung findest du auf der dortigen Seite.

Was gespeichert wird​

TabelleInhalt
<prefix>factsFacts jedes Spielers und jeder Gruppe: Entry-ID, Gruppen-ID, Spielmodus, Wert, letzte Aktualisierung.
<prefix>assetsArtifacts und andere Assets (Text oder binär), nach Pfad und Spielmodus.
<prefix>game_modesDem Netzwerk bekannte Spielmodi.
<prefix>game_mode_extensionsSpeicherregeln pro Spielmodus und Erweiterung.
<prefix>server_extensions, <prefix>extension_entry_filtersSynchronisierungseinstellungen pro Server und pro Entry.
serversRegister der laufenden Server. Sein Name hat kein Präfix.

Andere BTC-Erweiterungen erstellen ihre eigenen Tabellen in derselben Datenbank, zum Beispiel btc_guild_bank für die Guild-Bank und typewriter_profiles für Profiles. Tabellen- und Spaltennamen werden automatisch erstellt, und fehlende Spalten werden beim Start hinzugefügt.

Jede Fact- und Asset-Zeile trägt einen Spielmodus. Ein Server liest und schreibt nur die Zeilen seines eigenen mysql.game-mode.current (und als global markierte Zeilen), sodass zwei Spielmodi auch in derselben Datenbank nie Facts oder Artifacts teilen.

Serverübergreifende Synchronisierung​

Daten. Ohne Redis konvergieren die Server dennoch: Jeder fragt die Datenbank nach Änderungen der anderen ab. Mit Redis veröffentlicht ein Server, der Facts schreibt, eine kurze Meldung, und die anderen synchronisieren sofort. Betreibe alle Server in derselben Zeitzone, denn Fact-Zeitstempel werden in der lokalen Zeit jedes Servers gespeichert.

Soziale Nachrichten. Friend, Party und Guild veröffentlichen ihre Änderungen als JSON-Nachrichten auf dem Redis-Kanal. Ein Server ignoriert seine eigenen Nachrichten. Sie werden nur gesendet, wenn Redis verbunden und redis.group-id nicht leer ist.

Präsenz. Jeder Server schreibt für jeden Online-Spieler presence:<player name> in Redis, mit 120 Sekunden Ablaufzeit, alle 50 Sekunden erneuert und entfernt, wenn der Spieler geht. Funktionen wie „zu einem Freund teleportieren“ lesen sie, um den Server des Spielers zu finden.

Transfers. Um einen Spieler auf einen anderen Server zu verschieben, fragt die Erweiterung den Proxy über den Standard-Plugin-Kanal BungeeCord, und für clusterweite Verschiebungen über den vom BTC-Proxy verstandenen Kanal btc:bridge. Der redis.server-name jedes Servers muss dem dem Proxy bekannten Servernamen entsprechen.

Wiederverbindung. Fällt Redis aus, versucht das Veröffentlichen, sich wieder zu verbinden, und der Subscriber versucht es bis zu 10 Mal mit wachsender Verzögerung (5 Sekunden bis 5 Minuten).

Migration​

Wenn ein Spielmodus zum ersten Mal mit mysql.enabled: true gestartet wird:

  • Enthält die Fact-Tabelle keine Facts für diesen Spielmodus, werden die aktuell im Speicher befindlichen Facts (aus den lokalen Dateien) in die Datenbank kopiert. Andernfalls werden die Facts aus der Datenbank geladen, und die lokalen werden ignoriert.
  • Ist mysql.migrate-from-files true und die Asset-Tabelle für diesen Spielmodus leer, werden die Dateien von plugins/Typewriter/assets/ dorthin kopiert.

Bewahre vor dem ersten Start eine Sicherung von plugins/Typewriter/ auf. Zurück zu Dateien bedeutet, mysql.enabled: false zu setzen: Der Datenbankinhalt wird nicht zurückkopiert.

Administrationspanel​

Die Erweiterung beantwortet Verwaltungsanfragen aus dem BTC-Web-Panel: Server und ihren Zustand auflisten (TPS, Spieler, Speicher, installierte Erweiterungen, Redis-Latenz, Pool-Statistiken), Spielmodi erstellen und löschen, Erweiterungen pro Spielmodus aktivieren, die Daten eines Spielmodus exportieren, importieren und migrieren, die Speichertabellen ansehen und bearbeiten und aktuelle Datenbank-Logs lesen. Jede Anfrage prüft eine Berechtigung der Person, die das Panel nutzt, und ist ratenbegrenzt.

Berechtigungen​

Diese Berechtigungen werden für den Web-Panel-Benutzer geprüft. Sie sind ohne Standardwert registriert, vergib sie also an Administratoren.

BerechtigungErlaubt
typewriter.admin.server.listServer, Spielmodi, Speicher, Tabellen und gefundene Erweiterungen ansehen.
typewriter.admin.server.healthZustandsprüfungen und Datenbank-Logs ansehen.
typewriter.admin.server.deregisterEinen Server aus dem Register entfernen.
typewriter.admin.gamemode.createSpielmodi erstellen und löschen.
typewriter.admin.gamemode.configureErweiterungseinstellungen, Entry-Filter und Speicher-Überschreibungen ändern, Daten importieren, exportieren und migrieren, Tabellenzeilen bearbeiten.

Betrieb​

  • Reload. Das Veröffentlichen von config_update auf dem Redis-Kanal lässt jeden Server mysql/config.yml neu laden und neue Erweiterungen registrieren. Im Normalbetrieb wird die Datei einmal beim Start gelesen.
  • Server-Register. Die Tabelle servers wird alle 30 Sekunden aktualisiert. Einträge, die älter als 60 Sekunden sind, gelten als offline und werden beim Start entfernt, und ein Server entfernt sich selbst, wenn die JVM stoppt.
  • Deadlocks. Fact-Stapel werden bis zu 3 Mal wiederholt, wenn MySQL einen Deadlock meldet.
  • Sicherungen. Sichere die Tabellen <prefix>facts und <prefix>assets. Da eine Löschung eine Zeile mit dem Wert 0 ist, kann eine wiederhergestellte Sicherung, die älter als die Tombstone-Aufbewahrung ist, gelöschte Facts zurückbringen.
  • Updates. Aktualisiere die JAR auf allen Servern im selben Neustartfenster. Das Schema wird beim Start direkt aktualisiert.

Fehlerbehebung​

Der Server stoppt beim Start mit „Refusing to serve players on local file storage.“ mysql.enabled ist true und die Datenbank ist nicht erreichbar oder ein Wert ist unvollständig. Lies die Zeile davor: Die SEVERE-Meldung nennt user@host:port/database und den Fehler. Korrigiere die Zugangsdaten, das Netzwerk oder die Datenbank oder setze mysql.enabled: false, wenn dieser Server Dateien verwenden soll.

„Configuration incomplete: environment variable(s) X are referenced ... but are not set.“ Ein ${env:X}-Wert hat im Serverprozess keine passende, nicht leere Umgebungsvariable. Setze sie in der Dienstdefinition, nicht nur in deiner Shell.

Facts werden zwischen zwei Servern nicht geteilt. Prüfe, ob beide mysql.enabled: true, dieselbe Datenbank und dasselbe mysql.game-mode.current haben. Unterschiedliche Spielmodi speichern getrennte Facts. Ohne Redis kann es bis zum Abfrageintervall dauern, bis eine Änderung erscheint.

Freunde, Parties, Gilden oder Ghosts überschreiten keine Servergrenzen. Redis muss aktiviert und verbunden sein, redis.group-id muss auf jedem Server auf denselben nicht leeren Wert gesetzt sein, und redis.server-name muss pro Server eindeutig sein. Bei leerer Gruppen-ID werden soziale Nachrichten nicht gesendet.

Das Log zeigt „Failed to connect to Redis“. Prüfe Host, Port, Benutzername und Passwort. Ein Redis-Passwort aus requirepass benötigt redis.password. Die Erweiterung arbeitet ohne Redis weiter, nur mit Abfragen.

Eine Erweiterung speichert ihre Daten nicht in der Datenbank. Beim Start gefundene Erweiterungen werden deaktiviert registriert. Aktiviere die Erweiterung unter mysql.extensions in config.yml oder im Administrationspanel und starte dann neu.

Facts eines gelöschten Spielers oder ein gelöschter Fact kommen zurück. Ein Server war länger als fact-tombstone-retention-days offline und hat alte Daten erneut gespeichert. Erhöhe die Aufbewahrung und vermeide es, alte Kopien eines Servers wiederherzustellen.

„HikariPool ... connection is not available“ oder Timeouts. Der Pool ist erschöpft. Erhöhe mysql.pool.maximum-pool-size (und das eigene Verbindungslimit der Datenbank) und suche auf dem Datenbankserver nach langsamen Abfragen.

Zeitstempel wirken falsch oder Änderungen werden verpasst. Server, die sich eine Datenbank teilen, laufen in verschiedenen Zeitzonen. Gleiche sie an.

Verwandte Erweiterungen​

  • Profiles — nutzt den Abschnitt profiles und die Speicherregeln für Profile und Spielmodi.
  • Friend, Party, Guild — über Redis synchronisierte soziale Funktionen.
  • Ghost — zeigt Spieler anderer Server, über die Redis-Verbindung.
  • Translate, Rewards, BattlePass — Erweiterungen, die von dieser abhängen.