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:
Antone Barbaud
2026-06-09 16:06:19 +02:00
parent f92f22f6c8
commit 4651ccbe69
5 changed files with 242 additions and 1 deletions
+115 -1
View File
@@ -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.