Files
betterMcCommands/README.md
T

475 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ⚡ betterMcCommands
[![Java](https://img.shields.io/badge/Java-17%2B%20%2F%2021-orange.svg)](https://www.oracle.com/java/)
[![Paper](https://img.shields.io/badge/Paper-1.20.4%2B-blue.svg)](https://papermc.io/)
[![Kyori Adventure](https://img.shields.io/badge/Adventure-MiniMessage-purple.svg)](https://docs.advntr.dev/)
[![License](https://img.shields.io/badge/License-MIT-green.svg)](#)
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
- [📚 Guides Détaillés (Dossier `/docs`)](#-guides-détaillés-dossier-docs)
- [🌟 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)
---
## 📚 Guides Détaillés (Dossier `/docs`)
Pour aller plus loin, consultez la documentation modulaire :
* 📘 [**01. Guide de Démarrage Rapide**](docs/01_GETTING_STARTED.md) : Installation, structure de plugin et initialisation.
* 🏗️ [**02. Fluent Builder DSL**](docs/02_COMMAND_BUILDER_DSL.md) : Déclaration de commandes racines, sous-commandes imbriquées, restrictions et alias.
* 🧩 [**03. Arguments Typés & Auto-complétion**](docs/03_TYPED_ARGUMENTS.md) : Catalogue exhaustif des arguments, parsers personnalisés et Tab-Complete.
* 🎯 [**04. Système d'Événements & Cycle de Vie**](docs/04_LIFECYCLE_EVENTS.md) : Hooks d'exécution, écouteurs `@CommandEventHandler` et gestion des erreurs.
* 🛡️ [**05. Validation & Double Confirmation**](docs/05_VALIDATION_AND_CONFIRMATION.md) : Validateurs de pré-requis et confirmations interactives.
* ⏳ [**06. Cooldowns & Répétition de Commandes**](docs/06_COOLDOWNS_AND_REPEAT.md) : Temps de recharge, bypass et exécution répétée (`CommandRepeater`).
* ⚙️ [**07. Plateforme & Injection CommandMap**](docs/07_PLATFORM_AND_INJECTION.md) : Fonctionnement sous le capot, réflexion et hot-reload.
---
## 🌟 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).