docs: document MessagesService — single per-plugin YAML, defaults in jar
features.md: new section 8 "Service de messages" with the single-file model, two-layer in-memory (jar defaults + user file), API examples, template-override mechanism, and override-the-impl extension point. Bootstrap section renumbered to 9. decisions.md: new decision logging the choice of MessagesService design (YAML, single per-plugin file, in-jar fallback for new keys, template priority from the game plugin's own resource, programmatic set() for dynamic cases). README.md: feature list mentions externalized messages; diagrams index adds messages-class-diagram.puml. setup.md: new "Fichier messages" section explaining the file location, how to seed it from a game plugin's bundled template, and the API for hot reload / extras / programmatic set(). New diagram: docs/diagrams/messages-class-diagram.puml — MessagesService interface, YamlMessagesService impl, link to CRCore, with explanatory note on the two-source merge and template fallback at first boot. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+115
-1
@@ -570,7 +570,121 @@ la hook.
|
||||
|
||||
---
|
||||
|
||||
## 8. Bootstrap `CRCore`
|
||||
## 8. Service de messages (`fr.luc.crcore.message`)
|
||||
|
||||
**Statut** : implémenté. Toutes les commandes built-in `/core team ...` passent
|
||||
par ce service ; plus rien n'est hardcodé dans le code.
|
||||
|
||||
### Modèle « un seul fichier par plugin »
|
||||
|
||||
Au premier démarrage, CR-Core crée **un seul fichier** dans le dataFolder du
|
||||
plugin de jeu :
|
||||
|
||||
```
|
||||
<plugin-dataFolder>/<plugin-name-lowercase>-messages.yml
|
||||
```
|
||||
|
||||
(par exemple `cites-messages.yml` si le plugin s'appelle `Cites`.) C'est *le*
|
||||
fichier que l'admin du serveur édite. Pas de `crcore-messages.yml` séparé sur
|
||||
disque — les defaults CR-Core vivent dans le jar et sont chargés en mémoire
|
||||
comme couche de fallback.
|
||||
|
||||
### Deux couches en mémoire
|
||||
|
||||
| Ordre | Source | Mutabilité |
|
||||
|---|---|---|
|
||||
| 1 | `crcore-messages.yml` embarqué dans le jar CR-Core | Read-only, in-memory |
|
||||
| 2 | `<plugin>-messages.yml` dans le dataFolder | Lecture du disque |
|
||||
|
||||
La couche 2 écrase la couche 1 sur les clés communes. Une clé manquante dans
|
||||
le fichier user **retombe automatiquement** sur le default CR-Core. Si une
|
||||
future release CR-Core ajoute une nouvelle clé, l'admin n'a rien à faire — ça
|
||||
marche immédiatement.
|
||||
|
||||
### Création du fichier user au premier démarrage
|
||||
|
||||
L'ordre de priorité pour générer le starter file :
|
||||
|
||||
1. Si le plugin de jeu **bundle son propre** `<plugin-name-lowercase>-messages.yml`
|
||||
dans ses ressources → c'est ce fichier qui devient le template (donc tu peux
|
||||
pré-remplir avec tes overrides + tes messages perso au build).
|
||||
2. Sinon → copie des defaults CR-Core comme starter (l'admin voit toutes les
|
||||
clés CR-Core et peut les éditer).
|
||||
|
||||
### API `MessagesService`
|
||||
|
||||
```java
|
||||
// Lecture avec placeholders nommés
|
||||
core.messages().get("team.create.success",
|
||||
"name", team.getName(),
|
||||
"tag", team.getTag(),
|
||||
"visibility", team.getVisibility().name());
|
||||
// → "&aÉquipe Wolves [#WOLF] créée (PRIVATE, sans chef)." (codes & déjà traduits)
|
||||
|
||||
// Lecture brute (sans substitution ni couleur)
|
||||
core.messages().raw("team.create.success");
|
||||
|
||||
// Ajout/override programmatique en mémoire (non persisté)
|
||||
core.messages().set("mygame.welcome", "&aBienvenue {player} !");
|
||||
|
||||
// Charge un fichier YAML additionnel (en plus du fichier user principal)
|
||||
core.messages().loadAdditional("my-extras.yml");
|
||||
|
||||
// Hot reload (relit le fichier user, garde les defaults en mémoire)
|
||||
core.messages().reload();
|
||||
|
||||
// Toggle codes couleur
|
||||
core.messages().setApplyColorCodes(true); // défaut
|
||||
|
||||
// Chemin du fichier user (informationnel)
|
||||
File path = core.messages().getUserFile();
|
||||
```
|
||||
|
||||
### Placeholders
|
||||
|
||||
Format `{name}` avec substitution via varargs paire-par-paire. Codes couleur
|
||||
Bukkit `&a`, `&c`, `&7`, `&f`, etc. traduits automatiquement en `§…`.
|
||||
|
||||
### Clés manquantes
|
||||
|
||||
Si une clé n'existe ni dans le fichier user ni dans les defaults,
|
||||
`messages.get(...)` renvoie `[missing: key]` pour rendre visible la clé qu'il
|
||||
manque (debug facile).
|
||||
|
||||
### Override côté plugin de jeu
|
||||
|
||||
**Option 1 — Bundler son propre template** dans les ressources du plugin de
|
||||
jeu, fichier nommé `<plugin-name-lowercase>-messages.yml`. À la première
|
||||
exécution, ce fichier sert de starter dans le dataFolder.
|
||||
|
||||
**Option 2 — Éditer le fichier généré** après premier démarrage. Le YAML
|
||||
contient déjà les clés CR-Core ; ajoute / modifie / supprime ce que tu veux.
|
||||
|
||||
**Option 3 — Override programmatique** :
|
||||
```java
|
||||
core.messages().set("team.create.success", "Custom format for {name}");
|
||||
```
|
||||
|
||||
### Override de l'impl
|
||||
|
||||
`CRCore.buildMessagesService()` est `protected`. Sous-classe CRCore et
|
||||
redéfinis-la pour une impl custom (ex. messages venant d'une base de données,
|
||||
d'un microservice de traduction, etc.).
|
||||
|
||||
### Fichier `crcore-messages.yml` — référence
|
||||
|
||||
~25 clés organisées en sections : `common.*` (no-permission, player-only, …),
|
||||
`team.create.*`, `team.delete.success`, `team.add.*`, etc. Voir le fichier
|
||||
dans `src/main/resources/crcore-messages.yml` pour la liste complète avec les
|
||||
placeholders documentés en commentaire.
|
||||
|
||||
### Diagramme
|
||||
|
||||
- Classes : [messages-class-diagram.puml](diagrams/messages-class-diagram.puml)
|
||||
|
||||
---
|
||||
|
||||
## 9. Bootstrap `CRCore`
|
||||
|
||||
**Statut** : implémenté. Point d'entrée unique pour les plugins de jeu.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user