feat: moderation feature skeleton (/core admin + mod mode + tools)

New feature fr.luc.crcore.features.moderation, opt-in via
CRCoreConfig.setupModeration() (also enabled by setupAll()).

Core abstractions:
- ModerationState: full player snapshot (inv + armor + offhand, XP,
  health, food, location, gamemode, allowFlight/flying, walk/fly speed).
  Immutable, restoreTo(player) restores everything.
- ModerationService interface + ModerationServiceImpl (with
  protected onAfterEnter/onAfterExit hooks) +
  BukkitEventFiringModerationServiceImpl (fires ModerationEnterEvent /
  ModerationExitEvent).
- ModerationRepository interface + InMemoryModerationRepository
  (skeleton — SQLite impl with BukkitObjectOutputStream serialization
  planned).
- ModeratorTool interface: getKey/getSlot(0..8)/buildIcon +
  onLeftClick/onRightClick/onInteractEntity. ModeratorToolRegistry
  preserves registration order, slot collision = replace.
- Exceptions: ModerationException base + AlreadyActive + NotActive.
- Events: ModerationEvent base + Enter + Exit.

5 skeleton tools in the hotbar:
- slot 0: TeleportRandomPlayerTool (compass, right-click → tp random)
- slot 1: InventorySpyTool (chest, right-click on player → open inv)
- slot 2: FreezeTool (ice, right-click on player → toggle freeze)
- slot 7: VanishToggleTool (ender eye, click → toggle vanish)
- slot 8: ExitTool (barrier, click → exit mod mode)
Slots 3-6 free for custom tools.

ModerationListener routes interactions and locks hotbar:
- PlayerInteractEvent → tool.onLeftClick / onRightClick (with cancel).
- PlayerInteractEntityEvent → tool.onInteractEntity (with cancel).
- PlayerDropItemEvent / PlayerSwapHandItemsEvent: cancel for mods.
- InventoryClickEvent: cancel only when top inv is the mod's own inv
  (preserves InventorySpyTool's ability to manipulate target's inv).
- PlayerJoinEvent: re-applies vanish for already-vanished mods.
- PlayerQuitEvent: cleanup freeze state.
- PlayerMoveEvent: cancel block-position changes for frozen players,
  keeping head rotation free.

Mod mode lifecycle:
- enter: snapshot + clear inv + populate hotbar + CREATIVE +
  allowFlight + vanish + ModerationEnterEvent.
- exit: state.restoreTo(player) + unvanish + unfreeze + repo delete +
  ModerationExitEvent.

/core admin (perm crcore.admin, player-only): toggle on/off.
Messages moderation.enter.success / moderation.exit.success added
to crcore-messages.yml.

CRCoreConfig.setupModeration() + isModerationEnabled() flag.
CRCore: buildModerationService() and registerDefaultModeratorTools()
override points, moderation() / getModerationService() getters with
IllegalStateException guard. Builds + registers ModerationListener at
enable() when feature on. CoreCommand extended to take ModerationService;
registers AdminToggleSubCommand only when service non-null.

Skeleton limitations documented in features.md:
- In-memory repo only (server crash = lost inv) — SQLite planned.
- InventorySpyTool opens real inv (no read-only wrapping yet).
- TeleportRandomPlayerTool is a placeholder for a future player-picker
  GUI.
- No moderation.*.broadcast keys yet.
- No /core admin <player> (self-toggle only).

Docs: section 11 in features.md, decision logged in decisions.md
(skeleton scope + rationale), setup.md snippet updated,
new moderation-class-diagram.puml, README.md updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Antone Barbaud
2026-06-10 12:19:21 +02:00
parent 84735221f1
commit 4efaa5bbde
30 changed files with 1630 additions and 20 deletions
+8 -2
View File
@@ -44,8 +44,13 @@ d'initialisation côté plugin de jeu :
- **Framework GUI** — `AbstractInventoryGui` + `GuiListener` réutilisable
pour tout GUI custom. Détection par holder, clic toujours annulé,
`GuiItems` builder fluide avec codes couleur `&`.
- **Bootstrap unique** — `new CRCore(this).enable()` dans le `onEnable()`
du plugin de jeu, et tout est branché.
- **Modération (skeleton)** — `/core admin` toggle pour passer en
mod mode : snapshot complet du joueur (inv, XP, location, gamemode),
vanish, hotbar dotée d'outils (tp joueur, inv spy, freeze, vanish
toggle, exit). `ModeratorTool` + registry extensibles. Persistance
SQLite à venir.
- **Bootstrap unique** — `new CRCore(this, new CRCoreConfig().setupAll()).enable()`
dans le `onEnable()` du plugin de jeu, et tout est branché.
## Structure de la documentation
@@ -72,6 +77,7 @@ d'initialisation côté plugin de jeu :
| [broadcasts-class-diagram.puml](diagrams/broadcasts-class-diagram.puml) | Classe | Service de broadcasts YAML + listener |
| [team-config-class-diagram.puml](diagrams/team-config-class-diagram.puml) | Classe | Paramètres d'équipe (cascade + GUI) |
| [gui-class-diagram.puml](diagrams/gui-class-diagram.puml) | Classe | Framework GUI réutilisable |
| [moderation-class-diagram.puml](diagrams/moderation-class-diagram.puml) | Classe | Feature modération (skeleton) |
| [bootstrap-sequence.puml](diagrams/bootstrap-sequence.puml) | Séquence | `CRCore.enable()` côté plugin de jeu |
## Conventions