From 14df461dfbc468f1a2ece054d4de0f79a2dc2b89 Mon Sep 17 00:00:00 2001 From: GeminiAntigravityCLI Date: Thu, 20 Aug 2026 17:42:25 +0200 Subject: [PATCH] feat(commands): integrate betterMcCommands framework and implement complete /guild command suite --- build.gradle.kts | 5 + settings.gradle.kts | 3 +- src/main/java/fr/luc/gamingcore/Main.java | 21 +- .../luc/gamingcore/command/GuildCommands.java | 485 ++++++++++++++++++ .../fr/luc/gamingcore/model/GuildMember.java | 18 + 5 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 src/main/java/fr/luc/gamingcore/command/GuildCommands.java diff --git a/build.gradle.kts b/build.gradle.kts index bbf0029..d941e9a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,6 +7,7 @@ group = "fr.luc" version = "1.0.0-SNAPSHOT" repositories { + mavenLocal() mavenCentral() maven("https://repo.papermc.io/repository/maven-public/") maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") @@ -26,6 +27,9 @@ dependencies { // Vault API (Economy & Permissions) 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) implementation("net.kyori:adventure-platform-bukkit:4.3.4") 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("com.cryptomorin.xseries", "fr.luc.gamingcore.libs.xseries") relocate("net.kyori.adventure.platform.bukkit", "fr.luc.gamingcore.libs.adventure.platform") + relocate("fr.luc.bettermccommands", "fr.luc.gamingcore.libs.bettermccommands") } tasks.processResources { diff --git a/settings.gradle.kts b/settings.gradle.kts index 9b20e33..766dd77 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,2 @@ -rootProject.name = "gamingcore" \ No newline at end of file +rootProject.name = "gamingcore" +includeBuild("../betterMcCommands") \ No newline at end of file diff --git a/src/main/java/fr/luc/gamingcore/Main.java b/src/main/java/fr/luc/gamingcore/Main.java index 7d01c54..ef34527 100644 --- a/src/main/java/fr/luc/gamingcore/Main.java +++ b/src/main/java/fr/luc/gamingcore/Main.java @@ -27,6 +27,7 @@ public final class Main extends JavaPlugin { private GuildRepository guildRepository; private EconomyManager economyManager; private GuildManager guildManager; + private fr.luc.bettermccommands.BetterMcCommands betterMcCommands; /** * 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.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(); 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 public void onDisable() { + if (betterMcCommands != null) { + betterMcCommands.unregisterAll(); + } if (guildManager != null) { guildManager.shutdown(); } @@ -179,4 +187,13 @@ public final class Main extends JavaPlugin { public GuildManager getGuildManager() { return guildManager; } + + /** + * Obtient l'instance du framework betterMcCommands. + * + * @return L'instance BetterMcCommands. + */ + public fr.luc.bettermccommands.BetterMcCommands getBetterMcCommands() { + return betterMcCommands; + } } diff --git a/src/main/java/fr/luc/gamingcore/command/GuildCommands.java b/src/main/java/fr/luc/gamingcore/command/GuildCommands.java new file mode 100644 index 0000000..0e2e392 --- /dev/null +++ b/src/main/java/fr/luc/gamingcore/command/GuildCommands.java @@ -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("=== SYSTÈME DE GUILDE ==="); + context.reply("/guild create [tag] - Fonder une nouvelle guilde"); + context.reply("/guild disband - Dissoudre votre guilde"); + context.reply("/guild invite - Inviter un joueur"); + context.reply("/guild join - Rejoindre une guilde invitante"); + context.reply("/guild leave - Quitter votre guilde"); + context.reply("/guild kick - Expulser un membre"); + context.reply("/guild info [guilde] - Afficher les détails d'une guilde"); + context.reply("/guild members [guilde] - Liste des membres"); + context.reply("/guild claim - Revendiquer le chunk actuel"); + context.reply("/guild unclaim - Libérer le chunk actuel"); + context.reply("/guild deposit - Déposer dans la banque"); + context.reply("/guild withdraw - Retirer de la banque"); + context.reply("/guild sethome - Définir le point de ralliement"); + context.reply("/guild home - Se téléporter au home de guilde"); + }) + + // ------------------------------------------------------------- + // Sous-commande : /guild create [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 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 + // ------------------------------------------------------------- + .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 à " + target.getName() + " (Expire dans " + invite.getRemainingSeconds() + "s)."); + TextUtil.sendMessage(target, "[Guilde] Vous avez été invité à rejoindre la guilde " + guild.getName() + " par " + sender.getName() + " !"); + TextUtil.sendMessage(target, "Tapez /guild join " + guild.getName() + " pour accepter."); + }) + ) + + // ------------------------------------------------------------- + // Sous-commande : /guild join (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 + // ------------------------------------------------------------- + .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 + // ------------------------------------------------------------- + .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 + // ------------------------------------------------------------- + .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, "Téléportation au home de guilde réussie !"); + } + }); + }) + ) + + // ------------------------------------------------------------- + // 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 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("=== INFORMATIONS DE GUILDE ==="); + context.reply("Nom : " + targetGuild.getName() + " [" + targetGuild.getTag() + "]"); + context.reply("Chef : " + leaderName + ""); + context.reply("Membres : " + targetGuild.getMemberCount() + ""); + context.reply("Banque : " + guildManager.getEconomyManager().format(targetGuild.getBalance()) + ""); + context.reply("Territoires : " + targetGuild.getClaimCount() + " chunks (Prochain: " + guildManager.getEconomyManager().format(nextPrice) + ")"); + }) + ) + + // ------------------------------------------------------------- + // 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 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("=== MEMBRES : " + targetGuild.getName() + " ==="); + 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("" + rank.getName() + " (" + rank.getPriority() + ") : " + membersInRank + ""); + } + } + }) + ) + + .register(); + } +} diff --git a/src/main/java/fr/luc/gamingcore/model/GuildMember.java b/src/main/java/fr/luc/gamingcore/model/GuildMember.java index 9906e77..ba48e2a 100644 --- a/src/main/java/fr/luc/gamingcore/model/GuildMember.java +++ b/src/main/java/fr/luc/gamingcore/model/GuildMember.java @@ -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 public boolean equals(Object o) { if (this == o) return true;