Files
Cites_Plugins/docs/diagrams/command-class-diagram.puml
T
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

125 lines
3.4 KiB
Plaintext

@startuml command-class-diagram
title CR-Core — Command framework (class diagram, nested sub-commands)
skinparam classAttributeIconSize 0
hide empty members
package "fr.luc.crcore.util.command" {
interface Command {
+ getName(): String
+ getAliases(): List<String>
+ getPermission(): String
+ isPlayerOnly(): boolean
+ getDescription(): String
+ execute(ctx: CommandContext): CommandResult
+ tabComplete(sender, args: String[]): List<String>
+ matches(label: String): boolean
}
abstract class AbstractCommand {
- name: String
- aliases: List<String>
- permission: String
- playerOnly: boolean
- description: String
- usage: String
- arguments: List<ArgumentDef>
- subCommandsByName: Map<String, SubCommand>
- subCommandsByAlias: Map<String, SubCommand>
--
# addAlias(...) / permission / playerOnly / description / usage
# argument(name, type) / optionalArgument(name, type)
# addSubCommand(sub: SubCommand): void
--
+ findSubCommand(label): Optional<SubCommand>
+ getSubCommands(): Collection<SubCommand>
+ replaceSubCommand(name, newSub): Optional<SubCommand>
+ hasSubCommands(): boolean
--
+ dispatch(sender, label, args): CommandResult
+ tabComplete(sender, args): List<String>
+ execute(ctx): CommandResult
# listSubCommands(ctx): CommandResult
# checkAccess(sender): boolean
# buildContext(sender, label, rawArgs): CommandContext
}
abstract class BaseCommand {
+ onCommand(sender, cmd, label, args): boolean
+ onTabComplete(sender, cmd, alias, args): List<String>
# handleResult(sender, result): void
}
abstract class SubCommand
class CommandContext {
- sender: CommandSender
- label: String
- rawArgs: String[]
- parsedArgs: Map<String, Object>
+ getSender / isPlayer / getPlayer / requirePlayer
+ get(name): T
+ getOptional(name): Optional<T>
+ has(name): boolean
+ reply(msg): void
}
class CommandResult {
- type: Type
- message: String
+ {static} success / failure / invalidUsage / noPermission / playerOnly
}
enum "CommandResult.Type" as ResultType {
SUCCESS
FAILURE
INVALID_USAGE
NO_PERMISSION
PLAYER_ONLY
}
class CommandException
interface "ArgumentType<T>" as ArgumentType {
+ parse(input: String): T
+ suggestions(sender, partial): List<String>
}
class ArgumentTypes <<utility>> {
+ STRING / INTEGER / DOUBLE / BOOLEAN / ONLINE_PLAYER
+ enumOf(Class<E>): ArgumentType<E>
+ choice(String...): ArgumentType<String>
}
class ArgumentDef <<package-private>> {
- name: String
- type: ArgumentType<?>
- required: boolean
}
AbstractCommand ..|> Command
BaseCommand --|> AbstractCommand
SubCommand --|> AbstractCommand
BaseCommand ..|> "org.bukkit.command.CommandExecutor"
BaseCommand ..|> "org.bukkit.command.TabCompleter"
AbstractCommand "1" o-- "*" SubCommand : sub-commands\n(recursive)
AbstractCommand "1" *-- "*" ArgumentDef : arguments
ArgumentDef --> ArgumentType
CommandResult +-- ResultType
CommandException --|> RuntimeException
AbstractCommand ..> CommandContext : creates
AbstractCommand ..> CommandResult : returns
}
note bottom of AbstractCommand
Le routage est récursif :
/core team create → CoreCommand.dispatch("team", ["create",...])
→ TeamGroup.dispatch("create", [...])
→ TeamCreate.execute(ctx)
end note
@enduml