Aller au contenu principal

MySQL

Stockage MySQL ou PostgreSQL partagé pour les faits et artefacts, avec synchronisation Redis, présence et registre de serveurs.

Privéesv0.0.1Utilitaires
NécessiteTypeWriter0.9.0-beta-177 (BTC build)MySQL 8+ or PostgreSQLRedis or Valkeyfacultatif

Conçue pour le réseau BornToCraft. Cette extension est documentée à titre de référence et n'est pas distribuée.

Vue d'ensemble​

L'extension MySQL est le pont qui permet à plusieurs serveurs TypeWriter de partager les mêmes données. Lorsque vous l'activez, les facts (progression des joueurs) et les artefacts (fichiers de données créés par d'autres extensions) ne sont plus conservés dans des fichiers sous plugins/Typewriter/. Ils sont stockés dans une base de données MySQL ou PostgreSQL que chaque serveur de votre réseau lit et écrit.

Elle gère aussi la connexion facultative à Redis (ou Valkey). Redis transporte les notifications de changement instantanées, le registre « sur quel serveur se trouve ce joueur », et les messages utilisés par les extensions sociales (Friend, Party, Guild) et par Ghost. Plusieurs autres extensions BTC lisent leurs paramètres, leur mode de jeu et le nom du serveur depuis cette extension.

Cette extension n'a pas d'entrées : vous la configurez avec un fichier et, facultativement, depuis le panel web BTC.

Fonctionnalités​

  • Stockage en base de données — facts et artefacts dans MySQL 8 ou PostgreSQL, avec création automatique des tables et un pool de connexions.
  • Sûr par défaut — lorsque le stockage partagé est demandé et ne peut pas être atteint, le serveur s'arrête au lieu de jouer silencieusement sur des fichiers locaux.
  • Modes de jeu — données séparées par mode de jeu (survie, skyblock, mini-jeux) dans la même base de données.
  • Synchronisation entre serveurs — les changements sont repris par les autres serveurs en quelques secondes, instantanément avec Redis.
  • Redis et Valkey — messagerie pub/sub, présence des joueurs à l'échelle du réseau et transferts de joueurs via le proxy.
  • Règles de stockage par extension — choisissez quelles extensions utilisent la base de données, et si leurs données sont par profil et partagées entre modes de jeu.
  • Migration au premier démarrage — les facts et fichiers d'assets existants sont copiés dans la base de données lorsqu'elle est vide.
  • Registre des serveurs — chaque serveur signale son état (TPS, joueurs, mémoire, extensions) toutes les 30 secondes.
  • Secrets depuis l'environnement — n'importe quel paramètre peut être lu depuis une variable d'environnement.
  • Prise en charge du panneau d'administration — santé des serveurs, modes de jeu, export de données et navigation dans les tables pour le panel web BTC.

Installation​

  1. Créez une base de données vide et un utilisateur pour elle sur MySQL 8 ou plus récent, ou sur PostgreSQL. L'utilisateur doit avoir le droit de créer et de modifier des tables.
  2. Facultatif, pour plusieurs serveurs : lancez un serveur Redis ou Valkey que chaque backend peut atteindre.
  3. Placez le JAR de MySQL dans plugins/Typewriter/extensions/ et redémarrez une fois. Le fichier plugins/Typewriter/mysql/config.yml est créé.
  4. Modifiez le fichier comme décrit dans Premiers pas, puis redémarrez. Les pilotes de base de données, le pool de connexions et le client Redis sont inclus dans l'extension.

Premiers pas​

Faites passer un serveur sur une base de données partagée :

  1. Arrêtez le serveur et ouvrez plugins/Typewriter/mysql/config.yml.
  2. Sous mysql, renseignez host, port, database, username et password. Pour PostgreSQL, ajoutez aussi database-type: "POSTGRESQL" et utilisez le port 5432.
  3. Définissez mysql.game-mode.current sur le mode de jeu de ce serveur, par exemple survival. Les serveurs qui doivent partager des facts ont besoin de la même valeur.
  4. Définissez mysql.enabled: true.
  5. Pour un réseau, activez Redis : redis.enabled: true, avec host, port et password, un redis.server-name unique par serveur et le même redis.group-id sur tous les serveurs qui vont ensemble.
  6. Démarrez le serveur. Le journal affiche « Database storage initialized ». Les facts et fichiers existants sont copiés dans la base de données lorsqu'elle est encore vide (voir Migration).
  7. Répétez l'opération sur les autres serveurs avec leur propre server-name.
Choisissez enabled en connaissance de cause

Avec mysql.enabled: false, un serveur stocke tout dans ses propres fichiers. C'est acceptable pour un serveur permanent unique, mais si son répertoire est recréé à partir d'un modèle au démarrage, les données sont écrites dans un dossier qui n'existera plus la prochaine fois, et rien ne vous avertit. Avec mysql.enabled: true, un serveur qui ne peut pas atteindre la base de données s'arrête plutôt que de servir des joueurs sur des fichiers locaux.

Fonctionnement​

Au démarrage, l'extension remplace le stockage par fichiers de TypeWriter par le stockage en base de données, avant que toute autre extension ne lise ses données. TypeWriter garde les facts en mémoire et écrit les changements dans la base de données par petits lots. Les autres serveurs lisent les changements qu'ils n'ont pas encore vus en interrogeant périodiquement la base de données, et Redis les prévient immédiatement lorsque quelque chose change. Lorsqu'un joueur quitte ou est expulsé, ses facts en attente sont écrits immédiatement.

La base de données ne stocke que ce qui a changé. Un fact supprimé est stocké sous forme de ligne avec la valeur 0 (une pierre tombale), pour que les autres serveurs apprennent la suppression au lieu de réenregistrer l'ancienne valeur. Les pierres tombales plus anciennes que fact-tombstone-retention-days sont purgées au démarrage.

Configuration​

Le fichier est plugins/Typewriter/mysql/config.yml. La plupart des sections sont facultatives : toute clé manquante prend sa valeur par défaut.

Base de données​

CléPar défautSignification
mysql.enabledfalseUtiliser la base de données. Lorsque true, le serveur s'arrête si la base de données est inaccessible ou si un paramètre est incomplet.
mysql.database-typeMYSQLMYSQL ou POSTGRESQL. Absent du fichier généré, ajoutez-le si nécessaire.
mysql.host, mysql.portlocalhost, 3306Adresse de la base de données. Utilisez 5432 pour PostgreSQL.
mysql.databasetypewriterNom de la base de données.
mysql.username, mysql.passwordtypewriter, videIdentifiants.
mysql.use-sslfalseUtiliser SSL (require pour PostgreSQL).
mysql.allow-public-key-retrievaltrueMySQL uniquement.
mysql.table-prefixbtc_Préfixe des tables créées par cette extension. Les caractères autres que lettres, chiffres et _ deviennent _, et le préfixe est mis en minuscules.
mysql.migrate-from-filestrueCopie les fichiers d'assets existants dans la base de données lorsque la table des assets est vide.
mysql.fact-tombstone-retention-days30Jours avant la purge des lignes de suppression. Doit être supérieur à la durée pendant laquelle un serveur reste hors ligne.
mysql.sync-interval-seconds30Lu mais non utilisé dans cette version : l'intervalle d'interrogation est défini par TypeWriter lui-même.
mysql.pool.*voir ci-dessousPool de connexions.
mysql.game-mode.currentdefaultMode de jeu de ce serveur.

Les clés du pool sont maximum-pool-size (10), minimum-idle (2), connection-timeout (30000 ms), max-lifetime (1800000 ms), validation-timeout (5000 ms) et keepalive-time (0, désactivé).

Variables d'environnement​

Toute valeur égale exactement à ${env:NAME} est lue depuis la variable d'environnement NAME au chargement du fichier :

mysql:
password: ${env:BTC_TYPEWRITER_DB_PASSWORD}

Une valeur numérique ou booléenne (par exemple un port) est lue avec le bon type. Une variable non définie ou vide arrête le serveur avec un message nommant la variable. Seules les valeurs entières sont prises en charge, pas le texte qui contient simplement ${env:...}.

Redis et Valkey​

CléPar défautSignification
redis.enabledfalseSe connecter à Redis ou Valkey. Fonctionne même lorsque mysql.enabled vaut false.
redis.typeredisredis ou valkey. Les deux utilisent le même protocole.
redis.host, redis.portlocalhost, 6379Adresse du serveur.
redis.username, redis.passwordvideIdentifiants. Le nom d'utilisateur default ou un nom vide est traité comme l'absence de nom d'utilisateur.
redis.channeltypewriter:eventsCanal pub/sub partagé par tous les serveurs.
redis.server-namesurvival dans le code, server1 dans le fichier généréNom unique de ce serveur. C'est aussi le nom de serveur du proxy utilisé pour les transferts.
redis.group-idvideGroupe réseau de ce serveur. Lettres, chiffres, ., _, -, jusqu'à 64 caractères. Vide signifie isolé.

Le group-id délimite chaque fonctionnalité qui communique entre serveurs : les messages sociaux, les fantômes et les listes réseau ne circulent qu'entre serveurs ayant le même identifiant de groupe non vide. Les serveurs ayant un groupe différent ne se voient pas.

Stockage par extension​

Sous mysql.extensions.<name>, chaque entrée a trois clés :

  • enabled — indique si l'extension stocke ses propres données dans la base de données.
  • profile-mode — shared (un seul jeu de données pour tous les profils) ou per-profile.
  • network-mode — shared (les mêmes données dans tous les modes de jeu) ou isolated (un jeu par mode de jeu).

Le fichier généré liste des valeurs par défaut pour profiles, cosmetics, party, battlepass, translate et d'autres. Ces paramètres sont lus par les extensions qui les prennent en charge, par exemple Profiles. Ils n'affectent pas les facts et artefacts propres à TypeWriter, qui vont toujours dans la base de données lorsque mysql.enabled vaut true.

Les paramètres sont résolus dans cet ordre : l'entrée dans config.yml, puis la ligne de la table <prefix>game_mode_extensions pour le mode de jeu actuel. Au démarrage, chaque extension chargée y reçoit une ligne, désactivée, en attendant qu'un administrateur l'active. Les noms de clés sont normalisés : TypeWriter-ProfilesExtension et profiles sont identiques, et friends est un alias de party.

Section Profiles​

La section profiles du même fichier configure l'extension Profiles : 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 et creation-menu-entry-id. Voir cette page pour leur signification.

Ce qui est stocké​

TableContenu
<prefix>factsFacts de chaque joueur et groupe : identifiant d'entrée, identifiant de groupe, mode de jeu, valeur, dernière mise à jour.
<prefix>assetsArtefacts et autres assets (texte ou binaire), par chemin et mode de jeu.
<prefix>game_modesModes de jeu connus du réseau.
<prefix>game_mode_extensionsRègles de stockage par mode de jeu et par extension.
<prefix>server_extensions, <prefix>extension_entry_filtersParamètres de synchronisation par serveur et par entrée.
serversRegistre des serveurs en cours d'exécution. Son nom n'a pas de préfixe.

D'autres extensions BTC créent leurs propres tables dans la même base de données, par exemple btc_guild_bank pour la banque de Guild et typewriter_profiles pour Profiles. Les noms de tables et de colonnes sont créés automatiquement et les colonnes manquantes sont ajoutées au démarrage.

Chaque ligne de fact et d'asset porte un mode de jeu. Un serveur ne lit et n'écrit que les lignes de son propre mysql.game-mode.current (et les lignes marquées global) : deux modes de jeu ne partagent donc jamais de facts ni d'artefacts, même dans la même base de données.

Synchronisation entre serveurs​

Données. Sans Redis, les serveurs convergent tout de même : chacun interroge la base de données pour les changements faits par les autres. Avec Redis, un serveur qui écrit des facts publie un court avis, et les autres se synchronisent immédiatement. Faites fonctionner tous les serveurs dans le même fuseau horaire, car les horodatages des facts sont stockés à l'heure locale de chaque serveur.

Messages sociaux. Friend, Party et Guild publient leurs changements sous forme de messages JSON sur le canal Redis. Un serveur ignore ses propres messages. Ils ne sont envoyés que lorsque Redis est connecté et que redis.group-id n'est pas vide.

Présence. Chaque serveur écrit presence:<player name> dans Redis pour chaque joueur en ligne, avec une expiration de 120 secondes rafraîchie toutes les 50 secondes et supprimée lorsque le joueur quitte. Des fonctionnalités comme « se téléporter vers un ami » le lisent pour trouver le serveur du joueur.

Transferts. Pour déplacer un joueur vers un autre serveur, l'extension interroge le proxy via le canal de plugin standard BungeeCord, et pour les déplacements à l'échelle du cluster via le canal btc:bridge compris par le proxy BTC. Le redis.server-name de chaque serveur doit correspondre au nom de serveur connu du proxy.

Reconnexion. Si Redis tombe, la publication tente de se reconnecter, et l'abonné réessaie jusqu'à 10 fois avec un délai croissant (de 5 secondes à 5 minutes).

Migration​

La première fois qu'un mode de jeu est démarré avec mysql.enabled: true :

  • Si la table des facts ne contient aucun fact pour ce mode de jeu, les facts actuellement en mémoire (issus des fichiers locaux) sont copiés dans la base de données. Sinon, les facts sont chargés depuis la base de données et les facts locaux sont ignorés.
  • Si mysql.migrate-from-files vaut true et que la table des assets est vide pour ce mode de jeu, les fichiers de plugins/Typewriter/assets/ y sont copiés.

Conservez une sauvegarde de plugins/Typewriter/ avant le premier démarrage. Revenir aux fichiers revient à définir mysql.enabled: false : le contenu de la base de données n'est pas recopié.

Panneau d'administration​

L'extension répond aux requêtes de gestion du panel web BTC : lister les serveurs et leur santé (TPS, joueurs, mémoire, extensions installées, latence Redis, statistiques du pool), créer et supprimer des modes de jeu, activer des extensions par mode de jeu, exporter, importer et migrer les données d'un mode de jeu, parcourir et modifier les tables de stockage, et lire les journaux récents de la base de données. Chaque requête vérifie une permission de la personne qui utilise le panneau et est limitée en fréquence.

Permissions​

Ces permissions sont vérifiées pour l'utilisateur du panel web. Elles ne sont pas enregistrées avec une valeur par défaut : accordez-les donc aux administrateurs.

PermissionAutorise
typewriter.admin.server.listVoir les serveurs, modes de jeu, stockage, tables et extensions découvertes.
typewriter.admin.server.healthVoir les contrôles de santé et les journaux de la base de données.
typewriter.admin.server.deregisterRetirer un serveur du registre.
typewriter.admin.gamemode.createCréer et supprimer des modes de jeu.
typewriter.admin.gamemode.configureModifier les paramètres des extensions, les filtres d'entrées et les remplacements de stockage, importer, exporter et migrer des données, modifier des lignes de tables.

Exploitation​

  • Rechargement. Publier config_update sur le canal Redis fait recharger mysql/config.yml à chaque serveur et enregistrer les nouvelles extensions. En fonctionnement normal, le fichier n'est lu qu'une fois au démarrage.
  • Registre des serveurs. La table servers est rafraîchie toutes les 30 secondes. Les entrées de plus de 60 secondes sont considérées comme hors ligne et supprimées au démarrage, et un serveur se retire lui-même à l'arrêt de la JVM.
  • Interblocages. Les lots de facts sont retentés jusqu'à 3 fois lorsque MySQL signale un interblocage.
  • Sauvegardes. Sauvegardez les tables <prefix>facts et <prefix>assets. Comme une suppression est une ligne avec la valeur 0, une sauvegarde restaurée plus ancienne que la rétention des pierres tombales peut faire revenir des facts supprimés.
  • Mises à jour. Mettez à jour le JAR sur tous les serveurs dans la même fenêtre de redémarrage. Le schéma est mis à niveau sur place au démarrage.

Dépannage​

Le serveur s'arrête au démarrage avec « Refusing to serve players on local file storage. » mysql.enabled vaut true et la base de données est inaccessible ou une valeur est incomplète. Lisez la ligne précédente : le message SEVERE nomme user@host:port/database et l'erreur. Corrigez les identifiants, le réseau ou la base de données, ou définissez mysql.enabled: false si ce serveur doit utiliser des fichiers.

« Configuration incomplete: environment variable(s) X are referenced ... but are not set. » Une valeur ${env:X} n'a pas de variable d'environnement correspondante et non vide dans le processus du serveur. Définissez-la dans la définition du service, et pas seulement dans votre shell.

Les facts ne sont pas partagés entre deux serveurs. Vérifiez que les deux ont mysql.enabled: true, la même base de données et le même mysql.game-mode.current. Des modes de jeu différents stockent des facts séparés. Sans Redis, un changement peut mettre jusqu'à l'intervalle d'interrogation pour apparaître.

Les amis, groupes, guildes ou fantômes ne passent pas d'un serveur à l'autre. Redis doit être activé et connecté, redis.group-id doit être défini sur la même valeur non vide sur chaque serveur, et redis.server-name doit être unique par serveur. Avec un identifiant de groupe vide, les messages sociaux ne sont pas envoyés.

Le journal affiche « Failed to connect to Redis ». Vérifiez l'hôte, le port, le nom d'utilisateur et le mot de passe. Un mot de passe Redis requirepass nécessite redis.password. L'extension continue de fonctionner sans Redis, en s'appuyant uniquement sur l'interrogation périodique.

Une extension ne stocke pas ses données dans la base de données. Les extensions découvertes au démarrage sont enregistrées désactivées. Activez l'extension sous mysql.extensions dans config.yml, ou dans le panneau d'administration, puis redémarrez.

Les facts d'un joueur supprimé ou un fact supprimé reviennent. Un serveur est resté hors ligne plus longtemps que fact-tombstone-retention-days et a réenregistré d'anciennes données. Augmentez la rétention et évitez de restaurer d'anciennes copies d'un serveur.

« HikariPool ... connection is not available » ou délais d'attente dépassés. Le pool est épuisé. Augmentez mysql.pool.maximum-pool-size (et la limite de connexions de la base de données elle-même), et recherchez des requêtes lentes sur le serveur de base de données.

Les horodatages semblent erronés ou des changements sont manqués. Les serveurs qui partagent une base de données fonctionnent dans des fuseaux horaires différents. Alignez-les.

Extensions associées​

  • Profiles — utilise la section profiles, ainsi que les règles de stockage des profils et des modes de jeu.
  • Friend, Party, Guild — fonctionnalités sociales synchronisées via Redis.
  • Ghost — affiche les joueurs des autres serveurs, en utilisant la connexion Redis.
  • Translate, Rewards, BattlePass — extensions qui dépendent de celle-ci.