Commit Graph

12 Commits

Author SHA1 Message Date
Antone Barbaud 6648b3b375 docs: rename GEMINI.md → CLAUDE.md and update content
Renamed with git mv to preserve history. Refreshed the content to match
the current state of the project:

- Java 11 build target (was 16) — explicit warning not to reintroduce
  records / pattern matching / switch expressions.
- New three-layer architecture: util/ (always on) + features/ (opt-in
  via setupX()) + builtin/ (top-level commands).
- New features documented: messages, broadcasts, GUI framework, team
  settings, moderation skeleton.
- Diagrams layout: util/ + features/<feature>/ + cross-cutting at root.
- File generation pattern documented: <plugin>-messages.yml,
  <plugin>-broadcasts.yml, <plugin>-team-config.yml in dataFolder.
- Maven build + deploy commands and Gitea Packages publishing URL.
- Git workflow conventions: HTTPS URL with token, co-author trailer.

setup.md tree updated (GEMINI.md → CLAUDE.md reference).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 14:02:23 +02:00
Antone Barbaud 4efaa5bbde 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>
2026-06-10 12:19:21 +02:00
Antone Barbaud 84735221f1 refactor: split util/ vs features/ + modular opt-in setupX() config
Package restructure to prepare future modularization. Three layers now:

1. fr.luc.crcore.util.* (always active)
   - common, command framework, database, message, broadcast, gui,
     placeholder

2. fr.luc.crcore.features.* (opt-in)
   - team (entities, services, repos, events, exceptions, config + GUI,
     command/Team*SubCommand)
   - player (profile, ranking, services, repos, events, exceptions)

3. fr.luc.crcore.builtin.*
   - CoreCommand + CoreReloadSubCommand (top-level routing — not a
     feature, not an util)

FQN moves (game plugins importing these need their imports updated):
- fr.luc.crcore.common.*          → fr.luc.crcore.util.common.*
- fr.luc.crcore.command.*         → fr.luc.crcore.util.command.*
- fr.luc.crcore.command.builtin.team.*
                                  → fr.luc.crcore.features.team.command.*
- fr.luc.crcore.command.builtin.CoreCommand / CoreReloadSubCommand
                                  → fr.luc.crcore.builtin.*
- fr.luc.crcore.database.*        → fr.luc.crcore.util.database.*
- fr.luc.crcore.message.*         → fr.luc.crcore.util.message.*
- fr.luc.crcore.broadcast.*       → fr.luc.crcore.util.broadcast.*
- fr.luc.crcore.gui.*             → fr.luc.crcore.util.gui.*
- fr.luc.crcore.placeholder.*     → fr.luc.crcore.util.placeholder.*
- fr.luc.crcore.team.*            → fr.luc.crcore.features.team.*
- fr.luc.crcore.player.*          → fr.luc.crcore.features.player.*

CRCoreConfig — features opt-in via fluent setup:
- setupTeams()        enables team feature
- setupPlayers()      enables player feature
- setupPlaceholders() enables PAPI integration
- setupAll()          shortcut
By default no feature is active. Game plugin must opt-in.

CRCore.enable() now conditional:
- Util services always built (messages, broadcasts, gui listener).
- Team services + repos + config built only if setupTeams().
- Player services + repos built only if setupPlayers().
- Placeholder hook registered only if setupPlaceholders() (and PAPI
  installed at runtime).
- Getters of disabled features throw IllegalStateException with a clear
  message pointing to the missing setupX() call.
- CoreCommand only registers TeamGroupSubCommand if teamService and
  teamConfig are non-null. CoreReloadSubCommand handles teamConfig=null
  (just skips that reload). /core reload always available.

Docs:
- setup.md tree fully rewritten to reflect util/+features/+builtin
  layout (~70 lines of arborescence).
- setup.md code snippet shows the three opt-in patterns (setupAll /
  granular / with options).
- decisions.md logs both decisions (restructure + modular setup).
- All .puml diagrams auto-updated to new FQNs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 12:00:00 +02:00
Antone Barbaud 75d2fa866d 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>
2026-06-10 11:46:51 +02:00
Antone Barbaud a94bc56a5b feat: configurable broadcasts + /core reload
New fr.luc.crcore.broadcast module:
- BroadcastAudience enum (NONE, LEADER, TEAM, ADMIN, ALL).
- BroadcastContext (fluent: team + involvedPlayerId + placeholders).
- BroadcastService interface + YamlBroadcastService impl.
- CRCoreBroadcastListener (Bukkit listener) wires the 12 native events
  (9 team + 3 player) to broadcasts.broadcast(eventKey, ctx).

Same single-per-plugin file pattern as messages:
<plugin-dataFolder>/<plugin-name-lowercase>-broadcasts.yml. Defaults
bundled at resources/crcore-broadcasts.yml, copied on first boot (game
plugin's own resource of the same name takes priority as the template).
In-memory fallback so new CR-Core keys work without admin edit.

Routes (who) vs templates (what) are separated: broadcasts.yml lists
audiences per eventKey, messages.yml contains the templates under keys
<eventKey>.broadcast. Admin can change either independently.

12 new *.broadcast keys added to crcore-messages.yml with sensible
French defaults and color codes. Listener injects standard placeholders
(name, team_name, tag, color, visibility, player, new_leader,
old/new_value, etc.).

ADMIN audience resolved via crcore.broadcast.admin permission. Multi-
audiences via YAML list (e.g., [TEAM, ADMIN]); union of resolved
players, no duplicate.

New /core reload subcommand (permission crcore.reload) hot-reloads
both messages and broadcasts from disk without restart.

CRCore: protected buildBroadcastService() override point, getter
broadcasts(), wire of CRCoreBroadcastListener at enable(). CoreCommand
constructor extended to take BroadcastService, registers the reload
subcommand.

Docs/features.md: new section 9 "Service de broadcasts". docs/setup.md:
updated to mention both YAML files. decisions.md logs the routes-vs-
templates split, the audience model, and the reload semantics.
New diagram broadcasts-class-diagram.puml. README updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 11:16:34 +02:00
Antone Barbaud 923f48ffc7 refactor: split team/player/message into impl/ and exception/ subpackages
Each domain now has:
- Top-level package: contracts (interfaces, entities, enums, values, events).
- exception/ subpackage: exception hierarchy.
- impl/ subpackage: implementations CR-Core ships by default, swappable by
  a game plugin if needed.

Moved (FQN changes for consumers):
- fr.luc.crcore.team.TeamException (+ AlreadyExists, NotFound, Access)
    → fr.luc.crcore.team.exception.*
- fr.luc.crcore.team.TeamServiceImpl, BukkitEventFiringTeamServiceImpl,
  InMemoryTeamRepository, SqliteTeamRepository
    → fr.luc.crcore.team.impl.*
- fr.luc.crcore.player.PlayerException, PlayerProfileNotFoundException
    → fr.luc.crcore.player.exception.*
- fr.luc.crcore.player.PlayerProfileServiceImpl,
  BukkitEventFiringPlayerProfileServiceImpl,
  InMemoryPlayerProfileRepository, SqlitePlayerProfileRepository
    → fr.luc.crcore.player.impl.*
- fr.luc.crcore.message.YamlMessagesService
    → fr.luc.crcore.message.impl.YamlMessagesService

Unchanged top-level packages: database/, command/, common/ (already small
and well-organized). Events stay where they were (already in event/
subpackages).

setup.md tree updated to reflect the new layout. decisions.md logs the
rationale (consumer-facing FQNs, separation between contract and impl).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 10:54:35 +02:00
Antone Barbaud 4651ccbe69 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>
2026-06-09 16:06:19 +02:00
Antone Barbaud 8b7cad3fce feat: chef commands moved to admin + PlaceholderAPI integration
Chef → admin: the chef role no longer grants any command privilege.
All team-management subcommands now take <team> as an argument and are
gated by their crcore.team.<action> permission only:
- add <team> <player>
- remove <team> <player>
- transfer <team> <player>
- visibility <team> <PUBLIC|PRIVATE>
- setspawn <team> (still player-only — needs admin's location)

The LEADER role is kept in the data model (Team / TeamMember) and remains
usable by game plugins via the API, but does not unlock any default
command. Future work can re-introduce chef-specific commands if needed.

PlaceholderAPI: auto-detected at CRCore.enable(). If the PAPI plugin is
present on the server, CRCorePlaceholderExpansion registers automatically;
otherwise the lib runs without it (no NoClassDefFoundError thanks to the
indirection through doRegisterPlaceholderHook).

Placeholders exposed:
- Team: %crcore_team%, %crcore_team_name/tag/color/color_chat/size/
  visibility/leader_name/total_score%, %crcore_team_score_<name>%
- Player: %crcore_player_score_<name>%, %crcore_player_score_total%

Dependency: me.clip:placeholderapi:2.11.6, scope provided. New repo:
https://repo.extendedclip.com/content/repositories/placeholderapi/.

docs/features.md, decisions.md and the builtin-commands diagram updated to
reflect the simpler admin/player two-tier model and the PAPI section.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 15:05:02 +02:00
Antone Barbaud 5bd6e227d3 chore: downgrade compile target to Java 11
Uses <release>11</release> in maven-compiler-plugin (recommended over
source/target to guarantee bytecode and API surface match Java 11).

Code changes to drop Java 12-16 features:
- records (TeamRanking, PlayerRanking, internal tuples in
  SqliteTeamRepository) become hand-written immutable classes; same
  accessor names (rank()/team()/score()/...) so call sites are unchanged.
- instanceof X x pattern matching becomes classic instanceof + cast in
  CommandContext.requirePlayer and Database.normalize.
- switch expressions with -> arrows become classic switch + break, or
  if/else chains, in BaseCommand.handleResult, ArgumentTypes.BOOLEAN and
  TeamScoreSubCommand.execute.

docs/setup.md, features.md and decisions.md updated to reflect Java 11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 12:18:43 +02:00
Antone Barbaud 7ee349f206 feat: dynamic command registration + Maven publication setup
CRCore.registerCommand() now falls back to dynamic registration via the
server's internal CommandMap (reflection on CraftServer.commandMap) when
the command is absent from the host plugin's plugin.yml. Game plugins can
now use CR-Core with zero plugin.yml changes — just instantiate CRCore.
If the command IS declared in plugin.yml, CR-Core detects it and uses
setExecutor/setTabCompleter as before.

pom.xml: distributionManagement targeting Gitea Packages
(https://gitea.luc-rival.fr/api/packages/admin/maven), plus
maven-source-plugin (3.3.0) and maven-javadoc-plugin (3.6.3) so each
mvn deploy publishes the main jar, a -sources.jar and a -javadoc.jar.
doclint=none on javadoc to tolerate partial doc.

docs/setup.md: clarifies that the commands: entry in plugin.yml is now
optional. docs/decisions.md: new decision logged for the dynamic
registration approach.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 11:33:45 +02:00
Antone Barbaud c1b414f400 feat: SQLite persistence, default /core commands, Bukkit events, bootstrap
CRCore bootstrap class: one-line setup for game plugins (new CRCore(this).enable()).
Wires SQLite, services with event firing, and the /core command tree.

SQLite layer (fr.luc.crcore.database): Database wrapper exposing execute/update/
queryOne/query plus a fluent TableBuilder. ColumnType enum, RowMapper interface,
DatabaseException. Game plugins create their own tables in 2 lines via
db.table("foo").ifNotExists().column(...).create().

Repositories: SqliteTeamRepository and SqlitePlayerProfileRepository extend their
InMemory counterparts (write-through cache). 5 internal tables prefixed crcore_.

Command framework refactored for nested sub-commands: subcommand storage moved
from BaseCommand to AbstractCommand, recursive dispatch() and tabComplete(),
replaceSubCommand() for plugin overrides.

Default /core team commands (13 leaf sub-commands): create, delete, add, remove,
join, leave, info, list, transfer, visibility, score, top, setspawn. Each in its
own class under fr.luc.crcore.command.builtin.team, fully substitutable.

Bukkit events: 9 team events (Create/Dissolve/MemberAdd/MemberRemove/PlayerJoin/
LeadershipTransfer/VisibilityChange/ScoreChange/SpawnPointChange) + 3 player
events (ProfileCreate/Delete/ScoreChange). All post-only, non-cancellable.
BukkitEventFiringTeamServiceImpl and BukkitEventFiringPlayerProfileServiceImpl
override the on* hooks to call Bukkit.getPluginManager().callEvent.

JavaDoc on all new public classes and key existing ones. docs/, GEMINI.md and
PUML diagrams synced: new sections (built-in commands, events, database,
bootstrap), 4 new diagrams (builtin-commands, events, database, bootstrap-
sequence), and 7 new architecture decisions logged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 10:54:00 +02:00
Antone Barbaud ffc77c4213 feat: initial CR-Core library (team + player + command framework)
Pure Maven library for CR Minecraft game plugins, targeting Paper 1.16.5.

Common abstractions (fr.luc.crcore.common): Identifiable, Named, ScoreHolder,
AbstractEntity, Repository<T>.

Team domain (fr.luc.crcore.team): Team entity with name/tag/color/leader/
visibility (PUBLIC|PRIVATE)/members/scores/spawn point, TeamMember,
TeamRole/TeamColor/TeamVisibility enums, TeamRanking record, TeamService with
overridable hooks (factories, validations, lifecycle events), in-memory
repository, dedicated exception hierarchy.

Player domain (fr.luc.crcore.player): PlayerProfile with named scores per
player, PlayerProfileService with auto-creation, individual rankings,
exception hierarchy. Both Team and PlayerProfile implement ScoreHolder.

Command framework (fr.luc.crcore.command): Command interface,
AbstractCommand base, BaseCommand (CommandExecutor + TabCompleter), SubCommand,
CommandContext, CommandResult, ArgumentType<T> + ArgumentTypes catalogue
(STRING, INTEGER, DOUBLE, BOOLEAN, ONLINE_PLAYER, enumOf, choice).

Docs (docs/) is the single source of truth: README, setup, features,
decisions log, and 6 PlantUML diagrams (team class/sequence/activity/join,
player class, command class).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 17:17:56 +02:00