461 lines
19 KiB
Markdown
461 lines
19 KiB
Markdown
# ⚡ betterMcCommands
|
||
|
||
[](https://www.oracle.com/java/)
|
||
[](https://papermc.io/)
|
||
[](https://docs.advntr.dev/)
|
||
[](#)
|
||
|
||
Une bibliothèque Java moderne, fluide et événementielle permettant de créer, structurer et gérer des commandes Minecraft de façon hautement dynamique sans aucune déclaration préalable dans `plugin.yml`.
|
||
|
||
---
|
||
|
||
## 📑 Sommaire
|
||
- [🌟 Fonctionnalités](#-fonctionnalités)
|
||
- [🏗️ Architecture & Flux d'Exécution](#️-architecture--flux-dexécution)
|
||
- [📦 Installation & Configuration](#-installation--configuration)
|
||
- [🚀 Guide de Démarrage Rapide](#-guide-de-démarrage-rapide)
|
||
- [💡 Exemples de Commandes](#-exemples-de-commandes)
|
||
- [1. Commande de Démonstration Complète (`/commande-demo`)](#1-commande-de-démonstration-complète-commande-demo)
|
||
- [2. Sous-Commandes Imbriquées](#2-sous-commandes-imbriquées)
|
||
- [3. Arguments Gourmands (Greedy String)](#3-arguments-gourmands-greedy-string)
|
||
- [4. Système de Validation Métier (Pré-requis)](#4-système-de-validation-métier-pré-requis)
|
||
- [5. Confirmation Préalable & Double Validation (`.requireConfirmation`)](#5-confirmation-préalable--double-validation-requireconfirmation)
|
||
- [6. Répétition & Cadence de Commandes (`CommandRepeater`)](#6-répétition--cadence-de-commandes-commandrepeater)
|
||
- [7. Temps de Recharge (Cooldowns)](#7-temps-de-recharge-cooldowns)
|
||
- [🧩 Catalogue des Arguments Typés](#-catalogue-des-arguments-typés)
|
||
- [🎯 Système d'Événements & Cycle de Vie](#-système-dévénements--cycle-de-vie)
|
||
- [Liste des Événements Disponibles](#liste-des-événements-disponibles)
|
||
- [Écouteurs par Annotations (`@CommandEventHandler`)](#écouteurs-par-annotations-commandeventhandler)
|
||
- [📂 Organisation des Packages](#-organisation-des-packages)
|
||
|
||
---
|
||
|
||
## 🌟 Fonctionnalités
|
||
|
||
- **DSL Fluide & Déclaratif** : Déclaration intuitive basée sur le pattern Builder chainable (`BetterMcCommands.builder("ma-commande")`).
|
||
- **Zéro `plugin.yml`** : Injection directe par réflexion dans la `CommandMap` du serveur Minecraft avec support du dé-enregistrement à chaud.
|
||
- **Validation Métier Directe & Extensible** :
|
||
- Validateurs au niveau commande (`.validate(ctx -> condition, "Erreur...")`)
|
||
- Validateurs au niveau argument (`argument.validate(val -> condition, "Erreur...")`)
|
||
- **Confirmation Préalable (Double validation)** : Sécurisation des commandes critiques (`/disband`, `/delete-data`) avec expiration (`.requireConfirmation(Duration.ofSeconds(15))`).
|
||
- **Répétition & Tâches Cadencées (`CommandRepeater`)** : Répétition automatique d'une action à intervalles réguliers avec suivi de progression et annulation.
|
||
- **Système d'Arguments Typés & Auto-complétion** :
|
||
- Conversion et validation automatiques avec messages d'erreurs clairs.
|
||
- Auto-complétion dynamique (Tab-Complete) intelligente selon le type de chaque argument.
|
||
- **Moteur d'Événements Intégré & Annulable** :
|
||
- Interception des commandes au niveau local (sur la commande) ou global via un bus d'événements.
|
||
- Annulation de l'exécution (`PreExecuteEvent`) pour intégrer facilement des vérifications (combat tag, économie, inventaire).
|
||
- **Temps de recharge (Cooldowns) natifs** : Cooldowns par joueur avec support des permissions de bypass.
|
||
- **Formatage Moderne Kyori Adventure / MiniMessage** : Couleurs HEX, dégradés (`<gradient>`), composants enrichis et fallback automatique.
|
||
|
||
---
|
||
|
||
## 🏗️ Architecture & Flux d'Exécution
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Player["Joueur ou Console"] -->|Invoque /demo give Luc 10| Wrapper["PaperCommandWrapper (Bukkit)"]
|
||
Wrapper --> Dispatcher["CommandDispatcher (Moteur de routage)"]
|
||
|
||
Dispatcher --> STypeCheck{"Vérification Type Émetteur"}
|
||
STypeCheck -- Non conforme --> EvtPerm1["Dispatch PermissionDeniedEvent"]
|
||
|
||
STypeCheck -- Conforme --> PermCheck{"Vérification Permissions"}
|
||
PermCheck -- Manquante --> EvtPerm2["Dispatch PermissionDeniedEvent"]
|
||
|
||
PermCheck -- Valide --> CoolCheck{"Vérification Cooldown"}
|
||
CoolCheck -- Actif --> EvtCool["Dispatch CommandCooldownEvent"]
|
||
|
||
CoolCheck -- Inactif --> ArgParse{"Parsing & Validation des Arguments"}
|
||
ArgParse -- Erreur format / invalide --> EvtSyntax["Dispatch CommandSyntaxErrorEvent"]
|
||
|
||
ArgParse -- Succès --> ConfCheck{"Confirmation Requise ?"}
|
||
ConfCheck -- Non confirmée --> EvtConf["Dispatch ConfirmationRequiredEvent & Invite à retaper"]
|
||
|
||
ConfCheck -- Confirmée ou Non requise --> ValCheck{"Validateurs (CommandValidator)"}
|
||
ValCheck -- Invalide --> ValErr["Envoi Message d'Erreur & Arrêt"]
|
||
|
||
ValCheck -- Valide --> EvtPre{"Dispatch CommandPreExecuteEvent"}
|
||
EvtPre -- Annulé (setCancelled) --> Cancelled["Arrêt de l'exécution"]
|
||
|
||
EvtPre -- Non annulé --> Exec["Exécution du CommandExecutor métier"]
|
||
Exec --> ApplyCooldown["Application du Cooldown"]
|
||
Exec --> EvtPost["Dispatch CommandPostExecuteEvent (Métriques/Logs)"]
|
||
```
|
||
|
||
---
|
||
|
||
## 📦 Installation & Configuration
|
||
|
||
### Gradle (Kotlin DSL)
|
||
|
||
```kotlin
|
||
repositories {
|
||
mavenCentral()
|
||
maven("https://repo.papermc.io/repository/maven-public/")
|
||
}
|
||
|
||
dependencies {
|
||
implementation("fr.luc:betterMcCommands:1.0.0-SNAPSHOT")
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 Guide de Démarrage Rapide
|
||
|
||
### 1. Initialisation dans la classe principale (`JavaPlugin`)
|
||
|
||
```java
|
||
package fr.luc.monplugin;
|
||
|
||
import fr.luc.bettermccommands.BetterMcCommands;
|
||
import org.bukkit.plugin.java.JavaPlugin;
|
||
|
||
public class MonPlugin extends JavaPlugin {
|
||
|
||
private BetterMcCommands commands;
|
||
|
||
@Override
|
||
public void onEnable() {
|
||
// 1. Initialisation du gestionnaire pour ce plugin
|
||
this.commands = BetterMcCommands.create(this);
|
||
|
||
// 2. Enregistrement d'écouteurs d'événements globaux (optionnel)
|
||
this.commands.registerListeners(new MonEcouteurDeCommandes());
|
||
|
||
// 3. Enregistrement de vos commandes
|
||
creerCommandes();
|
||
}
|
||
|
||
private void creerCommandes() {
|
||
BetterMcCommands.builder("ping")
|
||
.description("Répond pong !")
|
||
.executes(context -> context.replySuccess("Pong !"))
|
||
.register();
|
||
}
|
||
|
||
@Override
|
||
public void onDisable() {
|
||
// Désenregistrement à chaud et nettoyage propre
|
||
if (commands != null) {
|
||
commands.unregisterAll();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💡 Exemples de Commandes
|
||
|
||
### 1. Commande de Démonstration Complète (`/commande-demo`)
|
||
|
||
```java
|
||
BetterMcCommands.builder("commande-demo")
|
||
.description("Commande principale de démonstration")
|
||
.aliases("demo", "cdemo")
|
||
.permission("bettermc.demo")
|
||
|
||
// Hook local avant exécution (annulable)
|
||
.onPreExecute(event -> {
|
||
if (event.isPlayer() && isInCombat(event.getPlayer())) {
|
||
event.setCancelled(true);
|
||
event.reply("<red>Vous ne pouvez pas exécuter cette commande en combat !</red>");
|
||
}
|
||
})
|
||
|
||
// Exécution de la commande racine
|
||
.executes(context -> {
|
||
context.reply("<gradient:#00d2ff:#3a7bd5><bold>=== betterMcCommands ===</bold></gradient>");
|
||
context.reply("<gray>Utilisez <yellow>/demo give</yellow> pour donner des ressources.</gray>");
|
||
})
|
||
|
||
// Sous-commande avec arguments typés et valeur par défaut
|
||
.subcommand(BetterMcCommands.subBuilder("give")
|
||
.description("Donne des ressources à un joueur cible")
|
||
.permission("bettermc.demo.give")
|
||
.argument(Arguments.player("cible").description("Joueur recevant les items"))
|
||
.argument(Arguments.integer("quantite", 1, 64).defaultValue(1).description("Nombre d'items (1-64)"))
|
||
.executes(context -> {
|
||
Player target = context.getTargetPlayer("cible");
|
||
int quantite = context.getInt("quantite");
|
||
|
||
context.replySuccess("Attribution de <gold>" + quantite + "</gold> items à <aqua>" + target.getName() + "</aqua> !");
|
||
})
|
||
)
|
||
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 2. Sous-Commandes Imbriquées
|
||
|
||
Créez des arbres hiérarchiques profonds de façon fluide :
|
||
|
||
```java
|
||
BetterMcCommands.builder("guilde")
|
||
.description("Gestion de votre guilde")
|
||
.subcommand(BetterMcCommands.subBuilder("admin")
|
||
.permission("guilde.admin")
|
||
.subcommand(BetterMcCommands.subBuilder("rank")
|
||
.subcommand(BetterMcCommands.subBuilder("set")
|
||
.argument(Arguments.player("joueur"))
|
||
.argument(Arguments.enumOf("grade", MonGradeEnum.class))
|
||
.executes(context -> {
|
||
Player p = context.getTargetPlayer("joueur");
|
||
MonGradeEnum grade = context.get("grade", MonGradeEnum.class);
|
||
context.replySuccess("Grade de " + p.getName() + " mis à jour vers " + grade.name());
|
||
})
|
||
)
|
||
)
|
||
)
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Arguments Gourmands (Greedy String)
|
||
|
||
Permet de capturer tout le reste de la ligne sans nécessiter de guillemets (idéal pour les annonces, motifs de sanctions, broadcasts) :
|
||
|
||
```java
|
||
BetterMcCommands.builder("broadcast")
|
||
.aliases("bc", "annonce")
|
||
.permission("bettermc.broadcast")
|
||
.argument(Arguments.greedyString("message").description("Le texte complet à diffuser"))
|
||
.executes(context -> {
|
||
String message = context.getString("message");
|
||
context.replySuccess("Diffusion : <yellow>" + message + "</yellow>");
|
||
})
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 4. Système de Validation Métier (Pré-requis)
|
||
|
||
Vous pouvez attacher des validateurs à vos commandes et arguments :
|
||
|
||
```java
|
||
// Validation au niveau de la commande
|
||
BetterMcCommands.builder("level-reward")
|
||
.playerOnly()
|
||
.validate(ctx -> ctx.getPlayer().getLevel() >= 10, "Vous devez être niveau 10 minimum !")
|
||
.executes(ctx -> {
|
||
ctx.replySuccess("Récompense de niveau réclamée !");
|
||
})
|
||
.register();
|
||
|
||
// Validation au niveau d'un argument
|
||
BetterMcCommands.builder("setprice")
|
||
.argument(Arguments.decimal("prix").validate(prix -> prix > 0, "Le prix doit être strictement positif !"))
|
||
.executes(ctx -> {
|
||
double prix = ctx.getDouble("prix");
|
||
ctx.replySuccess("Prix configuré à " + prix + " €.");
|
||
})
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 5. Confirmation Préalable & Double Validation (`.requireConfirmation`)
|
||
|
||
Sécurisez les commandes destructrices ou sensibles. Le joueur doit ré-exécuter la commande dans le temps imparti pour confirmer l'action :
|
||
|
||
```java
|
||
BetterMcCommands.builder("disband")
|
||
.description("Dissout votre guilde")
|
||
.playerOnly()
|
||
.requireConfirmation(Duration.ofSeconds(15), "<red><bold>ATTENTION</bold> : Cette action est irréversible ! Retapez <yellow>/disband</yellow> dans les 15s pour confirmer.</red>")
|
||
.executes(context -> {
|
||
context.replySuccess("Votre guilde a été dissoute.");
|
||
})
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 6. Répétition & Cadence de Commandes (`CommandRepeater`)
|
||
|
||
Permet de répéter une action à intervalle régulier (ex: compte à rebours, diffusion répétée, téléportation avec pulsation) :
|
||
|
||
```java
|
||
BetterMcCommands.builder("countdown")
|
||
.playerOnly()
|
||
.executes(context -> {
|
||
// Répète 5 fois toutes les 1 seconde
|
||
CommandRepeater.repeat(monPlugin, context, 5, Duration.ofSeconds(1),
|
||
progress -> {
|
||
int restants = progress.getTotalRuns() - progress.getCurrentRun() + 1;
|
||
context.reply("<gold>Lancement dans <yellow>" + restants + "</yellow>...</gold>");
|
||
},
|
||
() -> {
|
||
// Action finale
|
||
context.replySuccess("<bold>PARTEZ !</bold>");
|
||
}
|
||
);
|
||
})
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
### 7. Temps de Recharge (Cooldowns)
|
||
|
||
```java
|
||
BetterMcCommands.builder("kit")
|
||
.description("Récupère le kit quotidien")
|
||
.playerOnly()
|
||
.cooldown(Duration.ofHours(24))
|
||
.cooldownBypass("bettermc.bypass.kit")
|
||
.executes(context -> {
|
||
context.replySuccess("Vous avez reçu votre kit quotidien !");
|
||
})
|
||
.register();
|
||
```
|
||
|
||
---
|
||
|
||
## 🧩 Catalogue des Arguments Typés
|
||
|
||
| Méthode Factory | Type Java de retour | Description & Caractéristiques |
|
||
|---|---|---|
|
||
| `Arguments.string("nom")` | `String` | Chaîne de caractères simple (un mot ou délimité). |
|
||
| `Arguments.greedyString("message")` | `String` | Consomme tous les arguments restants jusqu'à la fin de la ligne. |
|
||
| `Arguments.integer("nb")` | `Integer` | Nombre entier sans restriction de bornes. |
|
||
| `Arguments.integer("nb", min, max)` | `Integer` | Nombre entier borné avec validation automatique. |
|
||
| `Arguments.decimal("prix")` | `Double` | Nombre décimal avec support des points (`.`) et virgules (`,`). |
|
||
| `Arguments.bool("actif")` | `Boolean` | Booléen (`true`/`false`, `oui`/`non`, `1`/`0`, `on`/`off`). |
|
||
| `Arguments.player("cible")` | `org.bukkit.entity.Player` | Joueur connecté avec auto-complétion des pseudos en ligne. |
|
||
| `Arguments.offlinePlayer("joueur")` | `org.bukkit.OfflinePlayer` | Joueur hors-ligne ou en ligne ciblé par pseudo ou UUID. |
|
||
| `Arguments.world("monde")` | `org.bukkit.World` | Monde Bukkit chargé avec suggestions des mondes existants. |
|
||
| `Arguments.location("coords")` | `org.bukkit.Location` | Coordonnées `x,y,z` avec support des coordonnées relatives (`~`). |
|
||
| `Arguments.duration("temps")` | `java.time.Duration` | Durées textuelles (ex: `30s`, `15m`, `2h`, `1d`, `7d`). |
|
||
| `Arguments.enumOf("val", Enum.class)`| `T extends Enum<T>` | Enum Java avec auto-complétion de toutes les constantes. |
|
||
| `Arguments.custom("cle", parseur)` | `T` | Type personnalisé implémentant `ArgumentType<T>`. |
|
||
|
||
---
|
||
|
||
## 🎯 Système d'Événements & Cycle de Vie
|
||
|
||
### Liste des Événements Disponibles
|
||
|
||
| Événement | Description | Annulable ? |
|
||
|---|---|:---:|
|
||
| `CommandPreExecuteEvent` | Déclenché juste avant l'exécution métier. Permet d'annuler ou modifier l'action. | ✅ Oui |
|
||
| `CommandPostExecuteEvent` | Déclenché après l'exécution. Contient la durée d'exécution et le statut final. | ❌ Non |
|
||
| `CommandConfirmationRequiredEvent` | Déclenché lors d'une demande de confirmation préalable pour personnaliser l'invite. | ✅ Oui |
|
||
| `CommandPermissionDeniedEvent` | Déclenché si la permission est manquante ou si l'émetteur n'est pas autorisé. | ✅ Oui |
|
||
| `CommandSyntaxErrorEvent` | Déclenché lors d'une erreur de syntaxe ou argument manquant. | ✅ Oui |
|
||
| `CommandCooldownEvent` | Déclenché lorsqu'un joueur tente d'exécuter une commande sous cooldown actif. | ✅ Oui |
|
||
| `CommandTabCompleteEvent` | Déclenché lors du calcul des suggestions pour filtrer ou injecter des valeurs. | ✅ Oui |
|
||
|
||
---
|
||
|
||
### Écouteurs par Annotations (`@CommandEventHandler`)
|
||
|
||
```java
|
||
package fr.luc.monplugin.listener;
|
||
|
||
import fr.luc.bettermccommands.event.*;
|
||
import fr.luc.bettermccommands.event.annotation.CommandEventHandler;
|
||
|
||
public class MonEcouteurDeCommandes {
|
||
|
||
// Intercepte toutes les commandes exécutées
|
||
@CommandEventHandler(priority = 5)
|
||
public void onPreExecute(CommandPreExecuteEvent event) {
|
||
System.out.println("[Audit] Commande /" + event.getNode().getFullName() + " par " + event.getSender().getName());
|
||
}
|
||
|
||
// Intercepte uniquement la commande 'commande-demo'
|
||
@CommandEventHandler(command = "commande-demo")
|
||
public void onDemoPostExecute(CommandPostExecuteEvent event) {
|
||
if (event.isSuccessful()) {
|
||
System.out.println("[Perf] Exécutée en " + event.getExecutionDuration().toMillis() + "ms.");
|
||
}
|
||
}
|
||
|
||
// Personnalise les messages de permission refusée
|
||
@CommandEventHandler
|
||
public void onPermissionDenied(CommandPermissionDeniedEvent event) {
|
||
event.setCustomErrorMessage("<dark_red><bold>Accès Refusé</bold></dark_red> : Vous devez posséder la permission <gray>[" + event.getRequiredPermission() + "]</gray>.");
|
||
}
|
||
|
||
// Personnalise les alertes de cooldown
|
||
@CommandEventHandler
|
||
public void onCooldown(CommandCooldownEvent event) {
|
||
event.setCustomMessage("<red>⏳ Patientez <gold>" + event.getRemainingCooldown().toSeconds() + "s</gold> avant de réutiliser cette commande.</red>");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📂 Organisation des Packages
|
||
|
||
```
|
||
fr.luc.bettermccommands/
|
||
├── BetterMcCommands.java (Manager principal & Façade d'accès)
|
||
├── api/ (Interfaces et contrats publics)
|
||
│ ├── Command.java (Commande racine)
|
||
│ ├── CommandNode.java (Nœud d'arborescence)
|
||
│ ├── CommandContext.java (Contexte d'exécution et réponses MiniMessage)
|
||
│ ├── CommandExecutor.java (Action métier exécutable)
|
||
│ ├── CommandSenderType.java (ALL, PLAYER_ONLY, CONSOLE_ONLY)
|
||
│ ├── CommandResult.java (SUCCESS, FAILED, CANCELLED, COOLDOWN, etc.)
|
||
│ └── suggestion/ (Suggestions de complétion)
|
||
├── builder/ (DSL Fluent Builder)
|
||
│ ├── AbstractCommandBuilder.java
|
||
│ ├── CommandBuilder.java
|
||
│ └── SubCommandBuilder.java
|
||
├── argument/ (Moteur d'arguments typés)
|
||
│ ├── CommandArgument.java
|
||
│ ├── ArgumentType.java
|
||
│ ├── Arguments.java (Factory d'arguments)
|
||
│ └── type/ (String, Integer, Player, Duration, Enum, etc.)
|
||
├── validation/ (Moteur de validation de commande et d'argument)
|
||
│ ├── CommandValidator.java
|
||
│ ├── ArgumentValidator.java
|
||
│ └── ValidationResult.java
|
||
├── confirmation/ (Système de confirmation / Double validation)
|
||
│ ├── ConfirmationManager.java
|
||
│ └── PendingConfirmation.java
|
||
├── repeat/ (Tâches répétées & cadence de commandes)
|
||
│ ├── CommandRepeater.java
|
||
│ └── CommandRepeatProgress.java
|
||
├── event/ (Bus d'événements & Lifecycle)
|
||
│ ├── CommandEvent.java
|
||
│ ├── CancellableCommandEvent.java
|
||
│ ├── CommandPreExecuteEvent.java
|
||
│ ├── CommandPostExecuteEvent.java
|
||
│ ├── CommandConfirmationRequiredEvent.java
|
||
│ ├── CommandPermissionDeniedEvent.java
|
||
│ ├── CommandSyntaxErrorEvent.java
|
||
│ ├── CommandCooldownEvent.java
|
||
│ ├── CommandTabCompleteEvent.java
|
||
│ ├── CommandEventManager.java
|
||
│ └── annotation/
|
||
│ └── CommandEventHandler.java
|
||
├── cooldown/ (Gestionnaire de Cooldowns par joueur)
|
||
│ └── CooldownManager.java
|
||
├── platform/ (Ponts plateformes & Injection CommandMap)
|
||
│ ├── CommandDispatcher.java
|
||
│ └── paper/
|
||
│ ├── PaperCommandMapInjector.java
|
||
│ └── PaperCommandWrapper.java
|
||
└── demo/ (Plugin de démonstration complet)
|
||
├── DemoPlugin.java
|
||
└── commands/
|
||
├── DemoBaseCommand.java
|
||
└── DemoListener.java
|
||
```
|
||
|
||
---
|
||
|
||
## 📄 Licence
|
||
|
||
Ce projet est sous licence [MIT](LICENSE).
|