feat(commands): integrate betterMcCommands framework and implement complete /guild command suite

This commit is contained in:
2026-08-20 17:42:25 +02:00
parent 875ae94da3
commit 14df461dfb
5 changed files with 529 additions and 3 deletions
+5
View File
@@ -7,6 +7,7 @@ group = "fr.luc"
version = "1.0.0-SNAPSHOT" version = "1.0.0-SNAPSHOT"
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
@@ -26,6 +27,9 @@ dependencies {
// Vault API (Economy & Permissions) // Vault API (Economy & Permissions)
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1") compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")
// betterMcCommands - Framework de commandes dynamique
implementation("fr.luc:betterMcCommands:1.0.0-SNAPSHOT")
// Adventure platform for Bukkit (cross-version RGB, MiniMessage, Titles, ActionBars) // Adventure platform for Bukkit (cross-version RGB, MiniMessage, Titles, ActionBars)
implementation("net.kyori:adventure-platform-bukkit:4.3.4") implementation("net.kyori:adventure-platform-bukkit:4.3.4")
implementation("net.kyori:adventure-text-minimessage:4.17.0") implementation("net.kyori:adventure-text-minimessage:4.17.0")
@@ -54,6 +58,7 @@ tasks.shadowJar {
// Relocate shaded libraries to avoid collisions with other plugins // Relocate shaded libraries to avoid collisions with other plugins
relocate("com.cryptomorin.xseries", "fr.luc.gamingcore.libs.xseries") relocate("com.cryptomorin.xseries", "fr.luc.gamingcore.libs.xseries")
relocate("net.kyori.adventure.platform.bukkit", "fr.luc.gamingcore.libs.adventure.platform") relocate("net.kyori.adventure.platform.bukkit", "fr.luc.gamingcore.libs.adventure.platform")
relocate("fr.luc.bettermccommands", "fr.luc.gamingcore.libs.bettermccommands")
} }
tasks.processResources { tasks.processResources {
+2 -1
View File
@@ -1 +1,2 @@
rootProject.name = "gamingcore" rootProject.name = "gamingcore"
includeBuild("../betterMcCommands")
+19 -2
View File
@@ -27,6 +27,7 @@ public final class Main extends JavaPlugin {
private GuildRepository guildRepository; private GuildRepository guildRepository;
private EconomyManager economyManager; private EconomyManager economyManager;
private GuildManager guildManager; private GuildManager guildManager;
private fr.luc.bettermccommands.BetterMcCommands betterMcCommands;
/** /**
* Méthode appelée lors de l'activation du plugin par le serveur Minecraft. * Méthode appelée lors de l'activation du plugin par le serveur Minecraft.
@@ -55,11 +56,15 @@ public final class Main extends JavaPlugin {
this.guildManager = new GuildManager(this, guildRepository, economyManager); this.guildManager = new GuildManager(this, guildRepository, economyManager);
this.guildManager.loadData(); this.guildManager.loadData();
// 6. Enregistrer les écouteurs d'événements // 6. Initialiser le framework betterMcCommands et enregistrer les commandes
this.betterMcCommands = fr.luc.bettermccommands.BetterMcCommands.create(this);
new fr.luc.gamingcore.command.GuildCommands(this, guildManager).register();
// 7. Enregistrer les écouteurs d'événements
PluginManager pm = getServer().getPluginManager(); PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new TerritoryProtectionListener(guildManager), this); pm.registerEvents(new TerritoryProtectionListener(guildManager), this);
getLogger().info("GamingCore (Système de Guilde - Cœur Métier) a ete active avec succes !"); getLogger().info("GamingCore (Système de Guilde - Cœur Métier & Commandes) a ete active avec succes !");
} }
/** /**
@@ -67,6 +72,9 @@ public final class Main extends JavaPlugin {
*/ */
@Override @Override
public void onDisable() { public void onDisable() {
if (betterMcCommands != null) {
betterMcCommands.unregisterAll();
}
if (guildManager != null) { if (guildManager != null) {
guildManager.shutdown(); guildManager.shutdown();
} }
@@ -179,4 +187,13 @@ public final class Main extends JavaPlugin {
public GuildManager getGuildManager() { public GuildManager getGuildManager() {
return guildManager; return guildManager;
} }
/**
* Obtient l'instance du framework betterMcCommands.
*
* @return L'instance BetterMcCommands.
*/
public fr.luc.bettermccommands.BetterMcCommands getBetterMcCommands() {
return betterMcCommands;
}
} }
@@ -0,0 +1,485 @@
package fr.luc.gamingcore.command;
import fr.luc.bettermccommands.BetterMcCommands;
import fr.luc.bettermccommands.argument.Arguments;
import fr.luc.gamingcore.Main;
import fr.luc.gamingcore.manager.GuildManager;
import fr.luc.gamingcore.manager.GuildResult;
import fr.luc.gamingcore.manager.InviteManager;
import fr.luc.gamingcore.model.*;
import fr.luc.gamingcore.util.TextUtil;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Enregistrement et définition des commandes de guilde via le framework fluent **betterMcCommands**.
*/
public class GuildCommands {
private final Main plugin;
private final GuildManager guildManager;
private final InviteManager inviteManager;
/**
* Constructeur des commandes de guilde.
*
* @param plugin Instance principale du plugin.
* @param guildManager Gestionnaire métier des guildes.
*/
public GuildCommands(Main plugin, GuildManager guildManager) {
this.plugin = plugin;
this.guildManager = guildManager;
this.inviteManager = guildManager.getInviteManager();
}
/**
* Enregistre l'arbre complet de la commande racine `/guild` et de toutes ses sous-commandes.
*/
public void register() {
double creationCost = plugin.getConfig().getDouble("guild.creation_cost", 1000.0);
BetterMcCommands.builder("guild")
.description("Commande principale de gestion des guildes")
.aliases("g", "guilde", "clan")
// -------------------------------------------------------------
// Racine /guild : Affichage du panneau d'aide
// -------------------------------------------------------------
.executes(context -> {
context.reply("<gradient:#00C9FF:#92FE9D><bold>=== SYSTÈME DE GUILDE ===</bold></gradient>");
context.reply("<yellow>/guild create <nom> [tag]</yellow> <gray>- Fonder une nouvelle guilde</gray>");
context.reply("<yellow>/guild disband</yellow> <gray>- Dissoudre votre guilde</gray>");
context.reply("<yellow>/guild invite <joueur></yellow> <gray>- Inviter un joueur</gray>");
context.reply("<yellow>/guild join <guilde></yellow> <gray>- Rejoindre une guilde invitante</gray>");
context.reply("<yellow>/guild leave</yellow> <gray>- Quitter votre guilde</gray>");
context.reply("<yellow>/guild kick <joueur></yellow> <gray>- Expulser un membre</gray>");
context.reply("<yellow>/guild info [guilde]</yellow> <gray>- Afficher les détails d'une guilde</gray>");
context.reply("<yellow>/guild members [guilde]</yellow> <gray>- Liste des membres</gray>");
context.reply("<yellow>/guild claim</yellow> <gray>- Revendiquer le chunk actuel</gray>");
context.reply("<yellow>/guild unclaim</yellow> <gray>- Libérer le chunk actuel</gray>");
context.reply("<yellow>/guild deposit <montant></yellow> <gray>- Déposer dans la banque</gray>");
context.reply("<yellow>/guild withdraw <montant></yellow> <gray>- Retirer de la banque</gray>");
context.reply("<yellow>/guild sethome</yellow> <gray>- Définir le point de ralliement</gray>");
context.reply("<yellow>/guild home</yellow> <gray>- Se téléporter au home de guilde</gray>");
})
// -------------------------------------------------------------
// Sous-commande : /guild create <nom> [tag]
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("create")
.description("Créer une nouvelle guilde")
.playerOnly()
.argument(Arguments.string("nom").description("Nom de la guilde (3-16 car)"))
.argument(Arguments.string("tag").optional().description("Tag court (ex: LEG)"))
.executes(context -> {
Player player = context.getPlayer();
String name = context.getString("nom");
Optional<String> tagOpt = context.getOptional("tag", String.class);
String tag = tagOpt.orElse(name.length() <= 4 ? name.toUpperCase() : name.substring(0, 4).toUpperCase());
GuildResult result = guildManager.createGuild(player, name, tag, creationCost);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild disband
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("disband")
.description("Dissoudre définitivement votre guilde")
.aliases("delete", "supprimer")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
GuildResult result = guildManager.disbandGuild(player, guild);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild invite <joueur>
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("invite")
.description("Inviter un joueur connecté à rejoindre votre guilde")
.playerOnly()
.argument(Arguments.player("joueur").description("Joueur cible"))
.executes(context -> {
Player sender = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(sender.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
if (!guild.hasPermission(sender.getUniqueId(), GuildPermission.INVITE)) {
context.replyError("Votre rang ne vous autorise pas à inviter des joueurs.");
return;
}
Player target = context.getTargetPlayer("joueur");
if (target.getUniqueId().equals(sender.getUniqueId())) {
context.replyError("Vous ne pouvez pas vous inviter vous-même.");
return;
}
if (guildManager.isInGuild(target.getUniqueId())) {
context.replyError("Ce joueur appartient déjà à une guilde.");
return;
}
GuildInvite invite = inviteManager.sendInvite(guild, sender, target);
context.replySuccess("Invitation envoyée à <white>" + target.getName() + "</white> (Expire dans " + invite.getRemainingSeconds() + "s).");
TextUtil.sendMessage(target, "<gradient:#00C9FF:#92FE9D>[Guilde]</gradient> Vous avez été invité à rejoindre la guilde <white><bold>" + guild.getName() + "</bold></white> par <yellow>" + sender.getName() + "</yellow> !");
TextUtil.sendMessage(target, "<gray>Tapez <yellow>/guild join " + guild.getName() + "</yellow> pour accepter.</gray>");
})
)
// -------------------------------------------------------------
// Sous-commande : /guild join <guilde> (ou /guild accept)
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("join")
.description("Accepter une invitation et rejoindre une guilde")
.aliases("accept", "rejoindre")
.playerOnly()
.argument(Arguments.string("guilde").description("Nom de la guilde"))
.executes(context -> {
Player player = context.getPlayer();
if (guildManager.isInGuild(player.getUniqueId())) {
context.replyError("Vous appartenez déjà à une guilde.");
return;
}
String guildName = context.getString("guilde");
Guild targetGuild = guildManager.getGuildByName(guildName);
if (targetGuild == null) {
context.replyError("La guilde '" + guildName + "' n'existe pas.");
return;
}
GuildInvite invite = inviteManager.getValidInvite(player, targetGuild.getId());
if (invite == null) {
context.replyError("Vous n'avez aucune invitation valide en attente pour cette guilde.");
return;
}
inviteManager.removeInvite(player, targetGuild.getId());
GuildResult result = guildManager.addMember(targetGuild, player);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild leave
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("leave")
.description("Quitter votre guilde actuelle")
.aliases("quitter")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
GuildResult result = guildManager.leaveGuild(player, guild);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild kick <joueur>
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("kick")
.description("Expulser un membre de votre guilde")
.playerOnly()
.argument(Arguments.player("joueur").description("Joueur à expulser"))
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
Player target = context.getTargetPlayer("joueur");
GuildResult result = guildManager.kickMember(player, guild, target.getUniqueId());
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild claim
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("claim")
.description("Revendiquer le chunk actuel pour votre guilde")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
Location loc = player.getLocation();
Chunk chunk = loc.getChunk();
GuildResult result = guildManager.claimChunk(player, guild, loc.getWorld(), chunk.getX(), chunk.getZ());
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild unclaim
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("unclaim")
.description("Libérer le chunk actuel")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
Location loc = player.getLocation();
Chunk chunk = loc.getChunk();
GuildResult result = guildManager.unclaimChunk(player, guild, loc.getWorld(), chunk.getX(), chunk.getZ());
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild deposit <montant>
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("deposit")
.description("Déposer de l'argent dans la banque de guilde")
.aliases("deposer", "don")
.playerOnly()
.argument(Arguments.decimal("montant", 1.0, 1000000000.0).description("Somme à déposer"))
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
double amount = context.getDouble("montant");
GuildResult result = guildManager.depositMoney(player, guild, amount);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild withdraw <montant>
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("withdraw")
.description("Retirer de l'argent de la banque de guilde")
.aliases("retirer")
.playerOnly()
.argument(Arguments.decimal("montant", 1.0, 1000000000.0).description("Somme à retirer"))
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
double amount = context.getDouble("montant");
GuildResult result = guildManager.withdrawMoney(player, guild, amount);
if (result.isSuccess()) {
context.replySuccess(result.getMessage());
} else {
context.replyError(result.getMessage());
}
})
)
// -------------------------------------------------------------
// Sous-commande : /guild sethome
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("sethome")
.description("Définir le home de guilde à votre position")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.SET_HOME)) {
context.replyError("Votre rang ne vous autorise pas à modifier le home de guilde.");
return;
}
Location loc = player.getLocation();
Chunk chunk = loc.getChunk();
if (!guild.isClaimed(loc.getWorld().getName(), chunk.getX(), chunk.getZ())) {
context.replyError("Le point de ralliement doit impérativement se situer sur un territoire possédé par la guilde !");
return;
}
guild.setHome(loc);
plugin.getGuildRepository().saveGuildAsync(guild);
context.replySuccess("Le home de guilde a été mis à jour avec succès !");
})
)
// -------------------------------------------------------------
// Sous-commande : /guild home
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("home")
.description("Se téléporter au point de ralliement de la guilde")
.playerOnly()
.executes(context -> {
Player player = context.getPlayer();
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
if (guild == null) {
context.replyError("Vous n'appartenez à aucune guilde.");
return;
}
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.HOME)) {
context.replyError("Votre rang ne vous autorise pas à vous téléporter au home de guilde.");
return;
}
Location homeLoc = guild.getHomeLocation();
if (homeLoc == null) {
context.replyError("Aucun home n'est défini pour votre guilde.");
return;
}
player.teleportAsync(homeLoc).thenAccept(success -> {
if (success) {
TextUtil.sendActionBar(player, "<green>Téléportation au home de guilde réussie !</green>");
}
});
})
)
// -------------------------------------------------------------
// Sous-commande : /guild info [guilde]
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("info")
.description("Afficher les informations d'une guilde")
.argument(Arguments.string("guilde").optional().description("Nom de la guilde"))
.executes(context -> {
Guild targetGuild;
Optional<String> nameOpt = context.getOptional("guilde", String.class);
if (nameOpt.isPresent()) {
targetGuild = guildManager.getGuildByName(nameOpt.get());
} else if (context.isPlayer()) {
targetGuild = guildManager.getGuildByPlayer(context.getPlayer().getUniqueId());
} else {
context.replyError("Veuillez préciser le nom de la guilde depuis la console.");
return;
}
if (targetGuild == null) {
context.replyError("Guilde introuvable.");
return;
}
double nextPrice = guildManager.getPriceCalculator().calculateNextChunkPrice(targetGuild);
GuildMember leader = targetGuild.getLeaderMember();
String leaderName = leader != null && leader.getOfflinePlayer() != null ? leader.getOfflinePlayer().getName() : "Inconnu";
context.reply("<gradient:#00C9FF:#92FE9D><bold>=== INFORMATIONS DE GUILDE ===</bold></gradient>");
context.reply("<gray>Nom :</gray> <white><bold>" + targetGuild.getName() + "</bold></white> <dark_gray>[" + targetGuild.getTag() + "]</dark_gray>");
context.reply("<gray>Chef :</gray> <gold>" + leaderName + "</gold>");
context.reply("<gray>Membres :</gray> <yellow>" + targetGuild.getMemberCount() + "</yellow>");
context.reply("<gray>Banque :</gray> <green>" + guildManager.getEconomyManager().format(targetGuild.getBalance()) + "</green>");
context.reply("<gray>Territoires :</gray> <aqua>" + targetGuild.getClaimCount() + " chunks</aqua> <dark_gray>(Prochain: " + guildManager.getEconomyManager().format(nextPrice) + ")</dark_gray>");
})
)
// -------------------------------------------------------------
// Sous-commande : /guild members [guilde]
// -------------------------------------------------------------
.subcommand(BetterMcCommands.subBuilder("members")
.description("Afficher la liste des membres d'une guilde")
.argument(Arguments.string("guilde").optional().description("Nom de la guilde"))
.executes(context -> {
Guild targetGuild;
Optional<String> nameOpt = context.getOptional("guilde", String.class);
if (nameOpt.isPresent()) {
targetGuild = guildManager.getGuildByName(nameOpt.get());
} else if (context.isPlayer()) {
targetGuild = guildManager.getGuildByPlayer(context.getPlayer().getUniqueId());
} else {
context.replyError("Veuillez préciser le nom de la guilde.");
return;
}
if (targetGuild == null) {
context.replyError("Guilde introuvable.");
return;
}
context.reply("<gradient:#00C9FF:#92FE9D><bold>=== MEMBRES : " + targetGuild.getName() + " ===</bold></gradient>");
for (GuildRank rank : targetGuild.getRanks()) {
String membersInRank = targetGuild.getMembers().stream()
.filter(m -> m.getRankId().equalsIgnoreCase(rank.getId()))
.map(m -> m.getOfflinePlayer() != null && m.getOfflinePlayer().getName() != null ? m.getOfflinePlayer().getName() : m.getPlayerUuid().toString().substring(0, 8))
.collect(Collectors.joining(", "));
if (!membersInRank.isEmpty()) {
context.reply("<gold>" + rank.getName() + " <dark_gray>(" + rank.getPriority() + ")</dark_gray> :</gold> <gray>" + membersInRank + "</gray>");
}
}
})
)
.register();
}
}
@@ -117,6 +117,24 @@ public class GuildMember {
} }
} }
/**
* Récupère l'instance Bukkit {@link org.bukkit.OfflinePlayer} correspondant au membre.
*
* @return L'instance OfflinePlayer.
*/
public org.bukkit.OfflinePlayer getOfflinePlayer() {
return org.bukkit.Bukkit.getOfflinePlayer(playerUuid);
}
/**
* Récupère l'instance Bukkit {@link org.bukkit.entity.Player} si le joueur est actuellement connecté.
*
* @return L'instance Player ou null si déconnecté.
*/
public org.bukkit.entity.Player getPlayer() {
return org.bukkit.Bukkit.getPlayer(playerUuid);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;