feat: typed team settings (cascade per-team → global → default) + in-game GUI

New fr.luc.crcore.team.config module:
- TeamSetting<T> (typed, with key/type/default/parser/serializer; factories
  ofBoolean/ofInt/ofString/ofEnum).
- TeamSettings registry: 8 standard settings (FRIENDLY_FIRE,
  PVP_PROTECTION_SECONDS, MAX_SIZE, MIN_SIZE, RESPAWN_AT_TEAM_SPAWN,
  TEAM_CHAT_ENABLED, SHOW_TAG_ABOVE_HEAD, TEAM_COLOR_IN_NAME), extensible
  via register() for game plugins.
- TeamConfigService interface with cascade get(team, setting) →
  per-team override (SQLite) → global YAML → hard default. Persists per-
  team via TeamRepository.save(), global via YamlConfiguration.save().
- YamlTeamConfigService default impl with bundled crcore-team-config.yml.

Storage:
- Team.getSettings() Map<String, Object> for per-team overrides.
- New SQLite table crcore_team_settings (team_id, key, value, type) with
  load + write-through persist in SqliteTeamRepository.
- Global YAML <plugin>-team-config.yml in dataFolder, auto-created at
  first boot (template from game plugin's resource of the same name
  takes priority).

New reusable GUI framework fr.luc.crcore.gui:
- AbstractInventoryGui (implements InventoryHolder, rebuild() abstract,
  setButton/setDecoration/clearSlot helpers, onClose hook, openTo()).
- GuiClickHandler FunctionalInterface.
- GuiListener (single Bukkit listener, detects via getHolder(), ALWAYS
  cancels clicks even on slots without handlers).
- GuiItems builder (named/of/filler + lore/amount/build, '&' color codes
  translated).

Concrete settings GUIs (fr.luc.crcore.team.config.gui):
- AbstractSettingsGui base renderer: 27 slots, settings in row 2,
  booleans = LIME_DYE / GRAY_DYE toggle, integers = BOOK with left +1 /
  right -1 (shift × 10), strings/enums display-only.
- GlobalSettingsGui: writes to YAML on each change.
- TeamSettingsGui: writes to per-team overrides, "override active" flag
  in lore when value differs from global, "Reset all overrides" footer
  button.

New /core team settings [team] subcommand:
- No arg → GlobalSettingsGui (perm crcore.team.settings.global).
- With arg → TeamSettingsGui (perm crcore.team.settings).
- Player-only (Bukkit needs HumanEntity to open inventory).
- Lives under /core team to stay modular (objective: split into modules
  later; everything team-related under /core team).

CRCore: buildTeamConfigService() override point, teamConfig()/getTeamConfig()
getters, GuiListener.registerOn(plugin) at enable(). CoreCommand,
TeamGroupSubCommand and CoreReloadSubCommand extended to receive
TeamConfigService. /core reload now reloads messages + broadcasts +
team-config.

Docs: new section 10 "Paramètres d'équipe", new decisions logged,
setup.md tree updated, two new diagrams (team-config + gui).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Antone Barbaud
2026-06-10 11:46:51 +02:00
parent a94bc56a5b
commit 75d2fa866d
25 changed files with 1686 additions and 26 deletions
+114 -1
View File
@@ -807,7 +807,120 @@ depuis les fichiers user du dataFolder. Les defaults en jar ne bougent pas
---
## 10. Bootstrap `CRCore`
## 10. Paramètres d'équipe (`fr.luc.crcore.team.config`)
**Statut** : implémenté. 8 settings standards + GUI in-game + cascade
per-team → global → default.
### Modèle de résolution
```
1. hard default défini en code dans TeamSettings (constantes)
2. global config <plugin>-team-config.yml ← admin via GUI ou YAML
3. per-team override table SQLite crcore_team_settings ← admin via GUI
```
`config.get(team, setting)` cascade per-team → global → default.
`config.getGlobal(setting)` cascade global → default (skip per-team).
Toutes les valeurs retournées sont **non-null** grâce au default en bout
de chaîne.
### Settings standards (`TeamSettings`)
| Constante | Clé YAML/SQL | Type | Défaut |
|---|---|---|---|
| `FRIENDLY_FIRE` | `friendly_fire` | bool | `false` |
| `PVP_PROTECTION_SECONDS` | `pvp_protection_seconds` | int | `0` |
| `MAX_SIZE` | `max_size` | int | `0` (illimité) |
| `MIN_SIZE` | `min_size` | int | `0` |
| `RESPAWN_AT_TEAM_SPAWN` | `respawn_at_team_spawn` | bool | `true` |
| `TEAM_CHAT_ENABLED` | `team_chat_enabled` | bool | `true` |
| `SHOW_TAG_ABOVE_HEAD` | `show_tag_above_head` | bool | `true` |
| `TEAM_COLOR_IN_NAME` | `team_color_in_name` | bool | `true` |
CR-Core fournit les défauts ; **c'est au plugin de jeu d'appliquer ces
settings** dans sa logique (ex. écouter `EntityDamageByEntityEvent` et
checker `config.get(team, FRIENDLY_FIRE)` pour décider si le coup passe).
### API typée
```java
boolean ff = core.teamConfig().get(team, TeamSettings.FRIENDLY_FIRE);
int max = core.teamConfig().getGlobal(TeamSettings.MAX_SIZE);
core.teamConfig().setPerTeam(team, TeamSettings.FRIENDLY_FIRE, true);
core.teamConfig().resetPerTeam(team, TeamSettings.FRIENDLY_FIRE);
core.teamConfig().setGlobal(TeamSettings.MAX_SIZE, 8); // persiste le YAML
core.teamConfig().reload();
```
### Settings custom (game plugin)
Un game plugin peut enregistrer ses propres settings :
```java
public static final TeamSetting<Boolean> CITES_PVP_ROUND_END =
TeamSetting.ofBoolean("cites_pvp_round_end", false);
@Override public void onEnable() {
core = new CRCore(this).enable();
TeamSettings.register(CITES_PVP_ROUND_END);
}
```
→ La clé apparaîtra automatiquement dans les GUI globaux et per-team, et
sera persistée en SQLite + YAML comme les standards.
### Commande GUI
`/core team settings [team]` — player-only, ouvre l'interface graphique.
- Sans argument → **GUI globaux** (perm `crcore.team.settings.global`).
Modif → écrit dans `<plugin>-team-config.yml`.
- Avec argument → **GUI per-team** (perm `crcore.team.settings`). Modif →
écrit en SQLite (overrides). Bouton "Reset tous les overrides" pour
remettre toutes les valeurs au global.
### Mécaniques GUI
- **Inventaire 27 slots**, settings sur la ligne du milieu (slots 10..16).
- **Booléens** : lampe verte (ON) / grise (OFF), clic = toggle.
- **Entiers** : item livre.
- Clic gauche = +1, shift = +10
- Clic droit = -1, shift = -10
- Clamp à 0 minimum
- **Strings/Enums** : affichage seul (édition via YAML — pas dans la V1
du GUI).
- **Per-team** : indication visuelle "Override per-team actif" dans la
lore quand une valeur est différente du global.
- **Slot 22** : bouton Fermer.
- **Slot 18** (per-team uniquement) : bouton "Reset tous les overrides".
### Framework GUI réutilisable
Le module `fr.luc.crcore.gui` est **générique** — réutilisable pour tout
futur GUI CR-Core ou game plugin :
- `AbstractInventoryGui implements InventoryHolder` — base abstraite,
`rebuild()`, `setButton(slot, item, handler)`, `setDecoration(...)`,
`clearSlot(...)`, hook `onClose(...)`.
- `GuiClickHandler` (FunctionalInterface) — handler de clic par slot.
- `GuiListener` — un seul Listener Bukkit qui route les clics et les
fermetures vers le bon GUI via `inventory.getHolder()`.
- `GuiItems` — builder fluide `named(material, "&aTitre").lore(...).build()`,
filler décoratif gris.
Pour faire un GUI custom : `extends AbstractInventoryGui`, créer
l'inventaire dans le constructeur, override `rebuild()`. Le `GuiListener`
est déjà enregistré par `CRCore.enable()`.
### Diagrammes
- [team-config-class-diagram.puml](diagrams/team-config-class-diagram.puml)
- [gui-class-diagram.puml](diagrams/gui-class-diagram.puml)
---
## 11. Bootstrap `CRCore`
**Statut** : implémenté. Point d'entrée unique pour les plugins de jeu.