From bb7b334ace196fcd8889014c90a0f9f6a9b53ccf Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+JRoy@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:29:20 -0500 Subject: [PATCH] Use WeakReference to store alternative commands (#5572) Co-authored-by: oop778 --- .../AlternativeCommandsHandler.java | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/AlternativeCommandsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/AlternativeCommandsHandler.java index 322cebb4d9f..1028c830087 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/AlternativeCommandsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/AlternativeCommandsHandler.java @@ -4,6 +4,7 @@ import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.plugin.Plugin; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -13,7 +14,7 @@ import java.util.logging.Level; public class AlternativeCommandsHandler { - private final transient Map> altcommands = new HashMap<>(); + private final transient Map>> altCommands = new HashMap<>(); private final transient Map disabledList = new HashMap<>(); private final transient IEssentials ess; @@ -35,17 +36,30 @@ public final void addPlugin(final Plugin plugin) { final String commandName = commandSplit.length > 1 ? commandSplit[1] : entry.getKey(); final Command command = entry.getValue(); - final List pluginCommands = altcommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>()); + final List> pluginCommands = altCommands.computeIfAbsent(commandName.toLowerCase(Locale.ENGLISH), k -> new ArrayList<>()); boolean found = false; - for (final Command pc2 : pluginCommands) { + + final Iterator> pluginCmdIterator = pluginCommands.iterator(); + while (pluginCmdIterator.hasNext()) { + final Command cmd = pluginCmdIterator.next().get(); + if (cmd == null) { + if (ess.getSettings().isDebug()) { + ess.getLogger().log(Level.INFO, "Essentials: Alternative command for " + commandName + " removed due to garbage collection"); + } + + pluginCmdIterator.remove(); + continue; + } + // Safe cast, everything that's added comes from getPluginCommands which already performs the cast check. - if (((PluginIdentifiableCommand) pc2).getPlugin().equals(plugin)) { + if (((PluginIdentifiableCommand) cmd).getPlugin().equals(plugin)) { found = true; break; } } + if (!found) { - pluginCommands.add(command); + pluginCommands.add(new WeakReference<>(command)); } } } @@ -61,10 +75,19 @@ private Map getPluginCommands(Plugin plugin) { } public void removePlugin(final Plugin plugin) { - final Iterator>> iterator = altcommands.entrySet().iterator(); + final Iterator>>> iterator = altCommands.entrySet().iterator(); while (iterator.hasNext()) { - final Map.Entry> entry = iterator.next(); - entry.getValue().removeIf(pc -> !(pc instanceof PluginIdentifiableCommand) || ((PluginIdentifiableCommand) pc).getPlugin().equals(plugin)); + final Map.Entry>> entry = iterator.next(); + + final Iterator> commands = entry.getValue().iterator(); + while (commands.hasNext()) { + final Command pc = commands.next().get(); + if (pc instanceof PluginIdentifiableCommand && !((PluginIdentifiableCommand) pc).getPlugin().equals(plugin)) { + continue; + } + commands.remove(); + } + if (entry.getValue().isEmpty()) { iterator.remove(); } @@ -72,21 +95,31 @@ public void removePlugin(final Plugin plugin) { } public Command getAlternative(final String label) { - final List commands = altcommands.get(label); + final List> commands = altCommands.get(label); if (commands == null || commands.isEmpty()) { return null; } + if (commands.size() == 1) { - return commands.get(0); + return commands.get(0).get(); } + // return the first command that is not an alias - for (final Command command : commands) { - if (command.getName().equalsIgnoreCase(label)) { - return command; + final Iterator> iterator = commands.iterator(); + while (iterator.hasNext()) { + final Command cmd = iterator.next().get(); + if (cmd == null) { + iterator.remove(); + continue; + } + + if (cmd.getName().equalsIgnoreCase(label)) { + return cmd; } } + // return the first alias - return commands.get(0); + return commands.get(0).get(); } public void executed(final String label, final Command pc) {