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
+63
View File
@@ -367,6 +367,69 @@ Format léger : une décision = un titre + contexte + choix + raison.
bases existantes, ALTER TABLE manuel ou suppression du fichier
(les bases d'event sont jetables).
## 2026-06-10 — Settings d'équipe : cascade per-team → global → default + GUI
- **Choix** : nouveau module `fr.luc.crcore.team.config` avec :
- `TeamSetting<T>` typé (factories `ofBoolean`, `ofInt`, `ofString`,
`ofEnum`) — chaque setting porte sa clé, son type, son default et sa
sérialisation YAML/SQL.
- `TeamSettings` registry des 8 settings standards
(`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 `TeamSettings.register(...)`
pour les game plugins.
- `TeamConfigService` (interface) + `YamlTeamConfigService` (impl).
- **Cascade de résolution** : per-team → global → hard default. Garantie
non-null grâce au default. La couche per-team est stockée dans
{@code Team.getSettings()} (Map<String, Object>) persistée en SQLite ;
la couche globale dans `<plugin>-team-config.yml` ; les defaults sont
des constantes Java.
- **Stockage per-team SQLite** : nouvelle table `crcore_team_settings`
(team_id, key, value, type). Le type tag (bool/int/str) permet de
reconstruire le type Java au load sans réflexion.
- **Settings custom (game plugin)** : le game plugin peut faire
`TeamSettings.register(MON_SETTING)` dans son onEnable() pour
l'enregistrer ; il apparaîtra automatiquement dans les GUI globaux et
per-team, et sera persisté comme les standards.
- **Pas d'application automatique** : CR-Core ne fait que stocker /
exposer les settings. C'est au game plugin d'écouter les events Bukkit
pertinents (ex. `EntityDamageByEntityEvent`) et de consulter
`config.get(team, FRIENDLY_FIRE)` pour appliquer la règle. CR-Core ne
veut pas hardcoder des semantics gameplay.
## 2026-06-10 — Framework GUI réutilisable (`fr.luc.crcore.gui`)
- **Choix** : module GUI générique avec
`AbstractInventoryGui implements InventoryHolder` (base abstraite),
`GuiClickHandler` (FunctionalInterface), `GuiListener` (un seul
Listener Bukkit pour TOUS les GUI CR-Core), `GuiItems` (builder fluide
d'`ItemStack` avec codes couleur).
- **Détection par holder** : `event.getInventory().getHolder() instanceof
AbstractInventoryGui` — propre, sans titre/UUID custom, marche même
après un translate.
- **Click toujours annulé** : le `GuiListener` cancel TOUT clic dans un
GUI CR-Core (avant invocation du handler) — l'utilisateur ne peut
jamais déplacer un item du GUI, même sur un slot sans handler.
- **Réutilisable** : c'est un framework, pas un GUI métier. Tout futur
GUI (settings, kits, classements interactifs, etc.) hérite
d'`AbstractInventoryGui`.
## 2026-06-10 — `/core team settings` (global = sans arg, per-team = avec arg)
- **Choix** : commande unique `/core team settings [team]` qui multiplexe :
- Sans arg → ouvre `GlobalSettingsGui` (perm
`crcore.team.settings.global`).
- Avec arg `team` → ouvre `TeamSettingsGui` (perm `crcore.team.settings`).
- **Pas `/core settings`** au top-level — l'objectif est de séparer
plus tard en modules (team, score, kits, …). Tout ce qui touche les
teams reste sous `/core team`.
- **Player-only** : Bukkit a besoin d'un `HumanEntity` pour ouvrir un
inventaire. Pas de fallback console.
- **Mécaniques** : booléens → toggle, entiers → clic gauche +1/right -1
(shift = ×10), strings/enums → édition différée au YAML (V1).
- **GUI per-team** : un bouton "Reset tous les overrides" qui efface
tous les per-team de l'équipe pour les faire retomber sur le global.
## 2026-06-10 — Système de broadcasts configurables + `/core reload`
- **Choix** : nouveau module `fr.luc.crcore.broadcast` avec