diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml new file mode 100644 index 00000000..c1a687d5 --- /dev/null +++ b/.github/workflows/gradle-publish.yml @@ -0,0 +1,45 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created +# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle + +name: Gradle Package + +on: + push: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Build with Gradle + run: ./gradlew buildAll + + # The USERNAME and TOKEN need to correspond to the credentials environment variables used in + # the publishing section of your build.gradle + - name: Publish to GitHub Packages + run: ./gradlew publish + env: + USERNAME: ${{ github.actor }} + TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Essentials/build.gradle b/Essentials/build.gradle index 0b535d18..14a5c4ac 100644 --- a/Essentials/build.gradle +++ b/Essentials/build.gradle @@ -1,9 +1,11 @@ plugins { id 'java' + id 'com.github.johnrengelman.shadow' version '7.1.0' } dependencies { compileOnly project(':EssentialsApi') + compileOnly project(':Hooks:Vault') } jar { @@ -12,4 +14,26 @@ jar { java { withSourcesJar() -} \ No newline at end of file +} + +compileJava.options.encoding = 'UTF-8' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +processResources { + filesMatching('plugin.yml') { + expand(project.properties) + } +} + +shadowJar { + + from(project(':EssentialsApi').sourceSets.main.output) + from(project(':Hooks:Vault').sourceSets.main.output) + + relocate 'com.tcoded.folialib', 'fr.maxlego08.essentials.folialib' +} + +assemble.dependsOn shadowJar \ No newline at end of file diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/MainConfiguration.java b/Essentials/src/main/java/fr/maxlego08/essentials/MainConfiguration.java new file mode 100644 index 00000000..72fc8c64 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/MainConfiguration.java @@ -0,0 +1,79 @@ +package fr.maxlego08.essentials; + +import fr.maxlego08.essentials.api.Configuration; +import fr.maxlego08.essentials.api.commands.CommandCooldown; +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; +import fr.maxlego08.essentials.api.storage.StorageType; +import fr.maxlego08.essentials.api.utils.CompactMaterial; +import fr.maxlego08.essentials.zutils.utils.YamlLoader; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.permissions.Permissible; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class MainConfiguration extends YamlLoader implements Configuration { + + private final ZEssentialsPlugin plugin; + private final List commandCooldowns = new ArrayList<>(); + private final List compactMaterials = new ArrayList<>(); + private final StorageType storageType = StorageType.JSON; + private boolean enableDebug; + private boolean enableCooldownBypass; + private int trashSize; + private DatabaseConfiguration databaseConfiguration; + + public MainConfiguration(ZEssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean isEnableDebug() { + return this.enableDebug; + } + + @Override + public boolean isEnableCooldownBypass() { + return this.enableCooldownBypass; + } + + @Override + public List getCommandCooldown() { + return this.commandCooldowns; + } + + @Override + public Optional getCooldown(Permissible permissible, String command) { + return this.commandCooldowns.stream().filter(e -> e.command().equalsIgnoreCase(command)).map(commandCooldown -> commandCooldown.permissions().stream().filter(e -> permissible.hasPermission((String) e.get("permission"))).mapToInt(e -> ((Number) e.get("cooldown")).intValue()).min().orElse(commandCooldown.cooldown())).findFirst(); + } + + @Override + public void load() { + + this.plugin.reloadConfig(); + + YamlConfiguration configuration = (YamlConfiguration) this.plugin.getConfig(); + this.loadYamlConfirmation(configuration); + } + + @Override + public int getTrashSize() { + return this.trashSize; + } + + @Override + public List getCompactMaterials() { + return this.compactMaterials; + } + + @Override + public StorageType getStorageType() { + return this.storageType; + } + + @Override + public DatabaseConfiguration getDatabaseConfiguration() { + return this.databaseConfiguration; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPlugin.java b/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPlugin.java new file mode 100644 index 00000000..0a566a0e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPlugin.java @@ -0,0 +1,223 @@ +package fr.maxlego08.essentials; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.tcoded.folialib.FoliaLib; +import com.tcoded.folialib.impl.ServerImplementation; +import fr.maxlego08.essentials.api.Configuration; +import fr.maxlego08.essentials.api.ConfigurationFile; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandManager; +import fr.maxlego08.essentials.api.database.MigrationManager; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.modules.ModuleManager; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import fr.maxlego08.essentials.api.placeholders.PlaceholderRegister; +import fr.maxlego08.essentials.api.storage.Persist; +import fr.maxlego08.essentials.api.storage.StorageManager; +import fr.maxlego08.essentials.api.storage.adapter.LocationAdapter; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.buttons.ButtonTeleportationConfirm; +import fr.maxlego08.essentials.commands.CommandLoader; +import fr.maxlego08.essentials.commands.ZCommandManager; +import fr.maxlego08.essentials.commands.commands.essentials.CommandEssentials; +import fr.maxlego08.essentials.database.ZMigrationManager; +import fr.maxlego08.essentials.economy.EconomyManager; +import fr.maxlego08.essentials.hooks.VaultEconomy; +import fr.maxlego08.essentials.listener.PlayerListener; +import fr.maxlego08.essentials.messages.MessageLoader; +import fr.maxlego08.essentials.module.ZModuleManager; +import fr.maxlego08.essentials.placeholders.DistantPlaceholder; +import fr.maxlego08.essentials.placeholders.LocalPlaceholder; +import fr.maxlego08.essentials.storage.ZStorageManager; +import fr.maxlego08.essentials.storage.adapter.UserTypeAdapter; +import fr.maxlego08.essentials.user.UserPlaceholders; +import fr.maxlego08.essentials.user.ZUser; +import fr.maxlego08.essentials.zutils.ZPlugin; +import fr.maxlego08.menu.api.ButtonManager; +import fr.maxlego08.menu.api.InventoryManager; +import fr.maxlego08.menu.api.pattern.PatternManager; +import fr.maxlego08.menu.button.loader.NoneLoader; +import org.bukkit.Location; + +import java.lang.reflect.Modifier; +import java.util.List; + +public final class ZEssentialsPlugin extends ZPlugin implements EssentialsPlugin { + + private InventoryManager inventoryManager; + private ButtonManager buttonManager; + private PatternManager patternManager; + + @Override + public void onEnable() { + + this.saveDefaultConfig(); + + FoliaLib foliaLib = new FoliaLib(this); + this.serverImplementation = foliaLib.getImpl(); + + this.migrationManager = new ZMigrationManager(this); + this.migrationManager.registerMigration(); + + this.placeholder = new LocalPlaceholder(this); + DistantPlaceholder distantPlaceholder = new DistantPlaceholder(this, this.placeholder); + distantPlaceholder.register(); + + this.economyProvider = new EconomyManager(this); + + this.inventoryManager = this.getProvider(InventoryManager.class); + this.buttonManager = this.getProvider(ButtonManager.class); + this.patternManager = this.getProvider(PatternManager.class); + this.registerButtons(); + + this.moduleManager = new ZModuleManager(this); + + this.gson = getGsonBuilder().create(); + this.persist = new Persist(this); + + // Configurations files + this.registerConfiguration(new MessageLoader(this)); + this.registerConfiguration(this.configuration = new MainConfiguration(this)); + + // Load configuration files + this.configurationFiles.forEach(ConfigurationFile::load); + + // Commands + this.commandManager = new ZCommandManager(this); + this.registerCommand("zessentials", new CommandEssentials(this), "ess"); + + CommandLoader commandLoader = new CommandLoader(this); + commandLoader.loadCommands(this.commandManager); + + this.getLogger().info("Create " + this.commandManager.countCommands() + " commands."); + + // Storage + this.storageManager = new ZStorageManager(this); + this.registerListener(this.storageManager); + this.storageManager.onEnable(); + + this.moduleManager.loadModules(); + + this.registerListener(new PlayerListener(this)); + this.registerPlaceholder(UserPlaceholders.class); + } + + @Override + public void onLoad() { + + try { + Class.forName("net.milkbowl.vault.economy.Economy"); + new VaultEconomy(this); + getLogger().info("Register Vault Economy."); + } catch (final ClassNotFoundException ignored) { + ignored.printStackTrace(); + } + + } + + @Override + public void onDisable() { + + // Storage + if (this.storageManager != null) this.storageManager.onDisable(); + } + + private void registerButtons() { + + this.buttonManager.register(new NoneLoader(this, ButtonTeleportationConfirm.class, "essentials_teleportation_confirm")); + + } + + @Override + public CommandManager getCommandManager() { + return this.commandManager; + } + + @Override + public List getConfigurationFiles() { + return this.configurationFiles; + } + + @Override + public Gson getGson() { + return this.gson; + } + + @Override + public Persist getPersist() { + return this.persist; + } + + @Override + public ServerImplementation getScheduler() { + return this.serverImplementation; + } + + @Override + public ModuleManager getModuleManager() { + return this.moduleManager; + } + + @Override + public InventoryManager getInventoryManager() { + return this.inventoryManager; + } + + @Override + public ButtonManager getButtonManager() { + return this.buttonManager; + } + + @Override + public PatternManager getPatternManager() { + return this.patternManager; + } + + @Override + public Placeholder getPlaceholder() { + return this.placeholder; + } + + @Override + public StorageManager getStorageManager() { + return this.storageManager; + } + + private GsonBuilder getGsonBuilder() { + return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls() + .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE) + .registerTypeAdapter(Location.class, new LocationAdapter(this)) + .registerTypeAdapter(User.class, new UserTypeAdapter(this)) + .registerTypeAdapter(ZUser.class, new UserTypeAdapter(this)); + } + + private void registerPlaceholder(Class placeholderClass) { + try { + PlaceholderRegister placeholderRegister = placeholderClass.getConstructor().newInstance(); + placeholderRegister.register(this.placeholder, this); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + @Override + public Configuration getConfiguration() { + return this.configuration; + } + + @Override + public MigrationManager getMigrationManager() { + return this.migrationManager; + } + + @Override + public boolean isEconomyEnable() { + return this.economyProvider.isEnable(); + } + + @Override + public EconomyProvider getEconomyProvider() { + return this.economyProvider; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPluginPlugin.java b/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPluginPlugin.java deleted file mode 100644 index c13aac01..00000000 --- a/Essentials/src/main/java/fr/maxlego08/essentials/ZEssentialsPluginPlugin.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.maxlego08.essentials; - -import fr.maxlego08.essentials.api.EssentialsPlugin; -import org.bukkit.plugin.java.JavaPlugin; - -public final class ZEssentialsPluginPlugin extends JavaPlugin implements EssentialsPlugin { - - @Override - public void onEnable() { - - - } - - @Override - public void onDisable() { - - } -} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/buttons/ButtonTeleportationConfirm.java b/Essentials/src/main/java/fr/maxlego08/essentials/buttons/ButtonTeleportationConfirm.java new file mode 100644 index 00000000..019a632e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/buttons/ButtonTeleportationConfirm.java @@ -0,0 +1,26 @@ +package fr.maxlego08.essentials.buttons; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.menu.api.utils.Placeholders; +import fr.maxlego08.menu.button.ZButton; +import fr.maxlego08.menu.inventory.inventories.InventoryDefault; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.plugin.Plugin; + +public class ButtonTeleportationConfirm extends ZButton { + + private final EssentialsPlugin plugin; + + public ButtonTeleportationConfirm(Plugin plugin) { + this.plugin = (EssentialsPlugin) plugin; + } + + @Override + public void onClick(Player player, InventoryClickEvent event, InventoryDefault inventory, int slot, Placeholders placeholders) { + super.onClick(player, event, inventory, slot, placeholders); + User user = this.plugin.getStorageManager().getStorage().getUser(player.getUniqueId()); + user.sendTeleportRequest(user.getTargetUser()); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/CommandLoader.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/CommandLoader.java new file mode 100644 index 00000000..6361804f --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/CommandLoader.java @@ -0,0 +1,122 @@ +package fr.maxlego08.essentials.commands; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandManager; +import fr.maxlego08.essentials.commands.commands.economy.CommandEconomy; +import fr.maxlego08.essentials.commands.commands.enderchest.CommandEnderChest; +import fr.maxlego08.essentials.commands.commands.enderchest.CommandEnderSee; +import fr.maxlego08.essentials.commands.commands.gamemode.CommandGameMode; +import fr.maxlego08.essentials.commands.commands.gamemode.CommandGameModeAdventure; +import fr.maxlego08.essentials.commands.commands.gamemode.CommandGameModeCreative; +import fr.maxlego08.essentials.commands.commands.gamemode.CommandGameModeSpectator; +import fr.maxlego08.essentials.commands.commands.gamemode.CommandGameModeSurvival; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleport; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportAccept; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportCancel; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportDeny; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportHere; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportTo; +import fr.maxlego08.essentials.commands.commands.teleport.CommandTeleportWorld; +import fr.maxlego08.essentials.commands.commands.utils.CommandCompact; +import fr.maxlego08.essentials.commands.commands.utils.CommandCraft; +import fr.maxlego08.essentials.commands.commands.utils.CommandEnchanting; +import fr.maxlego08.essentials.commands.commands.utils.CommandFeed; +import fr.maxlego08.essentials.commands.commands.utils.CommandGod; +import fr.maxlego08.essentials.commands.commands.utils.CommandHat; +import fr.maxlego08.essentials.commands.commands.utils.CommandHeal; +import fr.maxlego08.essentials.commands.commands.utils.CommandInvsee; +import fr.maxlego08.essentials.commands.commands.utils.CommandMore; +import fr.maxlego08.essentials.commands.commands.utils.CommandSpeed; +import fr.maxlego08.essentials.commands.commands.utils.CommandTop; +import fr.maxlego08.essentials.commands.commands.utils.CommandTrash; +import fr.maxlego08.essentials.commands.commands.weather.CommandDay; +import fr.maxlego08.essentials.commands.commands.weather.CommandNight; +import fr.maxlego08.essentials.commands.commands.weather.CommandPlayerTime; +import fr.maxlego08.essentials.commands.commands.weather.CommandPlayerWeather; +import fr.maxlego08.essentials.commands.commands.weather.CommandSun; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CommandLoader { + + private final ZEssentialsPlugin plugin; + private final List commands = new ArrayList<>(); + + public CommandLoader(ZEssentialsPlugin plugin) { + this.plugin = plugin; + } + + public void loadCommands(CommandManager commandManager) { + + register("gamemode", CommandGameMode.class, "gm"); + register("gmc", CommandGameModeCreative.class, "creat"); + register("gma", CommandGameModeAdventure.class, "advent"); + register("gms", CommandGameModeSurvival.class, "survi"); + register("gmsp", CommandGameModeSpectator.class, "spec"); + + register("day", CommandDay.class); + register("night", CommandNight.class); + register("sun", CommandSun.class); + register("player-weather", CommandPlayerWeather.class, "pweather"); + register("player-time", CommandPlayerTime.class, "ptime"); + + register("enderchest", CommandEnderChest.class, "ec"); + register("endersee", CommandEnderSee.class, "ecsee"); + + register("top", CommandTop.class); + register("speed", CommandSpeed.class); + register("god", CommandGod.class); + register("heal", CommandHeal.class); + register("more", CommandMore.class); + register("worldtp", CommandTeleportWorld.class, "wtp"); + register("trash", CommandTrash.class, "poubelle"); + register("feed", CommandFeed.class); + register("craft", CommandCraft.class); + register("enchanting", CommandEnchanting.class); + register("invsee", CommandInvsee.class); + register("compact", CommandCompact.class, "blocks"); + register("hat", CommandHat.class); + + register("tp", CommandTeleport.class); + register("tphere", CommandTeleportHere.class, "s"); + register("tpa", CommandTeleportTo.class); + register("tpaccept", CommandTeleportAccept.class, "tpyes"); + register("tpdeny", CommandTeleportDeny.class, "tpno"); + register("tpacancel", CommandTeleportCancel.class); + + register("economy", CommandEconomy.class, "eco"); + + + File file = new File(plugin.getDataFolder(), "commands.yml"); + if (!file.exists()) this.plugin.saveResource("commands.yml", false); + + this.loadCommands(YamlConfiguration.loadConfiguration(file), commandManager); + } + + private void register(String command, Class commandClass, String... aliases) { + commands.add(new RegisterCommand(command, commandClass, Arrays.asList(aliases))); + } + + private void loadCommands(YamlConfiguration configuration, CommandManager commandManager) { + + for (RegisterCommand command : commands) { + if (configuration.getBoolean(command.command, true)) { + try { + commandManager.registerCommand(this.plugin, command.command, command.commandClass.getConstructor(EssentialsPlugin.class).newInstance(this.plugin), command.aliases); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + } + + public record RegisterCommand(String command, Class commandClass, List aliases) { + + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/ZCommandManager.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/ZCommandManager.java new file mode 100644 index 00000000..69669328 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/ZCommandManager.java @@ -0,0 +1,196 @@ +package fr.maxlego08.essentials.commands; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandManager; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.EssentialsCommand; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.ZUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ZCommandManager extends ZUtils implements CommandManager { + + private static CommandMap commandMap; + private static Constructor constructor; + + static { + try { + Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap"); + bukkitCommandMap.setAccessible(true); + commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer()); + constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + constructor.setAccessible(true); + } catch (Exception ignored) { + } + } + + private final ZEssentialsPlugin plugin; + private final List commands = new ArrayList<>(); + + public ZCommandManager(ZEssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void registerCommand(EssentialsCommand command) { + this.commands.add(command); + } + + @Override + public void registerCommand(String string, EssentialsCommand command) { + command.addSubCommand(string); + this.commands.add(command); + this.plugin.getCommand(string).setExecutor(this); + this.plugin.getCommand(string).setTabCompleter(this); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) { + for (EssentialsCommand command : this.commands) { + if (command.getSubCommands().contains(cmd.getName().toLowerCase())) { + if ((args.length == 0 || command.isIgnoreParent()) && command.getParent() == null) { + CommandResultType type = processRequirements(command, sender, args); + if (!type.equals(CommandResultType.CONTINUE)) return true; + } + } else if (args.length >= 1 && command.getParent() != null && canExecute(args, cmd.getName().toLowerCase(), command)) { + CommandResultType type = processRequirements(command, sender, args); + if (!type.equals(CommandResultType.CONTINUE)) return true; + } + } + message(sender, Message.COMMAND_NO_ARG); + return true; + } + + private boolean canExecute(String[] args, String cmd, EssentialsCommand command) { + for (int index = args.length - 1; index > -1; index--) { + if (command.getSubCommands().contains(args[index].toLowerCase())) { + if (command.isIgnoreArgs() && (command.getParent() == null || canExecute(args, cmd, command.getParent(), index - 1))) + return true; + if (index < args.length - 1) return false; + return canExecute(args, cmd, command.getParent(), index - 1); + } + } + return false; + } + + private boolean canExecute(String[] args, String cmd, EssentialsCommand command, int index) { + if (index < 0 && command.getSubCommands().contains(cmd.toLowerCase())) return true; + else if (index < 0) return false; + else if (command.getSubCommands().contains(args[index].toLowerCase())) { + return canExecute(args, cmd, command.getParent(), index - 1); + } else return false; + } + + private CommandResultType processRequirements(EssentialsCommand command, CommandSender sender, String[] strings) { + + if (!(sender instanceof Player) && !command.isConsoleCanUse()) { + message(sender, Message.COMMAND_NO_CONSOLE); + return CommandResultType.DEFAULT; + } + if (command.getPermission() == null || sender.hasPermission(command.getPermission())) { + + CommandResultType returnType = command.prePerform(this.plugin, sender, strings); + if (returnType == CommandResultType.SYNTAX_ERROR) { + message(sender, Message.COMMAND_SYNTAX_ERROR, "%syntax%", command.getSyntax()); + } else if (returnType == CommandResultType.NO_PERMISSION) { + message(sender, Message.COMMAND_NO_PERMISSION); + } + return returnType; + } + message(sender, Message.COMMAND_NO_PERMISSION); + return CommandResultType.DEFAULT; + } + + @Override + public List onTabComplete(CommandSender sender, Command cmd, String str, String[] args) { + + for (EssentialsCommand command : commands) { + + if (command.getSubCommands().contains(cmd.getName().toLowerCase())) { + if (args.length == 1 && command.getParent() == null) { + return processTab(sender, command, args); + } + } else { + String[] newArgs = Arrays.copyOf(args, args.length - 1); + if (newArgs.length >= 1 && command.getParent() != null && canExecute(newArgs, cmd.getName().toLowerCase(), command)) { + return processTab(sender, command, args); + } + } + } + + return null; + } + + private List processTab(CommandSender sender, EssentialsCommand command, String[] args) { + + CommandResultType type = command.getTabCompleter(); + if (type.equals(CommandResultType.DEFAULT)) { + + String startWith = args[args.length - 1]; + + List tabCompleter = new ArrayList<>(); + for (EssentialsCommand vCommand : this.commands) { + if ((vCommand.getParent() != null && vCommand.getParent() == command)) { + String cmd = vCommand.getSubCommands().get(0); + if (vCommand.getPermission() == null || sender.hasPermission(vCommand.getPermission())) { + if (startWith.length() == 0 || cmd.startsWith(startWith)) { + tabCompleter.add(cmd); + } + } + } + } + return tabCompleter.size() == 0 ? null : tabCompleter; + + } else if (type.equals(CommandResultType.SUCCESS)) { + return command.toTab(this.plugin, sender, args); + } + + return null; + } + + /** + * Register spigot command without plugin.yml This method will allow to + * register a command in the spigot without using the plugin.yml This saves + * time and understanding, the plugin.yml file is clearer + * + * @param string - Main command + * @param vCommand - Command object + * @param aliases - Command aliases + */ + public void registerCommand(Plugin plugin, String string, EssentialsCommand vCommand, List aliases) { + try { + PluginCommand command = constructor.newInstance(string, plugin); + command.setExecutor(this); + command.setTabCompleter(this); + command.setAliases(aliases); + + vCommand.addSubCommand(string); + vCommand.addSubCommand(aliases); + commands.add(vCommand); + + if (!commandMap.register(command.getName(), plugin.getDescription().getName(), command)) { + plugin.getLogger().info("Unable to add the command " + vCommand.getSyntax()); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + @Override + public int countCommands() { + return this.commands.size(); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomy.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomy.java new file mode 100644 index 00000000..660f3c60 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomy.java @@ -0,0 +1,25 @@ +package fr.maxlego08.essentials.commands.commands.economy; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandEconomy extends VCommand { + + + public CommandEconomy(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ECO_USE); + this.setDescription(Message.DESCRIPTION_ECO); + this.addSubCommand(new CommandEconomyGive(plugin)); + this.addSubCommand(new CommandEconomyTake(plugin)); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + this.syntaxMessage(); + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyGive.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyGive.java new file mode 100644 index 00000000..37fcb6ab --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyGive.java @@ -0,0 +1,56 @@ +package fr.maxlego08.essentials.commands.commands.economy; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.OfflinePlayer; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +public class CommandEconomyGive extends VCommand { + + + public CommandEconomyGive(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ECO_GIVE); + this.setDescription(Message.DESCRIPTION_ECO_GIVE); + this.addSubCommand("give"); + this.addRequireArg("economy", (a, b) -> plugin.getEconomyProvider().getEconomies().stream().map(Economy::getName).toList()); + this.addRequireArg("player"); + this.addRequireArg("amount", (a, b) -> Stream.of(10, 20, 30, 40, 50, 60, 70, 80, 90).map(String::valueOf).toList()); + this.addOptionalArg("silent", (a, b) -> Arrays.asList("true", "false")); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + String economyName = this.argAsString(0); + OfflinePlayer offlinePlayer = this.argAsOfflinePlayer(1); + double amount = this.argAsDouble(2); + boolean silent = this.argAsBoolean(3, false); + + EconomyProvider economyProvider = plugin.getEconomyProvider(); + Optional optional = economyProvider.getEconomy(economyName); + if (optional.isEmpty()) { + message(sender, Message.COMMAND_ECONOMY_NOT_FOUND, "%name%", economyName); + return CommandResultType.DEFAULT; + } + Economy economy = optional.get(); + economyProvider.deposit(offlinePlayer.getUniqueId(), economy, new BigDecimal(amount)); + + String economyFormat = economy.format(economyProvider.format(amount), (long) amount); + message(sender, Message.COMMAND_ECONOMY_GIVE_SENDER, "%player%", offlinePlayer.getName(), "%economyFormat%", economyFormat); + if (offlinePlayer.isOnline() && !silent) { + message(offlinePlayer.getPlayer(), Message.COMMAND_ECONOMY_GIVE_RECEIVER, "%economyFormat%", economyFormat); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyTake.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyTake.java new file mode 100644 index 00000000..dd4c39a5 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/economy/CommandEconomyTake.java @@ -0,0 +1,56 @@ +package fr.maxlego08.essentials.commands.commands.economy; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.OfflinePlayer; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +public class CommandEconomyTake extends VCommand { + + + public CommandEconomyTake(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ECO_TAKE); + this.setDescription(Message.DESCRIPTION_ECO_TAKE); + this.addSubCommand("take"); + this.addRequireArg("economy", (a, b) -> plugin.getEconomyProvider().getEconomies().stream().map(Economy::getName).toList()); + this.addRequireArg("player"); + this.addRequireArg("amount", (a, b) -> Stream.of(10, 20, 30, 40, 50, 60, 70, 80, 90).map(String::valueOf).toList()); + this.addOptionalArg("silent", (a, b) -> Arrays.asList("true", "false")); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + String economyName = this.argAsString(0); + OfflinePlayer offlinePlayer = this.argAsOfflinePlayer(1); + double amount = this.argAsDouble(2); + boolean silent = this.argAsBoolean(3, false); + + EconomyProvider economyProvider = plugin.getEconomyProvider(); + Optional optional = economyProvider.getEconomy(economyName); + if (optional.isEmpty()) { + message(sender, Message.COMMAND_ECONOMY_NOT_FOUND, "%name%", economyName); + return CommandResultType.DEFAULT; + } + Economy economy = optional.get(); + economyProvider.withdraw(offlinePlayer.getUniqueId(), economy, new BigDecimal(amount)); + + String economyFormat = economy.format(economyProvider.format(amount), (long) amount); + message(sender, Message.COMMAND_ECONOMY_TAKE_SENDER, "%player%", offlinePlayer.getName(), "%economyFormat%", economyFormat); + if (offlinePlayer.isOnline() && !silent) { + message(offlinePlayer.getPlayer(), Message.COMMAND_ECONOMY_TAKE_RECEIVER, "%economyFormat%", economyFormat); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderChest.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderChest.java new file mode 100644 index 00000000..9054faa4 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderChest.java @@ -0,0 +1,23 @@ +package fr.maxlego08.essentials.commands.commands.enderchest; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandEnderChest extends VCommand { + + public CommandEnderChest(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ENDERCHEST); + this.setDescription(Message.DESCRIPTION_DAY); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + this.player.openInventory(this.player.getEnderChest()); + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderSee.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderSee.java new file mode 100644 index 00000000..6dade5ee --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/enderchest/CommandEnderSee.java @@ -0,0 +1,26 @@ +package fr.maxlego08.essentials.commands.commands.enderchest; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandEnderSee extends VCommand { + + public CommandEnderSee(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ENDERSEE); + this.setDescription(Message.DESCRIPTION_ENDERSEE); + this.addRequireArg("player"); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + Player targetPlayer = this.argAsPlayer(0); + this.player.openInventory(targetPlayer.getEnderChest()); + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentials.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentials.java new file mode 100644 index 00000000..bf0b45f6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentials.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.commands.commands.essentials; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandEssentials extends VCommand { + + public CommandEssentials(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_USE); + this.addSubCommand(new CommandEssentialsReload(plugin)); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + message(sender, Message.COMMAND_ESSENTIALS, "%version%", plugin.getDescription().getVersion()); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentialsReload.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentialsReload.java new file mode 100644 index 00000000..de1a7499 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/essentials/CommandEssentialsReload.java @@ -0,0 +1,28 @@ +package fr.maxlego08.essentials.commands.commands.essentials; + +import fr.maxlego08.essentials.api.ConfigurationFile; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandEssentialsReload extends VCommand { + + public CommandEssentialsReload(EssentialsPlugin plugin) { + super(plugin); + this.addSubCommand("reload", "rl"); + this.setPermission(Permission.ESSENTIALS_RELOAD); + this.setDescription(Message.DESCRIPTION_RELOAD); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + plugin.getConfigurationFiles().forEach(ConfigurationFile::load); + plugin.getModuleManager().loadConfigurations(); + message(sender, Message.COMMAND_RELOAD); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameMode.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameMode.java new file mode 100644 index 00000000..a076fd92 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameMode.java @@ -0,0 +1,42 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; + +public class CommandGameMode extends GameModeCommand { + + public CommandGameMode(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GAMEMODE); + this.setDescription(Message.DESCRIPTION_GAMEMODE); + this.addRequireArg("gamemode", (a, b) -> Arrays.stream(GameMode.values()).map(e -> e.name().toLowerCase()).collect(Collectors.toList())); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + String value = this.argAsString(0); + Player player = this.argAsPlayer(1, this.player); + + if (player == null) { + message(sender, Message.COMMAND_GAMEMODE_INVALID); + return CommandResultType.DEFAULT; + } + + Optional optional = Arrays.stream(GameMode.values()).filter(e -> value.equals(String.valueOf(e.getValue())) || e.name().equalsIgnoreCase(value)).findFirst(); + if (optional.isEmpty()) return CommandResultType.SYNTAX_ERROR; + + GameMode gameMode = optional.get(); + return changeGameMode(this.sender, gameMode, player); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeAdventure.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeAdventure.java new file mode 100644 index 00000000..74f38659 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeAdventure.java @@ -0,0 +1,31 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +public class CommandGameModeAdventure extends GameModeCommand { + + public CommandGameModeAdventure(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GAMEMODE_ADVENTURE); + this.setDescription(Message.DESCRIPTION_GAMEMODE_ADVENTURE); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (player == null) { + message(sender, Message.COMMAND_GAMEMODE_INVALID); + return CommandResultType.DEFAULT; + } + + return changeGameMode(this.sender, GameMode.ADVENTURE, player); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeCreative.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeCreative.java new file mode 100644 index 00000000..e2f378e5 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeCreative.java @@ -0,0 +1,36 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; + +public class CommandGameModeCreative extends GameModeCommand { + + public CommandGameModeCreative(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GAMEMODE_CREATIVE); + this.setDescription(Message.DESCRIPTION_GAMEMODE_CREATIVE); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (player == null) { + message(sender, Message.COMMAND_GAMEMODE_INVALID); + return CommandResultType.DEFAULT; + } + + return changeGameMode(this.sender, GameMode.CREATIVE, player); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSpectator.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSpectator.java new file mode 100644 index 00000000..52debcf6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSpectator.java @@ -0,0 +1,31 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +public class CommandGameModeSpectator extends GameModeCommand { + + public CommandGameModeSpectator(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GAMEMODE_SPECTATOR); + this.setDescription(Message.DESCRIPTION_GAMEMODE_SPECTATOR); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (player == null) { + message(sender, Message.COMMAND_GAMEMODE_INVALID); + return CommandResultType.DEFAULT; + } + + return changeGameMode(this.sender, GameMode.SPECTATOR, player); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSurvival.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSurvival.java new file mode 100644 index 00000000..b77481dd --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/CommandGameModeSurvival.java @@ -0,0 +1,31 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +public class CommandGameModeSurvival extends GameModeCommand { + + public CommandGameModeSurvival(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GAMEMODE_SURVIVAL); + this.setDescription(Message.DESCRIPTION_GAMEMODE_SURVIVAL); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (player == null) { + message(sender, Message.COMMAND_GAMEMODE_INVALID); + return CommandResultType.DEFAULT; + } + + return changeGameMode(this.sender, GameMode.SURVIVAL, player); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/GameModeCommand.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/GameModeCommand.java new file mode 100644 index 00000000..8799bbe0 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/gamemode/GameModeCommand.java @@ -0,0 +1,32 @@ +package fr.maxlego08.essentials.commands.commands.gamemode; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.GameMode; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public abstract class GameModeCommand extends VCommand { + public GameModeCommand(EssentialsPlugin plugin) { + super(plugin); + } + + protected CommandResultType changeGameMode(CommandSender sender, GameMode gameMode, Player player) { + if (player == this.player) { + + player.setGameMode(gameMode); + message(sender, Message.COMMAND_GAMEMODE, "%gamemode%", name(gameMode.name()), "%player%", Message.YOU.getMessage()); + + } else { + + if (!hasPermission(sender, Permission.ESSENTIALS_GAMEMODE_OTHER)) return CommandResultType.NO_PERMISSION; + + player.setGameMode(gameMode); + message(sender, Message.COMMAND_GAMEMODE, "%gamemode%", name(gameMode.name()), "%player%", player.getName()); + } + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleport.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleport.java new file mode 100644 index 00000000..4eb75bc0 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleport.java @@ -0,0 +1,31 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.module.modules.TeleportationModule; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandTeleport extends VCommand { + + public CommandTeleport(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TP); + this.setDescription(Message.DESCRIPTION_TP); + this.addRequireArg("player"); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player targetPlayer = this.argAsPlayer(0); + this.user.teleport(targetPlayer.getLocation()); + message(this.sender, Message.COMMAND_TP, targetPlayer); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportAccept.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportAccept.java new file mode 100644 index 00000000..28191d0b --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportAccept.java @@ -0,0 +1,39 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.TeleportRequest; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandTeleportAccept extends VCommand { + + public CommandTeleportAccept(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TPA_ACCEPT); + this.setDescription(Message.DESCRIPTION_TPA_ACCEPT); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + TeleportRequest teleportRequest = this.user.getTeleportRequest(); + if (teleportRequest == null) { + message(sender, Message.COMMAND_TPA_ERROR_TO_LATE); + return CommandResultType.DEFAULT; + } + + if (!teleportRequest.isValid()) { + this.user.setTeleportRequest(null); + message(sender, Message.COMMAND_TPA_ERROR_TO_LATE_2); + return CommandResultType.DEFAULT; + } + + teleportRequest.accept(); + this.user.setTeleportRequest(null); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportCancel.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportCancel.java new file mode 100644 index 00000000..1ad4bdff --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportCancel.java @@ -0,0 +1,29 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.TeleportRequest; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandTeleportCancel extends VCommand { + + public CommandTeleportCancel(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TPA_CANCEL); + this.setDescription(Message.DESCRIPTION_TPA_CANCEL); + this.addRequireArg("player"); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player targetPlayer = this.argAsPlayer(0); + this.user.cancelTeleportRequest(plugin.getStorageManager().getStorage().getUser(targetPlayer.getUniqueId())); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportDeny.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportDeny.java new file mode 100644 index 00000000..dab1b342 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportDeny.java @@ -0,0 +1,39 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.TeleportRequest; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandTeleportDeny extends VCommand { + + public CommandTeleportDeny(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TPA_DENY); + this.setDescription(Message.DESCRIPTION_TPA_DENY); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + TeleportRequest teleportRequest = this.user.getTeleportRequest(); + if (teleportRequest == null) { + message(sender, Message.COMMAND_TPA_ERROR_TO_LATE); + return CommandResultType.DEFAULT; + } + + if (!teleportRequest.isValid()) { + this.user.setTeleportRequest(null); + message(sender, Message.COMMAND_TPA_ERROR_TO_LATE_2); + return CommandResultType.DEFAULT; + } + + teleportRequest.deny(); + this.user.setTeleportRequest(null); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportHere.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportHere.java new file mode 100644 index 00000000..e3cb8f45 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportHere.java @@ -0,0 +1,29 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandTeleportHere extends VCommand { + + public CommandTeleportHere(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TP); + this.setDescription(Message.DESCRIPTION_TP_SELF); + this.addRequireArg("player"); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player targetPlayer = this.argAsPlayer(0); + getUser(targetPlayer).teleport(player.getLocation()); + message(this.sender, Message.COMMAND_TP_SELF, targetPlayer); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportTo.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportTo.java new file mode 100644 index 00000000..2a401418 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportTo.java @@ -0,0 +1,44 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.module.modules.TeleportationModule; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandTeleportTo extends VCommand { + + public CommandTeleportTo(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TPA); + this.setDescription(Message.DESCRIPTION_TPA); + this.addRequireArg("player"); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player targetPlayer = this.argAsPlayer(0); + User targetUser = plugin.getStorageManager().getStorage().getUser(targetPlayer.getUniqueId()); + + if (targetUser.getUniqueId().equals(this.player.getUniqueId())) { + message(this.sender, Message.COMMAND_TPA_ERROR_SAME); + return CommandResultType.DEFAULT; + } + + TeleportationModule teleportationModule = plugin.getModuleManager().getModule(TeleportationModule.class); + if (teleportationModule.isOpenConfirmInventoryForTpa()) { + this.user.setTargetUser(targetUser); + teleportationModule.openConfirmInventory(player); + return CommandResultType.SUCCESS; + } + + this.user.sendTeleportRequest(targetUser); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportWorld.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportWorld.java new file mode 100644 index 00000000..e40baaa4 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/teleport/CommandTeleportWorld.java @@ -0,0 +1,48 @@ +package fr.maxlego08.essentials.commands.commands.teleport; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.generator.WorldInfo; + +public class CommandTeleportWorld extends VCommand { + + public CommandTeleportWorld(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TP_WORLD); + this.setDescription(Message.DESCRIPTION_TP_WORLD); + this.addRequireArg("world", (a, b) -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + World world = this.argAsWorld(0); + Player player = this.argAsPlayer(1, this.player); + + if (player == null) return CommandResultType.SYNTAX_ERROR; + + player.teleport(world.getSpawnLocation()); + + if (player == this.player) { + + message(sender, Message.COMMAND_WORLD_TELEPORT_SELF, "%world%", world.getName()); + } else { + + if (!hasPermission(sender, Permission.ESSENTIALS_TP_WORLD_OTHER)) { + return CommandResultType.NO_PERMISSION; + } + + message(player, Message.COMMAND_WORLD_TELEPORT_SELF, "%world%", world.getName()); + message(sender, Message.COMMAND_WORLD_TELEPORT_OTHER, "%world%", world.getName(), player); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCompact.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCompact.java new file mode 100644 index 00000000..6f8de3f6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCompact.java @@ -0,0 +1,55 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.utils.CompactMaterial; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class CommandCompact extends VCommand { + public CommandCompact(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_COMPACT); + this.setDescription(Message.DESCRIPTION_COMPACT); + this.addRequireArg("type", (a, b) -> plugin.getConfiguration().getCompactMaterials().stream().map(e -> e.from().name().toLowerCase()).toList()); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Material material = Material.valueOf(this.argAsString(0).toUpperCase()); + + Optional optional = this.configuration.getCompactMaterials().stream().filter(e -> e.from().equals(material)).findFirst(); + if (optional.isEmpty()) { + + message(sender, Message.COMMAND_COMPACT_TYPE, "%material%", name(material.name())); + return CommandResultType.DEFAULT; + } + + CompactMaterial compactMaterial = optional.get(); + Material newMaterial = compactMaterial.to(); + + Inventory inventory = this.player.getInventory(); + int amountOf = count(inventory, material); + + if (amountOf <= 0) { + message(getPlayer(), Message.COMMAND_COMPACT_ERROR, "%item%", name(material.name())); + return CommandResultType.DEFAULT; + } + + int realAmount = amountOf / 9; + removeItems(inventory, new ItemStack(material), realAmount * 9); + give(getPlayer(), new ItemStack(newMaterial, realAmount)); + message(getPlayer(), Message.COMMAND_COMPACT_SUCCESS, "%amount%", realAmount * 9, "%item%", name(material.name()), + "%toAmount%", realAmount, "%toItem%", name(newMaterial.name())); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCraft.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCraft.java new file mode 100644 index 00000000..72e9708c --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandCraft.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandCraft extends VCommand { + public CommandCraft(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_CRAFT); + this.setDescription(Message.DESCRIPTION_CRAFT); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + this.player.getPlayer().openWorkbench(this.player.getLocation(), true); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandEnchanting.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandEnchanting.java new file mode 100644 index 00000000..4485b1af --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandEnchanting.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandEnchanting extends VCommand { + public CommandEnchanting(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_ENCHANTING); + this.setDescription(Message.DESCRIPTION_ENCHANTING); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + this.player.getPlayer().openEnchanting(this.player.getLocation(), true); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandFeed.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandFeed.java new file mode 100644 index 00000000..28c44984 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandFeed.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Player; + +public class CommandFeed extends VCommand { + public CommandFeed(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_FEED); + this.setDescription(Message.DESCRIPTION_FEED); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (this.player == null) return CommandResultType.SYNTAX_ERROR; + + if (player != this.player && !hasPermission(sender, Permission.ESSENTIALS_FEED_OTHER)) { + player = this.player; + } + + player.setFoodLevel(20); + + if (player == sender) { + + message(sender, Message.COMMAND_FEED_RECEIVER); + } else { + + message(sender, Message.COMMAND_FEED_SENDER, "%player%", player.getName()); + message(player, Message.COMMAND_FEED_RECEIVER); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandGod.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandGod.java new file mode 100644 index 00000000..b84625a6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandGod.java @@ -0,0 +1,54 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.attribute.Attribute; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class CommandGod extends VCommand { + public CommandGod(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_GOD); + this.setDescription(Message.DESCRIPTION_GOD); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (this.player == null) { + return CommandResultType.SYNTAX_ERROR; + } + + if (player == this.player) { + toggleGodMode(player, this.user, sender); + } else { + User otherUser = getUser(player); + toggleGodMode(player, otherUser, sender); + } + + return CommandResultType.SUCCESS; + } + + private void toggleGodMode(Player player, User user, CommandSender sender) { + + user.setOption(Option.GOD, !user.getOption(Option.GOD)); + boolean isGodEnabled = user.getOption(Option.GOD); + + if (isGodEnabled) { + player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue()); + player.setFoodLevel(20); + } + + Message messageKey = isGodEnabled ? Message.COMMAND_GOD_ENABLE : Message.COMMAND_GOD_DISABLE; + message(sender, messageKey, "%player%", user == this.user ? Message.YOU.getMessage() : player.getName()); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHat.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHat.java new file mode 100644 index 00000000..d0a97489 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHat.java @@ -0,0 +1,35 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.inventory.ItemStack; + +public class CommandHat extends VCommand { + public CommandHat(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_HAT); + this.setDescription(Message.DESCRIPTION_HAT); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + ItemStack itemStack = player.getInventory().getHelmet(); + ItemStack inHand = player.getInventory().getItemInMainHand(); + + if (inHand.getType().isAir()) { + message(this.sender, Message.COMMAND_HAT_ERROR); + return CommandResultType.DEFAULT; + } + + this.player.getInventory().setHelmet(inHand); + this.player.getInventory().setItemInMainHand(itemStack); + message(this.sender, Message.COMMAND_HAT_SUCCESS, "%item%", name(inHand.getType().name())); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHeal.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHeal.java new file mode 100644 index 00000000..6ca013ea --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandHeal.java @@ -0,0 +1,50 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Player; + +public class CommandHeal extends VCommand { + public CommandHeal(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_HEAL); + this.setDescription(Message.DESCRIPTION_HEAL); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0, this.player); + + if (this.player == null) return CommandResultType.SYNTAX_ERROR; + + if (player != this.player && !hasPermission(sender, Permission.ESSENTIALS_HEAL_OTHER)) { + player = this.player; + } + + if (!player.isValid()){ + message(sender, Message.COMMAND_HEAL_ERROR); + return CommandResultType.DEFAULT; + } + + player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue()); + player.setFoodLevel(20); + player.setFireTicks(0); + + if (player == sender) { + + message(sender, Message.COMMAND_HEAL_RECEIVER); + } else { + + message(sender, Message.COMMAND_HEAL_SENDER, "%player%", player.getName()); + message(player, Message.COMMAND_HEAL_RECEIVER); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandInvsee.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandInvsee.java new file mode 100644 index 00000000..c165fb43 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandInvsee.java @@ -0,0 +1,28 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +public class CommandInvsee extends VCommand { + public CommandInvsee(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_INVSEE); + this.setDescription(Message.DESCRIPTION_INVSEE); + this.addRequireArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Player player = this.argAsPlayer(0); + this.user.setOption(Option.INVSEE, true); + this.player.openInventory(player.getInventory()); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandMore.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandMore.java new file mode 100644 index 00000000..6194900c --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandMore.java @@ -0,0 +1,30 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +public class CommandMore extends VCommand { + public CommandMore(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_MORE); + this.setDescription(Message.DESCRIPTION_MORE); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + if (this.player.getInventory().getItemInMainHand().getType().isAir()) { + message(this.sender, Message.COMMAND_MORE_ERROR); + return CommandResultType.DEFAULT; + } + + this.player.getInventory().getItemInMainHand().setAmount(64); + message(this.sender, Message.COMMAND_MORE_SUCCESS); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandSpeed.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandSpeed.java new file mode 100644 index 00000000..657951ec --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandSpeed.java @@ -0,0 +1,55 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.entity.Player; + +import java.util.Arrays; + +public class CommandSpeed extends VCommand { + public CommandSpeed(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_SPEED); + this.setDescription(Message.DESCRIPTION_SPEED); + this.addRequireArg("speed", (a, b) -> Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10")); + this.addOptionalArg("player"); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + int speed = this.argAsInteger(0); + Player player = this.argAsPlayer(1, this.player); + + if (speed < 0 || speed > 10) { + + message(this.sender, Message.COMMAND_SPEED_ERROR); + return CommandResultType.DEFAULT; + } + + if (player == null) { + message(sender, Message.COMMAND_SPEED_INVALID); + return CommandResultType.DEFAULT; + } + + float speedFloat = speed / 10f; + + boolean isFlying = player.isFlying(); + Message speedTypeMessage = isFlying ? Message.COMMAND_SPEED_FLY : Message.COMMAND_SPEED_WALK; + + if (isFlying) { + player.setFlySpeed(speedFloat); + } else { + player.setWalkSpeed(speedFloat); + } + + String playerNameOrYou = player == this.player ? Message.YOU.getMessage() : player.getName(); + message(this.sender, speedTypeMessage, "%speed%", speed, "%player%", playerNameOrYou); + + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTop.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTop.java new file mode 100644 index 00000000..d0d1ab2e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTop.java @@ -0,0 +1,39 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Location; + +import java.util.Optional; + +public class CommandTop extends VCommand { + public CommandTop(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TOP); + this.setDescription(Message.DESCRIPTION_TOP); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Optional optional = this.topLocation(this.player.getLocation(), 0, this.player.getWorld().getMaxHeight()); + if (optional.isPresent()) { + + Location location = optional.get(); + location.setPitch(this.player.getLocation().getPitch()); + location.setYaw(this.player.getLocation().getYaw()); + location.add(0.5, 0, 0.5); + this.player.teleport(location); + message(this.sender, Message.COMMAND_TOP); + } else { + + message(this.sender, Message.COMMAND_TOP_ERROR); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTrash.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTrash.java new file mode 100644 index 00000000..3e9d25e6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/utils/CommandTrash.java @@ -0,0 +1,26 @@ +package fr.maxlego08.essentials.commands.commands.utils; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.inventory.Inventory; + +public class CommandTrash extends VCommand { + public CommandTrash(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_TRASH); + this.setDescription(Message.DESCRIPTION_GOD); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + Inventory inventory = componentMessage.createInventory(Message.TRASH.getMessage(), configuration.getTrashSize(), null); + this.player.openInventory(inventory); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandDay.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandDay.java new file mode 100644 index 00000000..d2f20ba0 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandDay.java @@ -0,0 +1,33 @@ +package fr.maxlego08.essentials.commands.commands.weather; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.generator.WorldInfo; + +import java.util.stream.Collectors; + +public class CommandDay extends VCommand { + + public CommandDay(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_DAY); + this.setDescription(Message.DESCRIPTION_DAY); + this.addOptionalArg("world", (a, b) -> Bukkit.getWorlds().stream().map(WorldInfo::getName).collect(Collectors.toList())); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + World world = this.argAsWorld(0, isPlayer() ? this.player.getWorld() : null); + world.setFullTime(1000); + + message(this.sender, Message.COMMAND_DAY, "%world%", world.getName()); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandNight.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandNight.java new file mode 100644 index 00000000..3aa42d8d --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandNight.java @@ -0,0 +1,33 @@ +package fr.maxlego08.essentials.commands.commands.weather; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.generator.WorldInfo; + +import java.util.stream.Collectors; + +public class CommandNight extends VCommand { + + public CommandNight(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_NIGHT); + this.setDescription(Message.DESCRIPTION_NIGHT); + this.addOptionalArg("world", (a, b) -> Bukkit.getWorlds().stream().map(WorldInfo::getName).collect(Collectors.toList())); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + World world = this.argAsWorld(0, isPlayer() ? this.player.getWorld() : null); + world.setFullTime(13000); + + message(this.sender, Message.COMMAND_NIGHT, "%world%", world.getName()); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerTime.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerTime.java new file mode 100644 index 00000000..4e7b0ae8 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerTime.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.commands.commands.weather; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; + +import java.util.Arrays; + +public class CommandPlayerTime extends VCommand { + + public CommandPlayerTime(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_PLAYER_TIME); + this.setDescription(Message.DESCRIPTION_PLAYER_TIME); + this.addOptionalArg("time", (a, b) -> Arrays.asList("0", "500", "1000", "1500", "2000")); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + long ticks = argAsLong(0, 0); + + if (ticks == 0) { + + player.resetPlayerTime(); + message(player, Message.COMMAND_PLAYER_TIME_RESET); + + } else { + + long time = player.getPlayerTime(); + time -= time % 24000L; + time += 24000L + ticks; + + player.setPlayerTime(time, true); + message(player, Message.COMMAND_PLAYER_TIME_CHANGE); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerWeather.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerWeather.java new file mode 100644 index 00000000..bc72f7da --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandPlayerWeather.java @@ -0,0 +1,40 @@ +package fr.maxlego08.essentials.commands.commands.weather; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.WeatherType; +import org.bukkit.entity.Player; + +import java.util.Arrays; + +public class CommandPlayerWeather extends VCommand { + + public CommandPlayerWeather(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_PLAYER_WEATHER); + this.setDescription(Message.DESCRIPTION_PLAYER_WEATHER); + this.addOptionalArg("weather", (a, b) -> Arrays.asList("sun", "storm", "thunder", "clear")); + this.onlyPlayers(); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + String weather = argAsString(0, null); + + if (weather == null || weather.equalsIgnoreCase("sun") || weather.equalsIgnoreCase("clear")) { + + this.player.resetPlayerWeather(); + message(sender, Message.COMMAND_PLAYER_WEATHER_RESET); + } else if (weather.equalsIgnoreCase("storm") || weather.equalsIgnoreCase("thunder")) { + + this.player.setPlayerWeather(WeatherType.DOWNFALL); + message(sender, Message.COMMAND_PLAYER_WEATHER_DOWNFALL); + } + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandSun.java b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandSun.java new file mode 100644 index 00000000..5658ce35 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/commands/commands/weather/CommandSun.java @@ -0,0 +1,35 @@ +package fr.maxlego08.essentials.commands.commands.weather; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.generator.WorldInfo; + +import java.util.stream.Collectors; + +public class CommandSun extends VCommand { + + public CommandSun(EssentialsPlugin plugin) { + super(plugin); + this.setPermission(Permission.ESSENTIALS_SUN); + this.setDescription(Message.DESCRIPTION_SUN); + this.addOptionalArg("world", (a, b) -> Bukkit.getWorlds().stream().map(WorldInfo::getName).collect(Collectors.toList())); + } + + @Override + protected CommandResultType perform(EssentialsPlugin plugin) { + + World world = this.argAsWorld(0, isPlayer() ? this.player.getWorld() : null); + world.setStorm(false); + world.setThunderDuration(0); + world.setThundering(false); + + message(this.sender, Message.COMMAND_SUN, "%world%", world.getName()); + + return CommandResultType.SUCCESS; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/ColumnDefinition.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/ColumnDefinition.java new file mode 100644 index 00000000..5081e65b --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/ColumnDefinition.java @@ -0,0 +1,129 @@ +package fr.maxlego08.essentials.database; + +public class ColumnDefinition { + private String name; + private String type; + private int length; + private boolean nullable = false; + private String defaultValue; + private boolean isPrimaryKey = false; + private boolean is = false; + private String referenceTable; + private Object object; + + public ColumnDefinition(String name, String type) { + this.name = name; + this.type = type; + } + + public ColumnDefinition(String name) { + this.name = name; + } + + public String build() { + StringBuilder columnSQL = new StringBuilder(name + " " + type); + + if (length != 0) { + columnSQL.append("(").append(length).append(")"); + } + + if (nullable) { + columnSQL.append(" NULL"); + } else { + columnSQL.append(" NOT NULL"); + } + + if (defaultValue != null) { + columnSQL.append(" DEFAULT ").append(defaultValue); + } + + return columnSQL.toString(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Integer getLength() { + return length; + } + + public ColumnDefinition setLength(Integer length) { + this.length = length; + return this; + } + + public Boolean getNullable() { + return nullable; + } + + public void setNullable(Boolean nullable) { + this.nullable = nullable; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + public boolean isPrimaryKey() { + return isPrimaryKey; + } + + public void setPrimaryKey(boolean primaryKey) { + isPrimaryKey = primaryKey; + } + + public String getReferenceTable() { + return referenceTable; + } + + public void setReferenceTable(String referenceTable) { + this.referenceTable = referenceTable; + } + + public ColumnDefinition setLength(int length) { + this.length = length; + return this; + } + + public boolean isNullable() { + return nullable; + } + + public void setNullable(boolean nullable) { + this.nullable = nullable; + } + + public boolean isIs() { + return is; + } + + public void setIs(boolean is) { + this.is = is; + } + + public Object getObject() { + return object; + } + + public ColumnDefinition setObject(Object object) { + this.object = object; + return this; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/SchemaBuilder.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/SchemaBuilder.java new file mode 100644 index 00000000..8ebc1189 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/SchemaBuilder.java @@ -0,0 +1,351 @@ +package fr.maxlego08.essentials.database; + +import fr.maxlego08.essentials.api.database.Schema; +import fr.maxlego08.essentials.api.database.SchemaType; +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.logging.Logger; + +public class SchemaBuilder implements Schema { + private final String tableName; + private final SchemaType schemaType; + private final List columns = new ArrayList<>(); + private final List primaryKeys = new ArrayList<>(); + private final List foreignKeys = new ArrayList<>(); + private final List whereConditions = new ArrayList<>(); + + private SchemaBuilder(String tableName, SchemaType schemaType) { + this.tableName = tableName; + this.schemaType = schemaType; + } + + public static Schema create(String tableName, Consumer consumer) { + Schema schema = new SchemaBuilder(tableName, SchemaType.CREATE); + ZMigrationManager.registerSchema(schema); + consumer.accept(schema); + return schema; + } + + public static Schema upsert(String tableName, Consumer consumer) { + Schema schema = new SchemaBuilder(tableName, SchemaType.UPSERT); + consumer.accept(schema); + return schema; + } + + public static Schema select(String tableName) { + return new SchemaBuilder(tableName, SchemaType.SELECT); + } + + public static Schema delete(String tableName) { + return new SchemaBuilder(tableName, SchemaType.DELETE); + } + + @Override + public Schema where(String column, Object value) { + this.whereConditions.add(new WhereCondition(column, value)); + return this; + } + + @Override + public Schema where(String column, String operator, Object value) { + this.whereConditions.add(new WhereCondition(column, operator, value)); + return this; + } + + @Override + public Schema uuid(String columnName) { + this.string(columnName, 36); + return this; + } + + @Override + public Schema uuid(String columnName, UUID value) { + return this.addColumn(new ColumnDefinition(columnName).setObject(value.toString())); + } + + @Override + public Schema string(String columnName, int length) { + return addColumn(new ColumnDefinition(columnName, "VARCHAR").setLength(length)); + } + + @Override + public Schema string(String columnName, String value) { + return this.addColumn(new ColumnDefinition(columnName).setObject(value)); + } + + @Override + public Schema bigInt(String columnName) { + return addColumn(new ColumnDefinition(columnName, "BIGINT")); + } + + @Override + public Schema bigInt(String columnName, long value) { + return this.addColumn(new ColumnDefinition(columnName).setObject(value)); + } + + @Override + public Schema bool(String columnName) { + return addColumn(new ColumnDefinition(columnName, "BOOLEAN")); + } + + @Override + public Schema bool(String columnName, boolean value) { + return this.addColumn(new ColumnDefinition(columnName).setObject(value)); + } + + @Override + public Schema foreignKey(String referenceTable) { + if (this.columns.isEmpty()) throw new IllegalStateException("No column defined to apply foreign key."); + ColumnDefinition lastColumn = this.columns.get(this.columns.size() - 1); + + String fkDefinition = String.format("FOREIGN KEY (%s) REFERENCES %s(%s) ON DELETE CASCADE", lastColumn.getName(), referenceTable, lastColumn.getName()); + this.foreignKeys.add(fkDefinition); + return this; + } + + + @Override + public Schema createdAt() { + ColumnDefinition column = new ColumnDefinition("created_at", "TIMESTAMP"); + column.setDefaultValue("CURRENT_TIMESTAMP"); + this.columns.add(column); + return this; + } + + @Override + public Schema updatedAt() { + ColumnDefinition column = new ColumnDefinition("updated_at", "TIMESTAMP"); + column.setDefaultValue("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"); + this.columns.add(column); + return this; + } + + @Override + public Schema nullable() { + getLastColumn().setNullable(true); + return this; + } + + @Override + public Schema defaultValue(String value) { + getLastColumn().setDefaultValue(value); + return this; + } + + @Override + public Schema primary() { + ColumnDefinition lastColumn = getLastColumn(); + lastColumn.setPrimaryKey(true); + primaryKeys.add(lastColumn.getName()); + return this; + } + + private Schema addColumn(ColumnDefinition column) { + columns.add(column); + return this; + } + + @Override + public Schema timestamps() { + this.createdAt(); + this.updatedAt(); + return this; + } + + @Override + public void execute(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException { + switch (this.schemaType) { + case CREATE -> this.executeCreate(connection, databaseConfiguration, logger); + case UPSERT -> this.executeUpsert(connection, databaseConfiguration, logger); + case DELETE -> this.executeDelete(connection, databaseConfiguration, logger); + case SELECT -> throw new IllegalArgumentException("Wrong method !"); + } + } + + private void executeUpsert(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException { + + StringBuilder insertQuery = new StringBuilder("INSERT INTO " + this.tableName + " ("); + StringBuilder valuesQuery = new StringBuilder("VALUES ("); + StringBuilder onUpdateQuery = new StringBuilder(" ON DUPLICATE KEY UPDATE "); + + List values = new ArrayList<>(); + + for (int i = 0; i < this.columns.size(); i++) { + ColumnDefinition columnDefinition = this.columns.get(i); + insertQuery.append(i > 0 ? ", " : "").append(columnDefinition.getName()); + valuesQuery.append(i > 0 ? ", " : "").append("?"); + onUpdateQuery.append(i > 0 ? ", " : "").append(columnDefinition.getName()).append(" = VALUES(").append(columnDefinition.getName()).append(")"); + values.add(columnDefinition.getObject()); + } + + insertQuery.append(") "); + valuesQuery.append(")"); + String upsertQuery = databaseConfiguration.replacePrefix(insertQuery + valuesQuery.toString() + onUpdateQuery); + + if (databaseConfiguration.debug()) { + logger.info("Executing SQL: " + upsertQuery); + } + + try (PreparedStatement preparedStatement = connection.prepareStatement(upsertQuery)) { + for (int i = 0; i < values.size(); i++) { + preparedStatement.setObject(i + 1, values.get(i)); + } + preparedStatement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + throw new SQLException("Failed to execute upsert: " + e.getMessage(), e); + } + + } + + private void executeCreate(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException { + StringBuilder createTableSQL = new StringBuilder("CREATE TABLE IF NOT EXISTS "); + createTableSQL.append(this.tableName).append(" ("); + + List columnSQLs = new ArrayList<>(); + for (ColumnDefinition column : this.columns) { + columnSQLs.add(column.build()); + } + createTableSQL.append(String.join(", ", columnSQLs)); + + if (!this.primaryKeys.isEmpty()) { + createTableSQL.append(", PRIMARY KEY (").append(String.join(", ", this.primaryKeys)).append(")"); + } + + for (String fk : this.foreignKeys) { + createTableSQL.append(", ").append(fk); + } + + createTableSQL.append(")"); + + String finalQuery = databaseConfiguration.replacePrefix(createTableSQL.toString()); + if (databaseConfiguration.debug()) { + logger.info("Executing SQL: " + finalQuery); + } + + try (PreparedStatement statement = connection.prepareStatement(finalQuery)) { + statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + throw new SQLException("Failed to execute schema creation: " + exception.getMessage(), exception); + } + } + + private ColumnDefinition getLastColumn() { + if (columns.isEmpty()) throw new IllegalStateException("No columns defined."); + return columns.get(columns.size() - 1); + } + + @Override + public List> executeSelect(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException { + List> results = new ArrayList<>(); + StringBuilder sql = new StringBuilder("SELECT * FROM " + tableName); + + if (!whereConditions.isEmpty()) { + List conditions = new ArrayList<>(); + for (WhereCondition condition : whereConditions) { + conditions.add(condition.getColumn() + " = ?"); + } + sql.append(" WHERE ").append(String.join(" AND ", conditions)); + } + + String finalQuery = databaseConfiguration.replacePrefix(sql.toString()); + if (databaseConfiguration.debug()) { + logger.info("Executing SQL: " + finalQuery); + } + + try (PreparedStatement statement = connection.prepareStatement(finalQuery)) { + int index = 1; + for (WhereCondition condition : whereConditions) { + statement.setObject(index++, condition.getValue()); + } + + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + Map row = new HashMap<>(); + for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { + row.put(resultSet.getMetaData().getColumnName(i), resultSet.getObject(i)); + } + results.add(row); + } + } + } catch (SQLException exception) { + exception.printStackTrace(); + throw new SQLException("Failed to execute schema select: " + exception.getMessage(), exception); + } + + return results; + } + + private void executeDelete(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException { + StringBuilder sql = new StringBuilder("DELETE FROM ").append(tableName); + + if (!whereConditions.isEmpty()) { + sql.append(" WHERE "); + List conditions = new ArrayList<>(); + for (WhereCondition condition : whereConditions) { + conditions.add(condition.getCondition()); + } + sql.append(String.join(" AND ", conditions)); + } + + String finalQuery = databaseConfiguration.replacePrefix(sql.toString()); + if (databaseConfiguration.debug()) { + logger.info("Executing SQL: " + finalQuery); + } + + try (PreparedStatement statement = connection.prepareStatement(finalQuery)) { + int index = 1; + for (WhereCondition condition : whereConditions) { + statement.setObject(index++, condition.getValue()); + } + statement.executeUpdate(); + } + } + + @Override + public List executeSelect(Class clazz, Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws Exception { + List> results = executeSelect(connection, databaseConfiguration, logger); + return transformResults(results, clazz); + } + + private List transformResults(List> results, Class clazz) throws Exception { + List transformedResults = new ArrayList<>(); + Constructor[] constructors = clazz.getDeclaredConstructors(); + Constructor firstConstructor = constructors[0]; + firstConstructor.setAccessible(true); + + for (Map row : results) { + Object[] params = new Object[firstConstructor.getParameterCount()]; + Parameter[] parameters = firstConstructor.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + Object value = row.get(parameter.getName()); + if (parameter.getType().isEnum()) { + @SuppressWarnings("unchecked") + Class enumType = (Class) parameter.getType(); + Object enumValue = Enum.valueOf(enumType, (String) value); + params[i] = enumValue; + } else { + params[i] = value; + } + } + T instance = (T) firstConstructor.newInstance(params); + transformedResults.add(instance); + } + return transformedResults; + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/WhereCondition.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/WhereCondition.java new file mode 100644 index 00000000..d4e3d930 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/WhereCondition.java @@ -0,0 +1,30 @@ +package fr.maxlego08.essentials.database; + +public class WhereCondition { + private final String column; + private final Object value; + private final String operator; + + public WhereCondition(String column, String operator, Object value) { + this.column = column; + this.operator = operator; + this.value = value; + } + + public WhereCondition(String column, Object value) { + this(column, "=", value); + } + + public String getCondition() { + return column + " " + operator + " ?"; + } + + public Object getValue() { + return value; + } + + public String getColumn() { + return column; + } +} + diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/ZMigrationManager.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/ZMigrationManager.java new file mode 100644 index 00000000..8603f573 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/ZMigrationManager.java @@ -0,0 +1,53 @@ +package fr.maxlego08.essentials.database; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.database.Migration; +import fr.maxlego08.essentials.api.database.MigrationManager; +import fr.maxlego08.essentials.api.database.Schema; +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; +import fr.maxlego08.essentials.database.migrations.CreateUserCooldownTableMigration; +import fr.maxlego08.essentials.database.migrations.CreateUserOptionTableMigration; +import fr.maxlego08.essentials.database.migrations.CreateUserTableMigration; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +public class ZMigrationManager implements MigrationManager { + + private static final List schemas = new ArrayList<>(); + private final EssentialsPlugin plugin; + private final List migrations = new ArrayList<>(); + + public ZMigrationManager(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + public static void registerSchema(Schema schema) { + schemas.add(schema); + } + + @Override + public void registerMigration() { + this.migrations.add(new CreateUserTableMigration()); + this.migrations.add(new CreateUserOptionTableMigration()); + this.migrations.add(new CreateUserCooldownTableMigration()); + } + + @Override + public void execute(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) { + this.migrations.forEach(migration -> { + migration.setPrefix(databaseConfiguration.prefix()); + migration.up(); + }); + schemas.forEach(schema -> { + try { + schema.execute(connection, databaseConfiguration, logger); + } catch (SQLException exception) { + exception.printStackTrace(); + } + }); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserCooldownTableMigration.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserCooldownTableMigration.java new file mode 100644 index 00000000..eb7e0f5b --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserCooldownTableMigration.java @@ -0,0 +1,16 @@ +package fr.maxlego08.essentials.database.migrations; + +import fr.maxlego08.essentials.api.database.Migration; +import fr.maxlego08.essentials.database.SchemaBuilder; + +public class CreateUserCooldownTableMigration extends Migration { + @Override + public void up() { + SchemaBuilder.create("%prefix%player_cooldowns", table -> { + table.uuid("unique_id").primary().foreignKey("%prefix%players"); + table.string("cooldown_name", 255).primary(); + table.bigInt("cooldown_value"); + table.timestamps(); + }); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserOptionTableMigration.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserOptionTableMigration.java new file mode 100644 index 00000000..d7c0ece6 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserOptionTableMigration.java @@ -0,0 +1,16 @@ +package fr.maxlego08.essentials.database.migrations; + +import fr.maxlego08.essentials.api.database.Migration; +import fr.maxlego08.essentials.database.SchemaBuilder; + +public class CreateUserOptionTableMigration extends Migration { + @Override + public void up() { + SchemaBuilder.create("%prefix%player_options", table -> { + table.uuid("unique_id").primary().foreignKey("%prefix%players"); + table.string("option_name", 255); + table.bool("option_value"); + table.timestamps(); + }); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserTableMigration.java b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserTableMigration.java new file mode 100644 index 00000000..905268be --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/database/migrations/CreateUserTableMigration.java @@ -0,0 +1,15 @@ +package fr.maxlego08.essentials.database.migrations; + +import fr.maxlego08.essentials.api.database.Migration; +import fr.maxlego08.essentials.database.SchemaBuilder; + +public class CreateUserTableMigration extends Migration { + @Override + public void up() { + SchemaBuilder.create("%prefix%players", table -> { + table.uuid("unique_id").primary(); + table.string("name", 16); + table.timestamps(); + }); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/economy/EconomyManager.java b/Essentials/src/main/java/fr/maxlego08/essentials/economy/EconomyManager.java new file mode 100644 index 00000000..76181964 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/economy/EconomyManager.java @@ -0,0 +1,116 @@ +package fr.maxlego08.essentials.economy; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.module.ZModule; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; + +public class EconomyManager extends ZModule implements EconomyProvider { + + private final List economies = new ArrayList<>(); + private String defaultEconomy; + + public EconomyManager(ZEssentialsPlugin plugin) { + super(plugin, "economy"); + } + + @Override + public void loadConfiguration() { + super.loadConfiguration(); + + this.economies.clear(); + + YamlConfiguration configuration = getConfiguration(); + ConfigurationSection configurationSection = configuration.getConfigurationSection("economies"); + if (configurationSection == null) return; + + configurationSection.getKeys(false).forEach(economyName -> { + + ConfigurationSection section = configurationSection.getConfigurationSection(economyName); + if (section == null) return; + + this.economies.add(new ZEconomy(section, economyName)); + this.plugin.getLogger().info("Create economy " + economyName + " !"); + }); + + System.out.println(economies); + } + + @Override + public boolean hasMoney(OfflinePlayer player, Economy economy) { + return false; + } + + @Override + public BigDecimal getBalance(OfflinePlayer player, Economy economy) { + return null; + } + + private void perform(UUID uniqueId, Consumer consumer) { + IStorage iStorage = this.plugin.getStorageManager().getStorage(); + User user = iStorage.getUser(uniqueId); + + if (user == null) { // Need to load the user, use async scheduler + + this.plugin.getScheduler().runAsync(wrappedTask -> iStorage.updateUserMoney(uniqueId, consumer)); + } else { + + consumer.accept(user); + } + } + + @Override + public boolean deposit(UUID uniqueId, Economy economy, BigDecimal amount) { + perform(uniqueId, user -> user.deposit(economy, amount)); + return true; + } + + @Override + public boolean withdraw(UUID uniqueId, Economy economy, BigDecimal amount) { + perform(uniqueId, user -> user.withdraw(economy, amount)); + return true; + } + + @Override + public boolean set(UUID uniqueId, Economy economy, BigDecimal amount) { + perform(uniqueId, user -> user.set(economy, amount)); + return true; + } + + @Override + public Collection getEconomies() { + return Collections.unmodifiableCollection(this.economies); + } + + @Override + public Optional getEconomy(String economyName) { + return this.economies.stream().filter(economy -> economy.getName().equalsIgnoreCase(economyName)).findFirst(); + } + + @Override + public Economy getDefaultEconomy() { + return getEconomy(this.defaultEconomy).orElse(null); + } + + @Override + public String format(double amount) { + // Rework for more configuration about that + DecimalFormat decimalFormat = new DecimalFormat("#,###.##"); + return decimalFormat.format(amount); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/economy/ZEconomy.java b/Essentials/src/main/java/fr/maxlego08/essentials/economy/ZEconomy.java new file mode 100644 index 00000000..e391d3af --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/economy/ZEconomy.java @@ -0,0 +1,65 @@ +package fr.maxlego08.essentials.economy; + +import fr.maxlego08.essentials.api.economy.Economy; +import org.bukkit.configuration.ConfigurationSection; + +public class ZEconomy implements Economy { + + private final String name; + private final String displayName; + private final String symbol; + private final String format; + private final boolean isVaultEconomy; + + public ZEconomy(String name, String displayName, String currency, String format, boolean isVaultEconomy) { + this.name = name; + this.displayName = displayName; + this.symbol = currency; + this.format = format; + this.isVaultEconomy = isVaultEconomy; + } + + public ZEconomy(ConfigurationSection section, String name) { + this.name = name; + this.displayName = section.getString("displayName", "default-money"); + this.symbol = section.getString("symbol", "$"); + this.format = section.getString("format", "%price%$"); + this.isVaultEconomy = section.getBoolean("vault", false); + } + + @Override + public String toString() { + return "ZEconomy{" + + "name='" + name + '\'' + + ", displayName='" + displayName + '\'' + + ", symbol='" + symbol + '\'' + + ", format='" + format + '\'' + + ", isVaultEconomy=" + isVaultEconomy + + '}'; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDisplayName() { + return displayName; + } + + @Override + public String getSymbol() { + return this.symbol; + } + + @Override + public String getFormat() { + return this.format; + } + + @Override + public boolean isVaultEconomy() { + return this.isVaultEconomy; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/listener/PlayerListener.java b/Essentials/src/main/java/fr/maxlego08/essentials/listener/PlayerListener.java new file mode 100644 index 00000000..a12b2923 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/listener/PlayerListener.java @@ -0,0 +1,65 @@ +package fr.maxlego08.essentials.listener; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; + +public class PlayerListener implements Listener { + + private final EssentialsPlugin plugin; + + public PlayerListener(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + private User getUser(Entity player) { + return this.plugin.getStorageManager().getStorage().getUser(player.getUniqueId()); + } + + private void cancelGoldEvent(Player player, Cancellable event) { + User user = getUser(player); + if (user.getOption(Option.GOD)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onDamage(EntityDamageEvent event) { + if (event.getEntity() instanceof Player player) { + cancelGoldEvent(player, event); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onFood(FoodLevelChangeEvent event) { + if (event.getEntity() instanceof Player player) { + cancelGoldEvent(player, event); + } + } + + @EventHandler + public void onClick(InventoryClickEvent event) { + User user = getUser(event.getWhoClicked()); + if (user.getOption(Option.INVSEE) && !user.hasPermission(Permission.ESSENTIALS_INVSEE_INTERACT)) { + event.setCancelled(true); + } + } + + @EventHandler + public void onClose(InventoryCloseEvent event) { + User user = getUser(event.getPlayer()); + if (user != null && user.getOption(Option.INVSEE)) user.setOption(Option.INVSEE, false); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/messages/MessageLoader.java b/Essentials/src/main/java/fr/maxlego08/essentials/messages/MessageLoader.java new file mode 100644 index 00000000..cd4232cf --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/messages/MessageLoader.java @@ -0,0 +1,92 @@ +package fr.maxlego08.essentials.messages; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.ConfigurationFile; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.messages.MessageType; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +public class MessageLoader implements ConfigurationFile { + + private final ZEssentialsPlugin plugin; + private final List loadedMessages = new ArrayList<>(); + + public MessageLoader(ZEssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void load() { + + File file = new File(plugin.getDataFolder(), "messages.yml"); + this.copyFile(file); + + this.loadMessages(YamlConfiguration.loadConfiguration(file)); + + if (this.loadedMessages.size() != Message.values().length) { + this.plugin.getLogger().log(Level.SEVERE, "Messages were not loaded correctly."); + for (Message value : Message.values()) { + if (!this.loadedMessages.contains(value)) { + this.plugin.getLogger().log(Level.SEVERE, value + " was not loaded."); + } + } + } + } + + private void copyFile(File file) { + if (!file.exists()) { + + // ToDo, detect the server country + + this.plugin.saveResource("messages/messages.yml", "messages.yml", false); + } + } + + private void loadMessages(YamlConfiguration configuration) { + + this.loadedMessages.clear(); + + for (String key : configuration.getKeys(false)) { + + String messageKey = key.replace("-", "_").toUpperCase(); + try { + + Message message = Message.valueOf(messageKey); + if (configuration.contains(key + ".type")) { + + MessageType messageType = MessageType.valueOf(configuration.getString(key + ".type", "TCHAT").toUpperCase()); + message.setMessageType(messageType); + switch (messageType) { + case ACTION -> { + message.setMessage(configuration.getString(key + ".message")); + } + case CENTER, TCHAT -> { + List messages = configuration.getStringList(key + ".messages"); + if (messages.isEmpty()) { + message.setMessage(configuration.getString(key + "message")); + } else message.setMessages(messages); + } + } + + } else { + message.setMessageType(MessageType.TCHAT); + List messages = configuration.getStringList(key); + if (messages.isEmpty()) { + message.setMessage(configuration.getString(key)); + } else message.setMessages(messages); + } + + this.loadedMessages.add(message); + + } catch (Exception exception) { + exception.printStackTrace(); + this.plugin.getLogger().log(Level.SEVERE, messageKey + " key was not found !"); + } + } + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModule.java b/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModule.java new file mode 100644 index 00000000..e63e9a0d --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModule.java @@ -0,0 +1,55 @@ +package fr.maxlego08.essentials.module; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.modules.Module; +import fr.maxlego08.essentials.zutils.utils.YamlLoader; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; + +public abstract class ZModule extends YamlLoader implements Module { + + protected final ZEssentialsPlugin plugin; + protected final String name; + protected boolean isEnable = false; + + public ZModule(ZEssentialsPlugin plugin, String name) { + this.plugin = plugin; + this.name = name; + } + + @Override + public void loadConfiguration() { + + File folfer = getFolder(); + if (!folfer.exists()) { + folfer.mkdirs(); + this.plugin.saveResource("modules/" + name + "/config.yml", false); + } + + YamlConfiguration configuration = getConfiguration(); + this.loadYamlConfirmation(configuration); + + this.isEnable = configuration.getBoolean("enable", true); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public File getFolder() { + return new File(this.plugin.getDataFolder(), "modules/" + name); + } + + @Override + public YamlConfiguration getConfiguration() { + return YamlConfiguration.loadConfiguration(new File(getFolder(), "config.yml")); + } + + @Override + public boolean isEnable() { + return this.isEnable; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModuleManager.java b/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModuleManager.java new file mode 100644 index 00000000..7f3cd78c --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/module/ZModuleManager.java @@ -0,0 +1,48 @@ +package fr.maxlego08.essentials.module; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.modules.Module; +import fr.maxlego08.essentials.api.modules.ModuleManager; +import fr.maxlego08.essentials.economy.EconomyManager; +import fr.maxlego08.essentials.module.modules.TeleportationModule; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class ZModuleManager implements ModuleManager { + + private final ZEssentialsPlugin plugin; + private final Map, Module> modules = new HashMap<>(); + + public ZModuleManager(ZEssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public File getFolder() { + return new File(this.plugin.getDataFolder(), "modules"); + } + + @Override + public void loadModules() { + + File folder = getFolder(); + if (!folder.exists()) folder.mkdirs(); + + this.modules.put(TeleportationModule.class, new TeleportationModule(this.plugin)); + this.modules.put(EconomyManager.class, plugin.getEconomyProvider()); + + this.loadConfigurations(); + } + + @Override + public void loadConfigurations() { + this.modules.values().forEach(Module::loadConfiguration); + } + + @Override + public T getModule(Class module) { + return (T) this.modules.get(module); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java b/Essentials/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java new file mode 100644 index 00000000..80b46349 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java @@ -0,0 +1,80 @@ +package fr.maxlego08.essentials.module.modules; + +import fr.maxlego08.essentials.ZEssentialsPlugin; +import fr.maxlego08.essentials.api.modules.Loadable; +import fr.maxlego08.essentials.module.ZModule; +import fr.maxlego08.menu.api.InventoryManager; +import fr.maxlego08.menu.exceptions.InventoryException; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class TeleportationModule extends ZModule { + + private final List teleportDelayPermissions = new ArrayList<>(); + private boolean teleportSafety; + private boolean teleportToCenter; + private int teleportDelay; + private int teleportTpaExpire; + private boolean teleportDelayBypass; + private boolean openConfirmInventoryForTpa; + + public TeleportationModule(ZEssentialsPlugin plugin) { + super(plugin, "teleportation"); + } + + @Override + public void loadConfiguration() { + super.loadConfiguration(); + + InventoryManager inventoryManager = this.plugin.getInventoryManager(); + + try { + inventoryManager.loadInventoryOrSaveResource(this.plugin, "modules/teleportation/confirm_request_inventory.yml"); + } catch (InventoryException exception) { + exception.printStackTrace(); + } + } + + public boolean isTeleportSafety() { + return teleportSafety; + } + + public boolean isTeleportToCenter() { + return teleportToCenter; + } + + public int getTeleportDelay() { + return teleportDelay; + } + + public boolean isTeleportDelayBypass() { + return teleportDelayBypass; + } + + public List getTeleportDelayPermissions() { + return teleportDelayPermissions; + } + + public int getTeleportTpaExpire() { + return teleportTpaExpire; + } + + public boolean isOpenConfirmInventoryForTpa() { + return openConfirmInventoryForTpa; + } + + public int getTeleportationDelay(Player player) { + return this.teleportDelayPermissions.stream().filter(teleportPermission -> player.hasPermission(teleportPermission.permission)).mapToInt(TeleportPermission::delay).min().orElse(this.teleportDelay); + } + + public void openConfirmInventory(Player player) { + this.plugin.getInventoryManager().openInventory(player, this.plugin, "confirm_request_inventory"); + } + + public record TeleportPermission(String permission, int delay) implements Loadable { + + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/AutoPlaceholder.java b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/AutoPlaceholder.java new file mode 100644 index 00000000..cc6f0c4b --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/AutoPlaceholder.java @@ -0,0 +1,53 @@ +package fr.maxlego08.essentials.placeholders; + +import fr.maxlego08.essentials.api.functionnals.ReturnBiConsumer; +import fr.maxlego08.essentials.api.functionnals.ReturnConsumer; +import org.bukkit.entity.Player; + +public class AutoPlaceholder { + + private final String startWith; + private final ReturnBiConsumer biConsumer; + private final ReturnConsumer consumer; + + public AutoPlaceholder(String startWith, ReturnBiConsumer biConsumer) { + super(); + this.startWith = startWith; + this.biConsumer = biConsumer; + this.consumer = null; + } + + public AutoPlaceholder(String startWith, ReturnConsumer consumer) { + this.startWith = startWith; + this.biConsumer = null; + this.consumer = consumer; + } + + /** + * @return the startWith + */ + public String getStartWith() { + return startWith; + } + + /** + * @return the biConsumer + */ + public ReturnBiConsumer getBiConsumer() { + return biConsumer; + } + + public ReturnConsumer getConsumer() { + return this.consumer; + } + + public String accept(Player player, String value) { + if (this.consumer != null) return this.consumer.accept(player); + if (this.biConsumer != null) return this.biConsumer.accept(player, value); + return "Error with consumer !"; + } + + public boolean startsWith(String string) { + return this.consumer != null ? this.startWith.equalsIgnoreCase(string) : string.startsWith(this.startWith); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/DistantPlaceholder.java b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/DistantPlaceholder.java new file mode 100644 index 00000000..e8aa39ea --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/DistantPlaceholder.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.placeholders; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.entity.Player; + +public class DistantPlaceholder extends PlaceholderExpansion { + + private final EssentialsPlugin plugin; + private final Placeholder placeholder; + + public DistantPlaceholder(EssentialsPlugin plugin, Placeholder placeholder) { + this.plugin = plugin; + this.placeholder = placeholder; + } + + @Override + public String getAuthor() { + return this.plugin.getDescription().getAuthors().get(0); + } + + @Override + public String getIdentifier() { + return this.placeholder.getPrefix(); + } + + @Override + public String getVersion() { + return this.plugin.getDescription().getVersion(); + } + + @Override + public boolean persist() { + return true; + } + + @Override + public String onPlaceholderRequest(Player player, String params) { + return this.placeholder.onRequest(player, params); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/LocalPlaceholder.java b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/LocalPlaceholder.java new file mode 100644 index 00000000..a4647ebb --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/placeholders/LocalPlaceholder.java @@ -0,0 +1,86 @@ +package fr.maxlego08.essentials.placeholders; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.functionnals.ReturnBiConsumer; +import fr.maxlego08.essentials.api.functionnals.ReturnConsumer; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class LocalPlaceholder implements Placeholder { + + /** + * static Singleton instance. + */ + private static volatile LocalPlaceholder instance; + private final Pattern pattern = Pattern.compile("[%]([^%]+)[%]"); + private final List autoPlaceholders = new ArrayList<>(); + private final EssentialsPlugin plugin; + private final String prefix = "zessentials"; + + public LocalPlaceholder(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + public String setPlaceholders(Player player, String placeholder) { + + if (placeholder == null || !placeholder.contains("%")) { + return placeholder; + } + + final String realPrefix = this.prefix + "_"; + + Matcher matcher = this.pattern.matcher(placeholder); + while (matcher.find()) { + String stringPlaceholder = matcher.group(0); + String regex = matcher.group(1).replace(realPrefix, ""); + String replace = this.onRequest(player, regex); + if (replace != null) { + placeholder = placeholder.replace(stringPlaceholder, replace); + } + } + + return placeholder; + } + + public List setPlaceholders(Player player, List lore) { + return lore == null ? null : lore.stream().map(e -> e = setPlaceholders(player, e)).collect(Collectors.toList()); + } + + @Override + public String onRequest(Player player, String string) { + + Optional optional = this.autoPlaceholders.stream().filter(autoPlaceholder -> autoPlaceholder.startsWith(string)).findFirst(); + if (optional.isPresent()) { + + AutoPlaceholder autoPlaceholder = optional.get(); + String value = string.replace(autoPlaceholder.getStartWith(), ""); + return autoPlaceholder.accept(player, value); + } + + return null; + } + + public void register(String startWith, ReturnBiConsumer biConsumer) { + this.autoPlaceholders.add(new AutoPlaceholder(startWith, biConsumer)); + } + + public void register(String startWith, ReturnConsumer biConsumer) { + this.autoPlaceholders.add(new AutoPlaceholder(startWith, biConsumer)); + } + + public String getPrefix() { + return prefix; + } + + + public EssentialsPlugin getPlugin() { + return plugin; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/ZStorageManager.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/ZStorageManager.java new file mode 100644 index 00000000..b550b15c --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/ZStorageManager.java @@ -0,0 +1,65 @@ +package fr.maxlego08.essentials.storage; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.storage.StorageManager; +import fr.maxlego08.essentials.api.storage.StorageType; +import fr.maxlego08.essentials.storage.storages.JsonStorage; +import fr.maxlego08.essentials.storage.storages.SqlStorage; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.UUID; + +public class ZStorageManager implements StorageManager { + + private final IStorage iStorage; + private final EssentialsPlugin plugin; + + public ZStorageManager(EssentialsPlugin plugin) { + this.plugin = plugin; + StorageType storageType = plugin.getConfiguration().getStorageType(); + if (storageType == StorageType.MYSQL) { + this.iStorage = new SqlStorage(plugin); + } else { + this.iStorage = new JsonStorage(plugin); + } + } + + @Override + public void onEnable() { + this.iStorage.onEnable(); + + Bukkit.getOnlinePlayers().forEach(player -> this.iStorage.createOrLoad(player.getUniqueId(), player.getName())); + } + + @Override + public void onDisable() { + this.iStorage.onDisable(); + } + + @Override + public IStorage getStorage() { + return this.iStorage; + } + + @Override + public StorageType getType() { + return this.plugin.getStorageManager().getType(); + } + + @EventHandler + public void onLogin(AsyncPlayerPreLoginEvent event) { + UUID playerUuid = event.getUniqueId(); + String playerName = event.getPlayerProfile().getName(); + + this.iStorage.createOrLoad(playerUuid, playerName); + } + + @EventHandler + public void onDisconnect(PlayerQuitEvent event) { + this.iStorage.onPlayerQuit(event.getPlayer().getUniqueId()); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/adapter/UserTypeAdapter.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/adapter/UserTypeAdapter.java new file mode 100644 index 00000000..91a2c48c --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/adapter/UserTypeAdapter.java @@ -0,0 +1,113 @@ +package fr.maxlego08.essentials.storage.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.database.dto.CooldownDTO; +import fr.maxlego08.essentials.api.database.dto.OptionDTO; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.user.ZUser; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +public class UserTypeAdapter extends TypeAdapter { + + private final EssentialsPlugin plugin; + + public UserTypeAdapter(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void write(JsonWriter out, User value) throws IOException { + out.beginObject(); + out.name("uniqueId").value(value.getUniqueId().toString()); + out.name("name").value(value.getName()); + + out.name("options").beginObject(); + for (Map.Entry entry : value.getOptions().entrySet()) { + if (entry.getValue()) { + out.name(entry.getKey().name()).value(entry.getValue()); + } + } + out.endObject(); + + out.name("cooldowns").beginObject(); + for (Map.Entry entry : value.getCooldowns().entrySet()) { + out.name(entry.getKey()).value(entry.getValue()); + } + out.endObject(); + + out.name("balances").beginObject(); + for (Map.Entry entry : value.getBalances().entrySet()) { + out.name(entry.getKey()).value(entry.getValue()); + } + out.endObject(); + + + out.endObject(); + } + + @Override + public User read(JsonReader in) throws IOException { + String name = null; + UUID uniqueId = null; // Temporary storage for the UUID + Map options = new HashMap<>(); + Map cooldowns = new HashMap<>(); + Map balances = new HashMap<>(); + + in.beginObject(); + while (in.hasNext()) { + switch (in.nextName()) { + case "uniqueId" -> uniqueId = UUID.fromString(in.nextString()); + case "name" -> name = in.nextString(); + case "options" -> { + in.beginObject(); + while (in.hasNext()) { + options.put(Option.valueOf(in.nextName()), in.nextBoolean()); + } + in.endObject(); + } + case "cooldowns" -> { + in.beginObject(); + while (in.hasNext()) { + cooldowns.put(in.nextName(), in.nextLong()); + } + in.endObject(); + } + case "balances" -> { + in.beginObject(); + while (in.hasNext()) { + String key = in.nextName(); + BigDecimal value = new BigDecimal(in.nextString()); + balances.put(key, value); + } + in.endObject(); + } + } + } + in.endObject(); + + // Ensure that uniqueId is not null before creating a ZUser + if (uniqueId == null) { + throw new IOException("UniqueId is missing from the JSON input."); + } + User user = new ZUser(this.plugin, uniqueId); // Create the ZUser here + + // Now, set the other properties + user.setName(name); + user.setOptions(options.entrySet().stream().map(e -> new OptionDTO(e.getKey(), e.getValue())).collect(Collectors.toList())); + user.setCooldowns(cooldowns.entrySet().stream().map(e -> new CooldownDTO(e.getKey(), e.getValue())).collect(Collectors.toList())); + balances.forEach(user::setBalance); + + return user; + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repositories.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repositories.java new file mode 100644 index 00000000..6844c6f2 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repositories.java @@ -0,0 +1,28 @@ +package fr.maxlego08.essentials.storage.requests; + +import java.util.HashMap; +import java.util.Map; + +public class Repositories { + + private final SqlConnection connection; + + private final Map, Repository> tables = new HashMap<>(); + + public Repositories(SqlConnection connection) { + this.connection = connection; + } + + public void register(Class tableClass) { + try { + Repository repository = tableClass.getConstructor(SqlConnection.class).newInstance(connection); + this.tables.put(tableClass, repository); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public T getTable(Class module) { + return (T) this.tables.get(module); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repository.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repository.java new file mode 100644 index 00000000..abcdbf7a --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/Repository.java @@ -0,0 +1,58 @@ +package fr.maxlego08.essentials.storage.requests; + +import fr.maxlego08.essentials.api.database.Schema; +import fr.maxlego08.essentials.database.SchemaBuilder; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public abstract class Repository { + + private final SqlConnection connection; + private final String tableName; + + public Repository(SqlConnection connection, String tableName) { + this.connection = connection; + this.tableName = tableName; + } + + protected Connection getConnection() { + return this.connection.getConnection(); + } + + public String getTableName() { + return this.connection.getDatabaseConfiguration().prefix() + tableName; + } + + protected void upsert(Consumer consumer) { + try { + SchemaBuilder.upsert(getTableName(), consumer).execute(this.connection.getConnection(), this.connection.getDatabaseConfiguration(), this.connection.getPlugin().getLogger()); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } + + protected List select(Class clazz, Consumer consumer) { + Schema schema = SchemaBuilder.select(getTableName()); + consumer.accept(schema); + try { + return schema.executeSelect(clazz, this.connection.getConnection(), this.connection.getDatabaseConfiguration(), this.connection.getPlugin().getLogger()); + } catch (Exception exception) { + exception.printStackTrace(); + } + return new ArrayList<>(); + } + + protected void delete(Consumer consumer) { + Schema schema = SchemaBuilder.delete(getTableName()); + consumer.accept(schema); + try { + schema.execute(this.connection.getConnection(), this.connection.getDatabaseConfiguration(), this.connection.getPlugin().getLogger()); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/SqlConnection.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/SqlConnection.java new file mode 100644 index 00000000..1fc28ca0 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/SqlConnection.java @@ -0,0 +1,99 @@ +package fr.maxlego08.essentials.storage.requests; + + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class SqlConnection { + + private final EssentialsPlugin plugin; + private final DatabaseConfiguration databaseConfiguration; + private Connection connection; + + public SqlConnection(EssentialsPlugin plugin) { + this.plugin = plugin; + this.databaseConfiguration = plugin.getConfiguration().getDatabaseConfiguration(); + } + + public EssentialsPlugin getPlugin() { + return plugin; + } + + public DatabaseConfiguration getDatabaseConfiguration() { + return databaseConfiguration; + } + + public boolean isValid() { + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException exception) { + exception.printStackTrace(); + return false; + } + + if (!isConnected(connection)) { + try { + Properties properties = new Properties(); + properties.setProperty("useSSL", "false"); + properties.setProperty("user", databaseConfiguration.user()); + properties.setProperty("password", databaseConfiguration.password()); + Connection temp_connection = DriverManager.getConnection("jdbc:mysql://" + databaseConfiguration.host() + ":" + databaseConfiguration.port() + "/" + databaseConfiguration.database(), properties); + + if (isConnected(temp_connection)) { + temp_connection.close(); + } + } catch (SQLException exception) { + exception.printStackTrace(); + return false; + } + } + + return true; + } + + private boolean isConnected(Connection connection) { + if (connection == null) { + return false; + } + + try { + return connection.isValid(1); + } catch (SQLException exception) { + return false; + } + } + + public void disconnect() { + if (isConnected(connection)) { + try { + connection.close(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } + } + + public void connect() { + if (!isConnected(connection)) { + try { + Properties properties = new Properties(); + properties.setProperty("useSSL", "false"); + properties.setProperty("user", databaseConfiguration.user()); + properties.setProperty("password", databaseConfiguration.password()); + connection = DriverManager.getConnection("jdbc:mysql://" + databaseConfiguration.host() + ":" + databaseConfiguration.port() + "/" + databaseConfiguration.database(), properties); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } + } + + public Connection getConnection() { + connect(); + return connection; + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserCooldownsRepository.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserCooldownsRepository.java new file mode 100644 index 00000000..b209dce0 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserCooldownsRepository.java @@ -0,0 +1,31 @@ +package fr.maxlego08.essentials.storage.requests.repositeries; + +import fr.maxlego08.essentials.api.database.dto.CooldownDTO; +import fr.maxlego08.essentials.storage.requests.Repository; +import fr.maxlego08.essentials.storage.requests.SqlConnection; + +import java.util.List; +import java.util.UUID; + +public class UserCooldownsRepository extends Repository { + + public UserCooldownsRepository(SqlConnection connection) { + super(connection, "player_cooldowns"); + } + + public void upsert(UUID uuid, String cooldownName, long cooldownValue) { + upsert(table -> { + table.uuid("unique_id", uuid); + table.string("cooldown_name", cooldownName); + table.bigInt("cooldown_value", cooldownValue); + }); + } + + public List selectCooldowns(UUID uuid) { + return select(CooldownDTO.class, schema -> schema.where("unique_id", uuid.toString())); + } + + public void deleteExpiredCooldowns() { + delete(table -> table.where("cooldown_value", "<", System.currentTimeMillis())); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserOptionRepository.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserOptionRepository.java new file mode 100644 index 00000000..284cfedc --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserOptionRepository.java @@ -0,0 +1,29 @@ +package fr.maxlego08.essentials.storage.requests.repositeries; + +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.database.dto.OptionDTO; +import fr.maxlego08.essentials.storage.requests.Repository; +import fr.maxlego08.essentials.storage.requests.SqlConnection; + +import java.util.List; +import java.util.UUID; + +public class UserOptionRepository extends Repository { + + public UserOptionRepository(SqlConnection connection) { + super(connection, "player_options"); + } + + public void upsert(UUID uuid, Option option, boolean optionValue) { + upsert(table -> { + table.uuid("unique_id", uuid); + table.string("option_name", option.name()); + table.bool("option_value", optionValue); + }); + } + + + public List selectOptions(UUID uuid) { + return select(OptionDTO.class, table -> table.where("unique_id", uuid.toString())); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserRepository.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserRepository.java new file mode 100644 index 00000000..02e8583e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/requests/repositeries/UserRepository.java @@ -0,0 +1,21 @@ +package fr.maxlego08.essentials.storage.requests.repositeries; + +import fr.maxlego08.essentials.storage.requests.Repository; +import fr.maxlego08.essentials.storage.requests.SqlConnection; + +import java.util.UUID; + +public class UserRepository extends Repository { + + public UserRepository(SqlConnection connection) { + super(connection, "players"); + } + + public void upsert(UUID uuid, String name) { + upsert(table -> { + table.uuid("unique_id", uuid); + table.string("name", name); + }); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/JsonStorage.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/JsonStorage.java new file mode 100644 index 00000000..3b1f0800 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/JsonStorage.java @@ -0,0 +1,127 @@ +package fr.maxlego08.essentials.storage.storages; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.event.UserEvent; +import fr.maxlego08.essentials.api.event.events.UserFirstJoinEvent; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.storage.Persist; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.user.ZUser; +import org.bukkit.Bukkit; + +import java.io.File; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class JsonStorage implements IStorage { + + private final EssentialsPlugin plugin; + private final Map users = new HashMap<>(); + + public JsonStorage(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + public File getFolder() { + return new File(this.plugin.getDataFolder(), "users"); + } + + private void createFolder() { + File folder = getFolder(); + if (!folder.exists()) { + folder.mkdir(); + } + } + + @Override + public void onEnable() { + this.createFolder(); + } + + @Override + public void onDisable() { + this.createFolder(); + Bukkit.getOnlinePlayers().forEach(player -> { + UUID uniqueId = player.getUniqueId(); + User user = getUser(uniqueId); + Persist persist = this.plugin.getPersist(); + persist.save(user, getUserFile(uniqueId)); + }); + } + + private File getUserFile(UUID uniqueId) { + return new File(getFolder(), uniqueId + ".json"); + } + + @Override + public User createOrLoad(UUID uniqueId, String playerName) { + + this.createFolder(); + + File file = getUserFile(uniqueId); + Persist persist = this.plugin.getPersist(); + User user = persist.load(User.class, file); + + // If user is null, we need to create a new user + if (user == null) { + + user = new ZUser(plugin, uniqueId); + user.setName(playerName); + + this.plugin.getLogger().info(String.format("%s (%s) is a new player !", playerName, uniqueId)); + UserEvent event = new UserFirstJoinEvent(user); + this.plugin.getScheduler().runNextTick(wrappedTask -> event.callEvent()); + + persist.save(user, file); + } + + this.users.put(uniqueId, user); + return user; + } + + private void saveFileAsync(UUID uniqueId) { + User user = getUser(uniqueId); + if (user == null) return; + this.plugin.getScheduler().runAsync(wrappedTask -> { + Persist persist = this.plugin.getPersist(); + persist.save(user, getUserFile(uniqueId)); + }); + } + + @Override + public void onPlayerQuit(UUID uniqueId) { + this.saveFileAsync(uniqueId); + this.users.remove(uniqueId); + } + + @Override + public User getUser(UUID uniqueId) { + return this.users.get(uniqueId); + } + + @Override + public void updateOption(UUID uniqueId, Option option, boolean value) { + this.saveFileAsync(uniqueId); + } + + @Override + public void updateCooldown(UUID uniqueId, String key, long expiredAt) { + this.saveFileAsync(uniqueId); + } + + @Override + public void updateEconomy(UUID uniqueId, Economy economy, BigDecimal bigDecimal) { + this.saveFileAsync(uniqueId); + } + + @Override + public void updateUserMoney(UUID uniqueId, Consumer consumer) { + User loadUser = createOrLoad(uniqueId, "offline"); + consumer.accept(loadUser); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java b/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java new file mode 100644 index 00000000..3b9ce50e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java @@ -0,0 +1,109 @@ +package fr.maxlego08.essentials.storage.storages; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.storage.requests.Repositories; +import fr.maxlego08.essentials.storage.requests.SqlConnection; +import fr.maxlego08.essentials.storage.requests.repositeries.UserCooldownsRepository; +import fr.maxlego08.essentials.storage.requests.repositeries.UserOptionRepository; +import fr.maxlego08.essentials.storage.requests.repositeries.UserRepository; +import fr.maxlego08.essentials.user.ZUser; +import org.bukkit.Bukkit; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class SqlStorage implements IStorage { + + private final SqlConnection connection; + private final EssentialsPlugin plugin; + private final Map users = new HashMap<>(); + private final Repositories repositories; + + public SqlStorage(EssentialsPlugin plugin) { + this.plugin = plugin; + this.connection = new SqlConnection(plugin); + + if (!this.connection.isValid()) { + plugin.getLogger().severe("Unable to connect to database !"); + Bukkit.getPluginManager().disablePlugin(plugin); + } else { + plugin.getLogger().info("The database connection is valid ! (" + connection.getDatabaseConfiguration().host() + ")"); + } + + + this.repositories = new Repositories(this.connection); + this.repositories.register(UserRepository.class); + this.repositories.register(UserOptionRepository.class); + this.repositories.register(UserCooldownsRepository.class); + + plugin.getMigrationManager().execute(this.connection.getConnection(), this.connection.getDatabaseConfiguration(), this.plugin.getLogger()); + this.repositories.getTable(UserCooldownsRepository.class).deleteExpiredCooldowns(); + } + + @Override + public void onEnable() { + + this.connection.connect(); + + } + + @Override + public void onDisable() { + + this.connection.disconnect(); + } + + @Override + public User createOrLoad(UUID uniqueId, String playerName) { + + User user = new ZUser(this.plugin, uniqueId); + user.setName(playerName); + this.users.put(uniqueId, user); + + this.plugin.getScheduler().runAsync(wrappedTask -> { + this.repositories.getTable(UserRepository.class).upsert(uniqueId, playerName); + user.setOptions(this.repositories.getTable(UserOptionRepository.class).selectOptions(uniqueId)); + user.setCooldowns(this.repositories.getTable(UserCooldownsRepository.class).selectCooldowns(uniqueId)); + }); + + return user; + } + + @Override + public void onPlayerQuit(UUID uniqueId) { + this.users.remove(uniqueId); + } + + @Override + public User getUser(UUID uniqueId) { + return this.users.get(uniqueId); + } + + @Override + public void updateOption(UUID uniqueId, Option option, boolean value) { + this.plugin.getScheduler().runAsync(wrappedTask -> this.repositories.getTable(UserOptionRepository.class).upsert(uniqueId, option, value)); + } + + @Override + public void updateCooldown(UUID uniqueId, String key, long expiredAt) { + this.plugin.getScheduler().runAsync(wrappedTask -> this.repositories.getTable(UserCooldownsRepository.class).upsert(uniqueId, key, expiredAt)); + } + + @Override + public void updateEconomy(UUID uniqueId, Economy economy, BigDecimal bigDecimal) { + // ToDo + } + + @Override + public void updateUserMoney(UUID uniqueId, Consumer consumer) { + User fakeUser = new ZUser(this.plugin, uniqueId); + consumer.accept(fakeUser); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/user/UserPlaceholders.java b/Essentials/src/main/java/fr/maxlego08/essentials/user/UserPlaceholders.java new file mode 100644 index 00000000..b9c3eb25 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/user/UserPlaceholders.java @@ -0,0 +1,22 @@ +package fr.maxlego08.essentials.user; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import fr.maxlego08.essentials.api.placeholders.PlaceholderRegister; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.user.User; + +public class UserPlaceholders implements PlaceholderRegister { + + @Override + public void register(Placeholder placeholder, EssentialsPlugin plugin) { + + IStorage iStorage = plugin.getStorageManager().getStorage(); + + placeholder.register("user_target_player_name", player -> { + User user = iStorage.getUser(player.getUniqueId()); + return user.getTargetUser() != null ? user.getTargetUser().getName() : "no"; + }); + + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/user/ZTeleportRequest.java b/Essentials/src/main/java/fr/maxlego08/essentials/user/ZTeleportRequest.java new file mode 100644 index 00000000..a77b9aa4 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/user/ZTeleportRequest.java @@ -0,0 +1,122 @@ +package fr.maxlego08.essentials.user; + +import com.tcoded.folialib.impl.ServerImplementation; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.TeleportRequest; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.module.modules.TeleportationModule; +import fr.maxlego08.essentials.zutils.utils.ZUtils; +import org.bukkit.Location; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ZTeleportRequest extends ZUtils implements TeleportRequest { + + private final EssentialsPlugin plugin; + private final User toUser; + private final User fromUser; + private final long expiredAt; + private boolean isTeleport = false; + + public ZTeleportRequest(EssentialsPlugin plugin, User toUser, User fromUser, long expiredAt) { + this.plugin = plugin; + this.toUser = toUser; + this.fromUser = fromUser; + this.expiredAt = expiredAt; + } + + @Override + public User getToUser() { + return this.toUser; + } + + @Override + public User getFromUser() { + return this.fromUser; + } + + @Override + public long getExpiredAt() { + return this.expiredAt; + } + + @Override + public boolean isValid() { + return this.expiredAt > System.currentTimeMillis() && this.toUser.isOnline() && this.fromUser.isOnline() && !isTeleport; + } + + @Override + public void accept() { + + message(this.fromUser, Message.COMMAND_TPA_ACCEPT_SENDER, this.toUser); + message(this.toUser, Message.COMMAND_TPA_ACCEPT_RECEIVER, this.fromUser); + + TeleportationModule teleportationModule = this.plugin.getModuleManager().getModule(TeleportationModule.class); + + if (teleportationModule.isTeleportDelayBypass() && this.fromUser.hasPermission(Permission.ESSENTIALS_TELEPORT_BYPASS)) { + this.teleport(teleportationModule); + return; + } + + Location playerLocation = fromUser.getPlayer().getLocation(); + AtomicInteger atomicInteger = new AtomicInteger(teleportationModule.getTeleportationDelay(fromUser.getPlayer())); + + ServerImplementation serverImplementation = this.plugin.getScheduler(); + serverImplementation.runAtLocationTimer(this.toUser.getPlayer().getLocation(), wrappedTask -> { + + if (!same(playerLocation, fromUser.getPlayer().getLocation())) { + + message(this.fromUser, Message.TELEPORT_MOVE); + wrappedTask.cancel(); + this.fromUser.removeTeleportRequest(this.toUser); + return; + } + + int currentSecond = atomicInteger.getAndDecrement(); + + if (!this.toUser.isOnline() || !this.fromUser.isOnline()) { + wrappedTask.cancel(); + return; + } + + if (currentSecond == 0) { + + wrappedTask.cancel(); + this.teleport(teleportationModule); + } else { + + message(this.fromUser, Message.TELEPORT_MESSAGE, "%seconds%", currentSecond); + } + + }, 0, 1, TimeUnit.SECONDS); + } + + private void teleport(TeleportationModule teleportationModule) { + Location playerLocation = toUser.getPlayer().getLocation(); + Location location = fromUser.getPlayer().isFlying() ? playerLocation : teleportationModule.isTeleportSafety() ? toSafeLocation(playerLocation) : playerLocation; + + if (teleportationModule.isTeleportToCenter()) { + location = location.getBlock().getLocation().add(0.5, 0, 0.5); + location.setYaw(playerLocation.getYaw()); + location.setPitch(playerLocation.getPitch()); + } + + this.fromUser.teleport(location); + this.fromUser.removeTeleportRequest(this.toUser); + + message(this.fromUser, Message.TELEPORT_SUCCESS); + this.isTeleport = true; + } + + @Override + public void deny() { + + message(this.fromUser, Message.COMMAND_TP_DENY_RECEIVER, this.toUser); + message(this.toUser, Message.COMMAND_TP_DENY_SENDER, this.fromUser); + this.isTeleport = true; + + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/user/ZUser.java b/Essentials/src/main/java/fr/maxlego08/essentials/user/ZUser.java new file mode 100644 index 00000000..d20b79fc --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/user/ZUser.java @@ -0,0 +1,266 @@ +package fr.maxlego08.essentials.user; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.database.dto.CooldownDTO; +import fr.maxlego08.essentials.api.database.dto.OptionDTO; +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.storage.IStorage; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.TeleportRequest; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.module.modules.TeleportationModule; +import fr.maxlego08.essentials.zutils.utils.ZUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class ZUser extends ZUtils implements User { + + private final EssentialsPlugin plugin; + private final Map teleports = new HashMap<>(); + private final Map cooldowns = new HashMap<>(); + private final UUID uniqueId; + private final Map options = new HashMap<>(); + private final Map balances = new HashMap<>(); + private String name; + private TeleportRequest teleportRequest; + private User targetUser; + + public ZUser(EssentialsPlugin plugin, UUID uniqueId) { + this.plugin = plugin; + this.uniqueId = uniqueId; + } + + private IStorage getStorage() { + return this.plugin.getStorageManager().getStorage(); + } + + @Override + public UUID getUniqueId() { + return this.uniqueId; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public Player getPlayer() { + return Bukkit.getPlayer(this.name); + } + + @Override + public boolean isOnline() { + return Bukkit.getOfflinePlayer(this.uniqueId).isOnline(); + } + + @Override + public boolean isIgnore(UUID uniqueId) { + return false; + } + + @Override + public void sendTeleportRequest(User targetUser) { + + if (targetUser == null || !targetUser.isOnline()) { + message(this, Message.COMMAND_TPA_ERROR_SAME); + return; + } + + if (targetUser.getUniqueId().equals(this.uniqueId)) { + message(this, Message.COMMAND_TPA_ERROR_SAME); + return; + } + + if (targetUser.isIgnore(this.uniqueId)) { + message(this, Message.COMMAND_TELEPORT_IGNORE_PLAYER, targetUser); + return; + } + + this.teleports.entrySet().removeIf(next -> !next.getValue().isValid()); + + if (this.teleports.containsKey(targetUser.getUniqueId())) { + message(this, Message.COMMAND_TPA_ERROR, targetUser); + return; + } + + TeleportationModule teleportationModule = this.plugin.getModuleManager().getModule(TeleportationModule.class); + long expired = System.currentTimeMillis() + (teleportationModule.getTeleportTpaExpire() * 1000L); + TeleportRequest teleportRequest = new ZTeleportRequest(this.plugin, targetUser, this, expired); + targetUser.setTeleportRequest(teleportRequest); + this.teleports.put(targetUser.getUniqueId(), teleportRequest); + + message(this, Message.COMMAND_TPA_SENDER, targetUser); + message(targetUser, Message.COMMAND_TPA_RECEIVER, getPlayer()); + } + + @Override + public void cancelTeleportRequest(User targetUser) { + + if (!this.teleports.containsKey(targetUser.getUniqueId())) { + message(this, Message.COMMAND_TP_CANCEL_ERROR, targetUser); + return; + } + + this.teleports.remove(targetUser.getUniqueId()); + + if (targetUser.getTeleportRequest() != null && targetUser.getTeleportRequest().getFromUser() == this) { + targetUser.setTeleportRequest(null); + } + + message(this, Message.COMMAND_TP_CANCEL_SENDER, targetUser); + message(targetUser, Message.COMMAND_TP_CANCEL_RECEIVER, this); + } + + @Override + public Collection getTeleportRequests() { + return this.teleports.values(); + } + + @Override + public TeleportRequest getTeleportRequest() { + return teleportRequest; + } + + @Override + public void setTeleportRequest(TeleportRequest teleportRequest) { + this.teleportRequest = teleportRequest; + } + + @Override + public void removeTeleportRequest(User user) { + this.teleports.remove(user.getUniqueId()); + } + + @Override + public void teleport(Location location) { + this.plugin.getScheduler().teleportAsync(this.getPlayer(), location); + } + + @Override + public boolean hasPermission(Permission permission) { + return getPlayer().hasPermission(permission.asPermission()); + } + + @Override + public User getTargetUser() { + return targetUser; + } + + @Override + public void setTargetUser(User targetUser) { + this.targetUser = targetUser; + } + + @Override + public boolean getOption(Option option) { + return options.getOrDefault(option, false); + } + + @Override + public void setOption(Option option, boolean value) { + this.options.put(option, value); + this.getStorage().updateOption(this.uniqueId, option, value); + } + + @Override + public Map getOptions() { + return this.options; + } + + @Override + public void setOptions(List options) { + options.forEach((optionDTO) -> this.options.put(optionDTO.option_name(), optionDTO.option_value())); + } + + @Override + public Map getCooldowns() { + long currentTime = System.currentTimeMillis(); + cooldowns.entrySet().removeIf(entry -> entry.getValue() <= currentTime); + return this.cooldowns; + } + + @Override + public void setCooldowns(List cooldowns) { + long currentTime = System.currentTimeMillis(); + cooldowns.stream().filter(cooldownDTO -> cooldownDTO.cooldown_value() > currentTime).forEach(cooldownDTO -> this.cooldowns.put(cooldownDTO.cooldown_name(), cooldownDTO.cooldown_value())); + } + + @Override + public void setCooldown(String key, long expiredAt) { + this.cooldowns.put(key, expiredAt); + this.getStorage().updateCooldown(this.uniqueId, key, expiredAt); + } + + @Override + public boolean isCooldown(String key) { + return this.cooldowns.containsKey(key) && this.cooldowns.get(key) >= System.currentTimeMillis(); + } + + @Override + public long getCooldown(String key) { + return this.cooldowns.getOrDefault(key, 0L); + } + + @Override + public long getCooldownSeconds(String key) { + long cooldown = getCooldown(key); + return cooldown == 0 ? 0 : (cooldown - System.currentTimeMillis()) / 1000; + } + + @Override + public void addCooldown(String key, long seconds) { + setCooldown(key, System.currentTimeMillis() + (1000L * seconds)); + } + + @Override + public BigDecimal getBalance(Economy economy) { + return this.balances.getOrDefault(economy.getName(), BigDecimal.ZERO); + } + + @Override + public boolean has(Economy economy, BigDecimal bigDecimal) { + return bigDecimal.compareTo(getBalance(economy)) > 0; + } + + @Override + public void set(Economy economy, BigDecimal bigDecimal) { + this.balances.put(economy.getName(), bigDecimal); + getStorage().updateEconomy(this.uniqueId, economy, bigDecimal); + } + + @Override + public void withdraw(Economy economy, BigDecimal bigDecimal) { + set(economy, getBalance(economy).subtract(bigDecimal)); + } + + @Override + public void deposit(Economy economy, BigDecimal bigDecimal) { + set(economy, getBalance(economy).add(bigDecimal)); + } + + @Override + public Map getBalances() { + return this.balances; + } + + @Override + public void setBalance(String key, BigDecimal value) { + this.balances.put(key, value); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/ZPlugin.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/ZPlugin.java new file mode 100644 index 00000000..37467964 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/ZPlugin.java @@ -0,0 +1,101 @@ +package fr.maxlego08.essentials.zutils; + +import com.google.gson.Gson; +import com.tcoded.folialib.impl.ServerImplementation; +import fr.maxlego08.essentials.api.Configuration; +import fr.maxlego08.essentials.api.ConfigurationFile; +import fr.maxlego08.essentials.api.commands.CommandManager; +import fr.maxlego08.essentials.api.database.MigrationManager; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.modules.ModuleManager; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import fr.maxlego08.essentials.api.storage.Persist; +import fr.maxlego08.essentials.api.storage.StorageManager; +import fr.maxlego08.essentials.zutils.utils.commands.VCommand; +import org.bukkit.Bukkit; +import org.bukkit.event.Listener; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; + +public class ZPlugin extends JavaPlugin { + + protected final List configurationFiles = new ArrayList<>(); + protected CommandManager commandManager; + protected StorageManager storageManager; + protected ModuleManager moduleManager; + protected Placeholder placeholder; + protected Configuration configuration; + protected MigrationManager migrationManager; + protected EconomyProvider economyProvider; + protected Gson gson; + protected Persist persist; + protected ServerImplementation serverImplementation; + + protected void registerCommand(String command, VCommand vCommand, String... aliases) { + this.commandManager.registerCommand(this, command, vCommand, Arrays.asList(aliases)); + } + + protected void registerConfiguration(ConfigurationFile configurationFile) { + this.configurationFiles.add(configurationFile); + } + + protected void registerListener(Listener listener) { + Bukkit.getPluginManager().registerEvents(listener, this); + } + + public void saveResource(String resourcePath, String toPath, boolean replace) { + if (resourcePath != null && !resourcePath.equals("")) { + resourcePath = resourcePath.replace('\\', '/'); + InputStream in = this.getResource(resourcePath); + if (in == null) { + throw new IllegalArgumentException( + "The embedded resource '" + resourcePath + "' cannot be found in " + this.getFile()); + } else { + File outFile = new File(getDataFolder(), toPath); + int lastIndex = toPath.lastIndexOf(47); + File outDir = new File(getDataFolder(), toPath.substring(0, Math.max(lastIndex, 0))); + if (!outDir.exists()) { + outDir.mkdirs(); + } + + try { + if (outFile.exists() && !replace) { + getLogger().log(Level.WARNING, "Could not save " + outFile.getName() + " to " + outFile + + " because " + outFile.getName() + " already exists."); + } else { + OutputStream out = Files.newOutputStream(outFile.toPath()); + byte[] buf = new byte[1024]; + + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + out.close(); + in.close(); + } + } catch (IOException exception) { + getLogger().log(Level.SEVERE, "Could not save " + outFile.getName() + " to " + outFile, exception); + } + + } + } else throw new IllegalArgumentException("ResourcePath cannot be null or empty"); + } + + protected T getProvider(Class classz) { + RegisteredServiceProvider provider = getServer().getServicesManager().getRegistration(classz); + if (provider == null) return null; + return provider.getProvider(); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/Base64.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/Base64.java new file mode 100644 index 00000000..22f1570a --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/Base64.java @@ -0,0 +1,269 @@ +package fr.maxlego08.essentials.zutils.utils; + +public final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static private final boolean fDebug = false; + static final private byte [] base64Alphabet = new byte[BASELENGTH]; + static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i-'A'); + } + for (int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i<=25; i++) + lookUpBase64Alphabet[i] = (char)('A'+i); + + for (int i = 26, j = 0; i<=51; i++, j++) + lookUpBase64Alphabet[i] = (char)('a'+ j); + + for (int i = 52, j = 0; i<=61; i++, j++) + lookUpBase64Alphabet[i] = (char)('0' + j); + lookUpBase64Alphabet[62] = (char)'+'; + lookUpBase64Alphabet[63] = (char)'/'; + + } + + protected static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + protected static boolean isPad(char octect) { + return (octect == PAD); + } + + protected static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + protected static boolean isBase64(char octect) { + return (isWhiteSpace(octect) || isPad(octect) || isData(octect)); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + + if (binaryData == null) + return null; + + int lengthDataBits = binaryData.length*EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet*4]; + + byte k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + if (fDebug) { + System.out.println("number of triplets = " + numberTriplets ); + } + + for (int i=0; i>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + } + + if (!isData( (d1 = base64Data[dataIndex++]) ) || + !isData( (d2 = base64Data[dataIndex++]) )) { + return null;//if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData( (d3 ) ) || + !isData( (d4 ) )) {//Check if they are PAD characters + if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad] + if ((b2 & 0xf) != 0)//last 4 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 1 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + return tmp; + } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ d3 ]; + if ((b3 & 0x3 ) != 0)//last 2 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 2 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ); + tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + return tmp; + } else { + return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data + } + } else { //No PAD e.g 3cQl + b3 = base64Alphabet[ d3 ]; + b4 = base64Alphabet[ d4 ]; + decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + + } + + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + protected static int removeWhiteSpace(char[] data) { + if (data == null) + return 0; + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) + data[newSize++] = data[i]; + } + return newSize; + } +} \ No newline at end of file diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ComponentMessage.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ComponentMessage.java new file mode 100644 index 00000000..56b8ac20 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ComponentMessage.java @@ -0,0 +1,141 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.essentials.api.cache.SimpleCache; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; +import net.kyori.adventure.title.Title; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.meta.ItemMeta; + +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class ComponentMessage extends PlaceholderUtils { + + private final MiniMessage MINI_MESSAGE = MiniMessage.builder().tags(TagResolver.builder().resolver(StandardTags.defaults()).build()).build(); + private final Map COLORS_MAPPINGS = new HashMap<>(); + private final SimpleCache cache = new SimpleCache<>(); + + public ComponentMessage() { + this.COLORS_MAPPINGS.put("0", "black"); + this.COLORS_MAPPINGS.put("1", "dark_blue"); + this.COLORS_MAPPINGS.put("2", "dark_green"); + this.COLORS_MAPPINGS.put("3", "dark_aqua"); + this.COLORS_MAPPINGS.put("4", "dark_red"); + this.COLORS_MAPPINGS.put("5", "dark_purple"); + this.COLORS_MAPPINGS.put("6", "gold"); + this.COLORS_MAPPINGS.put("7", "gray"); + this.COLORS_MAPPINGS.put("8", "dark_gray"); + this.COLORS_MAPPINGS.put("9", "blue"); + this.COLORS_MAPPINGS.put("a", "green"); + this.COLORS_MAPPINGS.put("b", "aqua"); + this.COLORS_MAPPINGS.put("c", "red"); + this.COLORS_MAPPINGS.put("d", "light_purple"); + this.COLORS_MAPPINGS.put("e", "yellow"); + this.COLORS_MAPPINGS.put("f", "white"); + this.COLORS_MAPPINGS.put("k", "obfuscated"); + this.COLORS_MAPPINGS.put("l", "bold"); + this.COLORS_MAPPINGS.put("m", "strikethrough"); + this.COLORS_MAPPINGS.put("n", "underlined"); + this.COLORS_MAPPINGS.put("o", "italic"); + this.COLORS_MAPPINGS.put("r", "reset"); + } + + private TextDecoration.State getState(String text) { + return text.contains("&o") || text.contains("") || text.contains("") || text.contains("") ? TextDecoration.State.TRUE : TextDecoration.State.FALSE; + } + + private void updateDisplayName(ItemMeta itemMeta, String text) { + Component component = this.cache.get(text, () -> { + return this.MINI_MESSAGE.deserialize(colorMiniMessage(text)).decoration(TextDecoration.ITALIC, getState(text)); // We will force the italics in false, otherwise it will activate for no reason + }); + itemMeta.displayName(component); + } + + public void updateDisplayName(ItemMeta itemMeta, String text, Player player) { + updateDisplayName(itemMeta, papi(text, player)); + } + + public void updateDisplayName(ItemMeta itemMeta, String text, OfflinePlayer offlinePlayer) { + updateDisplayName(itemMeta, papi(text, offlinePlayer)); + } + + public void updateLore(ItemMeta itemMeta, List lore, Player player) { + update(itemMeta, lore, player); + } + + public void updateLore(ItemMeta itemMeta, List lore, OfflinePlayer offlinePlayer) { + update(itemMeta, lore, offlinePlayer); + } + + public void update(ItemMeta itemMeta, List lore, OfflinePlayer offlinePlayer) { + List components = lore.stream().map(text -> { + String result = papi(text, offlinePlayer); + return this.cache.get(result, () -> { + return this.MINI_MESSAGE.deserialize(colorMiniMessage(result)).decoration(TextDecoration.ITALIC, getState(result)); // We will force the italics in false, otherwise it will activate for no reason + }); + }).collect(Collectors.toList()); + itemMeta.lore(components); + } + + public Inventory createInventory(String inventoryName, int size, InventoryHolder inventoryHolder) { + Component component = this.cache.get(inventoryName, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(inventoryName))); + return Bukkit.createInventory(inventoryHolder, size, component); + } + + private String colorMiniMessage(String message) { + StringBuilder stringBuilder = new StringBuilder(); + + Pattern pattern = Pattern.compile("(?"); + } + matcher.appendTail(stringBuilder); + + String newMessage = stringBuilder.toString(); + + for (Entry entry : this.COLORS_MAPPINGS.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + newMessage = newMessage.replace("&" + key, "<" + value + ">"); + newMessage = newMessage.replace("§" + key, "<" + value + ">"); + newMessage = newMessage.replace("&" + key.toUpperCase(), "<" + value + ">"); + newMessage = newMessage.replace("§" + key.toUpperCase(), "<" + value + ">"); + } + + return newMessage; + } + + public void sendMessage(CommandSender sender, String message) { + Component component = this.cache.get(message, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(message))); + sender.sendMessage(component); + } + + public void sendActionBar(CommandSender sender, String message) { + Component component = this.cache.get(message, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(message))); + sender.sendActionBar(component); + } + + public void sendTitle(Player player, String title, String subtitle, long start, long duration, long end) { + Title.Times times = Title.Times.times(Duration.ofMillis(start), Duration.ofMillis(duration), Duration.ofMillis(end)); + Component componentTitle = this.cache.get(title, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(papi(title, player)))); + Component componentSubTitle = this.cache.get(subtitle, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(papi(subtitle, player)))); + player.showTitle(Title.title(componentTitle, componentSubTitle, times)); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/MessageUtils.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/MessageUtils.java new file mode 100644 index 00000000..5dacab0e --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/MessageUtils.java @@ -0,0 +1,135 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.essentials.api.messages.DefaultFontInfo; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.User; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public abstract class MessageUtils extends PlaceholderUtils { + + protected final ComponentMessage componentMessage = new ComponentMessage(); + + protected void message(User sender, Message message, Object... args) { + message(sender.getPlayer(), message, args); + } + + protected void message(CommandSender sender, Message message, Object... args) { + + if (sender instanceof Player player) { + + switch (message.getMessageType()) { + + case ACTION -> { + this.componentMessage.sendActionBar(sender, getMessage(message, args)); + } + case TCHAT -> { + sendTchatMessage(sender, message, args); + } + case TITLE -> { + // ToDo + } + case CENTER -> { + if (message.getMessages().size() > 0) { + message.getMessages().forEach(msg -> this.componentMessage.sendMessage(sender, getCenteredMessage(getMessage(msg, args)))); + } else { + this.componentMessage.sendMessage(sender, getCenteredMessage(getMessage(message, args))); + } + } + } + + } else { + sendTchatMessage(sender, message, args); + } + } + + private void sendTchatMessage(CommandSender sender, Message message, Object... args) { + if (message.getMessages().size() > 0) { + message.getMessages().forEach(msg -> this.componentMessage.sendMessage(sender, getMessage(msg, args))); + } else { + this.componentMessage.sendMessage(sender, Message.PREFIX.getMessage() + getMessage(message, args)); + } + } + + protected String getMessage(Message message, Object... args) { + return getMessage(message.getMessage(), args); + } + + protected String getMessage(String message, Object... args) { + + List modifiedArgs = new ArrayList<>(); + for (Object arg : args) handleArg(arg, modifiedArgs); + Object[] newArgs = modifiedArgs.toArray(); + + if (newArgs.length % 2 != 0) { + throw new IllegalArgumentException("Number of invalid arguments. Arguments must be in pairs."); + } + + for (int i = 0; i < newArgs.length; i += 2) { + if (newArgs[i] == null || newArgs[i + 1] == null) { + throw new IllegalArgumentException("Keys and replacement values must not be null."); + } + message = message.replace(newArgs[i].toString(), newArgs[i + 1].toString()); + } + return message; + } + + private void handleArg(Object arg, List modifiedArgs) { + if (arg instanceof Player player) { + addPlayerDetails(modifiedArgs, player.getName(), player.getDisplayName()); + } else if (arg instanceof User user) { + addPlayerDetails(modifiedArgs, user.getName(), user.getPlayer().getDisplayName()); + } else { + modifiedArgs.add(arg); + } + } + + private void addPlayerDetails(List modifiedArgs, String name, String displayName) { + modifiedArgs.add("%player%"); + modifiedArgs.add(name); + modifiedArgs.add("%displayName%"); + modifiedArgs.add(displayName); + } + + // ToDo, rework with componrent + protected String getCenteredMessage(String message) { + if (message == null || message.equals("")) return ""; + + int CENTER_PX = 154; + + message = ChatColor.translateAlternateColorCodes('&', message); + + int messagePxSize = 0; + boolean previousCode = false; + boolean isBold = false; + + for (char c : message.toCharArray()) { + if (c == "§".charAt(0)) { + previousCode = true; + } else if (previousCode) { + previousCode = false; + isBold = c == 'l' || c == 'L'; + } else { + DefaultFontInfo dFI = DefaultFontInfo.getDefaultFontInfo(c); + messagePxSize += isBold ? dFI.getBoldLength() : dFI.getLength(); + messagePxSize++; + } + } + + int halvedMessageSize = messagePxSize / 2; + int toCompensate = CENTER_PX - halvedMessageSize; + int spaceLength = DefaultFontInfo.SPACE.getLength() + 1; + int compensated = 0; + StringBuilder sb = new StringBuilder(); + while (compensated < toCompensate) { + sb.append(" "); + compensated += spaceLength; + } + return sb + message; + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/PlaceholderUtils.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/PlaceholderUtils.java new file mode 100644 index 00000000..f2493300 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/PlaceholderUtils.java @@ -0,0 +1,19 @@ +package fr.maxlego08.essentials.zutils.utils; + +import org.bukkit.OfflinePlayer; + +import java.util.List; +import java.util.stream.Collectors; + +public abstract class PlaceholderUtils { + + protected String papi(String placeHolder, OfflinePlayer player) { + return placeHolder; + } + + protected List papi(List placeHolders, OfflinePlayer player) { + if (player == null) return placeHolders; + return placeHolders.stream().map(placeHolder -> papi(placeHolder, player)).collect(Collectors.toList()); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/TimerBuilder.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/TimerBuilder.java new file mode 100644 index 00000000..40c71e57 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/TimerBuilder.java @@ -0,0 +1,39 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.essentials.api.messages.Message; + +public class TimerBuilder { + + private static String formatDuration(double totalSeconds) { + long days = (long) (totalSeconds / 86400L); + long hours = (long) ((totalSeconds % 86400L) / 3600L); + long minutes = (long) ((totalSeconds % 3600L) / 60L); + long seconds = (long) (totalSeconds % 60L); + + StringBuilder message = new StringBuilder(); + if (days > 0) { + message.append(days).append(" ").append(days <= 1 ? Message.FORMAT_DAY.getMessage() : Message.FORMAT_DAYS.getMessage()).append(" "); + } + if (hours > 0) { + message.append(hours).append(" ").append(hours <= 1 ? Message.FORMAT_HOUR.getMessage() : Message.FORMAT_HOURS.getMessage()).append(" "); + } + if (minutes > 0) { + message.append(minutes).append(" ").append(minutes <= 1 ? Message.FORMAT_MINUTE.getMessage() : Message.FORMAT_MINUTES.getMessage()).append(" "); + } + if (totalSeconds < 10) { + message.append(String.format("%.1f", totalSeconds)).append(" ").append(Message.FORMAT_SECONDS.getMessage()); + } else if (seconds > 0 || message.length() == 0) { + message.append(seconds).append(" ").append(seconds <= 1 ? Message.FORMAT_SECOND.getMessage() : Message.FORMAT_SECONDS.getMessage()); + } + + return format(message.toString().trim()); + } + + public static String getStringTime(double milliseconds) { + return formatDuration(milliseconds / 1000.0); + } + + private static String format(String message) { + return message.replaceAll(" 0 [a-zA-Z]+(\\s|$)", ""); + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/YamlLoader.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/YamlLoader.java new file mode 100644 index 00000000..14e69783 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/YamlLoader.java @@ -0,0 +1,85 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.essentials.api.modules.Loadable; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public abstract class YamlLoader { + + protected void loadYamlConfirmation(YamlConfiguration configuration) { + for (Field field : this.getClass().getDeclaredFields()) { + field.setAccessible(true); + + String configKey = field.getName().replaceAll("([A-Z])", "-$1").toLowerCase(); + + try { + if (field.getType().equals(boolean.class)) { + field.setBoolean(this, configuration.getBoolean(configKey)); + } else if (field.getType().equals(int.class)) { + field.setInt(this, configuration.getInt(configKey)); + } else if (field.getType().equals(String.class)) { + field.set(this, configuration.getString(configKey)); + } else if (field.getType().isEnum()) { + Class enumType = (Class) field.getType(); + field.set(this, Enum.valueOf(enumType, configuration.getString(configKey).toUpperCase())); + } else if (field.getType().equals(List.class)) { + + Type genericFieldType = field.getGenericType(); + if (genericFieldType instanceof ParameterizedType type) { + Class fieldArgClass = (Class) type.getActualTypeArguments()[0]; + + if (Loadable.class.isAssignableFrom(fieldArgClass)) { + field.set(this, loadObjects(fieldArgClass, configuration.getMapList(configKey))); + continue; + } + } + + field.set(this, configuration.getStringList(configKey)); + } else { + ConfigurationSection configurationSection = configuration.getConfigurationSection(configKey); + if (configurationSection == null) continue; + Map map = new HashMap<>(); + configurationSection.getKeys(false).forEach(key -> map.put(key, configurationSection.get(key))); + field.set(this, createInstanceFromMap(((Class) field.getGenericType()).getConstructors()[0], map)); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + + private List loadObjects(Class fieldArgClass, List> maps) { + Constructor constructor = fieldArgClass.getConstructors()[0]; + return maps.stream().map(map -> createInstanceFromMap(constructor, map)).collect(Collectors.toList()); + } + + private Object createInstanceFromMap(Constructor constructor, Map map) { + try { + Object[] arguments = new Object[constructor.getParameterCount()]; + java.lang.reflect.Parameter[] parameters = constructor.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Class paramType = parameters[i].getType(); + String paramName = parameters[i].getName(); + Object value = map.get(paramName); + if (paramType.isEnum()) { + @SuppressWarnings("unchecked") + Class enumType = (Class) paramType; + value = Enum.valueOf(enumType, (String) value); + } + arguments[i] = value; + } + return constructor.newInstance(arguments); + } catch (Exception exception) { + throw new RuntimeException("Failed to create instance from map", exception); + } + } +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ZUtils.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ZUtils.java new file mode 100644 index 00000000..118f049a --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/ZUtils.java @@ -0,0 +1,122 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.essentials.api.commands.Permission; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; +import java.util.Optional; + +public abstract class ZUtils extends MessageUtils { + + protected boolean hasPermission(CommandSender sender, Permission permission) { + return sender.hasPermission(permission.asPermission()); + } + + protected String name(String string) { + String name = string.replace("_", " ").toLowerCase(); + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + + protected Optional topLocation(Location location, int step, int y) { + + if (step > location.getWorld().getMaxHeight()) { + return Optional.empty(); + } + + location.setY(y); + if (!location.getBlock().getType().isSolid() && !location.getBlock().getRelative(BlockFace.UP).getType().isSolid() && location.getBlock().getRelative(BlockFace.DOWN).getType().isSolid()) { + return Optional.of(location); + } + return this.topLocation(location.getBlock().getRelative(BlockFace.UP).getLocation(), step + 1, y - 1); + + } + + protected boolean same(Location l1, Location l2) { + return (l1.getBlockX() == l2.getBlockX()) && (l1.getBlockY() == l2.getBlockY()) && (l1.getBlockZ() == l2.getBlockZ()) && l1.getWorld().getName().equals(l2.getWorld().getName()); + } + + protected Location toSafeLocation(Location location) { + + Location defaultLocation = location.clone(); + + if (isValid(defaultLocation)) { + return defaultLocation; + } + + location = findMeSafeLocation(defaultLocation, BlockFace.UP, 1); + + return location; + } + + protected Location findMeSafeLocation(Location location, BlockFace blockFace, int distance) { + + if (distance > location.getWorld().getMaxHeight() * 2) { + return null; + } + + Location location2 = relative(location, blockFace, distance); + if (isValid(location2)) { + return location2; + } + + return findMeSafeLocation(location2, blockFace.equals(BlockFace.UP) ? BlockFace.DOWN : BlockFace.UP, + distance + 1); + } + + protected boolean isValid(Location location) { + return !location.getBlock().getType().isSolid() + && !relative(location, BlockFace.UP).getBlock().getType().isSolid() + && relative(location, BlockFace.DOWN).getBlock().getType().isSolid(); + } + + protected Location relative(Location location, BlockFace face) { + return relative(location, face, 1.0d); + } + + protected Location relative(Location location, BlockFace face, double distance) { + + Location cloneLocation = location.clone(); + switch (face) { + case UP -> cloneLocation.setY(cloneLocation.getY() + distance); + case DOWN -> cloneLocation.setY(cloneLocation.getY() - distance); + default -> { + } + } + + return cloneLocation; + } + + protected int count(Inventory inventory, Material material) { + return Arrays.stream(inventory.getContents()).filter(itemStack -> itemStack != null && itemStack.isSimilar(new ItemStack(material))).mapToInt(ItemStack::getAmount).sum(); + } + + + protected void removeItems(org.bukkit.inventory.Inventory inventory, ItemStack removeItemStack, int amount) { + for (ItemStack itemStack : inventory.getContents()) { + if (itemStack != null && itemStack.isSimilar(removeItemStack) && amount > 0) { + int currentAmount = itemStack.getAmount() - amount; + amount -= itemStack.getAmount(); + if (currentAmount <= 0) { + inventory.removeItem(itemStack); + } else { + itemStack.setAmount(currentAmount); + } + } + } + } + + protected void give(Player player, ItemStack itemStack) { + /*if (!player.isOnline() || hasInventoryFull(player)) { + MailManager.getInstance().addItems(player, itemStack); + } else { + }*/ + player.getInventory().addItem(itemStack); + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/Arguments.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/Arguments.java new file mode 100644 index 00000000..07b98ca4 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/Arguments.java @@ -0,0 +1,254 @@ +package fr.maxlego08.essentials.zutils.utils.commands; + +import fr.maxlego08.essentials.zutils.utils.ZUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +/** + * This abstract class is designed to handle command arguments, allowing for easy retrieval + * and conversion of argument values into various data types. It supports operations such as + * parsing strings, booleans, integers, longs, doubles, and specific Bukkit types like + * {@link Player}, {@link OfflinePlayer}, {@link EntityType}, and {@link World}. + */ +public abstract class Arguments extends ZUtils { + + protected String[] args; + protected int parentCount = 0; + + /** + * Retrieves the argument at the specified index as a String. + * + * @param index The index of the argument to retrieve, adjusted by parent command count. + * @return The argument at the specified index as a String, or null if an exception occurs. + */ + protected String argAsString(int index) { + try { + return this.args[index + this.parentCount]; + } catch (Exception ignored) { + return null; + } + } + + /** + * Retrieves the argument at the specified index as a String, with a default value. + * + * @param index The index of the argument to retrieve, adjusted by parent command count. + * @param defaultValue The default value to return if the argument cannot be retrieved. + * @return The argument at the specified index as a String, or the default value if an exception occurs. + */ + protected String argAsString(int index, String defaultValue) { + try { + return this.args[index + this.parentCount]; + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts and returns the argument at the specified index as a boolean. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @return The argument converted to a boolean. + */ + protected boolean argAsBoolean(int index) { + return Boolean.valueOf(argAsString(index)); + } + + /** + * Converts and returns the argument at the specified index as a boolean, with a default value. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @param defaultValue The default value to return if the argument cannot be converted. + * @return The argument converted to a boolean, or the default value if an exception occurs. + */ + protected boolean argAsBoolean(int index, boolean defaultValue) { + try { + return Boolean.valueOf(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts and returns the argument at the specified index as an integer. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @return The argument converted to an integer. + */ + protected int argAsInteger(int index) { + return Integer.valueOf(argAsString(index)); + } + + /** + * Converts and returns the argument at the specified index as an integer, with a default value. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @param defaultValue The default value to return if the argument cannot be converted. + * @return The argument converted to an integer, or the default value if an exception occurs. + */ + protected int argAsInteger(int index, int defaultValue) { + try { + return Integer.valueOf(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts and returns the argument at the specified index as a long. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @return The argument converted to a long. + */ + protected long argAsLong(int index) { + return Long.valueOf(argAsString(index)); + } + + /** + * Converts and returns the argument at the specified index as a long, with a default value. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @param defaultValue The default value to return if the argument cannot be converted. + * @return The argument converted to a long, or the default value if an exception occurs. + */ + protected long argAsLong(int index, long defaultValue) { + try { + return Long.valueOf(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts and returns the argument at the specified index as a double, with a default value. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @param defaultValue The default value to return if the argument cannot be converted. + * @return The argument converted to a double, or the default value if an exception occurs. + */ + protected double argAsDouble(int index, double defaultValue) { + try { + return Double.valueOf(argAsString(index).replace(",", ".")); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts and returns the argument at the specified index as a double. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @return The argument converted to a double. + */ + protected double argAsDouble(int index) { + return Double.valueOf(argAsString(index).replace(",", ".")); + } + + /** + * Attempts to retrieve a {@link Player} based on the argument at the specified index. + * + * @param index The index of the argument to use for the player lookup, adjusted by parent command count. + * @return The player if found, otherwise null. + */ + protected Player argAsPlayer(int index) { + return Bukkit.getPlayer(argAsString(index)); + } + + /** + * Attempts to retrieve a {@link Player} based on the argument at the specified index, with a default value. + * + * @param index The index of the argument to use for the player lookup, adjusted by parent command count. + * @param defaultValue The default value to return if the player cannot be found. + * @return The player if found, otherwise the default value. + */ + protected Player argAsPlayer(int index, Player defaultValue) { + try { + return Bukkit.getPlayer(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Attempts to retrieve an {@link OfflinePlayer} based on the argument at the specified index. + * + * @param index The index of the argument to use for the offline player lookup, adjusted by parent command count. + * @return The offline player if found, otherwise null. + */ + protected OfflinePlayer argAsOfflinePlayer(int index) { + return Bukkit.getOfflinePlayer(argAsString(index)); + } + + /** + * Attempts to retrieve an {@link OfflinePlayer} based on the argument at the specified index, with a default value. + * + * @param index The index of the argument to use for the offline player lookup, adjusted by parent command count. + * @param defaultValue The default value to return if the offline player cannot be found. + * @return The offline player if found, otherwise the default value. + */ + protected OfflinePlayer argAsOfflinePlayer(int index, OfflinePlayer defaultValue) { + try { + return Bukkit.getOfflinePlayer(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Converts the argument at the specified index to an {@link EntityType}. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @return The {@link EntityType} corresponding to the argument. + */ + protected EntityType argAsEntityType(int index) { + return EntityType.valueOf(argAsString(index).toUpperCase()); + } + + /** + * Converts the argument at the specified index to an {@link EntityType}, with a default value. + * + * @param index The index of the argument to convert, adjusted by parent command count. + * @param defaultValue The default value to return if the entity type cannot be determined. + * @return The {@link EntityType} corresponding to the argument, or the default value if an exception occurs. + */ + protected EntityType argAsEntityType(int index, EntityType defaultValue) { + try { + return EntityType.valueOf(argAsString(index).toUpperCase()); + } catch (Exception ignored) { + return defaultValue; + } + } + + /** + * Attempts to retrieve a {@link World} based on the argument at the specified index. + * + * @param index The index of the argument to use for the world lookup, adjusted by parent command count. + * @return The world if found, otherwise null. + */ + protected World argAsWorld(int index) { + try { + return Bukkit.getWorld(argAsString(index)); + } catch (Exception ignored) { + return null; + } + } + + /** + * Attempts to retrieve a {@link World} based on the argument at the specified index, with a specified default world. + * + * @param index The index of the argument to use for the world lookup, adjusted by parent command count. + * @param defaultValue The default world to return if the specified world cannot be found. + * @return The world if found, otherwise the specified default world. + */ + protected World argAsWorld(int index, World defaultValue) { + try { + return Bukkit.getWorld(argAsString(index)); + } catch (Exception ignored) { + return defaultValue; + } + } + +} diff --git a/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/VCommand.java b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/VCommand.java new file mode 100644 index 00000000..af8d9382 --- /dev/null +++ b/Essentials/src/main/java/fr/maxlego08/essentials/zutils/utils/commands/VCommand.java @@ -0,0 +1,436 @@ +package fr.maxlego08.essentials.zutils.utils.commands; + +import fr.maxlego08.essentials.api.Configuration; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.commands.CommandResultType; +import fr.maxlego08.essentials.api.commands.EssentialsCommand; +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.commands.Tab; +import fr.maxlego08.essentials.api.commands.TabCompletion; +import fr.maxlego08.essentials.api.messages.Message; +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.zutils.utils.TimerBuilder; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public abstract class VCommand extends Arguments implements EssentialsCommand { + + protected final EssentialsPlugin plugin; + protected final List subVCommands = new ArrayList<>(); + private final List subCommands = new ArrayList<>(); + private final List requireArgs = new ArrayList<>(); + private final List optionalArgs = new ArrayList<>(); + private final Map tabCompletions = new HashMap<>(); + protected VCommand parent; + protected CommandSender sender; + protected Player player; + protected User user; + protected Configuration configuration; + private boolean consoleCanUse = true; + private boolean ignoreParent = false; + private boolean ignoreArgs = false; + private String permission; + private String syntax; + private String description; + private int argsMinLength; + private int argsMaxLength; + private boolean extendedArgs = false; + private CommandResultType tabCompleter = CommandResultType.DEFAULT; + + public VCommand(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + public boolean isExtendedArgs() { + return extendedArgs; + } + + public void setExtendedArgs(boolean extendedArgs) { + this.extendedArgs = extendedArgs; + } + + public EssentialsPlugin getPlugin() { + return plugin; + } + + public List getSubVCommands() { + return subVCommands; + } + + @Override + public List getSubCommands() { + return subCommands; + } + + public List getRequireArgs() { + return requireArgs; + } + + public List getOptionalArgs() { + return optionalArgs; + } + + public Map getTabCompletions() { + return tabCompletions; + } + + @Override + public VCommand getParent() { + return parent; + } + + public void setParent(VCommand parent) { + this.parent = parent; + } + + protected User getUser(Player player) { + return this.plugin.getStorageManager().getStorage().getUser(player.getUniqueId()); + } + + @Override + public String getPermission() { + return permission; + } + + public void setPermission(String permission) { + this.permission = permission; + } + + public void setPermission(Permission permission) { + this.permission = permission.asPermission(); + } + + @Override + public String getSyntax() { + return syntax == null ? syntax = generateDefaultSyntax("") : syntax; + } + + public void setSyntax(String syntax) { + this.syntax = syntax; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDescription(Message description) { + this.description = description.getMessage(); + } + + public int getArgsMinLength() { + return argsMinLength; + } + + public void setArgsMinLength(int argsMinLength) { + this.argsMinLength = argsMinLength; + } + + public int getArgsMaxLength() { + return argsMaxLength; + } + + public void setArgsMaxLength(int argsMaxLength) { + this.argsMaxLength = argsMaxLength; + } + + public CommandSender getSender() { + return sender; + } + + public void setSender(CommandSender sender) { + this.sender = sender; + } + + protected void setTabCompleter() { + this.tabCompleter = CommandResultType.SUCCESS; + } + + public Player getPlayer() { + return player; + } + + @Override + public boolean isIgnoreParent() { + return ignoreParent; + } + + public void setIgnoreParent(boolean ignoreParent) { + this.ignoreParent = ignoreParent; + } + + @Override + public boolean isIgnoreArgs() { + return ignoreArgs; + } + + public void setIgnoreArgs(boolean ignoreArgs) { + this.ignoreArgs = ignoreArgs; + } + + protected void onlyPlayers() { + this.consoleCanUse = false; + } + + @Override + public CommandResultType getTabCompleter() { + return tabCompleter; + } + + public void setTabCompleter(CommandResultType tabCompleter) { + this.tabCompleter = tabCompleter; + } + + public Optional getCompletionAt(int index) { + return Optional.ofNullable(this.tabCompletions.getOrDefault(index, null)); + } + + protected void addRequireArg(String message) { + this.requireArgs.add(message); + this.ignoreParent = this.parent == null; + this.ignoreArgs = true; + } + + protected void addRequireArg(String message, TabCompletion runnable) { + this.addRequireArg(message); + int index = this.requireArgs.size(); + this.addCompletion(index - 1, runnable); + } + + protected void addOptionalArg(String message) { + this.optionalArgs.add(message); + this.ignoreParent = this.parent == null; + this.ignoreArgs = true; + } + + protected void addOptionalArg(String message, TabCompletion runnable) { + this.addOptionalArg(message); + int index = this.requireArgs.size() + this.optionalArgs.size(); + this.addCompletion(index - 1, runnable); + } + + private String generateDefaultSyntax(String syntax) { + boolean update = syntax.isEmpty(); + + StringBuilder syntaxBuilder = new StringBuilder(); + if (update) { + appendRequiredArguments(syntaxBuilder); + appendOptionalArguments(syntaxBuilder); + syntax = syntaxBuilder.toString(); + } + String tmpString = subCommands.get(0) + syntax; + return parent == null ? "/" + tmpString : parent.generateDefaultSyntax(" " + tmpString); + } + + private void appendRequiredArguments(StringBuilder syntaxBuilder) { + requireArgs.forEach(arg -> syntaxBuilder.append(" <").append(arg).append(">")); + } + + private void appendOptionalArguments(StringBuilder syntaxBuilder) { + optionalArgs.forEach(arg -> syntaxBuilder.append(" [<").append(arg).append(">]")); + } + + private int parentCount(int defaultParent) { + return parent == null ? defaultParent : parent.parentCount(defaultParent + 1); + } + + @Override + public boolean isConsoleCanUse() { + return consoleCanUse; + } + + protected boolean isPlayer() { + return this.player != null; + } + + public void setPlayer(Player player) { + this.player = player; + } + + @Override + public void addSubCommand(String subCommand) { + this.subCommands.add(subCommand); + } + + public VCommand addSubCommand(VCommand command) { + command.setParent(this); + this.plugin.getCommandManager().registerCommand(command); + this.subVCommands.add(command); + return this; + } + + public VCommand addSubCommand(String... subCommand) { + this.subCommands.addAll(Arrays.asList(subCommand)); + return this; + } + + protected void addCompletion(int index, TabCompletion runnable) { + this.tabCompletions.put(index, runnable); + this.setTabCompleter(); + } + + private String getMainCommand() { + return this.subCommands.get(0); + } + + @Override + public void addSubCommand(List aliases) { + this.subCommands.addAll(aliases); + } + + @Override + public CommandResultType prePerform(EssentialsPlugin plugin, CommandSender commandSender, String[] args) { + updateArgumentCounts(); + + if (this.syntax == null) { + this.syntax = generateDefaultSyntax(""); + } + + this.args = args; + + if (isSubCommandMatch()) { + return CommandResultType.CONTINUE; + } + + if (isSyntaxError(args.length)) { + return CommandResultType.SYNTAX_ERROR; + } + + this.sender = commandSender; + setPlayerIfApplicable(); + + return safelyPerformCommand(plugin); + } + + private void updateArgumentCounts() { + this.parentCount = this.parentCount(0); + this.argsMaxLength = this.requireArgs.size() + this.optionalArgs.size() + this.parentCount; + this.argsMinLength = this.requireArgs.size() + this.parentCount; + } + + private boolean isSubCommandMatch() { + String defaultString = super.argAsString(0); + if (defaultString != null) { + for (VCommand subCommand : subVCommands) { + if (subCommand.getSubCommands().contains(defaultString.toLowerCase())) { + return true; + } + } + } + return false; + } + + private boolean isSyntaxError(int argsLength) { + return (this.argsMinLength != 0 && argsLength < this.argsMinLength) || (this.argsMaxLength != 0 && argsLength > this.argsMaxLength && !this.extendedArgs); + } + + private void setPlayerIfApplicable() { + if (this.sender instanceof Player player) { + this.player = player; + this.user = this.plugin.getStorageManager().getStorage().getUser(player.getUniqueId()); + } else { + this.player = null; + this.user = null; + } + } + + private CommandResultType safelyPerformCommand(EssentialsPlugin plugin) { + try { + + int cooldownSeconds = 0; + String key = this.getMainCommand(); + configuration = this.plugin.getConfiguration(); + + // Check for cooldown + if (user != null && (!this.user.hasPermission(Permission.ESSENTIALS_BYPASS_COOLDOWN) || !configuration.isEnableCooldownBypass())) { + Optional optional = configuration.getCooldown(this.sender, key); + if (optional.isPresent()) { + cooldownSeconds = optional.get(); + if (this.user.isCooldown(key)) { + long milliSeconds = this.user.getCooldown(key) - System.currentTimeMillis(); + message(this.sender, Message.COOLDOWN, "%cooldown%", TimerBuilder.getStringTime(milliSeconds)); + return CommandResultType.COOLDOWN; + } + } + } + + CommandResultType commandResultType = perform(plugin); + + if (commandResultType != CommandResultType.SYNTAX_ERROR && cooldownSeconds != 0 && this.user != null && (!this.user.hasPermission(Permission.ESSENTIALS_BYPASS_COOLDOWN) || !configuration.isEnableCooldownBypass())) { + this.user.addCooldown(key, cooldownSeconds); + } + + return commandResultType; + } catch (Exception exception) { + if (plugin.getConfiguration().isEnableDebug()) { + exception.printStackTrace(); + } + return CommandResultType.SYNTAX_ERROR; + } + } + + protected abstract CommandResultType perform(EssentialsPlugin plugin); + + public boolean sameSubCommands() { + if (this.parent == null) { + return false; + } + for (String command : this.subCommands) { + if (this.parent.getSubCommands().contains(command)) return true; + } + return false; + } + + @Override + public List toTab(EssentialsPlugin plugin, CommandSender sender, String[] args) { + + this.parentCount = this.parentCount(0); + + int currentInex = (args.length - this.parentCount) - 1; + Optional optional = this.getCompletionAt(currentInex); + + if (optional.isPresent()) { + + TabCompletion collectionRunnable = optional.get(); + String startWith = args[args.length - 1]; + return this.generateList(collectionRunnable.accept(sender, args), startWith); + + } + + return null; + } + + protected List generateList(List defaultList, String startWith) { + return generateList(defaultList, startWith, Tab.CONTAINS); + } + + protected List generateList(List defaultList, String startWith, Tab tab) { + List newList = new ArrayList<>(); + for (String str : defaultList) { + if (startWith.length() == 0 || (tab.equals(Tab.START) ? str.toLowerCase().startsWith(startWith.toLowerCase()) : str.toLowerCase().contains(startWith.toLowerCase()))) { + newList.add(str); + } + } + return newList.size() == 0 ? null : newList; + } + + public void syntaxMessage() { + this.subVCommands.forEach(command -> { + if (command.getPermission() == null || sender.hasPermission(command.getPermission())) { + message(this.sender, Message.COMMAND_SYNTAXE_HELP, "%syntax%", command.getSyntax(), "%description%", + command.getDescription()); + } + }); + } + +} diff --git a/Essentials/src/main/resources/commands.yml b/Essentials/src/main/resources/commands.yml new file mode 100644 index 00000000..ec605803 --- /dev/null +++ b/Essentials/src/main/resources/commands.yml @@ -0,0 +1,32 @@ +gamemode: true +gmc: true +gma: true +gms: true +gmsp: true +day: true +night: true +sun: true +enderchest: true +endersee: true +top: true +speed: true +tpa: true +tpaccept: true +tpdeny: true +tpacancel: true +god: true +heal: true +more: true +worldtp: true +trash: true +feed: true +craft: true +enchanting: true +invsee: true +compact: true +hat: true +player-weather: true +player-time: true +tp: true +tphere: true +economy: true \ No newline at end of file diff --git a/Essentials/src/main/resources/config.yml b/Essentials/src/main/resources/config.yml new file mode 100644 index 00000000..bab8fece --- /dev/null +++ b/Essentials/src/main/resources/config.yml @@ -0,0 +1,63 @@ +######################################################################################################################## +# +# ███████╗███████╗░██████╗░██████╗███████╗███╗░░██╗████████╗██╗░█████╗░██╗░░░░░░██████╗ +# ╚════██║██╔════╝██╔════╝██╔════╝██╔════╝████╗░██║╚══██╔══╝██║██╔══██╗██║░░░░░██╔════╝ +# ░░███╔═╝█████╗░░╚█████╗░╚█████╗░█████╗░░██╔██╗██║░░░██║░░░██║███████║██║░░░░░╚█████╗░ +# ██╔══╝░░██╔══╝░░░╚═══██╗░╚═══██╗██╔══╝░░██║╚████║░░░██║░░░██║██╔══██║██║░░░░░░╚═══██╗ +# ███████╗███████╗██████╔╝██████╔╝███████╗██║░╚███║░░░██║░░░██║██║░░██║███████╗██████╔╝ +# ╚══════╝╚══════╝╚═════╝░╚═════╝░╚══════╝╚═╝░░╚══╝░░░╚═╝░░░╚═╝╚═╝░░╚═╝╚══════╝╚═════╝░ +# +# Placeholders: +# %zessentials_user_target_player_name% +# +######################################################################################################################## + +enable-debug: false + +storage-type: MYSQL + +database-configuration: + prefix: "zessentials_" + host: 192.168.10.10 + port: 3306 + user: homestead + password: 'secret' + database: zessentials + debug: false + +enable-cooldown-bypass: false + +command-cooldowns: + - command: heal + cooldown: 60 + permissions: + - permission: "essentials.cooldown.heal.vip" + cooldown: 40 + - permission: "essentials.cooldown.heal.staff" + cooldown: 20 + +trash-size: 27 + +compact-materials: + - from: COAL + to: COAL_BLOCK + - from: REDSTONE + to: REDSTONE_BLOCK + - from: LAPIS_LAZULI + to: LAPIS_BLOCK + - from: IRON_INGOT + to: IRON_BLOCK + - from: GOLD_INGOT + to: GOLD_BLOCK + - from: IRON_NUGGET + to: IRON_INGOT + - from: GOLD_NUGGET + to: GOLD_INGOT + - from: DIAMOND + to: DIAMOND_BLOCK + - from: EMERALD + to: EMERALD_BLOCK + - from: COPPER_INGOT + to: COPPER_BLOCK + - from: NETHERITE_INGOT + to: NETHERITE_BLOCK \ No newline at end of file diff --git a/Essentials/src/main/resources/messages/messages.yml b/Essentials/src/main/resources/messages/messages.yml new file mode 100644 index 00000000..2cd0c590 --- /dev/null +++ b/Essentials/src/main/resources/messages/messages.yml @@ -0,0 +1,147 @@ +prefix: "#03fcb6zEssentials #656665• " +you: "you" +trash: "&8Trash" + +# Commands +command-syntax-error: "#ff0000You must execute the command like this#656665: &f%syntax%" +command-no-permission: "#ff0000You do not have permission to run this command." +command-no-console: "#ff0000Only one player can execute this command." +command-no-arg: "#ff0000Impossible to find the command with its arguments." +command-syntaxe-help: "&f%syntax% #656665» &7%description%" + +command-reload: "#00ff40You have just reloaded the configuration files." +command-essentials: "&ezEssentials&8, &eVersion &f%version%" + + +# GameMode commands +command-gamemode: "&fSet game mode&e %gamemode%&f for &b%player%&f." +command-gamemode-invalid: "#ff0000You need to specify a valid player." + + +# Weather commands +command-day: "&fYou have just brought &edaylight&f into the world &a%world%&f." +command-night: "&fYou have just brought &enightfall&f into the world &a%world%&f." +command-sun: "&fYou have just brought the &esun&f into the world &a%world%&f." + + +# Admins commands +command-top: "&7You've just been teleported to &etop&7." +command-top-error: "#ff0000Unable to find a position to transport you safely." +command-speed-invalid: "#ff0000You need to specify a valid player." +command-speed-fly: "&7You have just set your &nfly&r&7 speed to &f%speed%&7 for &f%player%&7. &8(&f2 &7by default&8)" +command-speed-walk: "&7You have just set your &nwalk&r&7 speed to &f%speed%&7 for &f%player%&7. &8(&f2 &7by default&8)" +command-speed-error: "#ff0000You must enter a number between &60#ff0000 and &610#ff0000. &8(&f2 &7by default&8)" +command-god-enable: "&7God mode &aenable &7for &f%player%&a." +command-god-disable: "&7God mode &cdisable &7for &f%player%&a." +command-heal-sender: "&7You just healed the player &f%player%&7." +command-heal-receiver: "&aYou have been healed." +command-heal-error: "&cYou cannot heal someone who is dead !" +command-more-error: "&cYou cannot make this order in item in hand." +command-more-success: "&7You just put your item to &f64&7." +command-feed-sender: "&7You just feed the player &f%player%&7." +command-feed-receiver: "&aYou have been feed." +command-feed-error: "&cYou cannot feed someone who is dead !" +command-compact-type: "&cImpossible to compact the material &f%material%&c." +command-compact-error: "&cYou have no &f%item%&c in your inventory." +command-compact-success: "&7You have just transformed #0EEA93x%amount% #99E0FF%item% &7en #0EEA93x%toAmount% #99E0FF%toItem%&7." +command-hat-success: "&7You just put #0ef0ce%item% &7on your head." +command-hat-error: "&cYou cannot put air on your head." +command-player-weather-reset: "&7You just changed the weather to that of the server." +command-player-weather-downfall: "&7You just put the rain on for yourself." +command-player-time-reset: "&7You just changed the time to that of the server." +command-player-time-change: "&7You’re here to change your time." + +# Teleport commands +command-tpa-error: "#ff0000You have already sent a request to #99E0FF%player%#ff0000." +command-tpa-error-same: "#ff0000You cannot teleport to yourself." +command-tpa-error-offline: "#ff0000Unable to find player, must be offline." +command-tpa-error-to-late-empty: "#ff0000You do not have a teleport request." +command-tpa-error-to-late-expire: "#ff0000The teleport request has expired." +command-tpa-sender: + - "#00FF00✔ #99E0FFSent &f%displayName% #99E0FFa teleport request." + - " #99E0FFType #00FF00/tpacencel %player%#99E0FF to cancel your request." +command-tpa-receiver: + - "" + - "#F8F327⚠ &f%displayName% #99E0FFhas requested to teleport to you!" + - " #99E0FFType #00FF00/tpaccept #99E0FFto #00FF00accept#99E0FF." + - " #99E0FFType #ff0000/tpdeny #99E0FFto #ff0000deny#99E0FF." + - "" + - "&7&oYou have 60 seconds to accept the teleport request." +command-tpa-accept-receiver: "#99E0FFYou have just #00FF00accepted #99E0FFthe teleport request from #99E0FF%player%&a." +command-tpa-accept-sender: "#99E0FF%player%&a has just accepted your teleport request." +command-teleport-ignore-player: "#ff0000You cannot send a teleport request to #99E0FF%player%#ff0000 they are ignoring you." +command-teleport-world: "#ff0000You need to be in the same world to teleport." +command-tpa-error-to-late: "#ff0000You do not have a teleport request." +command-tpa-error-to-late-2: "#ff0000The request has expired." +command-tp-deny-sender: "#00FF00✔ Denied &f%player% #00FF00teleport request." +command-tp-deny-receiver: "#ff0000✘ &f%player% #ff0000has denied your teleport request." +command-tp-cancel-error: "#ff0000You did not send a teleport request at &f%player%#ff0000." +command-tp-cancel-sender: "#ff0000Cancelled #99E0FFyour teleport request to %player%." +command-tp-cancel-receiver: "&f%player% #ff0000cancelled their teleport request to you." +command-world-teleport-self: "&aYou have just been teleported into the world &f%world%&a." +command-world-teleport-other: "&aYou just teleported the player &f%player% &ain the world &f%world%&a." +command-tp: "&7You just teleport to the player #34cfe0%player%&f." +command-tp-self: "&7You just teleported #34cfe0%player%&7 to your position." + + +# Command description +description-reload: "Reload configuration files" +description-gamemode: "Change player gamemode" +description-gamemode-creative: "Change player gamemode to creative" +description-gamemode-survival: "Change player gamemode to survival" +description-gamemode-adventure: "Change player gamemode to adventure" +description-gamemode-spectator: "Change player gamemode to spectator" +description-day: "Set the day in your world" +description-night: "Set the night in your world" +description-sun: "Set the sun in your world" +description-top: "Teleporting to top" +description-speed: "Change player speed" +description-enderchest: "Open your enderchest" +description-endersee: "Open a player enderchest" +description-tpa: "Teleport to a player" +description-tpa-accept: "Accept a teleportation request" +description-tpa-deny: "Denied a teleportation request" +description-tpa-cancel: "Cancel a teleportation request" +description-god: "Toggle god mode" +description-heal: "Heal a player" +description-more: "Get more items" +description-tp-world: "Teleport to another world" +description-trash: "Open a trash can" +description-feed: "Feed a player" +description-craft: "Open workbench" +description-enchanting: "Open enchantment table" +description-invsee: "Open player's inventory" +description-compact: "Compact material" +description-hat: "Create yourself a pretty hat" +description-tp: "Teleport to a player" +description-tp-self: "Teleport a player to your location" +description-player-weather: "Change your weather" +description-player-time: "Change your time" + +# Time format +time-day: "%02d day %02d hour %02d minute %02d second" +time-hour: "%02d hour %02d minute(s) %02d second" +time-minute: "%02d minute %02d second" +time-second: "%02d second" +format-second: "second" +format-seconds: "seconds" +format-minute: "minute" +format-minutes: "minutes" +format-hour: "hour" +format-hours: "hours" +format-day: "d" +format-days: "days" +cooldown: "#ff0000✘ You must wait for &f%cooldown% #ff0000before performing this action." + + +# Teleportation +teleport-move: "#ff0000You must not move!" +teleport-message: + type: ACTION + message: "&7Teleporting in #0EEA93%seconds% &7seconds, you must not move." +teleport-error: "#ff0000You already have a teleportation in progress!" +teleport-success: + type: ACTION + message: "#99E0FFYou have just teleported successfully!" +teleport-damage: "#ff0000You must not take damage during teleportation." +teleport-error-location: "#ff0000Unable to teleport you safely." diff --git a/Essentials/src/main/resources/messages/messages_fr.yml b/Essentials/src/main/resources/messages/messages_fr.yml new file mode 100644 index 00000000..e69de29b diff --git a/Essentials/src/main/resources/modules/economy/config.yml b/Essentials/src/main/resources/modules/economy/config.yml new file mode 100644 index 00000000..6e152c67 --- /dev/null +++ b/Essentials/src/main/resources/modules/economy/config.yml @@ -0,0 +1,23 @@ +######################################################################################################################## +# +# ███████╗░█████╗░░█████╗░███╗░░██╗░█████╗░███╗░░░███╗██╗░░░██╗ +# ██╔════╝██╔══██╗██╔══██╗████╗░██║██╔══██╗████╗░████║╚██╗░██╔╝ +# █████╗░░██║░░╚═╝██║░░██║██╔██╗██║██║░░██║██╔████╔██║░╚████╔╝░ +# ██╔══╝░░██║░░██╗██║░░██║██║╚████║██║░░██║██║╚██╔╝██║░░╚██╔╝░░ +# ███████╗╚█████╔╝╚█████╔╝██║░╚███║╚█████╔╝██║░╚═╝░██║░░░██║░░░ +# ╚══════╝░╚════╝░░╚════╝░╚═╝░░╚══╝░╚════╝░╚═╝░░░░░╚═╝░░░╚═╝░░░ +# +# +# +######################################################################################################################## + +enable: true + +default-economy: "money" + +economies: + money: + displayName: money + symbol: "$" + format: "%price%$" + vault: true \ No newline at end of file diff --git a/Essentials/src/main/resources/modules/teleportation/config.yml b/Essentials/src/main/resources/modules/teleportation/config.yml new file mode 100644 index 00000000..23977a85 --- /dev/null +++ b/Essentials/src/main/resources/modules/teleportation/config.yml @@ -0,0 +1,41 @@ +######################################################################################################################## +# +# ████████╗███████╗██╗░░░░░███████╗██████╗░░█████╗░██████╗░████████╗░█████╗░████████╗██╗░█████╗░███╗░░██╗ +# ╚══██╔══╝██╔════╝██║░░░░░██╔════╝██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗╚══██╔══╝██║██╔══██╗████╗░██║ +# ░░░██║░░░█████╗░░██║░░░░░█████╗░░██████╔╝██║░░██║██████╔╝░░░██║░░░███████║░░░██║░░░██║██║░░██║██╔██╗██║ +# ░░░██║░░░██╔══╝░░██║░░░░░██╔══╝░░██╔═══╝░██║░░██║██╔══██╗░░░██║░░░██╔══██║░░░██║░░░██║██║░░██║██║╚████║ +# ░░░██║░░░███████╗███████╗███████╗██║░░░░░╚█████╔╝██║░░██║░░░██║░░░██║░░██║░░░██║░░░██║╚█████╔╝██║░╚███║ +# ░░░╚═╝░░░╚══════╝╚══════╝╚══════╝╚═╝░░░░░░╚════╝░╚═╝░░╚═╝░░░╚═╝░░░╚═╝░░╚═╝░░░╚═╝░░░╚═╝░╚════╝░╚═╝░░╚══╝ +# +# +# +######################################################################################################################## + +enable: true + +# If the teleport destination is unsafe, should players be teleported to the nearest safe location? +# If this is set to true, zEssentials will attempt to teleport players close to the intended destination. The destination will be on the same x and z, only the y will change. +# If this is set to false, attempted teleports to unsafe locations will be cancelled with a warning. +teleport-safety: true + +# Whether to make all teleportations go to the center of the block; where the x and z coordinates decimal become .5 +teleport-to-center: true + +# The delay, in seconds, before a user actually teleports. If the user moves or gets attacked in this timeframe, the teleport is cancelled. +teleport-delay: 5 + +# The delay, in seconds, before a user actually teleports. If the user has one or more permissions, the minimum delay will be taken. +teleport-delay-permissions: + - permission: "essentials.teleport.delay.vip" + delay: 4 + - permission: "essentials.teleport.delay.staff" + delay: 2 + +# Enable bypass of teleport delay on player to essentials.teleport.bypass permission +teleport-delay-bypass: false + +# The delay, in seconds, for the teleport request to expire. +teleport-tpa-expire: 60 + +# Opens a confirmation inventory for the /tpa command. +open-confirm-inventory-for-tpa: false \ No newline at end of file diff --git a/Essentials/src/main/resources/modules/teleportation/confirm_request_inventory.yml b/Essentials/src/main/resources/modules/teleportation/confirm_request_inventory.yml new file mode 100644 index 00000000..c861d0f3 --- /dev/null +++ b/Essentials/src/main/resources/modules/teleportation/confirm_request_inventory.yml @@ -0,0 +1,27 @@ +name: '#3f3f3fᴄᴏɴꜰɪʀᴍ ʀᴇǫᴜᴇѕᴛ' +size: 27 +items: + cancel: + slot: 10 + closeInventory: true + item: + material: RED_STAINED_GLASS_PANE + name: '#ff0000ᴄᴀɴᴄᴇʟ' + lore: + - '&7Click to cancel the teleport request' + + head: + slot: 13 + item: + playerHead: '%zessentials_user_target_player_name%' + name: '#99E0FF%zessentials_user_target_player_name%' + + confirm: + type: ESSENTIALS_TELEPORTATION_CONFIRM + slot: 16 + closeInventory: true + item: + material: GREEN_STAINED_GLASS_PANE + name: '#00ff00ᴄᴏɴғɪʀᴍ' + lore: + - '&7Click to send &n%zessentials_user_target_player_name%&r &7a tpa request' \ No newline at end of file diff --git a/Essentials/src/main/resources/plugin.yml b/Essentials/src/main/resources/plugin.yml index 438e6d2d..a4ca9656 100644 --- a/Essentials/src/main/resources/plugin.yml +++ b/Essentials/src/main/resources/plugin.yml @@ -1,4 +1,11 @@ name: Essentials version: '${version}' -main: fr.maxlego08.zessentials.Essentials +main: fr.maxlego08.essentials.ZEssentialsPlugin +folia-supported: true +description: Provides an essential, core set of commands for Bukkit. +depend: + - zMenu + - PlaceholderAPI +softdepend: + - Vault api-version: '1.20' diff --git a/EssentialsApi/src/main/java/fr.maxlego08.essentials.api/EssentialsPlugin.java b/EssentialsApi/src/main/java/fr.maxlego08.essentials.api/EssentialsPlugin.java deleted file mode 100644 index adb038a6..00000000 --- a/EssentialsApi/src/main/java/fr.maxlego08.essentials.api/EssentialsPlugin.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.maxlego08.essentials.api; - -public interface EssentialsPlugin { - - - -} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/Configuration.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/Configuration.java new file mode 100644 index 00000000..19b55349 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/Configuration.java @@ -0,0 +1,30 @@ +package fr.maxlego08.essentials.api; + +import fr.maxlego08.essentials.api.commands.CommandCooldown; +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; +import fr.maxlego08.essentials.api.storage.StorageType; +import fr.maxlego08.essentials.api.utils.CompactMaterial; +import org.bukkit.permissions.Permissible; + +import java.util.List; +import java.util.Optional; + +public interface Configuration extends ConfigurationFile { + + boolean isEnableDebug(); + + boolean isEnableCooldownBypass(); + + List getCommandCooldown(); + + Optional getCooldown(Permissible permissible, String command); + + int getTrashSize(); + + List getCompactMaterials(); + + StorageType getStorageType(); + + DatabaseConfiguration getDatabaseConfiguration(); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/ConfigurationFile.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/ConfigurationFile.java new file mode 100644 index 00000000..402e1bcf --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/ConfigurationFile.java @@ -0,0 +1,7 @@ +package fr.maxlego08.essentials.api; + +public interface ConfigurationFile { + + void load(); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java new file mode 100644 index 00000000..b59ca342 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java @@ -0,0 +1,50 @@ +package fr.maxlego08.essentials.api; + +import com.google.gson.Gson; +import com.tcoded.folialib.impl.ServerImplementation; +import fr.maxlego08.essentials.api.commands.CommandManager; +import fr.maxlego08.essentials.api.database.MigrationManager; +import fr.maxlego08.essentials.api.economy.EconomyProvider; +import fr.maxlego08.essentials.api.modules.ModuleManager; +import fr.maxlego08.essentials.api.placeholders.Placeholder; +import fr.maxlego08.essentials.api.storage.Persist; +import fr.maxlego08.essentials.api.storage.StorageManager; +import fr.maxlego08.menu.api.ButtonManager; +import fr.maxlego08.menu.api.InventoryManager; +import fr.maxlego08.menu.api.pattern.PatternManager; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +public interface EssentialsPlugin extends Plugin { + + CommandManager getCommandManager(); + + StorageManager getStorageManager(); + + List getConfigurationFiles(); + + Gson getGson(); + + Persist getPersist(); + + ServerImplementation getScheduler(); + + ModuleManager getModuleManager(); + + InventoryManager getInventoryManager(); + + ButtonManager getButtonManager(); + + PatternManager getPatternManager(); + + Placeholder getPlaceholder(); + + Configuration getConfiguration(); + + MigrationManager getMigrationManager(); + + boolean isEconomyEnable(); + + EconomyProvider getEconomyProvider(); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/cache/SimpleCache.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/cache/SimpleCache.java new file mode 100644 index 00000000..4a89b8ad --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/cache/SimpleCache.java @@ -0,0 +1,54 @@ +package fr.maxlego08.essentials.api.cache; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * A simple caching utility class that stores key-value pairs in memory using a ConcurrentHashMap. + * This class is thread-safe and can be used to cache objects such as messages, to reduce the need + * for repetitive operations like loading data from a database or a file system. + * + * @param the type of keys maintained by this cache + * @param the type of mapped values + */ +public class SimpleCache { + + private final ConcurrentHashMap cache; + + /** + * Constructs a new SimpleCache instance. + */ + public SimpleCache() { + this.cache = new ConcurrentHashMap<>(); + } + + /** + * Retrieves the value associated with the specified key from the cache. If the key is not + * found in the cache, the provided Loader is used to load the value, store it in the cache, + * and then return it. + * + * @param key the key whose associated value is to be returned + * @param loader the loader used to generate the value if it is not present in the cache + * @return the value associated with the specified key or the newly loaded value if the key + * was not found in the cache + */ + public V get(K key, Loader loader) { + return cache.computeIfAbsent(key, k -> loader.load()); + } + + /** + * Functional interface for loading values into the cache. Implementations of this interface + * provide a method to load a value, typically involving an operation such as fetching data + * from a database or a remote service. + * + * @param the type of value to be loaded + */ + @FunctionalInterface + public interface Loader { + /** + * Loads a value. + * + * @return the loaded value + */ + V load(); + } +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandCooldown.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandCooldown.java new file mode 100644 index 00000000..cf5c2bae --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandCooldown.java @@ -0,0 +1,9 @@ +package fr.maxlego08.essentials.api.commands; + +import fr.maxlego08.essentials.api.modules.Loadable; + +import java.util.List; +import java.util.Map; + +public record CommandCooldown(String command, int cooldown, List> permissions) implements Loadable { +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandManager.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandManager.java new file mode 100644 index 00000000..4e301123 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandManager.java @@ -0,0 +1,18 @@ +package fr.maxlego08.essentials.api.commands; + +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.TabCompleter; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +public interface CommandManager extends CommandExecutor, TabCompleter { + + void registerCommand(EssentialsCommand command); + + void registerCommand(String string, EssentialsCommand command); + + void registerCommand(Plugin plugin, String string, EssentialsCommand vCommand, List aliases); + + int countCommands(); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandResultType.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandResultType.java new file mode 100644 index 00000000..ce67caa8 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/CommandResultType.java @@ -0,0 +1,12 @@ +package fr.maxlego08.essentials.api.commands; + +public enum CommandResultType { + + SUCCESS, + SYNTAX_ERROR, + NO_PERMISSION, + DEFAULT, + CONTINUE, + COOLDOWN; + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/EssentialsCommand.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/EssentialsCommand.java new file mode 100644 index 00000000..05070798 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/EssentialsCommand.java @@ -0,0 +1,33 @@ +package fr.maxlego08.essentials.api.commands; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public interface EssentialsCommand { + + void addSubCommand(String string); + + void addSubCommand(List aliases); + + String getSyntax(); + + List getSubCommands(); + + boolean isIgnoreParent(); + + EssentialsCommand getParent(); + + boolean isConsoleCanUse(); + + String getPermission(); + + CommandResultType prePerform(EssentialsPlugin plugin, CommandSender sender, String[] strings); + + CommandResultType getTabCompleter(); + + List toTab(EssentialsPlugin plugin, CommandSender sender, String[] args); + + boolean isIgnoreArgs(); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Permission.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Permission.java new file mode 100644 index 00000000..a2f8f0f0 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Permission.java @@ -0,0 +1,44 @@ +package fr.maxlego08.essentials.api.commands; + +public enum Permission { + + ESSENTIALS_USE, + ESSENTIALS_RELOAD, + ESSENTIALS_GAMEMODE, + ESSENTIALS_GAMEMODE_OTHER, + ESSENTIALS_GAMEMODE_CREATIVE, + ESSENTIALS_GAMEMODE_SURVIVAL, + ESSENTIALS_GAMEMODE_SPECTATOR, + ESSENTIALS_GAMEMODE_ADVENTURE, + ESSENTIALS_DAY, + ESSENTIALS_NIGHT, + ESSENTIALS_SUN, + ESSENTIALS_ENDERCHEST, + ESSENTIALS_ENDERSEE, + ESSENTIALS_TOP, + ESSENTIALS_GOD, + ESSENTIALS_HEAL, + ESSENTIALS_SPEED, + ESSENTIALS_TELEPORT_BYPASS, + ESSENTIALS_TPA, + ESSENTIALS_TPA_ACCEPT, + ESSENTIALS_TPA_DENY, + ESSENTIALS_TPA_CANCEL, + ESSENTIALS_BYPASS_COOLDOWN, + ESSENTIALS_MORE, + ESSENTIALS_TP_WORLD, + ESSENTIALS_TP_WORLD_OTHER, + ESSENTIALS_TRASH, + ESSENTIALS_FEED, + ESSENTIALS_INVSEE, + ESSENTIALS_FEED_OTHER, + ESSENTIALS_HEAL_OTHER, + ESSENTIALS_CRAFT, + ESSENTIALS_ENCHANTING, ESSENTIALS_INVSEE_INTERACT, ESSENTIALS_COMPACT, ESSENTIALS_HAT, ESSENTIALS_PLAYER_WEATHER, ESSENTIALS_PLAYER_TIME, ESSENTIALS_TP, ESSENTIALS_ECO_USE, ESSENTIALS_ECO_GIVE, ESSENTIALS_ECO_TAKE; + + + public String asPermission() { + return name().toLowerCase().replace("_", "."); + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Tab.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Tab.java new file mode 100644 index 00000000..53e26d3e --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/Tab.java @@ -0,0 +1,8 @@ +package fr.maxlego08.essentials.api.commands; + +public enum Tab { + + START, + CONTAINS, + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/TabCompletion.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/TabCompletion.java new file mode 100644 index 00000000..25fcfc96 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/commands/TabCompletion.java @@ -0,0 +1,12 @@ +package fr.maxlego08.essentials.api.commands; + +import org.bukkit.command.CommandSender; + +import java.util.List; + +@FunctionalInterface +public interface TabCompletion { + + List accept(CommandSender sender, String[] args); + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Migration.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Migration.java new file mode 100644 index 00000000..e57804b4 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Migration.java @@ -0,0 +1,12 @@ +package fr.maxlego08.essentials.api.database; + +public abstract class Migration { + + protected String prefix; + + public abstract void up(); + + public void setPrefix(String prefix) { + this.prefix = prefix; + } +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/MigrationManager.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/MigrationManager.java new file mode 100644 index 00000000..a026dd12 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/MigrationManager.java @@ -0,0 +1,13 @@ +package fr.maxlego08.essentials.api.database; + +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; + +import java.sql.Connection; +import java.util.logging.Logger; + +public interface MigrationManager { + + void registerMigration(); + + void execute(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Schema.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Schema.java new file mode 100644 index 00000000..066576e9 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/Schema.java @@ -0,0 +1,53 @@ +package fr.maxlego08.essentials.api.database; + +import fr.maxlego08.essentials.api.storage.DatabaseConfiguration; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; + +public interface Schema { + Schema uuid(String columnName); + + Schema uuid(String columnName, UUID value); + + Schema string(String columnName, int length); + + Schema string(String columnName, String value); + + Schema bigInt(String columnName); + + Schema bigInt(String columnName, long value); + + Schema bool(String columnName); + + Schema bool(String columnName, boolean value); + + Schema primary(); + + Schema foreignKey(String referenceTable); + + Schema createdAt(); + + Schema updatedAt(); + + Schema timestamps(); + + Schema nullable(); + + Schema defaultValue(String value); + + Schema where(String column, Object value); + + Schema where(String column, String operator, Object value); + + void execute(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException; + + List> executeSelect(Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws SQLException; + + List executeSelect(Class clazz, Connection connection, DatabaseConfiguration databaseConfiguration, Logger logger) throws Exception; +} + diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/SchemaType.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/SchemaType.java new file mode 100644 index 00000000..7be2eada --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/SchemaType.java @@ -0,0 +1,10 @@ +package fr.maxlego08.essentials.api.database; + +public enum SchemaType { + + CREATE, + UPSERT, + SELECT, + DELETE, + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/CooldownDTO.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/CooldownDTO.java new file mode 100644 index 00000000..ce183c13 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/CooldownDTO.java @@ -0,0 +1,4 @@ +package fr.maxlego08.essentials.api.database.dto; + +public record CooldownDTO(String cooldown_name, long cooldown_value) { +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/OptionDTO.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/OptionDTO.java new file mode 100644 index 00000000..446dd349 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/database/dto/OptionDTO.java @@ -0,0 +1,6 @@ +package fr.maxlego08.essentials.api.database.dto; + +import fr.maxlego08.essentials.api.user.Option; + +public record OptionDTO(Option option_name, boolean option_value) { +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/Economy.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/Economy.java new file mode 100644 index 00000000..9b1a86fc --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/Economy.java @@ -0,0 +1,19 @@ +package fr.maxlego08.essentials.api.economy; + +public interface Economy { + + String getName(); + + String getDisplayName(); + + String getSymbol(); + + String getFormat(); + + boolean isVaultEconomy(); + + default String format(String priceAsString, long amount) { + return getFormat().replace("%price%", priceAsString).replace("%s%", amount > 1 ? "s" : ""); + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/EconomyProvider.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/EconomyProvider.java new file mode 100644 index 00000000..151ded8a --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/economy/EconomyProvider.java @@ -0,0 +1,30 @@ +package fr.maxlego08.essentials.api.economy; + +import fr.maxlego08.essentials.api.modules.Module; +import org.bukkit.OfflinePlayer; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +public interface EconomyProvider extends Module { + + boolean hasMoney(OfflinePlayer player, Economy economy); + + BigDecimal getBalance(OfflinePlayer player, Economy economy); + + boolean deposit(UUID uniqueId, Economy economy, BigDecimal amount); + + boolean withdraw(UUID uniqueId, Economy economy, BigDecimal amount); + + boolean set(UUID uniqueId, Economy economy, BigDecimal amount); + + Collection getEconomies(); + + Optional getEconomy(String economyName); + + Economy getDefaultEconomy(); + + String format(double amount); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/UserEvent.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/UserEvent.java new file mode 100644 index 00000000..a86cfad0 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/UserEvent.java @@ -0,0 +1,28 @@ +package fr.maxlego08.essentials.api.event; + +import fr.maxlego08.essentials.api.user.User; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class UserEvent extends Event { + + private final static HandlerList handlers = new HandlerList(); + private final User user; + + public UserEvent(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/events/UserFirstJoinEvent.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/events/UserFirstJoinEvent.java new file mode 100644 index 00000000..d20120fe --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/event/events/UserFirstJoinEvent.java @@ -0,0 +1,11 @@ +package fr.maxlego08.essentials.api.event.events; + +import fr.maxlego08.essentials.api.user.User; +import fr.maxlego08.essentials.api.event.UserEvent; + +public class UserFirstJoinEvent extends UserEvent { + + public UserFirstJoinEvent(User user) { + super(user); + } +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/CollectionConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/CollectionConsumer.java new file mode 100644 index 00000000..0a686229 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/CollectionConsumer.java @@ -0,0 +1,10 @@ +package fr.maxlego08.essentials.api.functionnals; + +import java.util.Collection; + +@FunctionalInterface +public interface CollectionConsumer { + + Collection accept(T t); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ResultSetConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ResultSetConsumer.java new file mode 100644 index 00000000..c957dddc --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ResultSetConsumer.java @@ -0,0 +1,11 @@ +package fr.maxlego08.essentials.api.functionnals; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@FunctionalInterface +public interface ResultSetConsumer { + + void accept(ResultSet statement) throws SQLException; + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnBiConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnBiConsumer.java new file mode 100644 index 00000000..e69aa488 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnBiConsumer.java @@ -0,0 +1,7 @@ +package fr.maxlego08.essentials.api.functionnals; +@FunctionalInterface +public interface ReturnBiConsumer { + + C accept(T t, G g); + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnConsumer.java new file mode 100644 index 00000000..fc59b002 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/ReturnConsumer.java @@ -0,0 +1,7 @@ +package fr.maxlego08.essentials.api.functionnals; +@FunctionalInterface +public interface ReturnConsumer { + + G accept(T t); + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StatementConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StatementConsumer.java new file mode 100644 index 00000000..3ab7c5ae --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StatementConsumer.java @@ -0,0 +1,11 @@ +package fr.maxlego08.essentials.api.functionnals; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +@FunctionalInterface +public interface StatementConsumer { + + void accept(PreparedStatement statement) throws SQLException; + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StringConsumer.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StringConsumer.java new file mode 100644 index 00000000..d38fa764 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/functionnals/StringConsumer.java @@ -0,0 +1,8 @@ +package fr.maxlego08.essentials.api.functionnals; + +@FunctionalInterface +public interface StringConsumer { + + String accept(T t); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/DefaultFontInfo.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/DefaultFontInfo.java new file mode 100644 index 00000000..83a32933 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/DefaultFontInfo.java @@ -0,0 +1,133 @@ +package fr.maxlego08.essentials.api.messages; + +public enum DefaultFontInfo{ + + A('A', 5), + a('a', 5), + B('B', 5), + b('b', 5), + C('C', 5), + c('c', 5), + D('D', 5), + d('d', 5), + E('E', 5), + e('e', 5), + F('F', 5), + f('f', 4), + G('G', 5), + g('g', 5), + H('H', 5), + h('h', 5), + I('I', 3), + i('i', 1), + J('J', 5), + j('j', 5), + K('K', 5), + k('k', 4), + L('L', 5), + l('l', 2), + M('M', 5), + m('m', 5), + N('N', 5), + n('n', 5), + O('O', 5), + o('o', 5), + P('P', 5), + p('p', 5), + Q('Q', 5), + q('q', 5), + R('R', 5), + r('r', 5), + S('S', 5), + s('s', 5), + T('T', 5), + t('t', 3), + U('U', 5), + u('u', 5), + V('V', 5), + v('v', 5), + W('W', 5), + w('w', 5), + X('X', 5), + x('x', 5), + Y('Y', 5), + y('y', 5), + Z('Z', 5), + z('z', 5), + NUM_1('1', 5), + NUM_2('2', 5), + NUM_3('3', 5), + NUM_4('4', 5), + NUM_5('5', 5), + NUM_6('6', 5), + NUM_7('7', 5), + NUM_8('8', 5), + NUM_9('9', 5), + NUM_0('0', 5), + EXCLAMATION_POINT('!', 1), + AT_SYMBOL('@', 6), + NUM_SIGN('#', 5), + DOLLAR_SIGN('$', 5), + PERCENT('%', 5), + UP_ARROW('^', 5), + AMPERSAND('&', 5), + ASTERISK('*', 5), + LEFT_PARENTHESIS('(', 4), + RIGHT_PERENTHESIS(')', 4), + MINUS('-', 5), + UNDERSCORE('_', 5), + PLUS_SIGN('+', 5), + EQUALS_SIGN('=', 5), + LEFT_CURL_BRACE('{', 4), + RIGHT_CURL_BRACE('}', 4), + LEFT_BRACKET('[', 3), + RIGHT_BRACKET(']', 3), + COLON(':', 1), + SEMI_COLON(';', 1), + DOUBLE_QUOTE('"', 3), + SINGLE_QUOTE('\'', 1), + LEFT_ARROW('<', 4), + RIGHT_ARROW('>', 4), + QUESTION_MARK('?', 5), + SLASH('/', 5), + BACK_SLASH('\\', 5), + LINE('|', 1), + TILDE('~', 5), + TICK('`', 2), + PERIOD('.', 1), + COMMA(',', 1), + SPACE(' ', 3), + DEFAULT('a', 5), + + + ; + + private char character; + private int length; + + DefaultFontInfo(char character, int length) { + this.character = character; + this.length = length; + } + + public char getCharacter(){ + return this.character; + } + + public int getLength(){ + return this.length; + } + + public int getBoldLength(){ + if(this == DefaultFontInfo.SPACE) return this.getLength(); + return this.length + 1; + } + + public static DefaultFontInfo getDefaultFontInfo(char c){ + for(DefaultFontInfo dFI : DefaultFontInfo.values()){ + if(dFI.getCharacter() == c) return dFI; + } + return DefaultFontInfo.DEFAULT; + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/Message.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/Message.java new file mode 100644 index 00000000..730348ab --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/Message.java @@ -0,0 +1,204 @@ +package fr.maxlego08.essentials.api.messages; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public enum Message { + + // Rework message for a better system + + PREFIX("&8(&6zEssentials&8) "), + + TIME_DAY("%02d %day% %02d %hour% %02d %minute% %02d %second%"), + TIME_HOUR("%02d %hour% %02d minute(s) %02d %second%"), + TIME_MINUTE("%02d %minute% %02d %second%"), + TIME_SECOND("%02d %second%"), + + FORMAT_SECOND("second"), + FORMAT_SECONDS("seconds"), + + FORMAT_MINUTE("minute"), + FORMAT_MINUTES("minutes"), + + FORMAT_HOUR("hour"), + FORMAT_HOURS("hours"), + + FORMAT_DAY("d"), + FORMAT_DAYS("days"), + + COMMAND_SYNTAX_ERROR("&cYou must execute the command like this&7: &a%syntax%"), + COMMAND_NO_PERMISSION("&cYou do not have permission to run this command."), + COMMAND_NO_CONSOLE("&cOnly one player can execute this command."), + COMMAND_NO_ARG("&cImpossible to find the command with its arguments."), + COMMAND_SYNTAXE_HELP("&f%syntax% &7» &7%description%"), + + COMMAND_RELOAD("&aYou have just reloaded the configuration files."), + COMMAND_ESSENTIALS("zEssentials, version %version%"), + COMMAND_GAMEMODE("&fSet game mode&e %gamemode% &ffor &b%player%&f."), + COMMAND_GAMEMODE_INVALID("&cYou need to specify a valid player."), + COMMAND_DAY("&fYou have just brought &edaylight&f into the world &a%world%&f."), + COMMAND_NIGHT("&fYou have just brought &enightfall&f into the world &a%world%&f."), + COMMAND_SUN("&fYou have just brought the &esun&f into the world &a%world%&f."), + COMMAND_TOP("&7You've just been teleported to &etop&7."), + COMMAND_TOP_ERROR("&cUnable to find a position to transport you safely."), + COMMAND_SPEED_INVALID("&cYou need to specify a valid player."), + COMMAND_SPEED_FLY("&7You have just set your &nfly&r&7 speed to &f%speed%&7 for &f%player%&7. &8(&f2 &7by default&8)"), + COMMAND_SPEED_WALK("&7You have just set your &nwalk&r&7 speed to &f%speed%&7 for &f%player%&7. &8(&f2 &7by default&8)"), + COMMAND_SPEED_ERROR("&cYou must enter a number between &60&c and &610&c. &8(&f2 &7by default&8)"), + + COMMAND_GOD_ENABLE("&7God mode &aenable &7for &f%player%&a."), + COMMAND_GOD_DISABLE("&7God mode &cdisable &7for &f%player%&a."), + COMMAND_HEAL_SENDER("&7You just healed the player &f%player%&7."), + COMMAND_HEAL_RECEIVER("&aYou have been healed."), + COMMAND_HEAL_ERROR("&cYou cannot heal someone who is dead !"), + COMMAND_FEED_SENDER("&7You just feed the player &f%player%&7."), + COMMAND_FEED_RECEIVER("&aYou have been feed."), + COMMAND_FEED_ERROR("&cYou cannot feed someone who is dead !"), + + // Teleport Command + COMMAND_TPA_ERROR("&cYou have already sent a request to #34cfe0%player%&c."), + COMMAND_TPA_ERROR_SAME("&cYou cannot teleport to yourself."), + COMMAND_TPA_ERROR_OFFLINE("&cUnable to find player, must be offline."), + COMMAND_TPA_ERROR_TO_LATE_EMPTY("&cYou do not have a teleport request."), + COMMAND_TPA_ERROR_TO_LATE_EXPIRE("&cThe teleport request has expired."), + COMMAND_TPA_SENDER("&7You have just sent a teleport request to #34cfe0%player%&7."), + COMMAND_TPA_RECEIVER( + "&7You have just received a teleport request from #34cfe0%player%&7.", + "&7You have &c60 &6seconds&e to accept the teleport request.", + "&7To accept the request do #0EEA93/tpaccept&7." + ), + COMMAND_TPA_ACCEPT_RECEIVER("&aYou have just accepted the teleport request from #34cfe0%player%&a."), + COMMAND_TPA_ACCEPT_SENDER("#34cfe0%player%&a has just accepted your teleport request."), + COMMAND_TELEPORT_IGNORE_PLAYER("&cYou cannot send a teleport request to #34cfe0%player%&c they are ignoring you."), + COMMAND_TELEPORT_WORLD("&cYou need to be in the same world to teleport."), + COMMAND_TPA_ERROR_TO_LATE("&cYou do not have a teleport request."), + COMMAND_TPA_ERROR_TO_LATE_2("&cThe request has expired."), + COMMAND_TP_DENY_SENDER("Denied %player% teleport request."), + COMMAND_TP_DENY_RECEIVER("%player% has denied your teleport request"), + COMMAND_TP_CANCEL_ERROR("#ff0000You did not send a teleport request at &f%player%#ff0000."), + COMMAND_TP_CANCEL_SENDER("#ff0000Cancelled #99E0FFyour teleport request to %player%."), + COMMAND_TP_CANCEL_RECEIVER("&f%player% #ff0000cancelled their teleport request to you."), + COMMAND_TP("&7You just teleport to the player #34cfe0%player%&f."), + COMMAND_TP_SELF("&7You just teleported #34cfe0%player%&7 to your position."), + + COMMAND_MORE_ERROR("&cYou cannot make this order in item in hand."), + COMMAND_MORE_SUCCESS("&7You just put your item to &f64&7."), + COMMAND_WORLD_TELEPORT_SELF("&aYou have just been teleported into the world &f%world%&a."), + COMMAND_WORLD_TELEPORT_OTHER("&aYou just teleported the player &f%player% &ain the world &f%world%&a."), + + COMMAND_COMPACT_TYPE("&cImpossible to compact the material &f%material%&c."), + COMMAND_COMPACT_ERROR("&cYou have no &f%item%&c in your inventory."), + COMMAND_COMPACT_SUCCESS("&7You have just transformed #0EEA93x%amount% #34cfe0%item% &7en #0EEA93x%toAmount% #34cfe0%toItem%&7."), + COMMAND_HAT_SUCCESS("&7You just put #0ef0ce%item% &7on your head."), + COMMAND_HAT_ERROR("&cYou cannot put air on your head."), + COMMAND_PLAYER_WEATHER_RESET("&7You just changed the weather to that of the server."), + COMMAND_PLAYER_WEATHER_DOWNFALL("&7You just put the rain on for yourself."), + COMMAND_PLAYER_TIME_RESET("&7You just changed the time to that of the server."), + COMMAND_PLAYER_TIME_CHANGE("&7You’re here to change your time."), + + DESCRIPTION_RELOAD("Reload configuration files"), + DESCRIPTION_GAMEMODE("Change player gamemode"), + DESCRIPTION_GAMEMODE_CREATIVE("Change player gamemode to creative"), + DESCRIPTION_GAMEMODE_SURVIVAL("Change player gamemode to survival"), + DESCRIPTION_GAMEMODE_ADVENTURE("Change player gamemode to adventure"), + DESCRIPTION_GAMEMODE_SPECTATOR("Change player gamemode to spectator"), + DESCRIPTION_DAY("Set the day in your world"), + DESCRIPTION_NIGHT("Set the night in your world"), + DESCRIPTION_GOD("Toggle god mode"), + DESCRIPTION_HEAL("Heal a player"), + DESCRIPTION_SUN("Set the sun in your world"), + DESCRIPTION_ENDERCHEST("Open your enderchest"), + DESCRIPTION_ENDERSEE("Open a player enderchest"), + DESCRIPTION_TOP("Teleporting to top"), + DESCRIPTION_SPEED("Change player speed"), + DESCRIPTION_TPA("Teleport to a player"), + DESCRIPTION_TP("Teleport to a player"), + DESCRIPTION_TP_SELF("Teleport a player to your location"), + DESCRIPTION_TPA_ACCEPT("Accept a teleportation request"), + DESCRIPTION_TPA_DENY("Denied a teleportation request"), + DESCRIPTION_TPA_CANCEL("Cancel a teleportation request"), + DESCRIPTION_MORE("Get more items"), + DESCRIPTION_TP_WORLD("Teleport to another world"), + DESCRIPTION_TRASH("Open a trash can"), + DESCRIPTION_FEED("Feed a player"), + DESCRIPTION_CRAFT("Open workbrench"), + DESCRIPTION_ENCHANTING("Open enchantment table"), + DESCRIPTION_INVSEE("Open player's inventory"), + DESCRIPTION_COMPACT("Compact material"), + DESCRIPTION_HAT("Create your custom hat !"), + DESCRIPTION_PLAYER_WEATHER("Change your weather"), + DESCRIPTION_PLAYER_TIME("Change your time"), + DESCRIPTION_ECO("Manages the server economies"), + DESCRIPTION_ECO_SET("Sets the specified player's balance to the specified amount of money"), + DESCRIPTION_ECO_TAKE("Takes the specified amount of money from the specified player"), + DESCRIPTION_ECO_GIVE("Gives the specified player the specified amount of money"), + DESCRIPTION_ECO_RESET("Resets the specified player's balance to the server's starting balance"), + + YOU("you"), + TRASH("&8Trash"), + + // Teleportation + + TELEPORT_MOVE("&cYou must not move!"), + TELEPORT_MESSAGE(MessageType.ACTION, "&7Teleporting in #0EEA93%seconds% &7seconds, you must not move."), + TELEPORT_ERROR("&cYou already have a teleportation in progress!"), + TELEPORT_SUCCESS("&eYou have just teleported successfully!"), + TELEPORT_DAMAGE("&cYou must not take damage during teleportation."), + TELEPORT_ERROR_LOCATION("&cUnable to teleport you safely."), + + COOLDOWN("#ff0000✘ You must wait for &f%cooldown% #ff0000before performing this action."), + + // Economy + + COMMAND_ECONOMY_NOT_FOUND("#ff0000 Can’t find a economy with the name &f%name%#ff0000."), + COMMAND_ECONOMY_GIVE_SENDER("#99E0FFYou just gave &f%economyFormat% #99E0FFto the player &7%player%#99E0FF."), + COMMAND_ECONOMY_GIVE_RECEIVER("#99E0FFYou have just received &f%economyFormat%."), + COMMAND_ECONOMY_TAKE_SENDER("#99E0FFYou just take &f%economyFormat% #99E0FFto the player &7%player%#99E0FF."), + COMMAND_ECONOMY_TAKE_RECEIVER("#99E0FFYou have just lost &f%economyFormat%."), + ; + + private String message; + private List messages; + private MessageType messageType = MessageType.TCHAT; + + Message(String message) { + this.message = message; + this.messages = new ArrayList<>(); + } + + Message(MessageType messageType, String message) { + this.message = message; + this.messages = new ArrayList<>(); + this.messageType = messageType; + } + + Message(String... message) { + this.message = null; + this.messages = Arrays.asList(message); + } + + public String getMessage() { + return message; + } + + public List getMessages() { + return messages; + } + + public MessageType getMessageType() { + return messageType; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setMessages(List messages) { + this.messages = messages; + } + + public void setMessageType(MessageType messageType) { + this.messageType = messageType; + } +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/MessageType.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/MessageType.java new file mode 100644 index 00000000..050436f6 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/messages/MessageType.java @@ -0,0 +1,11 @@ +package fr.maxlego08.essentials.api.messages; + +public enum MessageType { + + ACTION, + TCHAT, + TITLE, + CENTER, + NONE, + +} \ No newline at end of file diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Loadable.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Loadable.java new file mode 100644 index 00000000..5ebf86d6 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Loadable.java @@ -0,0 +1,4 @@ +package fr.maxlego08.essentials.api.modules; + +public interface Loadable { +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Module.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Module.java new file mode 100644 index 00000000..57c23f05 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/Module.java @@ -0,0 +1,20 @@ +package fr.maxlego08.essentials.api.modules; + +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; + +public interface Module { + + String getName(); + + void loadConfiguration(); + + File getFolder(); + + YamlConfiguration getConfiguration(); + + boolean isEnable(); + + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/ModuleManager.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/ModuleManager.java new file mode 100644 index 00000000..95d3df39 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/modules/ModuleManager.java @@ -0,0 +1,15 @@ +package fr.maxlego08.essentials.api.modules; + +import java.io.File; + +public interface ModuleManager { + + void loadModules(); + + void loadConfigurations(); + + T getModule(Class module); + + File getFolder(); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/Placeholder.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/Placeholder.java new file mode 100644 index 00000000..91b12062 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/Placeholder.java @@ -0,0 +1,16 @@ +package fr.maxlego08.essentials.api.placeholders; + +import fr.maxlego08.essentials.api.functionnals.ReturnBiConsumer; +import fr.maxlego08.essentials.api.functionnals.ReturnConsumer; +import org.bukkit.entity.Player; + +public interface Placeholder { + + void register(String startWith, ReturnBiConsumer biConsumer); + + void register(String startWith, ReturnConsumer biConsumer); + + String getPrefix(); + + String onRequest(Player player, String params); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/PlaceholderRegister.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/PlaceholderRegister.java new file mode 100644 index 00000000..bdda7afe --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/placeholders/PlaceholderRegister.java @@ -0,0 +1,9 @@ +package fr.maxlego08.essentials.api.placeholders; + +import fr.maxlego08.essentials.api.EssentialsPlugin; + +public interface PlaceholderRegister { + + void register(Placeholder placeholder, EssentialsPlugin plugin); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DatabaseConfiguration.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DatabaseConfiguration.java new file mode 100644 index 00000000..80305fb9 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DatabaseConfiguration.java @@ -0,0 +1,10 @@ +package fr.maxlego08.essentials.api.storage; + +public record DatabaseConfiguration(String prefix, String user, String password, int port, String host, + String database, boolean debug) { + + public String replacePrefix(String tableName) { + return tableName.replaceAll("%prefix%", prefix); + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DiscUtils.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DiscUtils.java new file mode 100644 index 00000000..b1917b53 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/DiscUtils.java @@ -0,0 +1,137 @@ +package fr.maxlego08.essentials.api.storage; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; + +public class DiscUtils { + + // -------------------------------------------- // + // CONSTANTS + // -------------------------------------------- // + + private final static String UTF8 = "UTF-8"; + + // -------------------------------------------- // + // BYTE + // -------------------------------------------- // + + public static byte[] readBytes(File file) throws IOException { + int length = (int) file.length(); + byte[] output = new byte[length]; + InputStream in = new FileInputStream(file); + int offset = 0; + while (offset < length) { + offset += in.read(output, offset, (length - offset)); + } + in.close(); + return output; + } + + public static void writeBytes(File file, byte[] bytes) throws IOException { + FileOutputStream out = new FileOutputStream(file); + out.write(bytes); + out.close(); + } + + // -------------------------------------------- // + // STRING + // -------------------------------------------- // + + public static void write(File file, String content) throws IOException { + writeBytes(file, utf8(content)); + } + + public static String read(File file) throws IOException { + return utf8(readBytes(file)); + } + + // -------------------------------------------- // + // CATCH + // -------------------------------------------- // + + public static boolean writeCatch(File file, String content) { + try { + write(file, content); + return true; + } catch (Exception e) { + return false; + } + } + + public static String readCatch(File file) { + try { + return read(file); + } catch (IOException e) { + return null; + } + } + + // -------------------------------------------- // + // DOWNLOAD + // -------------------------------------------- // + + public static boolean downloadUrl(String urlstring, File file) { + try { + URL url = new URL(urlstring); + ReadableByteChannel rbc = Channels.newChannel(url.openStream()); + @SuppressWarnings("resource") + FileOutputStream fos = new FileOutputStream(file); + fos.getChannel().transferFrom(rbc, 0, 1 << 24); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public static boolean downloadUrl(String urlstring, String filename) { + return downloadUrl(urlstring, new File(filename)); + } + + // -------------------------------------------- // + // FILE DELETION + // -------------------------------------------- // + + public static boolean deleteRecursive(File path) throws FileNotFoundException { + if (!path.exists()) + throw new FileNotFoundException(path.getAbsolutePath()); + boolean ret = true; + if (path.isDirectory()) { + for (File f : path.listFiles()) { + ret = ret && deleteRecursive(f); + } + } + return ret && path.delete(); + } + + // -------------------------------------------- // + // UTF8 ENCODE AND DECODE + // -------------------------------------------- // + + public static byte[] utf8(String string) { + try { + return string.getBytes(UTF8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + public static String utf8(byte[] bytes) { + try { + return new String(bytes, UTF8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Folder.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Folder.java new file mode 100644 index 00000000..0522d594 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Folder.java @@ -0,0 +1,14 @@ +package fr.maxlego08.essentials.api.storage; + +public enum Folder { + + USERS, + + ; + + + public String toFolder(){ + return name().toLowerCase(); + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/IStorage.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/IStorage.java new file mode 100644 index 00000000..d4fa517c --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/IStorage.java @@ -0,0 +1,30 @@ +package fr.maxlego08.essentials.api.storage; + +import fr.maxlego08.essentials.api.economy.Economy; +import fr.maxlego08.essentials.api.user.Option; +import fr.maxlego08.essentials.api.user.User; + +import java.math.BigDecimal; +import java.util.UUID; +import java.util.function.Consumer; + +public interface IStorage { + + void onEnable(); + + void onDisable(); + + User createOrLoad(UUID uniqueId, String playerName); + + void onPlayerQuit(UUID uniqueId); + + User getUser(UUID uniqueId); + + void updateOption(UUID uniqueId, Option option, boolean value); + + void updateCooldown(UUID uniqueId, String key, long expiredAt); + + void updateEconomy(UUID uniqueId, Economy economy, BigDecimal bigDecimal); + + void updateUserMoney(UUID uniqueId, Consumer consumer); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Persist.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Persist.java new file mode 100644 index 00000000..feae5af8 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/Persist.java @@ -0,0 +1,182 @@ +package fr.maxlego08.essentials.api.storage; + + +import fr.maxlego08.essentials.api.EssentialsPlugin; + +import java.io.File; +import java.lang.reflect.Type; + +public class Persist { + + private EssentialsPlugin plugin; + + public Persist(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + // ------------------------------------------------------------ // + // GET NAME - What should we call this type of object? + // ------------------------------------------------------------ // + + public static String getName(Class clazz) { + return clazz.getSimpleName().toLowerCase(); + } + + public static String getName(Object o) { + return getName(o.getClass()); + } + + public static String getName(Type type) { + return getName(type.getClass()); + } + + // ------------------------------------------------------------ // + // GET FILE - In which file would we like to store this object? + // ------------------------------------------------------------ // + + public File getFile(String name) { + return new File(plugin.getDataFolder(), name + ".json"); + } + + public File getFile(Class clazz) { + return getFile(getName(clazz)); + } + + public File getFile(Object obj) { + return getFile(getName(obj)); + } + + public File getFile(Type type) { + return getFile(getName(type)); + } + + // NICE WRAPPERS + + public T loadOrSaveDefault(T def, Class clazz) { + return loadOrSaveDefault(def, clazz, getFile(clazz)); + } + + public T loadOrSaveDefault(T def, Class clazz, String name) { + return loadOrSaveDefault(def, clazz, getFile(name)); + } + + public T loadOrSaveDefault(T def, Class clazz, Folder folder, String name) { + return loadOrSaveDefault(def, clazz, getFile(folder.toFolder() + File.separator + name)); + } + + public T loadOrSaveDefault(T def, Class clazz, File file) { + if (!file.exists()) { + plugin.getLogger().info("Creating default: " + file); + this.save(def, file); + return def; + } + + T loaded = this.load(clazz, file); + + if (loaded == null) { + plugin.getLogger().info("Using default as I failed to load: " + file); + + /* + * Create new config backup + */ + + File backup = new File(file.getPath() + "_bad"); + if (backup.exists()) + backup.delete(); + plugin.getLogger().info("Backing up copy of bad file to: " + backup); + + file.renameTo(backup); + + return def; + } else { + + plugin.getLogger().info(file.getAbsolutePath() + " loaded successfully !"); + + } + + return loaded; + } + + // SAVE + + public boolean save(Object instance) { + return save(instance, getFile(instance)); + } + + public boolean save(Object instance, String name) { + return save(instance, getFile(name)); + } + + public boolean save(Object instance, Folder folder, String name) { + return save(instance, getFile(folder.toFolder() + File.separator + name)); + } + + public boolean save(Object instance, File file) { + + try { + + boolean result = DiscUtils.writeCatch(file, plugin.getGson().toJson(instance)); + plugin.getLogger().info(file.getAbsolutePath() + " successfully saved !"); + return result; + + } catch (Exception exception) { + + plugin.getLogger().info("cannot save file " + file.getAbsolutePath()); + exception.printStackTrace(); + return false; + } + } + + // LOAD BY CLASS + + public T load(Class clazz) { + return load(clazz, getFile(clazz)); + } + + public T load(Class clazz, String name) { + return load(clazz, getFile(name)); + } + + public T load(Class clazz, File file) { + String content = DiscUtils.readCatch(file); + if (content == null) { + return null; + } + + try { + T instance = plugin.getGson().fromJson(content, clazz); + return instance; + } catch (Exception ex) { // output the error message rather than full + // stack trace; error parsing the file, most + // likely + plugin.getLogger().info(ex.getMessage()); + } + + return null; + } + + // LOAD BY TYPE + @SuppressWarnings("unchecked") + public T load(Type typeOfT, String name) { + return (T) load(typeOfT, getFile(name)); + } + + @SuppressWarnings("unchecked") + public T load(Type typeOfT, File file) { + String content = DiscUtils.readCatch(file); + if (content == null) { + return null; + } + + try { + return (T) plugin.getGson().fromJson(content, typeOfT); + } catch (Exception ex) { // output the error message rather than full + // stack trace; error parsing the file, most + // likely + plugin.getLogger().info(ex.getMessage()); + } + + return null; + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageManager.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageManager.java new file mode 100644 index 00000000..0b288b9d --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageManager.java @@ -0,0 +1,15 @@ +package fr.maxlego08.essentials.api.storage; + +import org.bukkit.event.Listener; + +public interface StorageManager extends Listener { + + void onEnable(); + + void onDisable(); + + IStorage getStorage(); + + StorageType getType(); + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageType.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageType.java new file mode 100644 index 00000000..f0586003 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/StorageType.java @@ -0,0 +1,8 @@ +package fr.maxlego08.essentials.api.storage; + +public enum StorageType { + + JSON, + MYSQL, + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/adapter/LocationAdapter.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/adapter/LocationAdapter.java new file mode 100644 index 00000000..02b2e8f4 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/storage/adapter/LocationAdapter.java @@ -0,0 +1,75 @@ +package fr.maxlego08.essentials.api.storage.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +public class LocationAdapter extends TypeAdapter { + + private static final Type seriType = new TypeToken>() { + }.getType(); + private static final String NAME = "name"; + private static final String X = "x"; + private static final String Y = "y"; + private static final String Z = "z"; + private static final String YAW = "yaw"; + private static final String PITCH = "pitch"; + private final EssentialsPlugin plugin; + + /** + * @param plugin + */ + public LocationAdapter(EssentialsPlugin plugin) { + super(); + this.plugin = plugin; + } + + @Override + public void write(JsonWriter jsonWriter, Location location) throws IOException { + if (location == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.value(getRaw(location)); + } + + @Override + public Location read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + return fromRaw(jsonReader.nextString()); + } + + private String getRaw(Location location) { + Map serial = new HashMap<>(); + serial.put(NAME, location.getWorld().getName()); + serial.put(X, Double.toString(location.getX())); + serial.put(Y, Double.toString(location.getY())); + serial.put(Z, Double.toString(location.getZ())); + serial.put(YAW, Float.toString(location.getYaw())); + serial.put(PITCH, Float.toString(location.getPitch())); + return plugin.getGson().toJson(serial); + } + + private Location fromRaw(String raw) { + Map keys = this.plugin.getGson().fromJson(raw, seriType); + World w = Bukkit.getWorld((String) keys.get(NAME)); + return new Location(w, Double.parseDouble((String) keys.get(X)), Double.parseDouble((String) keys.get(Y)), + Double.parseDouble((String) keys.get(Z)), Float.parseFloat((String) keys.get(YAW)), + Float.parseFloat((String) keys.get(PITCH))); + } + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/Option.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/Option.java new file mode 100644 index 00000000..1fcdb249 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/Option.java @@ -0,0 +1,9 @@ +package fr.maxlego08.essentials.api.user; + +public enum Option { + + SOCIAL_PSY, + GOD, + MESSAGE_DISABLE, INVSEE, + +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/TeleportRequest.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/TeleportRequest.java new file mode 100644 index 00000000..6d9b82a2 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/TeleportRequest.java @@ -0,0 +1,16 @@ +package fr.maxlego08.essentials.api.user; + +public interface TeleportRequest { + + User getToUser(); + + User getFromUser(); + + long getExpiredAt(); + + boolean isValid(); + + void accept(); + + void deny(); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/User.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/User.java new file mode 100644 index 00000000..5a8b161c --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/user/User.java @@ -0,0 +1,85 @@ +package fr.maxlego08.essentials.api.user; + +import fr.maxlego08.essentials.api.commands.Permission; +import fr.maxlego08.essentials.api.database.dto.CooldownDTO; +import fr.maxlego08.essentials.api.database.dto.OptionDTO; +import fr.maxlego08.essentials.api.economy.Economy; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public interface User { + + UUID getUniqueId(); + + String getName(); + + void setName(String name); + + void sendTeleportRequest(User targetUser); + + void cancelTeleportRequest(User targetUser); + + Player getPlayer(); + + boolean isOnline(); + + boolean isIgnore(UUID uniqueId); + + TeleportRequest getTeleportRequest(); + + void setTeleportRequest(TeleportRequest teleportRequest); + + Collection getTeleportRequests(); + + void removeTeleportRequest(User user); + + void teleport(Location location); + + boolean hasPermission(Permission permission); + + User getTargetUser(); + + void setTargetUser(User user); + + boolean getOption(Option option); + + void setOption(Option option, boolean value); + + void setOptions(List options); + + Map getOptions(); + + Map getCooldowns(); + + void setCooldown(String key, long expiredAt); + + void setCooldowns(List cooldowns); + + boolean isCooldown(String key); + + long getCooldown(String key); + + long getCooldownSeconds(String key); + + void addCooldown(String key, long seconds); + + BigDecimal getBalance(Economy economy); + + boolean has(Economy economy, BigDecimal bigDecimal); + + void set(Economy economy, BigDecimal bigDecimal); + + void withdraw(Economy economy, BigDecimal bigDecimal); + + void deposit(Economy economy, BigDecimal bigDecimal); + + Map getBalances(); + + void setBalance(String key, BigDecimal value); +} diff --git a/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/utils/CompactMaterial.java b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/utils/CompactMaterial.java new file mode 100644 index 00000000..d04b0fc7 --- /dev/null +++ b/EssentialsApi/src/main/java/fr/maxlego08/essentials/api/utils/CompactMaterial.java @@ -0,0 +1,7 @@ +package fr.maxlego08.essentials.api.utils; + +import fr.maxlego08.essentials.api.modules.Loadable; +import org.bukkit.Material; + +public record CompactMaterial(Material from, Material to) implements Loadable { +} diff --git a/Hooks/Vault/.gitignore b/Hooks/Vault/.gitignore new file mode 100644 index 00000000..b63da455 --- /dev/null +++ b/Hooks/Vault/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/Hooks/Vault/build.gradle b/Hooks/Vault/build.gradle new file mode 100644 index 00000000..39e18b8b --- /dev/null +++ b/Hooks/Vault/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'java' +} + +repositories { + maven { url 'https://jitpack.io' } +} +dependencies { + compileOnly "com.github.MilkBowl:VaultAPI:1.7" + compileOnly project(':EssentialsApi') +} \ No newline at end of file diff --git a/Hooks/Vault/src/main/java/fr/maxlego08/essentials/hooks/VaultEconomy.java b/Hooks/Vault/src/main/java/fr/maxlego08/essentials/hooks/VaultEconomy.java new file mode 100644 index 00000000..db8829d7 --- /dev/null +++ b/Hooks/Vault/src/main/java/fr/maxlego08/essentials/hooks/VaultEconomy.java @@ -0,0 +1,245 @@ +package fr.maxlego08.essentials.hooks; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.economy.EconomyResponse; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.plugin.ServicePriority; + +import java.math.BigDecimal; +import java.util.List; + +public class VaultEconomy implements Economy { + + private final EssentialsPlugin essentialsPlugin; + + public VaultEconomy(EssentialsPlugin essentialsPlugin) { + this.essentialsPlugin = essentialsPlugin; + Bukkit.getServer().getServicesManager().register(Economy.class, this, this.essentialsPlugin, ServicePriority.Normal); + } + + private fr.maxlego08.essentials.api.economy.Economy getEconomy() { + return this.essentialsPlugin.getEconomyProvider().getDefaultEconomy(); + } + + @Override + public boolean isEnabled() { + return essentialsPlugin.isEconomyEnable(); + } + + @Override + public String getName() { + return "zEssentials Economy"; + } + + @Override + public boolean hasBankSupport() { + return false; + } + + @Override + public int fractionalDigits() { + return -1; + } + + @Override + public String format(double amount) { + return getEconomy().format(this.essentialsPlugin.getEconomyProvider().format(amount), (long) amount); + } + + @Override + public String currencyNamePlural() { + return null; + } + + @Override + public String currencyNameSingular() { + return null; + } + + @Override + public boolean hasAccount(String playerName) { + return false; + } + + @Override + public boolean hasAccount(OfflinePlayer player) { + return false; + } + + @Override + public boolean hasAccount(String playerName, String worldName) { + return false; + } + + @Override + public boolean hasAccount(OfflinePlayer player, String worldName) { + return false; + } + + @Override + public double getBalance(String playerName) { + return 0; + } + + @Override + public double getBalance(OfflinePlayer player) { + return 0; + } + + @Override + public double getBalance(String playerName, String world) { + return 0; + } + + @Override + public double getBalance(OfflinePlayer player, String world) { + return 0; + } + + @Override + public boolean has(String playerName, double amount) { + return false; + } + + @Override + public boolean has(OfflinePlayer player, double amount) { + return false; + } + + @Override + public boolean has(String playerName, String worldName, double amount) { + return false; + } + + @Override + public boolean has(OfflinePlayer player, String worldName, double amount) { + return false; + } + + @Override + public EconomyResponse withdrawPlayer(String playerName, double amount) { + return null; + } + + @Override + public EconomyResponse withdrawPlayer(OfflinePlayer player, double amount) { + return null; + } + + @Override + public EconomyResponse withdrawPlayer(String playerName, String worldName, double amount) { + return null; + } + + @Override + public EconomyResponse withdrawPlayer(OfflinePlayer player, String worldName, double amount) { + return null; + } + + @Override + public EconomyResponse depositPlayer(String playerName, double amount) { + return null; + } + + @Override + public EconomyResponse depositPlayer(OfflinePlayer player, double amount) { + return null; + } + + @Override + public EconomyResponse depositPlayer(String playerName, String worldName, double amount) { + return null; + } + + @Override + public EconomyResponse depositPlayer(OfflinePlayer player, String worldName, double amount) { + return null; + } + + @Override + public EconomyResponse createBank(String name, String player) { + return null; + } + + @Override + public EconomyResponse createBank(String name, OfflinePlayer player) { + return null; + } + + @Override + public EconomyResponse deleteBank(String name) { + return null; + } + + @Override + public EconomyResponse bankBalance(String name) { + return null; + } + + @Override + public EconomyResponse bankHas(String name, double amount) { + return null; + } + + @Override + public EconomyResponse bankWithdraw(String name, double amount) { + return null; + } + + @Override + public EconomyResponse bankDeposit(String name, double amount) { + return null; + } + + @Override + public EconomyResponse isBankOwner(String name, String playerName) { + return null; + } + + @Override + public EconomyResponse isBankOwner(String name, OfflinePlayer player) { + return null; + } + + @Override + public EconomyResponse isBankMember(String name, String playerName) { + return null; + } + + @Override + public EconomyResponse isBankMember(String name, OfflinePlayer player) { + return null; + } + + @Override + public List getBanks() { + return null; + } + + @Override + public boolean createPlayerAccount(String playerName) { + return false; + } + + @Override + public boolean createPlayerAccount(OfflinePlayer player) { + return false; + } + + @Override + public boolean createPlayerAccount(String playerName, String worldName) { + return false; + } + + @Override + public boolean createPlayerAccount(OfflinePlayer player, String worldName) { + return false; + } + + private double getDoubleValue(final BigDecimal value) { + double amount = value.doubleValue(); + return new BigDecimal(amount).compareTo(value) > 0 ? Math.nextAfter(amount, Double.NEGATIVE_INFINITY) : amount; + } +} diff --git a/build.gradle b/build.gradle index a2414ec2..73120639 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,10 @@ plugins { id 'java' + id("com.dorongold.task-tree") version "2.1.1" } group = 'fr.maxlego08.essentials' -version = '1.0.0' +version = property('version') def targetJavaVersion = 17 java { @@ -15,6 +16,12 @@ java { } } +compileJava.options.encoding = 'UTF-8' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + tasks.withType(JavaCompile).configureEach { if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { options.release = targetJavaVersion @@ -34,7 +41,7 @@ subprojects { apply plugin: 'java' group = 'fr.maxlego08.essentials' - version = '1.0.0' + version = property('version') repositories { mavenCentral() @@ -43,13 +50,27 @@ subprojects { name = "devmart-other" url = "https://nexuslite.gcnt.net/repos/other/" } + maven { url 'https://jitpack.io' } + maven {url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/'} } dependencies { implementation "com.tcoded:FoliaLib:0.3.1" compileOnly 'io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT' + compileOnly 'com.github.Maxlego08:zMenu-API:1.0.2.9' + compileOnly 'me.clip:placeholderapi:2.11.5' testImplementation 'junit:junit:4.12' } -} \ No newline at end of file +} + +tasks.register("buildAll") { + group = "essentials" + description = "Build all Essentials related plugins" + dependsOn( + ":EssentialsApi:build", + ":Hooks:Vault:build", + ":Essentials:build" + ) +} diff --git a/gradle.properties b/gradle.properties index e69de29b..02339e6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -0,0 +1,2 @@ +version=1.0.0 +systemProp.file.encoding=utf-8 \ No newline at end of file diff --git a/readme.md b/readme.md index b9a86ce0..60c30587 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,79 @@ # zEssentials -zEssentials takes the concept of the Essentials plugin but thought to be used with Folia and Paper. \ No newline at end of file +zEssentials takes the concept of the Essentials plugin but thought to be used with Folia and Paper. + +# ToDo + +- [ ] Command /sethome (limit by grade/permission) +- [ ] Command /delhome +- [ ] Command /home (as gui or not) + +- [ ] Command /tpall +- [ ] Command /tpaall +- [x] Command /tpa +- [x] Command /tp +- [x] Command /tphere +- [x] Command /tpyes (alias: tpaccept) +- [x] Command /tpno (alias: tpcancel) +- [ ] Command /tpahere + +- [x] Command /hat +- [x] Command /top +- [ ] Command /repair all & hand (ability to set custom cooldown by grade/permission) +- [x] Command /compact +- [x] Command /trash +- [x] Command /ec (alias: enderchest) +- [x] Command /endersee +- [ ] Command /ext +- [ ] Command /near (ability to set custom radius by grade/permission) +- [x] Command /craft +- [ ] Command /anvil +- [ ] Command /back +- [x] Command /feed + +- [x] Command /gm 1, gm0, gm3 +- [x] Command /speed <1;2;3….> +- [ ] Command /bc (alias: broadcast) +- [ ] Command /list +- [x] Command /invsee +- [ ] Command /kill +- [ ] Command /enchant +- [ ] Command /give +- [ ] Command /fly +- [x] Command /god +- [ ] Command /skull +- [ ] Command /ci +- [ ] Command /itemdb +- [ ] Command /exp give, set, show +- [ ] Command /playtime +- [ ] Command /spawner +- [x] Command /weather +- [ ] Command /seen, whois +- [ ] Command /vanish +- [x] Command /time +- [x] Command /pweather +- [x] Command /ptime +- [x] Command /heal + +- [ ] Command /setwarp +- [ ] Command /delwarp +- [ ] Command /warp + +- [ ] Command /msg +- [ ] Command /msgtoggle +- [ ] Command /socialspy + +- [ ] Command /paytoggle +- [ ] Command /balancetop (alias: baltop) +- [ ] Command /balance (alias: money) +- [ ] Command /eco give, take, set,reset +- [ ] Command /pay + +- [ ] Command /createkit +- [ ] Command /kitreset +- [ ] Command /deletekit +- [ ] Command /kit (as gui or not) +- [ ] Command /showkit (Preview kit as gui) + +- [ ] Command /setspawn +- [ ] Command /spawn diff --git a/settings.gradle b/settings.gradle index 63fdc5c7..fc51da7b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,8 @@ include('Essentials') project(':Essentials').projectDir = file("Essentials") include('EssentialsChat') -project(':EssentialsChat').projectDir = file("EssentialsChat") \ No newline at end of file +project(':EssentialsChat').projectDir = file("EssentialsChat") + +include 'Hooks:Vault' +project(':Hooks:Vault').projectDir = file("Hooks/Vault") +