refactor: clean base with WorldGuard, WorldEdit, and Vault dependencies

This commit is contained in:
2026-08-20 17:10:42 +02:00
parent 0f6a77f3bf
commit 0ba297a648
18 changed files with 1136 additions and 2 deletions
+3
View File
@@ -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")
+69 -1
View File
@@ -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 -1
View File
@@ -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