From d2600d980540da124fb1745c40f989e9a588d431 Mon Sep 17 00:00:00 2001 From: BlitzOffline <52609756+BlitzOffline@users.noreply.github.com> Date: Fri, 17 Apr 2026 03:20:33 +0300 Subject: [PATCH 1/2] Refactor --- .gitignore | 1 + .../extendedclip/deluxemenus/DeluxeMenus.java | 69 ++- .../action/ClickActionExecutor.java | 468 ++++++++++++++++++ .../deluxemenus/action/ClickActionTask.java | 453 +---------------- .../deluxemenus/hooks/BaseHeadHook.java | 7 +- .../deluxemenus/hooks/CraftEngineHook.java | 6 +- .../hooks/ExecutableBlocksHook.java | 7 +- .../hooks/ExecutableItemsHook.java | 7 +- .../deluxemenus/hooks/ItemStackCache.java | 38 ++ .../deluxemenus/hooks/ItemsAdderHook.java | 7 +- .../deluxemenus/hooks/MMOItemsHook.java | 6 +- .../deluxemenus/hooks/NamedHeadHook.java | 7 +- .../deluxemenus/hooks/NexoHook.java | 7 +- .../deluxemenus/hooks/OraxenHook.java | 7 +- .../hooks/SimpleItemGeneratorHook.java | 6 +- .../deluxemenus/hooks/TextureHeadHook.java | 7 +- .../deluxemenus/listener/ClickDebouncer.java | 37 ++ .../deluxemenus/listener/PlayerListener.java | 19 +- 18 files changed, 607 insertions(+), 552 deletions(-) create mode 100644 src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java create mode 100644 src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java create mode 100644 src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java diff --git a/.gitignore b/.gitignore index a73dd02a..3a64ad69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .gradle .idea +.vscode build test-server/ \ No newline at end of file diff --git a/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java b/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java index a5b4b354..c22983ce 100644 --- a/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java +++ b/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java @@ -37,6 +37,7 @@ import java.util.*; import java.util.function.Function; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; @@ -255,50 +256,44 @@ private void setUpItemHooks() { final NamedHeadHook namedHeadHook = new NamedHeadHook(this); namedHeadHook.register(); - this.itemHooks.put(HeadType.NAMED.getHookName(), namedHeadHook); - this.itemHooks.put(HeadType.BASE64.getHookName(), new BaseHeadHook(this)); - this.itemHooks.put(HeadType.TEXTURE.getHookName(), new TextureHeadHook(this)); - - if (Bukkit.getPluginManager().isPluginEnabled("HeadDatabase")) { - try { - Class.forName("me.arcaniax.hdb.api.HeadDatabaseAPI"); - this.itemHooks.put(HeadType.HDB.getHookName(), new HeadDatabaseHook(this)); - } catch (ClassNotFoundException ignored) { - // We are looking for this specific class because we've had issues with other plugins being named HeadDatabase - // in the past - } - } - - if (Bukkit.getPluginManager().isPluginEnabled("CraftEngine")) { - this.itemHooks.put("craftengine", new CraftEngineHook()); - } - - if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) { - this.itemHooks.put("itemsadder", new ItemsAdderHook()); - } - - if (Bukkit.getPluginManager().isPluginEnabled("Nexo")) { - this.itemHooks.put("nexo", new NexoHook()); - } + registerItemHook(HeadType.NAMED.getHookName(), namedHeadHook); + registerItemHook(HeadType.BASE64.getHookName(), new BaseHeadHook(this)); + registerItemHook(HeadType.TEXTURE.getHookName(), new TextureHeadHook(this)); + + registerHeadDatabaseHook(); + registerItemHookIfEnabled("CraftEngine", "craftengine", CraftEngineHook::new); + registerItemHookIfEnabled("ItemsAdder", "itemsadder", ItemsAdderHook::new); + registerItemHookIfEnabled("Nexo", "nexo", NexoHook::new); + registerItemHookIfEnabled("Oraxen", "oraxen", OraxenHook::new); + registerItemHookIfEnabled("MMOItems", "mmoitems", () -> new MMOItemsHook(this)); + registerItemHookIfEnabled("ExecutableItems", "executableitems", ExecutableItemsHook::new); + registerItemHookIfEnabled("ExecutableBlocks", "executableblocks", ExecutableBlocksHook::new); + registerItemHookIfEnabled("SimpleItemGenerator", "simpleitemgenerator", () -> new SimpleItemGeneratorHook(this)); + } - if (Bukkit.getPluginManager().isPluginEnabled("Oraxen")) { - this.itemHooks.put("oraxen", new OraxenHook()); - } + private void registerItemHook(@NotNull final String hookName, @NotNull final ItemHook itemHook) { + this.itemHooks.put(hookName, itemHook); + } - if (Bukkit.getPluginManager().isPluginEnabled("MMOItems")) { - this.itemHooks.put("mmoitems", new MMOItemsHook(this)); + private void registerItemHookIfEnabled(@NotNull final String pluginName, @NotNull final String hookName, @NotNull final Supplier itemHookSupplier) { + if (!Bukkit.getPluginManager().isPluginEnabled(pluginName)) { + return; } - if (Bukkit.getPluginManager().isPluginEnabled("ExecutableItems")) { - this.itemHooks.put("executableitems", new ExecutableItemsHook()); - } + registerItemHook(hookName, itemHookSupplier.get()); + } - if (Bukkit.getPluginManager().isPluginEnabled("ExecutableBlocks")) { - this.itemHooks.put("executableblocks", new ExecutableBlocksHook()); + private void registerHeadDatabaseHook() { + if (!Bukkit.getPluginManager().isPluginEnabled("HeadDatabase")) { + return; } - if (Bukkit.getPluginManager().isPluginEnabled("SimpleItemGenerator")) { - this.itemHooks.put("simpleitemgenerator", new SimpleItemGeneratorHook(this)); + try { + Class.forName("me.arcaniax.hdb.api.HeadDatabaseAPI"); + registerItemHook(HeadType.HDB.getHookName(), new HeadDatabaseHook(this)); + } catch (ClassNotFoundException ignored) { + // We are looking for this specific class because we've had issues with other plugins being named HeadDatabase + // in the past } } diff --git a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java new file mode 100644 index 00000000..1657eedf --- /dev/null +++ b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java @@ -0,0 +1,468 @@ +package com.extendedclip.deluxemenus.action; + +import com.extendedclip.deluxemenus.DeluxeMenus; +import com.extendedclip.deluxemenus.menu.Menu; +import com.extendedclip.deluxemenus.menu.MenuHolder; +import com.extendedclip.deluxemenus.persistentmeta.PersistentMetaHandler; +import com.extendedclip.deluxemenus.utils.AdventureUtils; +import com.extendedclip.deluxemenus.utils.DebugLevel; +import com.extendedclip.deluxemenus.utils.ExpUtils; +import com.extendedclip.deluxemenus.utils.SoundUtils; +import com.extendedclip.deluxemenus.utils.StringUtils; +import com.extendedclip.deluxemenus.utils.VersionHelper; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Level; + +final class ClickActionExecutor { + + private final DeluxeMenus plugin; + private final Player player; + private final Optional holder; + private final ActionType actionType; + private final String executable; + + ClickActionExecutor( + @NotNull final DeluxeMenus plugin, + @NotNull final Player player, + @NotNull final Optional holder, + @NotNull final ActionType actionType, + @NotNull final String executable + ) { + this.plugin = plugin; + this.player = player; + this.holder = holder; + this.actionType = actionType; + this.executable = executable; + } + + void execute() { + switch (actionType) { + case META: + executeMetaAction(); + break; + case PLAYER: + case PLAYER_COMMAND_EVENT: + player.chat("/" + executable); + break; + case PLACEHOLDER: + holder.ifPresent(value -> value.setPlaceholders(executable)); + break; + case CHAT: + player.chat(executable); + break; + case CONSOLE: + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), executable); + break; + case MINI_MESSAGE: + plugin.audiences().player(player).sendMessage(MiniMessage.miniMessage().deserialize(executable)); + break; + case MINI_BROADCAST: + plugin.audiences().all().sendMessage(MiniMessage.miniMessage().deserialize(executable)); + break; + case MESSAGE: + player.sendMessage(StringUtils.color(executable)); + break; + case LOG: + executeLogAction(); + break; + case BROADCAST: + Bukkit.broadcastMessage(StringUtils.color(executable)); + break; + case CLOSE: + Menu.closeMenu(plugin, player, true, true); + break; + case OPEN_GUI_MENU: + case OPEN_MENU: + executeOpenMenuAction(); + break; + case CONNECT: + plugin.connect(player, executable); + break; + case JSON_MESSAGE: + AdventureUtils.sendJson(plugin, player, executable); + break; + case JSON_BROADCAST: + case BROADCAST_JSON: + plugin.audiences().all().sendMessage(AdventureUtils.fromJson(executable)); + break; + case REFRESH: + executeRefreshAction(); + break; + case TAKE_MONEY: + executeMoneyAction(false); + break; + case GIVE_MONEY: + executeMoneyAction(true); + break; + case TAKE_EXP: + case GIVE_EXP: + executeExperienceAction(); + break; + case GIVE_PERM: + executePermissionAction(true); + break; + case TAKE_PERM: + executePermissionAction(false); + break; + case BROADCAST_SOUND: + case BROADCAST_RAW_SOUND: + case BROADCAST_WORLD_SOUND: + case BROADCAST_WORLD_RAW_SOUND: + case PLAY_RAW_SOUND: + case PLAY_SOUND: + executeSoundAction(); + break; + default: + break; + } + } + + private void executeMetaAction() { + if (!VersionHelper.IS_PDC_VERSION || plugin.getPersistentMetaHandler() == null) { + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Meta action not supported on this server version."); + return; + } + + final PersistentMetaHandler.OperationResult result = plugin.getPersistentMetaHandler().parseAndExecuteMetaActionFromString(player, executable); + switch (result) { + case INVALID_SYNTAX: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Make sure you have the right syntax."); + break; + case NEW_VALUE_IS_DIFFERENT_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! New value is a different type than the old value!"); + break; + case INVALID_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! The specified type is not supported for the specified action!"); + break; + case EXISTENT_VALUE_IS_DIFFERENT_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Existent value is a different type than the new value!"); + break; + case VALUE_NOT_FOUND: + case SUCCESS: + default: + break; + } + } + + private void executeLogAction() { + final String[] logParts = executable.split(" ", 2); + + if (logParts.length == 0 || logParts[0].isBlank()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "LOG command requires at least a message"); + return; + } + + Level logLevel; + String message; + + if (logParts.length == 1) { + logLevel = Level.INFO; + message = logParts[0]; + } else { + message = logParts[1]; + + try { + logLevel = Level.parse(logParts[0].toUpperCase()); + } catch (IllegalArgumentException exception) { + logLevel = Level.INFO; + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Log level " + logParts[0] + " is not a valid log level! Using INFO instead."); + } + } + + plugin.getLogger().log(logLevel, String.format("[%s]: %s", holder.map(MenuHolder::getMenuName).orElse("Unknown Menu"), message)); + } + + private void executeOpenMenuAction() { + final String temporaryExecutable = executable.replaceAll("\\s+", " ").replace(" ", " "); + final String[] executableParts = temporaryExecutable.split(" ", 2); + + if (executableParts.length == 0) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); + return; + } + + final String menuName = executableParts[0]; + final Optional optionalMenuToOpen = Menu.getMenuByName(menuName); + + if (optionalMenuToOpen.isEmpty()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); + return; + } + + final Menu menuToOpen = optionalMenuToOpen.get(); + final List menuArgumentNames = menuToOpen.options().arguments(); + + String[] passedArgumentValues = null; + if (executableParts.length > 1) { + passedArgumentValues = executableParts[1].split(" "); + } + + if (menuArgumentNames.isEmpty()) { + if (passedArgumentValues != null && passedArgumentValues.length > 0) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Arguments were given for menu " + menuName + " in action [openguimenu] or [openmenu], but the menu does not support arguments!" + ); + } + + openMenuWithCurrentArguments(menuToOpen); + return; + } + + if (passedArgumentValues == null || passedArgumentValues.length == 0) { + openMenuWithCurrentArguments(menuToOpen); + return; + } + + if (passedArgumentValues.length < menuArgumentNames.size()) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" + ); + return; + } + + final Map argumentsMap = new HashMap<>(); + if (holder.isPresent() && holder.get().getTypedArgs() != null) { + argumentsMap.putAll(holder.get().getTypedArgs()); + } + + for (int index = 0; index < menuArgumentNames.size(); index++) { + final String argumentName = menuArgumentNames.get(index); + + if (passedArgumentValues.length <= index) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" + ); + break; + } + + if (menuArgumentNames.size() == index + 1) { + final String lastArgumentValue = String.join(" ", Arrays.asList(passedArgumentValues).subList(index, passedArgumentValues.length)); + argumentsMap.put(argumentName, lastArgumentValue); + break; + } + + argumentsMap.put(argumentName, passedArgumentValues[index]); + } + + if (holder.isEmpty()) { + menuToOpen.openMenu(player, argumentsMap, null); + return; + } + + menuToOpen.openMenu(player, argumentsMap, holder.get().getPlaceholderPlayer()); + } + + private void openMenuWithCurrentArguments(@NotNull final Menu menuToOpen) { + if (holder.isEmpty()) { + menuToOpen.openMenu(player); + return; + } + + menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); + } + + private void executeRefreshAction() { + if (holder.isEmpty()) { + plugin.debug( + DebugLevel.MEDIUM, + Level.WARNING, + player.getName() + " does not have menu open! Nothing to refresh!" + ); + return; + } + + holder.get().refreshMenu(); + } + + private void executeMoneyAction(final boolean give) { + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, give ? "Vault not hooked! Cannot give money!" : "Vault not hooked! Cannot take money!"); + return; + } + + try { + final double amount = Double.parseDouble(executable); + if (give) { + plugin.getVault().giveMoney(player, amount); + return; + } + + plugin.getVault().takeMoney(player, amount); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + give + ? "Amount for give money action: " + executable + ", is not a valid number!" + : "Amount for take money action: " + executable + ", is not a valid number!" + ); + } + } + + private void executeExperienceAction() { + final String lowerCaseExecutable = executable.toLowerCase(); + + try { + if (Integer.parseInt(lowerCaseExecutable.replaceAll("l", "")) <= 0) { + return; + } + + if (actionType == ActionType.TAKE_EXP) { + ExpUtils.setExp(player, "-" + lowerCaseExecutable); + return; + } + + ExpUtils.setExp(player, lowerCaseExecutable); + } catch (final NumberFormatException exception) { + if (actionType == ActionType.TAKE_EXP) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for take exp action: " + executable + ", is not a valid number!" + ); + return; + } + + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for give exp action: " + executable + ", is not a valid number!" + ); + } + } + + private void executePermissionAction(final boolean give) { + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + give + ? "Vault not hooked! Cannot give permission: " + executable + "!" + : "Vault not hooked! Cannot take permission: " + executable + "!" + ); + return; + } + + if (give) { + plugin.getVault().givePermission(player, executable); + return; + } + + plugin.getVault().takePermission(player, executable); + } + + private void executeSoundAction() { + final boolean raw = isRaw(actionType); + Sound sound = null; + String soundName = executable; + float volume = 1; + float pitch = 1; + + if (!executable.contains(" ")) { + try { + sound = SoundUtils.getSound(executable.toUpperCase()); + } catch (final IllegalArgumentException exception) { + plugin.printStacktrace( + "Sound name given for sound action: " + executable + ", is not a valid sound!", + exception + ); + return; + } + } else { + final String[] parts = executable.split(" ", 3); + + try { + sound = SoundUtils.getSound(parts[0].toUpperCase()); + } catch (final IllegalArgumentException exception) { + plugin.printStacktrace( + "Sound name given for sound action: " + parts[0] + ", is not a valid sound!", + exception + ); + return; + } + + if (parts.length == 3) { + try { + pitch = Float.parseFloat(parts[2]); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Pitch given for sound action: " + parts[2] + ", is not a valid number!" + ); + + plugin.printStacktrace( + "Pitch given for sound action: " + parts[2] + ", is not a valid number!", + exception + ); + } + } + + try { + volume = Float.parseFloat(parts[1]); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Volume given for sound action: " + parts[1] + ", is not a valid number!" + ); + + plugin.printStacktrace( + "Volume given for sound action: " + parts[1] + ", is not a valid number!", + exception + ); + } + } + + switch (actionType) { + case BROADCAST_WORLD_RAW_SOUND: + for (final Player broadcastTarget : player.getWorld().getPlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); + } + break; + case BROADCAST_RAW_SOUND: + for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); + } + break; + case PLAY_RAW_SOUND: + player.playSound(player.getLocation(), soundName, volume, pitch); + break; + case BROADCAST_SOUND: + for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); + } + break; + case BROADCAST_WORLD_SOUND: + for (final Player broadcastTarget : player.getWorld().getPlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); + } + break; + case PLAY_SOUND: + player.playSound(player.getLocation(), sound, volume, pitch); + break; + default: + break; + } + } + + private boolean isRaw(final ActionType actionType) { + return actionType == ActionType.PLAY_RAW_SOUND || actionType == ActionType.BROADCAST_RAW_SOUND || actionType == ActionType.BROADCAST_WORLD_RAW_SOUND; + } +} diff --git a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java index 5966aeae..dbd942fe 100644 --- a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java +++ b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java @@ -3,36 +3,22 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.menu.Menu; import com.extendedclip.deluxemenus.menu.MenuHolder; -import com.extendedclip.deluxemenus.persistentmeta.PersistentMetaHandler; -import com.extendedclip.deluxemenus.utils.AdventureUtils; -import com.extendedclip.deluxemenus.utils.DebugLevel; -import com.extendedclip.deluxemenus.utils.ExpUtils; -import com.extendedclip.deluxemenus.utils.SoundUtils; import com.extendedclip.deluxemenus.utils.StringUtils; -import com.extendedclip.deluxemenus.utils.VersionHelper; -import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Bukkit; -import org.bukkit.Sound; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; -import java.util.logging.Level; public class ClickActionTask extends BukkitRunnable { private final DeluxeMenus plugin; private final UUID uuid; private final ActionType actionType; - private final String exec; - // Ugly hack to get around the fact that arguments are not available at task execution time + private final String executableTemplate; private final Map arguments; private final boolean parsePlaceholdersInArguments; private final boolean parsePlaceholdersAfterArguments; @@ -49,7 +35,7 @@ public ClickActionTask( this.plugin = plugin; this.uuid = uuid; this.actionType = actionType; - this.exec = exec; + this.executableTemplate = exec; this.arguments = arguments; this.parsePlaceholdersInArguments = parsePlaceholdersInArguments; this.parsePlaceholdersAfterArguments = parsePlaceholdersAfterArguments; @@ -63,442 +49,13 @@ public void run() { } final Optional holder = Menu.getMenuHolder(player); - final Player target = holder.isPresent() && holder.get().getPlaceholderPlayer() != null - ? holder.get().getPlaceholderPlayer() - : player; - - final String executable = StringUtils.replacePlaceholdersAndArguments( - this.exec, + this.executableTemplate, this.arguments, - target, + holder.isPresent() && holder.get().getPlaceholderPlayer() != null ? holder.get().getPlaceholderPlayer() : player, this.parsePlaceholdersInArguments, this.parsePlaceholdersAfterArguments); - - switch (actionType) { - case META: - if (!VersionHelper.IS_PDC_VERSION || plugin.getPersistentMetaHandler() == null) { - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Meta action not supported on this server version."); - break; - } - final PersistentMetaHandler.OperationResult result = plugin.getPersistentMetaHandler().parseAndExecuteMetaActionFromString(player, executable); - switch (result) { - case INVALID_SYNTAX: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Make sure you have the right syntax."); - break; - case NEW_VALUE_IS_DIFFERENT_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! New value is a different type than the old value!"); - break; - case INVALID_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! The specified type is not supported for the specified action!"); - break; - case EXISTENT_VALUE_IS_DIFFERENT_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Existent value is a different type than the new value!"); - break; - case VALUE_NOT_FOUND: - case SUCCESS: - default: - break; - } - break; - - case PLAYER: - case PLAYER_COMMAND_EVENT: - player.chat("/" + executable); - break; - - case PLACEHOLDER: - holder.ifPresent(it -> it.setPlaceholders(executable)); - break; - - case CHAT: - player.chat(executable); - break; - - case CONSOLE: - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), executable); - break; - - case MINI_MESSAGE: - plugin.audiences().player(player).sendMessage(MiniMessage.miniMessage().deserialize(executable)); - break; - - case MINI_BROADCAST: - plugin.audiences().all().sendMessage(MiniMessage.miniMessage().deserialize(executable)); - break; - - case MESSAGE: - player.sendMessage(StringUtils.color(executable)); - break; - - case LOG: - final String[] logParts = executable.split(" ", 2); - - if (logParts.length == 0 || logParts[0].isBlank()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "LOG command requires at least a message"); - break; - } - - Level logLevel; - String message; - - if(logParts.length == 1) { - logLevel = Level.INFO; - message = logParts[0]; - } else { - message = logParts[1]; - - try { - logLevel = Level.parse(logParts[0].toUpperCase()); - } catch (IllegalArgumentException e) { - logLevel = Level.INFO; - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Log level " + logParts[0] + " is not a valid log level! Using INFO instead."); - } - } - - plugin.getLogger().log(logLevel, String.format("[%s]: %s", holder.map(MenuHolder::getMenuName).orElse("Unknown Menu"), message)); - break; - - case BROADCAST: - Bukkit.broadcastMessage(StringUtils.color(executable)); - break; - - case CLOSE: - Menu.closeMenu(plugin, player, true, true); - break; - - case OPEN_GUI_MENU: - case OPEN_MENU: - final String temporaryExecutable = executable.replaceAll("\\s+", " ").replace(" ", " "); - final String[] executableParts = temporaryExecutable.split(" ", 2); - - if (executableParts.length == 0) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); - break; - } - - final String menuName = executableParts[0]; - - final Optional optionalMenuToOpen = Menu.getMenuByName(menuName); - - if (optionalMenuToOpen.isEmpty()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); - break; - } - - final Menu menuToOpen = optionalMenuToOpen.get(); - - final List menuArgumentNames = menuToOpen.options().arguments(); - - String[] passedArgumentValues = null; - if (executableParts.length > 1) { - passedArgumentValues = executableParts[1].split(" "); - } - - if (menuArgumentNames.isEmpty()) { - if (passedArgumentValues != null && passedArgumentValues.length > 0) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Arguments were given for menu " + menuName + " in action [openguimenu] or [openmenu], but the menu does not support arguments!" - ); - } - - if (holder.isEmpty()) { - menuToOpen.openMenu(player); - break; - } - - menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); - break; - } - - if (passedArgumentValues == null || passedArgumentValues.length == 0) { - // Replicate old behavior: If no arguments are given, open the menu with the arguments from the current menu - if (holder.isEmpty()) { - menuToOpen.openMenu(player); - break; - } - - menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); - break; - } - - if (passedArgumentValues.length < menuArgumentNames.size()) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" - ); - break; - } - - final Map argumentsMap = new HashMap<>(); - if (holder.isPresent() && holder.get().getTypedArgs() != null) { - // Pass the arguments from the current menu to the new menu. If the new menu has arguments with the - // same name, they will be overwritten - argumentsMap.putAll(holder.get().getTypedArgs()); - } - - for (int index = 0; index < menuArgumentNames.size(); index++) { - final String argumentName = menuArgumentNames.get(index); - - if (passedArgumentValues.length <= index) { - // This should never be the case! - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" - ); - break; - } - - if (menuArgumentNames.size() == index + 1) { - // If this is the last argument, get all remaining values and join them - final String lastArgumentValue = String.join(" ", Arrays.asList(passedArgumentValues).subList(index, passedArgumentValues.length)); - argumentsMap.put(argumentName, lastArgumentValue); - break; - } - - argumentsMap.put(argumentName, passedArgumentValues[index]); - } - - if (holder.isEmpty()) { - menuToOpen.openMenu(player, argumentsMap, null); - break; - } - - menuToOpen.openMenu(player, argumentsMap, holder.get().getPlaceholderPlayer()); - break; - - case CONNECT: - plugin.connect(player, executable); - break; - - case JSON_MESSAGE: - AdventureUtils.sendJson(plugin, player, executable); - break; - - case JSON_BROADCAST: - case BROADCAST_JSON: - plugin.audiences().all().sendMessage(AdventureUtils.fromJson(executable)); - break; - - case REFRESH: - if (holder.isEmpty()) { - plugin.debug( - DebugLevel.MEDIUM, - Level.WARNING, - player.getName() + " does not have menu open! Nothing to refresh!" - ); - break; - } - - holder.get().refreshMenu(); - break; - - case TAKE_MONEY: - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Vault not hooked! Cannot take money!"); - break; - } - - try { - plugin.getVault().takeMoney(player, Double.parseDouble(executable)); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for take money action: " + executable + ", is not a valid number!" - ); - } - break; - - case GIVE_MONEY: - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Vault not hooked! Cannot give money!"); - break; - } - - try { - plugin.getVault().giveMoney(player, Double.parseDouble(executable)); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for give money action: " + executable + ", is not a valid number!" - ); - } - break; - - case TAKE_EXP: - case GIVE_EXP: - final String lowerCaseExecutable = executable.toLowerCase(); - - try { - if (Integer.parseInt(lowerCaseExecutable.replaceAll("l", "")) <= 0) break; - - if (actionType == ActionType.TAKE_EXP) { - ExpUtils.setExp(player, "-" + lowerCaseExecutable); - break; - } - - ExpUtils.setExp(player, lowerCaseExecutable); - break; - - } catch (final NumberFormatException exception) { - if (actionType == ActionType.TAKE_EXP) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for take exp action: " + executable + ", is not a valid number!" - ); - break; - } - - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for give exp action: " + executable + ", is not a valid number!" - ); - break; - } - - case GIVE_PERM: - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Vault not hooked! Cannot give permission: " + executable + "!"); - break; - } - - plugin.getVault().givePermission(player, executable); - break; - - case TAKE_PERM: - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Vault not hooked! Cannot take permission: " + executable + "!"); - break; - } - - plugin.getVault().takePermission(player, executable); - break; - - case BROADCAST_SOUND: - case BROADCAST_RAW_SOUND: - case BROADCAST_WORLD_SOUND: - case BROADCAST_WORLD_RAW_SOUND: - case PLAY_RAW_SOUND: - case PLAY_SOUND: - boolean isRaw = isRaw(actionType); - - Sound sound = null; - String soundName = executable; - float volume = 1; - float pitch = 1; - - if (!executable.contains(" ")) { - try { - sound = SoundUtils.getSound(executable.toUpperCase()); - } catch (final IllegalArgumentException exception) { - plugin.printStacktrace( - "Sound name given for sound action: " + executable + ", is not a valid sound!", - exception - ); - break; - } - } else { - String[] parts = executable.split(" ", 3); - - try { - sound = SoundUtils.getSound(parts[0].toUpperCase()); - } catch (final IllegalArgumentException exception) { - plugin.printStacktrace( - "Sound name given for sound action: " + parts[0] + ", is not a valid sound!", - exception - ); - break; - } - - if (parts.length == 3) { - try { - pitch = Float.parseFloat(parts[2]); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Pitch given for sound action: " + parts[2] + ", is not a valid number!" - ); - - plugin.printStacktrace( - "Pitch given for sound action: " + parts[2] + ", is not a valid number!", - exception - ); - } - } - - - try { - volume = Float.parseFloat(parts[1]); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Volume given for sound action: " + parts[1] + ", is not a valid number!" - ); - - plugin.printStacktrace( - "Volume given for sound action: " + parts[1] + ", is not a valid number!", - exception - ); - } - } - - switch (actionType) { - case BROADCAST_WORLD_RAW_SOUND: - for (final Player broadcastTarget : player.getWorld().getPlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); - } - break; - - case BROADCAST_RAW_SOUND: - for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); - } - break; - - case PLAY_RAW_SOUND: - player.playSound(player.getLocation(), soundName, volume, pitch); - break; - case BROADCAST_SOUND: - for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); - } - break; - - case BROADCAST_WORLD_SOUND: - for (final Player broadcastTarget : player.getWorld().getPlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); - } - break; - - case PLAY_SOUND: - player.playSound(player.getLocation(), sound, volume, pitch); - break; - } - break; - - default: - break; - } - } - - private boolean isRaw(ActionType actionType) { - return actionType == ActionType.PLAY_RAW_SOUND || actionType == ActionType.BROADCAST_RAW_SOUND || actionType == ActionType.BROADCAST_WORLD_RAW_SOUND; + new ClickActionExecutor(this.plugin, player, holder, this.actionType, executable).execute(); } } \ No newline at end of file diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java index 0178ec75..dfe57344 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java @@ -3,16 +3,13 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.utils.SkullUtils; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class BaseHeadHook implements ItemHook, SimpleCache { private final DeluxeMenus plugin; - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); public BaseHeadHook(@NotNull final DeluxeMenus plugin) { this.plugin = plugin; @@ -56,6 +53,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java index 741a9655..87cdc7cb 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java @@ -10,17 +10,15 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; public class CraftEngineHook implements ItemHook, SimpleCache { private static final ItemStack EMPTY = new ItemStack(Material.STONE); - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } @Override diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java index 58ec1bf2..f89ba565 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java @@ -2,10 +2,7 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.ssomar.score.api.executableblocks.ExecutableBlocksAPI; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - import com.ssomar.score.api.executableblocks.config.ExecutableBlockInterface; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -13,7 +10,7 @@ public class ExecutableBlocksHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @SuppressWarnings("deprecation") @Override @@ -43,7 +40,7 @@ public String getPrefix() { @Override public void clearCache() { - this.cache.clear(); + this.cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java index 9bdf1266..b2e72d14 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java @@ -2,10 +2,7 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.ssomar.score.api.executableitems.ExecutableItemsAPI; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - import com.ssomar.score.api.executableitems.config.ExecutableItemInterface; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -13,7 +10,7 @@ public class ExecutableItemsHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -50,7 +47,7 @@ public String getPrefix() { @Override public void clearCache() { - this.cache.clear(); + this.cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java new file mode 100644 index 00000000..28fd2ecd --- /dev/null +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java @@ -0,0 +1,38 @@ +package com.extendedclip.deluxemenus.hooks; + +import com.extendedclip.deluxemenus.cache.SimpleCache; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +final class ItemStackCache implements SimpleCache { + + private final Map cache = new ConcurrentHashMap<>(); + + @Nullable + ItemStack get(@NotNull final String key) { + return cache.get(key); + } + + @Nullable + ItemStack computeIfAbsent(@NotNull final String key, @NotNull final Function loader) { + return cache.computeIfAbsent(key, loader); + } + + void put(@NotNull final String key, @NotNull final ItemStack value) { + cache.put(key, value); + } + + void remove(@NotNull final String key) { + cache.remove(key); + } + + @Override + public void clearCache() { + cache.clear(); + } +} diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java index ac3760b0..b5664400 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java @@ -2,16 +2,13 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import dev.lone.itemsadder.api.CustomStack; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class ItemsAdderHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @Override public ItemStack getItem(@NotNull final String... arguments) { @@ -52,6 +49,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java index 69d51653..3928297c 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java @@ -3,8 +3,6 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.utils.DebugLevel; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -17,7 +15,7 @@ public class MMOItemsHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); private final DeluxeMenus plugin; public MMOItemsHook(final @NotNull DeluxeMenus plugin) { @@ -82,6 +80,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java index aa880ba5..433e6e1d 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java @@ -4,9 +4,6 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.listener.Listener; import com.extendedclip.deluxemenus.utils.SkullUtils; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; @@ -14,7 +11,7 @@ public class NamedHeadHook extends Listener implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); public NamedHeadHook(@NotNull final DeluxeMenus plugin) { super(plugin); @@ -59,6 +56,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java index e1f3265f..331e4ec4 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java @@ -7,12 +7,9 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class NexoHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -43,6 +40,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java index 166fd23e..887f09fd 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java @@ -7,12 +7,9 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class OraxenHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -43,6 +40,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java index 58e7eccb..ce989684 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java @@ -9,14 +9,12 @@ import org.jetbrains.annotations.NotNull; import ua.valeriishymchuk.simpleitemgenerator.api.SimpleItemGenerator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; public class SimpleItemGeneratorHook implements ItemHook, SimpleCache { - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); private final DeluxeMenus plugin; public SimpleItemGeneratorHook(DeluxeMenus plugin) { @@ -25,7 +23,7 @@ public SimpleItemGeneratorHook(DeluxeMenus plugin) { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } @Override diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java index 127a8356..a45f42f1 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java @@ -6,13 +6,10 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class TextureHeadHook implements ItemHook, SimpleCache { private final DeluxeMenus plugin; - private final Map cache = new ConcurrentHashMap<>(); + private final ItemStackCache cache = new ItemStackCache(); public TextureHeadHook(@NotNull final DeluxeMenus plugin) { this.plugin = plugin; @@ -48,6 +45,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clear(); + cache.clearCache(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java b/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java new file mode 100644 index 00000000..9d6acc0f --- /dev/null +++ b/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java @@ -0,0 +1,37 @@ +package com.extendedclip.deluxemenus.listener; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +final class ClickDebouncer { + + private static final long CLICK_DEBOUNCE_MILLIS = 75L; + private static final long SHIFT_CLICK_DEBOUNCE_MILLIS = 200L; + + private final Cache clickDebounceCache = CacheBuilder.newBuilder() + .expireAfterWrite(CLICK_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS) + .build(); + + private final Cache shiftClickDebounceCache = CacheBuilder.newBuilder() + .expireAfterWrite(SHIFT_CLICK_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS) + .build(); + + boolean shouldIgnoreClick(@NotNull final Player player) { + final UUID uniqueId = player.getUniqueId(); + return clickDebounceCache.getIfPresent(uniqueId) != null + || shiftClickDebounceCache.getIfPresent(uniqueId) != null; + } + + void markClick(@NotNull final Player player) { + clickDebounceCache.put(player.getUniqueId(), System.currentTimeMillis()); + } + + void markShiftClick(@NotNull final Player player) { + shiftClickDebounceCache.put(player.getUniqueId(), System.currentTimeMillis()); + } +} diff --git a/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java b/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java index af69231b..8485a65b 100644 --- a/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java +++ b/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java @@ -6,8 +6,6 @@ import com.extendedclip.deluxemenus.menu.MenuHolder; import com.extendedclip.deluxemenus.menu.MenuItem; import com.extendedclip.deluxemenus.requirement.RequirementList; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -21,15 +19,10 @@ import org.jetbrains.annotations.NotNull; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.TimeUnit; public class PlayerListener extends Listener { - private final Cache cache = CacheBuilder.newBuilder().expireAfterWrite(75, TimeUnit.MILLISECONDS).build(); - - // This is so dumb. Mojang fix your shit. - private final Cache shiftCache = CacheBuilder.newBuilder().expireAfterWrite(200, TimeUnit.MILLISECONDS).build(); + private final ClickDebouncer clickDebouncer = new ClickDebouncer(); public PlayerListener(@NotNull final DeluxeMenus plugin) { super(plugin); @@ -136,11 +129,7 @@ public void onClick(InventoryClickEvent event) { return; } - if (this.cache.getIfPresent(player.getUniqueId()) != null) { - return; - } - - if (this.shiftCache.getIfPresent(player.getUniqueId()) != null) { + if (clickDebouncer.shouldIgnoreClick(player)) { return; } @@ -149,7 +138,7 @@ public void onClick(InventoryClickEvent event) { } if (event.getClick() == ClickType.SHIFT_LEFT) { - this.shiftCache.put(player.getUniqueId(), System.currentTimeMillis()); + clickDebouncer.markShiftClick(player); } if (handleClick(player, holder, item.options().clickHandler(), item.options().clickRequirements())) { @@ -213,7 +202,7 @@ private boolean handleClick(final @NotNull Player player, final @NotNull MenuHol } } - this.cache.put(player.getUniqueId(), System.currentTimeMillis()); + clickDebouncer.markClick(player); handler.get().onClick(holder); return true; From 9f82e52fb81345a70bbb3e7b9ca8ae5995dd82d3 Mon Sep 17 00:00:00 2001 From: BlitzOffline <52609756+BlitzOffline@users.noreply.github.com> Date: Fri, 17 Apr 2026 03:29:05 +0300 Subject: [PATCH 2/2] Revert "Refactor" This reverts commit d2600d980540da124fb1745c40f989e9a588d431. --- .gitignore | 1 - .../extendedclip/deluxemenus/DeluxeMenus.java | 69 +-- .../action/ClickActionExecutor.java | 468 ------------------ .../deluxemenus/action/ClickActionTask.java | 453 ++++++++++++++++- .../deluxemenus/hooks/BaseHeadHook.java | 7 +- .../deluxemenus/hooks/CraftEngineHook.java | 6 +- .../hooks/ExecutableBlocksHook.java | 7 +- .../hooks/ExecutableItemsHook.java | 7 +- .../deluxemenus/hooks/ItemStackCache.java | 38 -- .../deluxemenus/hooks/ItemsAdderHook.java | 7 +- .../deluxemenus/hooks/MMOItemsHook.java | 6 +- .../deluxemenus/hooks/NamedHeadHook.java | 7 +- .../deluxemenus/hooks/NexoHook.java | 7 +- .../deluxemenus/hooks/OraxenHook.java | 7 +- .../hooks/SimpleItemGeneratorHook.java | 6 +- .../deluxemenus/hooks/TextureHeadHook.java | 7 +- .../deluxemenus/listener/ClickDebouncer.java | 37 -- .../deluxemenus/listener/PlayerListener.java | 19 +- 18 files changed, 552 insertions(+), 607 deletions(-) delete mode 100644 src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java delete mode 100644 src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java delete mode 100644 src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java diff --git a/.gitignore b/.gitignore index 3a64ad69..a73dd02a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .gradle .idea -.vscode build test-server/ \ No newline at end of file diff --git a/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java b/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java index c22983ce..a5b4b354 100644 --- a/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java +++ b/src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java @@ -37,7 +37,6 @@ import java.util.*; import java.util.function.Function; -import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; @@ -256,44 +255,50 @@ private void setUpItemHooks() { final NamedHeadHook namedHeadHook = new NamedHeadHook(this); namedHeadHook.register(); - registerItemHook(HeadType.NAMED.getHookName(), namedHeadHook); - registerItemHook(HeadType.BASE64.getHookName(), new BaseHeadHook(this)); - registerItemHook(HeadType.TEXTURE.getHookName(), new TextureHeadHook(this)); - - registerHeadDatabaseHook(); - registerItemHookIfEnabled("CraftEngine", "craftengine", CraftEngineHook::new); - registerItemHookIfEnabled("ItemsAdder", "itemsadder", ItemsAdderHook::new); - registerItemHookIfEnabled("Nexo", "nexo", NexoHook::new); - registerItemHookIfEnabled("Oraxen", "oraxen", OraxenHook::new); - registerItemHookIfEnabled("MMOItems", "mmoitems", () -> new MMOItemsHook(this)); - registerItemHookIfEnabled("ExecutableItems", "executableitems", ExecutableItemsHook::new); - registerItemHookIfEnabled("ExecutableBlocks", "executableblocks", ExecutableBlocksHook::new); - registerItemHookIfEnabled("SimpleItemGenerator", "simpleitemgenerator", () -> new SimpleItemGeneratorHook(this)); - } + this.itemHooks.put(HeadType.NAMED.getHookName(), namedHeadHook); + this.itemHooks.put(HeadType.BASE64.getHookName(), new BaseHeadHook(this)); + this.itemHooks.put(HeadType.TEXTURE.getHookName(), new TextureHeadHook(this)); + + if (Bukkit.getPluginManager().isPluginEnabled("HeadDatabase")) { + try { + Class.forName("me.arcaniax.hdb.api.HeadDatabaseAPI"); + this.itemHooks.put(HeadType.HDB.getHookName(), new HeadDatabaseHook(this)); + } catch (ClassNotFoundException ignored) { + // We are looking for this specific class because we've had issues with other plugins being named HeadDatabase + // in the past + } + } - private void registerItemHook(@NotNull final String hookName, @NotNull final ItemHook itemHook) { - this.itemHooks.put(hookName, itemHook); - } + if (Bukkit.getPluginManager().isPluginEnabled("CraftEngine")) { + this.itemHooks.put("craftengine", new CraftEngineHook()); + } - private void registerItemHookIfEnabled(@NotNull final String pluginName, @NotNull final String hookName, @NotNull final Supplier itemHookSupplier) { - if (!Bukkit.getPluginManager().isPluginEnabled(pluginName)) { - return; + if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) { + this.itemHooks.put("itemsadder", new ItemsAdderHook()); } - registerItemHook(hookName, itemHookSupplier.get()); - } + if (Bukkit.getPluginManager().isPluginEnabled("Nexo")) { + this.itemHooks.put("nexo", new NexoHook()); + } - private void registerHeadDatabaseHook() { - if (!Bukkit.getPluginManager().isPluginEnabled("HeadDatabase")) { - return; + if (Bukkit.getPluginManager().isPluginEnabled("Oraxen")) { + this.itemHooks.put("oraxen", new OraxenHook()); } - try { - Class.forName("me.arcaniax.hdb.api.HeadDatabaseAPI"); - registerItemHook(HeadType.HDB.getHookName(), new HeadDatabaseHook(this)); - } catch (ClassNotFoundException ignored) { - // We are looking for this specific class because we've had issues with other plugins being named HeadDatabase - // in the past + if (Bukkit.getPluginManager().isPluginEnabled("MMOItems")) { + this.itemHooks.put("mmoitems", new MMOItemsHook(this)); + } + + if (Bukkit.getPluginManager().isPluginEnabled("ExecutableItems")) { + this.itemHooks.put("executableitems", new ExecutableItemsHook()); + } + + if (Bukkit.getPluginManager().isPluginEnabled("ExecutableBlocks")) { + this.itemHooks.put("executableblocks", new ExecutableBlocksHook()); + } + + if (Bukkit.getPluginManager().isPluginEnabled("SimpleItemGenerator")) { + this.itemHooks.put("simpleitemgenerator", new SimpleItemGeneratorHook(this)); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java deleted file mode 100644 index 1657eedf..00000000 --- a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionExecutor.java +++ /dev/null @@ -1,468 +0,0 @@ -package com.extendedclip.deluxemenus.action; - -import com.extendedclip.deluxemenus.DeluxeMenus; -import com.extendedclip.deluxemenus.menu.Menu; -import com.extendedclip.deluxemenus.menu.MenuHolder; -import com.extendedclip.deluxemenus.persistentmeta.PersistentMetaHandler; -import com.extendedclip.deluxemenus.utils.AdventureUtils; -import com.extendedclip.deluxemenus.utils.DebugLevel; -import com.extendedclip.deluxemenus.utils.ExpUtils; -import com.extendedclip.deluxemenus.utils.SoundUtils; -import com.extendedclip.deluxemenus.utils.StringUtils; -import com.extendedclip.deluxemenus.utils.VersionHelper; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Bukkit; -import org.bukkit.Sound; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; - -final class ClickActionExecutor { - - private final DeluxeMenus plugin; - private final Player player; - private final Optional holder; - private final ActionType actionType; - private final String executable; - - ClickActionExecutor( - @NotNull final DeluxeMenus plugin, - @NotNull final Player player, - @NotNull final Optional holder, - @NotNull final ActionType actionType, - @NotNull final String executable - ) { - this.plugin = plugin; - this.player = player; - this.holder = holder; - this.actionType = actionType; - this.executable = executable; - } - - void execute() { - switch (actionType) { - case META: - executeMetaAction(); - break; - case PLAYER: - case PLAYER_COMMAND_EVENT: - player.chat("/" + executable); - break; - case PLACEHOLDER: - holder.ifPresent(value -> value.setPlaceholders(executable)); - break; - case CHAT: - player.chat(executable); - break; - case CONSOLE: - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), executable); - break; - case MINI_MESSAGE: - plugin.audiences().player(player).sendMessage(MiniMessage.miniMessage().deserialize(executable)); - break; - case MINI_BROADCAST: - plugin.audiences().all().sendMessage(MiniMessage.miniMessage().deserialize(executable)); - break; - case MESSAGE: - player.sendMessage(StringUtils.color(executable)); - break; - case LOG: - executeLogAction(); - break; - case BROADCAST: - Bukkit.broadcastMessage(StringUtils.color(executable)); - break; - case CLOSE: - Menu.closeMenu(plugin, player, true, true); - break; - case OPEN_GUI_MENU: - case OPEN_MENU: - executeOpenMenuAction(); - break; - case CONNECT: - plugin.connect(player, executable); - break; - case JSON_MESSAGE: - AdventureUtils.sendJson(plugin, player, executable); - break; - case JSON_BROADCAST: - case BROADCAST_JSON: - plugin.audiences().all().sendMessage(AdventureUtils.fromJson(executable)); - break; - case REFRESH: - executeRefreshAction(); - break; - case TAKE_MONEY: - executeMoneyAction(false); - break; - case GIVE_MONEY: - executeMoneyAction(true); - break; - case TAKE_EXP: - case GIVE_EXP: - executeExperienceAction(); - break; - case GIVE_PERM: - executePermissionAction(true); - break; - case TAKE_PERM: - executePermissionAction(false); - break; - case BROADCAST_SOUND: - case BROADCAST_RAW_SOUND: - case BROADCAST_WORLD_SOUND: - case BROADCAST_WORLD_RAW_SOUND: - case PLAY_RAW_SOUND: - case PLAY_SOUND: - executeSoundAction(); - break; - default: - break; - } - } - - private void executeMetaAction() { - if (!VersionHelper.IS_PDC_VERSION || plugin.getPersistentMetaHandler() == null) { - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Meta action not supported on this server version."); - return; - } - - final PersistentMetaHandler.OperationResult result = plugin.getPersistentMetaHandler().parseAndExecuteMetaActionFromString(player, executable); - switch (result) { - case INVALID_SYNTAX: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Make sure you have the right syntax."); - break; - case NEW_VALUE_IS_DIFFERENT_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! New value is a different type than the old value!"); - break; - case INVALID_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! The specified type is not supported for the specified action!"); - break; - case EXISTENT_VALUE_IS_DIFFERENT_TYPE: - plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Existent value is a different type than the new value!"); - break; - case VALUE_NOT_FOUND: - case SUCCESS: - default: - break; - } - } - - private void executeLogAction() { - final String[] logParts = executable.split(" ", 2); - - if (logParts.length == 0 || logParts[0].isBlank()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "LOG command requires at least a message"); - return; - } - - Level logLevel; - String message; - - if (logParts.length == 1) { - logLevel = Level.INFO; - message = logParts[0]; - } else { - message = logParts[1]; - - try { - logLevel = Level.parse(logParts[0].toUpperCase()); - } catch (IllegalArgumentException exception) { - logLevel = Level.INFO; - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Log level " + logParts[0] + " is not a valid log level! Using INFO instead."); - } - } - - plugin.getLogger().log(logLevel, String.format("[%s]: %s", holder.map(MenuHolder::getMenuName).orElse("Unknown Menu"), message)); - } - - private void executeOpenMenuAction() { - final String temporaryExecutable = executable.replaceAll("\\s+", " ").replace(" ", " "); - final String[] executableParts = temporaryExecutable.split(" ", 2); - - if (executableParts.length == 0) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); - return; - } - - final String menuName = executableParts[0]; - final Optional optionalMenuToOpen = Menu.getMenuByName(menuName); - - if (optionalMenuToOpen.isEmpty()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); - return; - } - - final Menu menuToOpen = optionalMenuToOpen.get(); - final List menuArgumentNames = menuToOpen.options().arguments(); - - String[] passedArgumentValues = null; - if (executableParts.length > 1) { - passedArgumentValues = executableParts[1].split(" "); - } - - if (menuArgumentNames.isEmpty()) { - if (passedArgumentValues != null && passedArgumentValues.length > 0) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Arguments were given for menu " + menuName + " in action [openguimenu] or [openmenu], but the menu does not support arguments!" - ); - } - - openMenuWithCurrentArguments(menuToOpen); - return; - } - - if (passedArgumentValues == null || passedArgumentValues.length == 0) { - openMenuWithCurrentArguments(menuToOpen); - return; - } - - if (passedArgumentValues.length < menuArgumentNames.size()) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" - ); - return; - } - - final Map argumentsMap = new HashMap<>(); - if (holder.isPresent() && holder.get().getTypedArgs() != null) { - argumentsMap.putAll(holder.get().getTypedArgs()); - } - - for (int index = 0; index < menuArgumentNames.size(); index++) { - final String argumentName = menuArgumentNames.get(index); - - if (passedArgumentValues.length <= index) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" - ); - break; - } - - if (menuArgumentNames.size() == index + 1) { - final String lastArgumentValue = String.join(" ", Arrays.asList(passedArgumentValues).subList(index, passedArgumentValues.length)); - argumentsMap.put(argumentName, lastArgumentValue); - break; - } - - argumentsMap.put(argumentName, passedArgumentValues[index]); - } - - if (holder.isEmpty()) { - menuToOpen.openMenu(player, argumentsMap, null); - return; - } - - menuToOpen.openMenu(player, argumentsMap, holder.get().getPlaceholderPlayer()); - } - - private void openMenuWithCurrentArguments(@NotNull final Menu menuToOpen) { - if (holder.isEmpty()) { - menuToOpen.openMenu(player); - return; - } - - menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); - } - - private void executeRefreshAction() { - if (holder.isEmpty()) { - plugin.debug( - DebugLevel.MEDIUM, - Level.WARNING, - player.getName() + " does not have menu open! Nothing to refresh!" - ); - return; - } - - holder.get().refreshMenu(); - } - - private void executeMoneyAction(final boolean give) { - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug(DebugLevel.HIGHEST, Level.WARNING, give ? "Vault not hooked! Cannot give money!" : "Vault not hooked! Cannot take money!"); - return; - } - - try { - final double amount = Double.parseDouble(executable); - if (give) { - plugin.getVault().giveMoney(player, amount); - return; - } - - plugin.getVault().takeMoney(player, amount); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - give - ? "Amount for give money action: " + executable + ", is not a valid number!" - : "Amount for take money action: " + executable + ", is not a valid number!" - ); - } - } - - private void executeExperienceAction() { - final String lowerCaseExecutable = executable.toLowerCase(); - - try { - if (Integer.parseInt(lowerCaseExecutable.replaceAll("l", "")) <= 0) { - return; - } - - if (actionType == ActionType.TAKE_EXP) { - ExpUtils.setExp(player, "-" + lowerCaseExecutable); - return; - } - - ExpUtils.setExp(player, lowerCaseExecutable); - } catch (final NumberFormatException exception) { - if (actionType == ActionType.TAKE_EXP) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for take exp action: " + executable + ", is not a valid number!" - ); - return; - } - - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Amount for give exp action: " + executable + ", is not a valid number!" - ); - } - } - - private void executePermissionAction(final boolean give) { - if (plugin.getVault() == null || !plugin.getVault().hooked()) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - give - ? "Vault not hooked! Cannot give permission: " + executable + "!" - : "Vault not hooked! Cannot take permission: " + executable + "!" - ); - return; - } - - if (give) { - plugin.getVault().givePermission(player, executable); - return; - } - - plugin.getVault().takePermission(player, executable); - } - - private void executeSoundAction() { - final boolean raw = isRaw(actionType); - Sound sound = null; - String soundName = executable; - float volume = 1; - float pitch = 1; - - if (!executable.contains(" ")) { - try { - sound = SoundUtils.getSound(executable.toUpperCase()); - } catch (final IllegalArgumentException exception) { - plugin.printStacktrace( - "Sound name given for sound action: " + executable + ", is not a valid sound!", - exception - ); - return; - } - } else { - final String[] parts = executable.split(" ", 3); - - try { - sound = SoundUtils.getSound(parts[0].toUpperCase()); - } catch (final IllegalArgumentException exception) { - plugin.printStacktrace( - "Sound name given for sound action: " + parts[0] + ", is not a valid sound!", - exception - ); - return; - } - - if (parts.length == 3) { - try { - pitch = Float.parseFloat(parts[2]); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Pitch given for sound action: " + parts[2] + ", is not a valid number!" - ); - - plugin.printStacktrace( - "Pitch given for sound action: " + parts[2] + ", is not a valid number!", - exception - ); - } - } - - try { - volume = Float.parseFloat(parts[1]); - } catch (final NumberFormatException exception) { - plugin.debug( - DebugLevel.HIGHEST, - Level.WARNING, - "Volume given for sound action: " + parts[1] + ", is not a valid number!" - ); - - plugin.printStacktrace( - "Volume given for sound action: " + parts[1] + ", is not a valid number!", - exception - ); - } - } - - switch (actionType) { - case BROADCAST_WORLD_RAW_SOUND: - for (final Player broadcastTarget : player.getWorld().getPlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); - } - break; - case BROADCAST_RAW_SOUND: - for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); - } - break; - case PLAY_RAW_SOUND: - player.playSound(player.getLocation(), soundName, volume, pitch); - break; - case BROADCAST_SOUND: - for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); - } - break; - case BROADCAST_WORLD_SOUND: - for (final Player broadcastTarget : player.getWorld().getPlayers()) { - broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); - } - break; - case PLAY_SOUND: - player.playSound(player.getLocation(), sound, volume, pitch); - break; - default: - break; - } - } - - private boolean isRaw(final ActionType actionType) { - return actionType == ActionType.PLAY_RAW_SOUND || actionType == ActionType.BROADCAST_RAW_SOUND || actionType == ActionType.BROADCAST_WORLD_RAW_SOUND; - } -} diff --git a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java index dbd942fe..5966aeae 100644 --- a/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java +++ b/src/main/java/com/extendedclip/deluxemenus/action/ClickActionTask.java @@ -3,22 +3,36 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.menu.Menu; import com.extendedclip.deluxemenus.menu.MenuHolder; +import com.extendedclip.deluxemenus.persistentmeta.PersistentMetaHandler; +import com.extendedclip.deluxemenus.utils.AdventureUtils; +import com.extendedclip.deluxemenus.utils.DebugLevel; +import com.extendedclip.deluxemenus.utils.ExpUtils; +import com.extendedclip.deluxemenus.utils.SoundUtils; import com.extendedclip.deluxemenus.utils.StringUtils; +import com.extendedclip.deluxemenus.utils.VersionHelper; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Bukkit; +import org.bukkit.Sound; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.logging.Level; public class ClickActionTask extends BukkitRunnable { private final DeluxeMenus plugin; private final UUID uuid; private final ActionType actionType; - private final String executableTemplate; + private final String exec; + // Ugly hack to get around the fact that arguments are not available at task execution time private final Map arguments; private final boolean parsePlaceholdersInArguments; private final boolean parsePlaceholdersAfterArguments; @@ -35,7 +49,7 @@ public ClickActionTask( this.plugin = plugin; this.uuid = uuid; this.actionType = actionType; - this.executableTemplate = exec; + this.exec = exec; this.arguments = arguments; this.parsePlaceholdersInArguments = parsePlaceholdersInArguments; this.parsePlaceholdersAfterArguments = parsePlaceholdersAfterArguments; @@ -49,13 +63,442 @@ public void run() { } final Optional holder = Menu.getMenuHolder(player); + final Player target = holder.isPresent() && holder.get().getPlaceholderPlayer() != null + ? holder.get().getPlaceholderPlayer() + : player; + + final String executable = StringUtils.replacePlaceholdersAndArguments( - this.executableTemplate, + this.exec, this.arguments, - holder.isPresent() && holder.get().getPlaceholderPlayer() != null ? holder.get().getPlaceholderPlayer() : player, + target, this.parsePlaceholdersInArguments, this.parsePlaceholdersAfterArguments); - new ClickActionExecutor(this.plugin, player, holder, this.actionType, executable).execute(); + + switch (actionType) { + case META: + if (!VersionHelper.IS_PDC_VERSION || plugin.getPersistentMetaHandler() == null) { + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Meta action not supported on this server version."); + break; + } + final PersistentMetaHandler.OperationResult result = plugin.getPersistentMetaHandler().parseAndExecuteMetaActionFromString(player, executable); + switch (result) { + case INVALID_SYNTAX: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Make sure you have the right syntax."); + break; + case NEW_VALUE_IS_DIFFERENT_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! New value is a different type than the old value!"); + break; + case INVALID_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! The specified type is not supported for the specified action!"); + break; + case EXISTENT_VALUE_IS_DIFFERENT_TYPE: + plugin.debug(DebugLevel.HIGHEST, Level.INFO, "Invalid meta action! Existent value is a different type than the new value!"); + break; + case VALUE_NOT_FOUND: + case SUCCESS: + default: + break; + } + break; + + case PLAYER: + case PLAYER_COMMAND_EVENT: + player.chat("/" + executable); + break; + + case PLACEHOLDER: + holder.ifPresent(it -> it.setPlaceholders(executable)); + break; + + case CHAT: + player.chat(executable); + break; + + case CONSOLE: + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), executable); + break; + + case MINI_MESSAGE: + plugin.audiences().player(player).sendMessage(MiniMessage.miniMessage().deserialize(executable)); + break; + + case MINI_BROADCAST: + plugin.audiences().all().sendMessage(MiniMessage.miniMessage().deserialize(executable)); + break; + + case MESSAGE: + player.sendMessage(StringUtils.color(executable)); + break; + + case LOG: + final String[] logParts = executable.split(" ", 2); + + if (logParts.length == 0 || logParts[0].isBlank()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "LOG command requires at least a message"); + break; + } + + Level logLevel; + String message; + + if(logParts.length == 1) { + logLevel = Level.INFO; + message = logParts[0]; + } else { + message = logParts[1]; + + try { + logLevel = Level.parse(logParts[0].toUpperCase()); + } catch (IllegalArgumentException e) { + logLevel = Level.INFO; + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Log level " + logParts[0] + " is not a valid log level! Using INFO instead."); + } + } + + plugin.getLogger().log(logLevel, String.format("[%s]: %s", holder.map(MenuHolder::getMenuName).orElse("Unknown Menu"), message)); + break; + + case BROADCAST: + Bukkit.broadcastMessage(StringUtils.color(executable)); + break; + + case CLOSE: + Menu.closeMenu(plugin, player, true, true); + break; + + case OPEN_GUI_MENU: + case OPEN_MENU: + final String temporaryExecutable = executable.replaceAll("\\s+", " ").replace(" ", " "); + final String[] executableParts = temporaryExecutable.split(" ", 2); + + if (executableParts.length == 0) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); + break; + } + + final String menuName = executableParts[0]; + + final Optional optionalMenuToOpen = Menu.getMenuByName(menuName); + + if (optionalMenuToOpen.isEmpty()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not find and open menu " + executable); + break; + } + + final Menu menuToOpen = optionalMenuToOpen.get(); + + final List menuArgumentNames = menuToOpen.options().arguments(); + + String[] passedArgumentValues = null; + if (executableParts.length > 1) { + passedArgumentValues = executableParts[1].split(" "); + } + + if (menuArgumentNames.isEmpty()) { + if (passedArgumentValues != null && passedArgumentValues.length > 0) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Arguments were given for menu " + menuName + " in action [openguimenu] or [openmenu], but the menu does not support arguments!" + ); + } + + if (holder.isEmpty()) { + menuToOpen.openMenu(player); + break; + } + + menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); + break; + } + + if (passedArgumentValues == null || passedArgumentValues.length == 0) { + // Replicate old behavior: If no arguments are given, open the menu with the arguments from the current menu + if (holder.isEmpty()) { + menuToOpen.openMenu(player); + break; + } + + menuToOpen.openMenu(player, holder.get().getTypedArgs(), holder.get().getPlaceholderPlayer()); + break; + } + + if (passedArgumentValues.length < menuArgumentNames.size()) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" + ); + break; + } + + final Map argumentsMap = new HashMap<>(); + if (holder.isPresent() && holder.get().getTypedArgs() != null) { + // Pass the arguments from the current menu to the new menu. If the new menu has arguments with the + // same name, they will be overwritten + argumentsMap.putAll(holder.get().getTypedArgs()); + } + + for (int index = 0; index < menuArgumentNames.size(); index++) { + final String argumentName = menuArgumentNames.get(index); + + if (passedArgumentValues.length <= index) { + // This should never be the case! + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Not enough arguments given for menu " + menuName + " when opening using the [openguimenu] or [openmenu] action!" + ); + break; + } + + if (menuArgumentNames.size() == index + 1) { + // If this is the last argument, get all remaining values and join them + final String lastArgumentValue = String.join(" ", Arrays.asList(passedArgumentValues).subList(index, passedArgumentValues.length)); + argumentsMap.put(argumentName, lastArgumentValue); + break; + } + + argumentsMap.put(argumentName, passedArgumentValues[index]); + } + + if (holder.isEmpty()) { + menuToOpen.openMenu(player, argumentsMap, null); + break; + } + + menuToOpen.openMenu(player, argumentsMap, holder.get().getPlaceholderPlayer()); + break; + + case CONNECT: + plugin.connect(player, executable); + break; + + case JSON_MESSAGE: + AdventureUtils.sendJson(plugin, player, executable); + break; + + case JSON_BROADCAST: + case BROADCAST_JSON: + plugin.audiences().all().sendMessage(AdventureUtils.fromJson(executable)); + break; + + case REFRESH: + if (holder.isEmpty()) { + plugin.debug( + DebugLevel.MEDIUM, + Level.WARNING, + player.getName() + " does not have menu open! Nothing to refresh!" + ); + break; + } + + holder.get().refreshMenu(); + break; + + case TAKE_MONEY: + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Vault not hooked! Cannot take money!"); + break; + } + + try { + plugin.getVault().takeMoney(player, Double.parseDouble(executable)); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for take money action: " + executable + ", is not a valid number!" + ); + } + break; + + case GIVE_MONEY: + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug(DebugLevel.HIGHEST, Level.WARNING, "Vault not hooked! Cannot give money!"); + break; + } + + try { + plugin.getVault().giveMoney(player, Double.parseDouble(executable)); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for give money action: " + executable + ", is not a valid number!" + ); + } + break; + + case TAKE_EXP: + case GIVE_EXP: + final String lowerCaseExecutable = executable.toLowerCase(); + + try { + if (Integer.parseInt(lowerCaseExecutable.replaceAll("l", "")) <= 0) break; + + if (actionType == ActionType.TAKE_EXP) { + ExpUtils.setExp(player, "-" + lowerCaseExecutable); + break; + } + + ExpUtils.setExp(player, lowerCaseExecutable); + break; + + } catch (final NumberFormatException exception) { + if (actionType == ActionType.TAKE_EXP) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for take exp action: " + executable + ", is not a valid number!" + ); + break; + } + + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Amount for give exp action: " + executable + ", is not a valid number!" + ); + break; + } + + case GIVE_PERM: + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Vault not hooked! Cannot give permission: " + executable + "!"); + break; + } + + plugin.getVault().givePermission(player, executable); + break; + + case TAKE_PERM: + if (plugin.getVault() == null || !plugin.getVault().hooked()) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Vault not hooked! Cannot take permission: " + executable + "!"); + break; + } + + plugin.getVault().takePermission(player, executable); + break; + + case BROADCAST_SOUND: + case BROADCAST_RAW_SOUND: + case BROADCAST_WORLD_SOUND: + case BROADCAST_WORLD_RAW_SOUND: + case PLAY_RAW_SOUND: + case PLAY_SOUND: + boolean isRaw = isRaw(actionType); + + Sound sound = null; + String soundName = executable; + float volume = 1; + float pitch = 1; + + if (!executable.contains(" ")) { + try { + sound = SoundUtils.getSound(executable.toUpperCase()); + } catch (final IllegalArgumentException exception) { + plugin.printStacktrace( + "Sound name given for sound action: " + executable + ", is not a valid sound!", + exception + ); + break; + } + } else { + String[] parts = executable.split(" ", 3); + + try { + sound = SoundUtils.getSound(parts[0].toUpperCase()); + } catch (final IllegalArgumentException exception) { + plugin.printStacktrace( + "Sound name given for sound action: " + parts[0] + ", is not a valid sound!", + exception + ); + break; + } + + if (parts.length == 3) { + try { + pitch = Float.parseFloat(parts[2]); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Pitch given for sound action: " + parts[2] + ", is not a valid number!" + ); + + plugin.printStacktrace( + "Pitch given for sound action: " + parts[2] + ", is not a valid number!", + exception + ); + } + } + + + try { + volume = Float.parseFloat(parts[1]); + } catch (final NumberFormatException exception) { + plugin.debug( + DebugLevel.HIGHEST, + Level.WARNING, + "Volume given for sound action: " + parts[1] + ", is not a valid number!" + ); + + plugin.printStacktrace( + "Volume given for sound action: " + parts[1] + ", is not a valid number!", + exception + ); + } + } + + switch (actionType) { + case BROADCAST_WORLD_RAW_SOUND: + for (final Player broadcastTarget : player.getWorld().getPlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); + } + break; + + case BROADCAST_RAW_SOUND: + for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), soundName, volume, pitch); + } + break; + + case PLAY_RAW_SOUND: + player.playSound(player.getLocation(), soundName, volume, pitch); + break; + case BROADCAST_SOUND: + for (final Player broadcastTarget : Bukkit.getOnlinePlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); + } + break; + + case BROADCAST_WORLD_SOUND: + for (final Player broadcastTarget : player.getWorld().getPlayers()) { + broadcastTarget.playSound(broadcastTarget.getLocation(), sound, volume, pitch); + } + break; + + case PLAY_SOUND: + player.playSound(player.getLocation(), sound, volume, pitch); + break; + } + break; + + default: + break; + } + } + + private boolean isRaw(ActionType actionType) { + return actionType == ActionType.PLAY_RAW_SOUND || actionType == ActionType.BROADCAST_RAW_SOUND || actionType == ActionType.BROADCAST_WORLD_RAW_SOUND; } } \ No newline at end of file diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java index dfe57344..0178ec75 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/BaseHeadHook.java @@ -3,13 +3,16 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.utils.SkullUtils; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class BaseHeadHook implements ItemHook, SimpleCache { private final DeluxeMenus plugin; - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); public BaseHeadHook(@NotNull final DeluxeMenus plugin) { this.plugin = plugin; @@ -53,6 +56,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java index 87cdc7cb..741a9655 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/CraftEngineHook.java @@ -10,15 +10,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; public class CraftEngineHook implements ItemHook, SimpleCache { private static final ItemStack EMPTY = new ItemStack(Material.STONE); - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } @Override diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java index f89ba565..58ec1bf2 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableBlocksHook.java @@ -2,7 +2,10 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.ssomar.score.api.executableblocks.ExecutableBlocksAPI; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + import com.ssomar.score.api.executableblocks.config.ExecutableBlockInterface; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -10,7 +13,7 @@ public class ExecutableBlocksHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @SuppressWarnings("deprecation") @Override @@ -40,7 +43,7 @@ public String getPrefix() { @Override public void clearCache() { - this.cache.clearCache(); + this.cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java index b2e72d14..9bdf1266 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ExecutableItemsHook.java @@ -2,7 +2,10 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.ssomar.score.api.executableitems.ExecutableItemsAPI; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + import com.ssomar.score.api.executableitems.config.ExecutableItemInterface; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -10,7 +13,7 @@ public class ExecutableItemsHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -47,7 +50,7 @@ public String getPrefix() { @Override public void clearCache() { - this.cache.clearCache(); + this.cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java deleted file mode 100644 index 28fd2ecd..00000000 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemStackCache.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.extendedclip.deluxemenus.hooks; - -import com.extendedclip.deluxemenus.cache.SimpleCache; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -final class ItemStackCache implements SimpleCache { - - private final Map cache = new ConcurrentHashMap<>(); - - @Nullable - ItemStack get(@NotNull final String key) { - return cache.get(key); - } - - @Nullable - ItemStack computeIfAbsent(@NotNull final String key, @NotNull final Function loader) { - return cache.computeIfAbsent(key, loader); - } - - void put(@NotNull final String key, @NotNull final ItemStack value) { - cache.put(key, value); - } - - void remove(@NotNull final String key) { - cache.remove(key); - } - - @Override - public void clearCache() { - cache.clear(); - } -} diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java index b5664400..ac3760b0 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/ItemsAdderHook.java @@ -2,13 +2,16 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import dev.lone.itemsadder.api.CustomStack; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class ItemsAdderHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @Override public ItemStack getItem(@NotNull final String... arguments) { @@ -49,6 +52,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java index 3928297c..69d51653 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/MMOItemsHook.java @@ -3,6 +3,8 @@ import com.extendedclip.deluxemenus.DeluxeMenus; import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.utils.DebugLevel; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -15,7 +17,7 @@ public class MMOItemsHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); private final DeluxeMenus plugin; public MMOItemsHook(final @NotNull DeluxeMenus plugin) { @@ -80,6 +82,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java index 433e6e1d..aa880ba5 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/NamedHeadHook.java @@ -4,6 +4,9 @@ import com.extendedclip.deluxemenus.cache.SimpleCache; import com.extendedclip.deluxemenus.listener.Listener; import com.extendedclip.deluxemenus.utils.SkullUtils; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; @@ -11,7 +14,7 @@ public class NamedHeadHook extends Listener implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); public NamedHeadHook(@NotNull final DeluxeMenus plugin) { super(plugin); @@ -56,6 +59,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java index 331e4ec4..e1f3265f 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/NexoHook.java @@ -7,9 +7,12 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class NexoHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -40,6 +43,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java index 887f09fd..166fd23e 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/OraxenHook.java @@ -7,9 +7,12 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class OraxenHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); @Override public ItemStack getItem(@NotNull String... arguments) { @@ -40,6 +43,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java index ce989684..58e7eccb 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/SimpleItemGeneratorHook.java @@ -9,12 +9,14 @@ import org.jetbrains.annotations.NotNull; import ua.valeriishymchuk.simpleitemgenerator.api.SimpleItemGenerator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; public class SimpleItemGeneratorHook implements ItemHook, SimpleCache { - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); private final DeluxeMenus plugin; public SimpleItemGeneratorHook(DeluxeMenus plugin) { @@ -23,7 +25,7 @@ public SimpleItemGeneratorHook(DeluxeMenus plugin) { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } @Override diff --git a/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java b/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java index a45f42f1..127a8356 100644 --- a/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java +++ b/src/main/java/com/extendedclip/deluxemenus/hooks/TextureHeadHook.java @@ -6,10 +6,13 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class TextureHeadHook implements ItemHook, SimpleCache { private final DeluxeMenus plugin; - private final ItemStackCache cache = new ItemStackCache(); + private final Map cache = new ConcurrentHashMap<>(); public TextureHeadHook(@NotNull final DeluxeMenus plugin) { this.plugin = plugin; @@ -45,6 +48,6 @@ public String getPrefix() { @Override public void clearCache() { - cache.clearCache(); + cache.clear(); } } diff --git a/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java b/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java deleted file mode 100644 index 9d6acc0f..00000000 --- a/src/main/java/com/extendedclip/deluxemenus/listener/ClickDebouncer.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.extendedclip.deluxemenus.listener; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -final class ClickDebouncer { - - private static final long CLICK_DEBOUNCE_MILLIS = 75L; - private static final long SHIFT_CLICK_DEBOUNCE_MILLIS = 200L; - - private final Cache clickDebounceCache = CacheBuilder.newBuilder() - .expireAfterWrite(CLICK_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS) - .build(); - - private final Cache shiftClickDebounceCache = CacheBuilder.newBuilder() - .expireAfterWrite(SHIFT_CLICK_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS) - .build(); - - boolean shouldIgnoreClick(@NotNull final Player player) { - final UUID uniqueId = player.getUniqueId(); - return clickDebounceCache.getIfPresent(uniqueId) != null - || shiftClickDebounceCache.getIfPresent(uniqueId) != null; - } - - void markClick(@NotNull final Player player) { - clickDebounceCache.put(player.getUniqueId(), System.currentTimeMillis()); - } - - void markShiftClick(@NotNull final Player player) { - shiftClickDebounceCache.put(player.getUniqueId(), System.currentTimeMillis()); - } -} diff --git a/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java b/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java index 8485a65b..af69231b 100644 --- a/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java +++ b/src/main/java/com/extendedclip/deluxemenus/listener/PlayerListener.java @@ -6,6 +6,8 @@ import com.extendedclip.deluxemenus.menu.MenuHolder; import com.extendedclip.deluxemenus.menu.MenuItem; import com.extendedclip.deluxemenus.requirement.RequirementList; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -19,10 +21,15 @@ import org.jetbrains.annotations.NotNull; import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; public class PlayerListener extends Listener { - private final ClickDebouncer clickDebouncer = new ClickDebouncer(); + private final Cache cache = CacheBuilder.newBuilder().expireAfterWrite(75, TimeUnit.MILLISECONDS).build(); + + // This is so dumb. Mojang fix your shit. + private final Cache shiftCache = CacheBuilder.newBuilder().expireAfterWrite(200, TimeUnit.MILLISECONDS).build(); public PlayerListener(@NotNull final DeluxeMenus plugin) { super(plugin); @@ -129,7 +136,11 @@ public void onClick(InventoryClickEvent event) { return; } - if (clickDebouncer.shouldIgnoreClick(player)) { + if (this.cache.getIfPresent(player.getUniqueId()) != null) { + return; + } + + if (this.shiftCache.getIfPresent(player.getUniqueId()) != null) { return; } @@ -138,7 +149,7 @@ public void onClick(InventoryClickEvent event) { } if (event.getClick() == ClickType.SHIFT_LEFT) { - clickDebouncer.markShiftClick(player); + this.shiftCache.put(player.getUniqueId(), System.currentTimeMillis()); } if (handleClick(player, holder, item.options().clickHandler(), item.options().clickRequirements())) { @@ -202,7 +213,7 @@ private boolean handleClick(final @NotNull Player player, final @NotNull MenuHol } } - clickDebouncer.markClick(player); + this.cache.put(player.getUniqueId(), System.currentTimeMillis()); handler.get().onClick(holder); return true;