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>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
@startuml broadcasts-class-diagram
|
||||
title CR-Core — Broadcast service (class diagram)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
hide empty members
|
||||
|
||||
package "fr.luc.crcore.broadcast" {
|
||||
|
||||
enum BroadcastAudience {
|
||||
NONE
|
||||
LEADER
|
||||
TEAM
|
||||
ADMIN
|
||||
ALL
|
||||
}
|
||||
|
||||
class BroadcastContext {
|
||||
- team: Team
|
||||
- involvedPlayerId: UUID
|
||||
- placeholders: Map<String, String>
|
||||
--
|
||||
+ {static} of(team): BroadcastContext
|
||||
+ {static} empty(): BroadcastContext
|
||||
+ involving(playerId): BroadcastContext
|
||||
+ with(key, value): BroadcastContext
|
||||
+ getTeam(): Optional<Team>
|
||||
+ getInvolvedPlayerId(): Optional<UUID>
|
||||
+ getPlaceholders(): Map<String, String>
|
||||
+ toPlaceholderPairs(): Object[]
|
||||
}
|
||||
|
||||
interface BroadcastService {
|
||||
+ broadcast(eventKey, context): void
|
||||
+ getAudiences(eventKey): List<BroadcastAudience>
|
||||
+ reload(): void
|
||||
}
|
||||
|
||||
class CRCoreBroadcastListener {
|
||||
- broadcasts: BroadcastService
|
||||
+ registerOn(plugin: JavaPlugin): void
|
||||
--
|
||||
@ onTeamCreate(TeamCreateEvent)
|
||||
@ onTeamDissolve(TeamDissolveEvent)
|
||||
@ onTeamMemberAdd(TeamMemberAddEvent)
|
||||
@ onTeamMemberRemove(TeamMemberRemoveEvent)
|
||||
@ onPlayerJoinTeam(PlayerJoinTeamEvent)
|
||||
@ onLeadershipTransfer(TeamLeadershipTransferEvent)
|
||||
@ onVisibilityChange(TeamVisibilityChangeEvent)
|
||||
@ onTeamScoreChange(TeamScoreChangeEvent)
|
||||
@ onTeamSpawnChange(TeamSpawnPointChangeEvent)
|
||||
@ onProfileCreate(PlayerProfileCreateEvent)
|
||||
@ onProfileDelete(PlayerProfileDeleteEvent)
|
||||
@ onPlayerScoreChange(PlayerScoreChangeEvent)
|
||||
}
|
||||
CRCoreBroadcastListener ..|> "org.bukkit.event.Listener"
|
||||
|
||||
package "fr.luc.crcore.broadcast.impl" {
|
||||
class YamlBroadcastService {
|
||||
- plugin: JavaPlugin
|
||||
- messages: MessagesService
|
||||
- defaults: Map<String, List<BroadcastAudience>>
|
||||
- audiences: Map<String, List<BroadcastAudience>>
|
||||
- userFile: File
|
||||
--
|
||||
+ YamlBroadcastService(plugin, messages)
|
||||
- loadDefaultsFromResource(): void
|
||||
- ensureUserFile(): void
|
||||
- rebuildEffectiveAudiences(): void
|
||||
- resolveRecipients(list, ctx): Set<Player>
|
||||
}
|
||||
YamlBroadcastService ..|> BroadcastService
|
||||
}
|
||||
|
||||
BroadcastService ..> BroadcastContext : consumes
|
||||
BroadcastContext --> BroadcastAudience
|
||||
YamlBroadcastService --> "fr.luc.crcore.message.MessagesService" : reads templates
|
||||
CRCoreBroadcastListener --> BroadcastService : delegates
|
||||
CRCoreBroadcastListener ..> BroadcastContext : builds
|
||||
}
|
||||
|
||||
package "fr.luc.crcore" {
|
||||
class CRCore {
|
||||
+ broadcasts(): BroadcastService
|
||||
# buildBroadcastService(messages): BroadcastService
|
||||
}
|
||||
CRCore "1" *-- "1" BroadcastService : owns
|
||||
CRCore ..> CRCoreBroadcastListener : registers
|
||||
}
|
||||
|
||||
note bottom of YamlBroadcastService
|
||||
Modèle "un seul fichier par plugin" :
|
||||
|
||||
Sources en mémoire :
|
||||
1. crcore-broadcasts.yml ← jar (fallback)
|
||||
2. <plugin>-broadcasts.yml ← dataFolder (édité par l'admin)
|
||||
|
||||
Séparation routes / templates :
|
||||
- Routes = ce fichier (qui reçoit quoi)
|
||||
- Templates = MessagesService (clés <event>.broadcast)
|
||||
end note
|
||||
|
||||
@enduml
|
||||
Reference in New Issue
Block a user