refactor: clean base with WorldGuard, WorldEdit, and Vault dependencies
This commit is contained in:
@@ -23,6 +23,9 @@ dependencies {
|
|||||||
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
|
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
|
||||||
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.3.0")
|
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.3.0")
|
||||||
|
|
||||||
|
// Vault API (Economy & Permissions)
|
||||||
|
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")
|
||||||
|
|
||||||
// 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")
|
||||||
|
|||||||
@@ -1,23 +1,91 @@
|
|||||||
package fr.luc.gamingcore;
|
package fr.luc.gamingcore;
|
||||||
|
|
||||||
|
import com.sk89q.worldguard.WorldGuard;
|
||||||
|
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||||
|
import fr.luc.gamingcore.command.CommandManager;
|
||||||
|
import fr.luc.gamingcore.util.TextUtil;
|
||||||
|
import net.milkbowl.vault.economy.Economy;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public final class Main extends JavaPlugin {
|
public final class Main extends JavaPlugin {
|
||||||
|
|
||||||
private static Main instance;
|
private static Main instance;
|
||||||
|
|
||||||
|
private Economy economy;
|
||||||
|
private RegionContainer regionContainer;
|
||||||
|
private CommandManager commandManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
getLogger().info("GamingCore a ete active avec succes !");
|
saveDefaultConfig();
|
||||||
|
|
||||||
|
// 1. Initialiser le préfixe de messages MiniMessage
|
||||||
|
TextUtil.setPrefix(getConfig().getString("prefix", "<gradient:#00C9FF:#92FE9D>[Guilde]</gradient> <dark_gray>»</dark_gray> <gray>"));
|
||||||
|
|
||||||
|
// 2. Connexion à WorldGuard
|
||||||
|
setupWorldGuard();
|
||||||
|
|
||||||
|
// 3. Connexion à Vault (Économie)
|
||||||
|
setupEconomy();
|
||||||
|
|
||||||
|
// 4. Initialisation du CommandManager dynamique
|
||||||
|
this.commandManager = new CommandManager(this);
|
||||||
|
|
||||||
|
getLogger().info("GamingCore (Système de Guilde) a ete active avec succes !");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
if (commandManager != null) {
|
||||||
|
commandManager.shutdown();
|
||||||
|
}
|
||||||
getLogger().info("GamingCore a ete desactive !");
|
getLogger().info("GamingCore a ete desactive !");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupWorldGuard() {
|
||||||
|
try {
|
||||||
|
this.regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||||
|
getLogger().info("Connexion avec WorldGuard 7 etablie avec succes !");
|
||||||
|
} catch (Throwable t) {
|
||||||
|
getLogger().warning("Impossible d'initialiser WorldGuard : " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupEconomy() {
|
||||||
|
if (getServer().getPluginManager().getPlugin("Vault") == null) {
|
||||||
|
getLogger().warning("Vault n'a pas ete detecte ! Le support economique sera desactive.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
|
||||||
|
if (rsp == null) {
|
||||||
|
getLogger().warning("Aucun provider d'economie (ex: Essentials, TheNewEconomy) trouve via Vault !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.economy = rsp.getProvider();
|
||||||
|
getLogger().info("Connexion avec l'economie Vault (" + economy.getName() + ") etablie avec succes !");
|
||||||
|
}
|
||||||
|
|
||||||
public static Main getInstance() {
|
public static Main getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Economy getEconomy() {
|
||||||
|
return economy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEconomy() {
|
||||||
|
return economy != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionContainer getRegionContainer() {
|
||||||
|
return regionContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandManager getCommandManager() {
|
||||||
|
return commandManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParseException;
|
||||||
|
import fr.luc.gamingcore.command.argument.CommandArgument;
|
||||||
|
import fr.luc.gamingcore.command.cooldown.CooldownManager;
|
||||||
|
import fr.luc.gamingcore.util.TextUtil;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class AppCommand {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger("GamingCore");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final List<String> aliases;
|
||||||
|
private final String description;
|
||||||
|
private final String permission;
|
||||||
|
private final String permissionMessage;
|
||||||
|
private final boolean playerOnly;
|
||||||
|
private final long cooldownMillis;
|
||||||
|
private final String cooldownBypassPermission;
|
||||||
|
private final List<CommandArgument<?>> arguments;
|
||||||
|
private final Map<String, AppCommand> subCommands;
|
||||||
|
private final CommandHandler handler;
|
||||||
|
|
||||||
|
public AppCommand(String name, List<String> aliases, String description, String permission,
|
||||||
|
String permissionMessage, boolean playerOnly, long cooldownMillis,
|
||||||
|
String cooldownBypassPermission, List<CommandArgument<?>> arguments,
|
||||||
|
Map<String, AppCommand> subCommands, CommandHandler handler) {
|
||||||
|
this.name = name.toLowerCase();
|
||||||
|
this.aliases = aliases != null ? aliases : Collections.emptyList();
|
||||||
|
this.description = description != null ? description : "";
|
||||||
|
this.permission = permission;
|
||||||
|
this.permissionMessage = permissionMessage != null ? permissionMessage : "<red>Tu n'as pas la permission d'exécuter cette commande.</red>";
|
||||||
|
this.playerOnly = playerOnly;
|
||||||
|
this.cooldownMillis = cooldownMillis;
|
||||||
|
this.cooldownBypassPermission = cooldownBypassPermission != null ? cooldownBypassPermission : "gamingcore.cooldown.bypass";
|
||||||
|
this.arguments = arguments != null ? arguments : Collections.emptyList();
|
||||||
|
this.subCommands = subCommands != null ? subCommands : Collections.emptyMap();
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAliases() {
|
||||||
|
return aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlayerOnly() {
|
||||||
|
return playerOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCooldownMillis() {
|
||||||
|
return cooldownMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CommandArgument<?>> getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, AppCommand> getSubCommands() {
|
||||||
|
return subCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppCommand getSubCommand(String name) {
|
||||||
|
if (name == null) return null;
|
||||||
|
String lower = name.toLowerCase();
|
||||||
|
AppCommand direct = subCommands.get(lower);
|
||||||
|
if (direct != null) return direct;
|
||||||
|
for (AppCommand sub : subCommands.values()) {
|
||||||
|
if (sub.getAliases().stream().anyMatch(a -> a.equalsIgnoreCase(lower))) {
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(CommandSender sender, String label, String[] args, CooldownManager cooldownManager, String currentPath) {
|
||||||
|
String fullPath = currentPath.isEmpty() ? name : currentPath + " " + name;
|
||||||
|
|
||||||
|
// 1. Permission check
|
||||||
|
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
|
||||||
|
TextUtil.sendMessage(sender, permissionMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Player-only check
|
||||||
|
if (playerOnly && !(sender instanceof Player)) {
|
||||||
|
sender.sendMessage("Cette commande doit être exécutée par un joueur.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Sub-command check
|
||||||
|
if (args.length > 0) {
|
||||||
|
AppCommand sub = getSubCommand(args[0]);
|
||||||
|
if (sub != null) {
|
||||||
|
String[] nextArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||||
|
sub.execute(sender, args[0], nextArgs, cooldownManager, fullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. If no sub-command matched but handler is null, show help
|
||||||
|
if (handler == null) {
|
||||||
|
sendHelp(sender, fullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = sender instanceof Player ? (Player) sender : null;
|
||||||
|
|
||||||
|
// 5. Cooldown check
|
||||||
|
if (player != null && cooldownMillis > 0 && !player.hasPermission(cooldownBypassPermission)) {
|
||||||
|
String cooldownKey = fullPath;
|
||||||
|
if (cooldownManager.isOnCooldown(player, cooldownKey)) {
|
||||||
|
double remaining = cooldownManager.getRemainingSeconds(player, cooldownKey);
|
||||||
|
TextUtil.sendMessage(player, "<red>⏳ Veuillez patienter <yellow>" + remaining + "s</yellow> avant de réutiliser cette commande.</red>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Argument parsing
|
||||||
|
Map<String, Object> parsedArgs = new HashMap<>();
|
||||||
|
CommandContext preliminaryContext = new CommandContext(sender, label, args, parsedArgs, fullPath);
|
||||||
|
|
||||||
|
int argIndex = 0;
|
||||||
|
for (int i = 0; i < arguments.size(); i++) {
|
||||||
|
CommandArgument<?> argument = arguments.get(i);
|
||||||
|
|
||||||
|
if (argIndex >= args.length) {
|
||||||
|
if (argument.isRequired()) {
|
||||||
|
TextUtil.sendMessage(sender, "<red>Syntaxe incorrecte : <yellow>/" + fullPath + " " + getSyntax() + "</yellow></red>");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
parsedArgs.put(argument.getName().toLowerCase(), argument.getDefaultValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String inputString;
|
||||||
|
if (argument.isGreedy()) {
|
||||||
|
// Consume all remaining arguments
|
||||||
|
inputString = String.join(" ", Arrays.copyOfRange(args, argIndex, args.length));
|
||||||
|
argIndex = args.length;
|
||||||
|
} else {
|
||||||
|
inputString = args[argIndex];
|
||||||
|
argIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object parsed = argument.getParser().parse(preliminaryContext, inputString);
|
||||||
|
parsedArgs.put(argument.getName().toLowerCase(), parsed);
|
||||||
|
} catch (ArgumentParseException e) {
|
||||||
|
TextUtil.sendMessage(sender, "<red>" + e.getMessage() + "</red>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Execution
|
||||||
|
CommandContext finalContext = new CommandContext(sender, label, args, parsedArgs, fullPath);
|
||||||
|
try {
|
||||||
|
handler.execute(finalContext);
|
||||||
|
|
||||||
|
// Apply cooldown on success
|
||||||
|
if (player != null && cooldownMillis > 0 && !player.hasPermission(cooldownBypassPermission)) {
|
||||||
|
cooldownManager.applyCooldown(player, fullPath, cooldownMillis);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
TextUtil.sendMessage(sender, "<red>Une erreur est survenue lors de l'exécution de la commande.</red>");
|
||||||
|
LOGGER.log(Level.SEVERE, "Erreur lors de l'exécution de la commande " + fullPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> tabComplete(CommandSender sender, String label, String[] args, String currentPath) {
|
||||||
|
String fullPath = currentPath.isEmpty() ? name : currentPath + " " + name;
|
||||||
|
|
||||||
|
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
String prefix = args[0].toLowerCase();
|
||||||
|
List<String> suggestions = new ArrayList<>();
|
||||||
|
|
||||||
|
// Suggest subcommands
|
||||||
|
for (AppCommand sub : subCommands.values()) {
|
||||||
|
if (sub.getPermission() == null || sub.getPermission().isEmpty() || sender.hasPermission(sub.getPermission())) {
|
||||||
|
if (sub.getName().toLowerCase().startsWith(prefix)) {
|
||||||
|
suggestions.add(sub.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check first argument completions if applicable
|
||||||
|
if (!arguments.isEmpty()) {
|
||||||
|
CommandContext ctx = new CommandContext(sender, label, args, Collections.emptyMap(), fullPath);
|
||||||
|
suggestions.addAll(arguments.get(0).getParser().complete(ctx, args[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if first arg matches a subcommand
|
||||||
|
AppCommand sub = getSubCommand(args[0]);
|
||||||
|
if (sub != null) {
|
||||||
|
String[] nextArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||||
|
return sub.tabComplete(sender, args[0], nextArgs, fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Argument completions
|
||||||
|
int targetArgIndex = args.length - 1;
|
||||||
|
if (targetArgIndex < arguments.size()) {
|
||||||
|
CommandArgument<?> argument = arguments.get(targetArgIndex);
|
||||||
|
CommandContext ctx = new CommandContext(sender, label, args, Collections.emptyMap(), fullPath);
|
||||||
|
return argument.getParser().complete(ctx, args[targetArgIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSyntax() {
|
||||||
|
if (arguments.isEmpty()) return "";
|
||||||
|
return arguments.stream()
|
||||||
|
.map(CommandArgument::getFormattedSyntax)
|
||||||
|
.collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendHelp(CommandSender sender, String fullPath) {
|
||||||
|
TextUtil.sendRawMessage(sender, "<gradient:#00C9FF:#92FE9D>═══════════ [ " + fullPath.toUpperCase() + " ] ═══════════</gradient>");
|
||||||
|
if (!description.isEmpty()) {
|
||||||
|
TextUtil.sendRawMessage(sender, " <gray>" + description + "</gray>");
|
||||||
|
}
|
||||||
|
if (!subCommands.isEmpty()) {
|
||||||
|
for (AppCommand sub : subCommands.values()) {
|
||||||
|
if (sub.getPermission() == null || sub.getPermission().isEmpty() || sender.hasPermission(sub.getPermission())) {
|
||||||
|
String subSyntax = sub.getSyntax();
|
||||||
|
String syntaxPart = subSyntax.isEmpty() ? "" : " " + subSyntax;
|
||||||
|
TextUtil.sendRawMessage(sender, " <yellow>/" + fullPath + " " + sub.getName() + syntaxPart + "</yellow> <dark_gray>-</dark_gray> <gray>" + sub.getDescription() + "</gray>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextUtil.sendRawMessage(sender, "<gradient:#00C9FF:#92FE9D>════════════════════════════════════════</gradient>");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.cooldown.CooldownManager;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BukkitCommandWrapper extends Command {
|
||||||
|
|
||||||
|
private final AppCommand appCommand;
|
||||||
|
private final CooldownManager cooldownManager;
|
||||||
|
|
||||||
|
public BukkitCommandWrapper(AppCommand appCommand, CooldownManager cooldownManager) {
|
||||||
|
super(appCommand.getName(), appCommand.getDescription(), "/" + appCommand.getName(), appCommand.getAliases());
|
||||||
|
this.appCommand = appCommand;
|
||||||
|
this.cooldownManager = cooldownManager;
|
||||||
|
if (appCommand.getPermission() != null && !appCommand.getPermission().isEmpty()) {
|
||||||
|
setPermission(appCommand.getPermission());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||||
|
appCommand.execute(sender, commandLabel, args, cooldownManager, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
return appCommand.tabComplete(sender, alias, args, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppCommand getAppCommand() {
|
||||||
|
return appCommand;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class CommandBuilder {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final List<String> aliases = new ArrayList<>();
|
||||||
|
private String description = "";
|
||||||
|
private String permission = null;
|
||||||
|
private String permissionMessage = null;
|
||||||
|
private boolean playerOnly = false;
|
||||||
|
private long cooldownMillis = 0L;
|
||||||
|
private String cooldownBypassPermission = "gamingcore.cooldown.bypass";
|
||||||
|
private final List<CommandArgument<?>> arguments = new ArrayList<>();
|
||||||
|
private final Map<String, AppCommand> subCommands = new LinkedHashMap<>();
|
||||||
|
private CommandHandler handler = null;
|
||||||
|
|
||||||
|
private CommandBuilder(String name) {
|
||||||
|
this.name = Objects.requireNonNull(name, "Command name cannot be null").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandBuilder create(String name) {
|
||||||
|
return new CommandBuilder(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder aliases(String... aliases) {
|
||||||
|
if (aliases != null) {
|
||||||
|
this.aliases.addAll(Arrays.asList(aliases));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder description(String description) {
|
||||||
|
this.description = description != null ? description : "";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder permission(String permission) {
|
||||||
|
this.permission = permission;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder permissionMessage(String message) {
|
||||||
|
this.permissionMessage = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder playerOnly() {
|
||||||
|
this.playerOnly = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder playerOnly(boolean playerOnly) {
|
||||||
|
this.playerOnly = playerOnly;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder cooldown(long amount, TimeUnit unit) {
|
||||||
|
this.cooldownMillis = unit.toMillis(amount);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder cooldownSeconds(int seconds) {
|
||||||
|
return cooldown(seconds, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder cooldownBypass(String permission) {
|
||||||
|
this.cooldownBypassPermission = permission;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder argument(CommandArgument<?> argument) {
|
||||||
|
if (argument != null) {
|
||||||
|
this.arguments.add(argument);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder subCommand(AppCommand subCommand) {
|
||||||
|
if (subCommand != null) {
|
||||||
|
this.subCommands.put(subCommand.getName().toLowerCase(), subCommand);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder subCommand(CommandBuilder subBuilder) {
|
||||||
|
if (subBuilder != null) {
|
||||||
|
AppCommand built = subBuilder.build();
|
||||||
|
this.subCommands.put(built.getName().toLowerCase(), built);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder executes(CommandHandler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppCommand build() {
|
||||||
|
return new AppCommand(name, aliases, description, permission, permissionMessage,
|
||||||
|
playerOnly, cooldownMillis, cooldownBypassPermission, arguments, subCommands, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.util.TextUtil;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CommandContext {
|
||||||
|
|
||||||
|
private final CommandSender sender;
|
||||||
|
private final String label;
|
||||||
|
private final String[] rawArgs;
|
||||||
|
private final Map<String, Object> parsedArgs;
|
||||||
|
private final String fullCommandPath;
|
||||||
|
|
||||||
|
public CommandContext(CommandSender sender, String label, String[] rawArgs, Map<String, Object> parsedArgs, String fullCommandPath) {
|
||||||
|
this.sender = sender;
|
||||||
|
this.label = label;
|
||||||
|
this.rawArgs = rawArgs != null ? rawArgs : new String[0];
|
||||||
|
this.parsedArgs = parsedArgs != null ? parsedArgs : Collections.emptyMap();
|
||||||
|
this.fullCommandPath = fullCommandPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSender getSender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlayer() {
|
||||||
|
return sender instanceof Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConsole() {
|
||||||
|
return !isPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return isPlayer() ? (Player) sender : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getRawArgs() {
|
||||||
|
return rawArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullCommandPath() {
|
||||||
|
return fullCommandPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(String argName) {
|
||||||
|
return parsedArgs.containsKey(argName.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(String argName, Class<T> clazz) {
|
||||||
|
Object value = parsedArgs.get(argName.toLowerCase());
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (clazz.isInstance(value)) {
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
throw new ClassCastException("L'argument '" + argName + "' est de type " + value.getClass().getSimpleName() + ", attendu: " + clazz.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String argName) {
|
||||||
|
return parsedArgs.get(argName.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String argName) {
|
||||||
|
return get(argName, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String argName) {
|
||||||
|
Integer val = get(argName, Integer.class);
|
||||||
|
return val != null ? val : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(String argName) {
|
||||||
|
Double val = get(argName, Double.class);
|
||||||
|
return val != null ? val : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getTargetPlayer(String argName) {
|
||||||
|
return get(argName, Player.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reply(String message) {
|
||||||
|
TextUtil.sendMessage(sender, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendRaw(String message) {
|
||||||
|
TextUtil.sendRawMessage(sender, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(String errorMessage) {
|
||||||
|
TextUtil.sendMessage(sender, "<red>" + errorMessage + "</red>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendActionBar(String message) {
|
||||||
|
if (isPlayer()) {
|
||||||
|
TextUtil.sendActionBar(getPlayer(), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface CommandHandler {
|
||||||
|
void execute(CommandContext context) throws Exception;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package fr.luc.gamingcore.command;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.Main;
|
||||||
|
import fr.luc.gamingcore.command.cooldown.CooldownManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
|
import org.bukkit.command.SimpleCommandMap;
|
||||||
|
import org.bukkit.plugin.SimplePluginManager;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class CommandManager {
|
||||||
|
|
||||||
|
private final Main plugin;
|
||||||
|
private final CooldownManager cooldownManager;
|
||||||
|
private final Map<String, BukkitCommandWrapper> registeredCommands = new ConcurrentHashMap<>();
|
||||||
|
private CommandMap commandMap;
|
||||||
|
|
||||||
|
public CommandManager(Main plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.cooldownManager = new CooldownManager();
|
||||||
|
this.commandMap = resolveCommandMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandMap resolveCommandMap() {
|
||||||
|
// Try direct Bukkit.getCommandMap() (Paper API)
|
||||||
|
try {
|
||||||
|
Method method = Bukkit.getServer().getClass().getMethod("getCommandMap");
|
||||||
|
return (CommandMap) method.invoke(Bukkit.getServer());
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
// Fallback: Reflection on SimplePluginManager
|
||||||
|
try {
|
||||||
|
Field field = SimplePluginManager.class.getDeclaredField("commandMap");
|
||||||
|
field.setAccessible(true);
|
||||||
|
return (CommandMap) field.get(Bukkit.getPluginManager());
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Impossible de recuperer le CommandMap de Bukkit !", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(AppCommand appCommand) {
|
||||||
|
if (commandMap == null) {
|
||||||
|
commandMap = resolveCommandMap();
|
||||||
|
if (commandMap == null) {
|
||||||
|
plugin.getLogger().severe("Impossible d'enregistrer la commande " + appCommand.getName() + " : CommandMap introuvable !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BukkitCommandWrapper wrapper = new BukkitCommandWrapper(appCommand, cooldownManager);
|
||||||
|
commandMap.register(plugin.getName().toLowerCase(), wrapper);
|
||||||
|
registeredCommands.put(appCommand.getName().toLowerCase(), wrapper);
|
||||||
|
|
||||||
|
plugin.getLogger().info("Commande dynamique enregistree : /" + appCommand.getName() + " (alias: " + String.join(", ", appCommand.getAliases()) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(CommandBuilder builder) {
|
||||||
|
if (builder != null) {
|
||||||
|
register(builder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister(String commandName) {
|
||||||
|
if (commandName == null) return;
|
||||||
|
BukkitCommandWrapper wrapper = registeredCommands.remove(commandName.toLowerCase());
|
||||||
|
if (wrapper != null && commandMap instanceof SimpleCommandMap) {
|
||||||
|
try {
|
||||||
|
Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
|
||||||
|
knownCommandsField.setAccessible(true);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Command> knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
|
||||||
|
knownCommands.remove(wrapper.getName().toLowerCase());
|
||||||
|
for (String alias : wrapper.getAliases()) {
|
||||||
|
knownCommands.remove(alias.toLowerCase());
|
||||||
|
}
|
||||||
|
wrapper.unregister(commandMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "Erreur lors du desenregistrement de la commande " + commandName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
for (String name : registeredCommands.keySet()) {
|
||||||
|
unregister(name);
|
||||||
|
}
|
||||||
|
registeredCommands.clear();
|
||||||
|
cooldownManager.cleanExpired();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CooldownManager getCooldownManager() {
|
||||||
|
return cooldownManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument;
|
||||||
|
|
||||||
|
public class ArgumentParseException extends Exception {
|
||||||
|
|
||||||
|
public ArgumentParseException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.CommandContext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ArgumentParser<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the string input into the target typed object.
|
||||||
|
*
|
||||||
|
* @param ctx The current command execution context
|
||||||
|
* @param input The raw argument string entered by the user
|
||||||
|
* @return The parsed object
|
||||||
|
* @throws ArgumentParseException If the input is invalid
|
||||||
|
*/
|
||||||
|
T parse(CommandContext ctx, String input) throws ArgumentParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides dynamic tab completions for this argument.
|
||||||
|
*
|
||||||
|
* @param ctx The current command context
|
||||||
|
* @param input The current prefix typed by the user
|
||||||
|
* @return A list of suggestions
|
||||||
|
*/
|
||||||
|
default List<String> complete(CommandContext ctx, String input) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument;
|
||||||
|
|
||||||
|
public class CommandArgument<T> {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final String description;
|
||||||
|
private final ArgumentParser<T> parser;
|
||||||
|
private final boolean required;
|
||||||
|
private final T defaultValue;
|
||||||
|
private final boolean greedy;
|
||||||
|
|
||||||
|
public CommandArgument(String name, String description, ArgumentParser<T> parser, boolean required, T defaultValue, boolean greedy) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.parser = parser;
|
||||||
|
this.required = required;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.greedy = greedy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> required(String name, ArgumentParser<T> parser) {
|
||||||
|
return new CommandArgument<>(name, "", parser, true, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> required(String name, String description, ArgumentParser<T> parser) {
|
||||||
|
return new CommandArgument<>(name, description, parser, true, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> optional(String name, ArgumentParser<T> parser) {
|
||||||
|
return new CommandArgument<>(name, "", parser, false, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> optional(String name, ArgumentParser<T> parser, T defaultValue) {
|
||||||
|
return new CommandArgument<>(name, "", parser, false, defaultValue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> optional(String name, String description, ArgumentParser<T> parser, T defaultValue) {
|
||||||
|
return new CommandArgument<>(name, description, parser, false, defaultValue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommandArgument<T> greedy(String name, String description, ArgumentParser<T> parser, boolean required, T defaultValue) {
|
||||||
|
return new CommandArgument<>(name, description, parser, required, defaultValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArgumentParser<T> getParser() {
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequired() {
|
||||||
|
return required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getDefaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGreedy() {
|
||||||
|
return greedy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormattedSyntax() {
|
||||||
|
return required ? "<" + name + ">" : "[" + name + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument.parsers;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.CommandContext;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParser;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParseException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DoubleArgument implements ArgumentParser<Double> {
|
||||||
|
|
||||||
|
private final double min;
|
||||||
|
private final double max;
|
||||||
|
|
||||||
|
public DoubleArgument() {
|
||||||
|
this(Double.MIN_VALUE, Double.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleArgument(double min, double max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleArgument decimal() {
|
||||||
|
return new DoubleArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleArgument min(double min) {
|
||||||
|
return new DoubleArgument(min, Double.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleArgument range(double min, double max) {
|
||||||
|
return new DoubleArgument(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double parse(CommandContext ctx, String input) throws ArgumentParseException {
|
||||||
|
try {
|
||||||
|
double value = Double.parseDouble(input.replace(',', '.'));
|
||||||
|
if (value < min || value > max) {
|
||||||
|
throw new ArgumentParseException("La valeur doit être comprise entre " + min + " et " + max + ".");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ArgumentParseException("'" + input + "' n'est pas un nombre décimal valide.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandContext ctx, String input) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument.parsers;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.CommandContext;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParser;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParseException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IntegerArgument implements ArgumentParser<Integer> {
|
||||||
|
|
||||||
|
private final int min;
|
||||||
|
private final int max;
|
||||||
|
|
||||||
|
public IntegerArgument() {
|
||||||
|
this(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerArgument(int min, int max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntegerArgument integer() {
|
||||||
|
return new IntegerArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntegerArgument min(int min) {
|
||||||
|
return new IntegerArgument(min, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntegerArgument range(int min, int max) {
|
||||||
|
return new IntegerArgument(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer parse(CommandContext ctx, String input) throws ArgumentParseException {
|
||||||
|
try {
|
||||||
|
int value = Integer.parseInt(input);
|
||||||
|
if (value < min || value > max) {
|
||||||
|
throw new ArgumentParseException("Le nombre doit être compris entre " + min + " et " + max + ".");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ArgumentParseException("'" + input + "' n'est pas un nombre entier valide.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandContext ctx, String input) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument.parsers;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.CommandContext;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParser;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParseException;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class PlayerArgument implements ArgumentParser<Player> {
|
||||||
|
|
||||||
|
public static PlayerArgument player() {
|
||||||
|
return new PlayerArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player parse(CommandContext ctx, String input) throws ArgumentParseException {
|
||||||
|
if (input == null || input.isEmpty()) {
|
||||||
|
throw new ArgumentParseException("Veuillez spécifier un pseudo de joueur.");
|
||||||
|
}
|
||||||
|
Player target = Bukkit.getPlayerExact(input);
|
||||||
|
if (target == null) {
|
||||||
|
target = Bukkit.getPlayer(input);
|
||||||
|
}
|
||||||
|
if (target == null || !target.isOnline()) {
|
||||||
|
throw new ArgumentParseException("Le joueur '<red>" + input + "</red>' n'est pas connecté.");
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandContext ctx, String input) {
|
||||||
|
String lower = input != null ? input.toLowerCase() : "";
|
||||||
|
return Bukkit.getOnlinePlayers().stream()
|
||||||
|
.map(Player::getName)
|
||||||
|
.filter(name -> name.toLowerCase().startsWith(lower))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package fr.luc.gamingcore.command.argument.parsers;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.command.CommandContext;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParser;
|
||||||
|
import fr.luc.gamingcore.command.argument.ArgumentParseException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class StringArgument implements ArgumentParser<String> {
|
||||||
|
|
||||||
|
private final List<String> suggestions;
|
||||||
|
private final Supplier<List<String>> dynamicSuggestions;
|
||||||
|
|
||||||
|
public StringArgument() {
|
||||||
|
this.suggestions = null;
|
||||||
|
this.dynamicSuggestions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringArgument(String... suggestions) {
|
||||||
|
this.suggestions = Arrays.asList(suggestions);
|
||||||
|
this.dynamicSuggestions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringArgument(Supplier<List<String>> dynamicSuggestions) {
|
||||||
|
this.suggestions = null;
|
||||||
|
this.dynamicSuggestions = dynamicSuggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgument word() {
|
||||||
|
return new StringArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgument choices(String... choices) {
|
||||||
|
return new StringArgument(choices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgument dynamic(Supplier<List<String>> supplier) {
|
||||||
|
return new StringArgument(supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String parse(CommandContext ctx, String input) throws ArgumentParseException {
|
||||||
|
if (input == null || input.trim().isEmpty()) {
|
||||||
|
throw new ArgumentParseException("Le texte ne peut pas être vide.");
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandContext ctx, String input) {
|
||||||
|
List<String> list = suggestions;
|
||||||
|
if (dynamicSuggestions != null) {
|
||||||
|
list = dynamicSuggestions.get();
|
||||||
|
}
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
String lower = input != null ? input.toLowerCase() : "";
|
||||||
|
return list.stream()
|
||||||
|
.filter(s -> s.toLowerCase().startsWith(lower))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package fr.luc.gamingcore.command.cooldown;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class CooldownManager {
|
||||||
|
|
||||||
|
private final Map<UUID, Map<String, Long>> cooldowns = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public boolean isOnCooldown(Player player, String commandKey) {
|
||||||
|
if (player == null || commandKey == null) return false;
|
||||||
|
long remaining = getRemainingMillis(player, commandKey);
|
||||||
|
return remaining > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRemainingMillis(Player player, String commandKey) {
|
||||||
|
if (player == null || commandKey == null) return 0L;
|
||||||
|
Map<String, Long> userCooldowns = cooldowns.get(player.getUniqueId());
|
||||||
|
if (userCooldowns == null) return 0L;
|
||||||
|
|
||||||
|
Long expireAt = userCooldowns.get(commandKey.toLowerCase());
|
||||||
|
if (expireAt == null) return 0L;
|
||||||
|
|
||||||
|
long diff = expireAt - System.currentTimeMillis();
|
||||||
|
if (diff <= 0) {
|
||||||
|
userCooldowns.remove(commandKey.toLowerCase());
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRemainingSeconds(Player player, String commandKey) {
|
||||||
|
long millis = getRemainingMillis(player, commandKey);
|
||||||
|
if (millis <= 0) return 0.0;
|
||||||
|
return Math.round((millis / 1000.0) * 10.0) / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyCooldown(Player player, String commandKey, long durationMillis) {
|
||||||
|
if (player == null || commandKey == null || durationMillis <= 0) return;
|
||||||
|
cooldowns.computeIfAbsent(player.getUniqueId(), k -> new ConcurrentHashMap<>())
|
||||||
|
.put(commandKey.toLowerCase(), System.currentTimeMillis() + durationMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCooldown(Player player, String commandKey) {
|
||||||
|
if (player == null || commandKey == null) return;
|
||||||
|
Map<String, Long> userCooldowns = cooldowns.get(player.getUniqueId());
|
||||||
|
if (userCooldowns != null) {
|
||||||
|
userCooldowns.remove(commandKey.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanExpired() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
cooldowns.forEach((uuid, map) -> {
|
||||||
|
map.entrySet().removeIf(entry -> entry.getValue() <= now);
|
||||||
|
});
|
||||||
|
cooldowns.entrySet().removeIf(entry -> entry.getValue().isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package fr.luc.gamingcore.util;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public final class TextUtil {
|
||||||
|
|
||||||
|
private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
|
||||||
|
private static final LegacyComponentSerializer AMPERSAND_SERIALIZER = LegacyComponentSerializer.legacyAmpersand();
|
||||||
|
|
||||||
|
private static String prefix = "<gradient:#00C9FF:#92FE9D>[Guilde]</gradient> <dark_gray>»</dark_gray> <gray>";
|
||||||
|
|
||||||
|
private TextUtil() {}
|
||||||
|
|
||||||
|
public static void setPrefix(String newPrefix) {
|
||||||
|
if (newPrefix != null) {
|
||||||
|
prefix = newPrefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string containing MiniMessage tags or legacy color codes into a Component.
|
||||||
|
*/
|
||||||
|
public static Component parse(String input) {
|
||||||
|
if (input == null || input.isEmpty()) {
|
||||||
|
return Component.empty();
|
||||||
|
}
|
||||||
|
String formatted = input.replace('§', '&');
|
||||||
|
if (formatted.contains("&")) {
|
||||||
|
return AMPERSAND_SERIALIZER.deserialize(formatted);
|
||||||
|
}
|
||||||
|
return MINI_MESSAGE.deserialize(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(CommandSender sender, String message) {
|
||||||
|
if (sender == null || message == null) return;
|
||||||
|
sender.sendMessage(parse(prefix + message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendRawMessage(CommandSender sender, String message) {
|
||||||
|
if (sender == null || message == null) return;
|
||||||
|
sender.sendMessage(parse(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendActionBar(Player player, String message) {
|
||||||
|
if (player == null || message == null) return;
|
||||||
|
player.sendActionBar(parse(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@ version: 1.0.0
|
|||||||
main: fr.luc.gamingcore.Main
|
main: fr.luc.gamingcore.Main
|
||||||
api-version: '1.16'
|
api-version: '1.16'
|
||||||
author: Luc
|
author: Luc
|
||||||
description: GamingCore Plugin
|
description: GamingCore Plugin - Système de Guilde
|
||||||
depend:
|
depend:
|
||||||
- WorldGuard
|
- WorldGuard
|
||||||
|
- Vault
|
||||||
softdepend:
|
softdepend:
|
||||||
- WorldEdit
|
- WorldEdit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user