diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java index 8bbaf12..feb3e3b 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java @@ -13,11 +13,13 @@ import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import net.frankheijden.serverutils.bukkit.entities.BukkitPluginDescription; import net.frankheijden.serverutils.bukkit.events.BukkitPluginDisableEvent; import net.frankheijden.serverutils.bukkit.events.BukkitPluginEnableEvent; import net.frankheijden.serverutils.bukkit.events.BukkitPluginLoadEvent; import net.frankheijden.serverutils.bukkit.events.BukkitPluginUnloadEvent; +import net.frankheijden.serverutils.bukkit.reflection.RCommandDispatcher; import net.frankheijden.serverutils.bukkit.reflection.RCommandMap; import net.frankheijden.serverutils.bukkit.reflection.RCraftServer; import net.frankheijden.serverutils.bukkit.reflection.RCraftingManager; @@ -220,11 +222,14 @@ public class BukkitPluginManager extends AbstractPluginManager knownCommands = getKnownCommands(); if (knownCommands == null) return; - knownCommands.values().removeIf(c -> { + List unregisteredCommands = new ArrayList<>(); + knownCommands.entrySet().removeIf(e -> { + Command c = e.getValue(); if (c instanceof PluginIdentifiableCommand) { PluginIdentifiableCommand pc = (PluginIdentifiableCommand) c; if (pc.getPlugin().getName().equals(plugin.getName())) { c.unregister(RCraftServer.getCommandMap()); + unregisteredCommands.add(e.getKey()); return true; } return false; @@ -232,7 +237,8 @@ public class BukkitPluginManager extends AbstractPluginManager= 17) { + reflection = MinecraftReflection.of("net.minecraft.commands.CommandDispatcher"); + } else { + reflection = MinecraftReflection.of("net.minecraft.server.%s.CommandDispatcher"); + } + + getCommandDispatcherMethod = Arrays.stream(RMinecraftServer.getReflection().getClazz().getDeclaredMethods()) + .filter(m -> m.getReturnType().equals(reflection.getClazz())) + .findAny() + .get(); + getDispatcherMethod = Arrays.stream(getCommandDispatcherMethod.getReturnType().getDeclaredMethods()) + .filter(m -> CommandDispatcher.class.equals(m.getReturnType())) + .findAny() + .get(); + } + } + + public RCommandDispatcher() {} + + /** + * Retrieves the command dispatcher. + */ + public static CommandDispatcher getDispatcher() { + try { + Object minecraftDispatcher = getCommandDispatcherMethod.invoke(RCraftServer.getConsole()); + return (CommandDispatcher) getDispatcherMethod.invoke(minecraftDispatcher); + } catch (ReflectiveOperationException ex) { + throw new MinecraftReflectionException(ex); + } + } + + /** + * Removes commands from the brigadier root node. + */ + public static void removeCommands(Collection commands) { + if (MinecraftReflectionVersion.MINOR < 13) return; + CommandDispatcher dispatcher = getDispatcher(); + for (String command : commands) { + RCommandNode.removeCommand(dispatcher.getRoot(), command); + } + } +} diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCommandNode.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCommandNode.java new file mode 100644 index 0000000..4ef8d6d --- /dev/null +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCommandNode.java @@ -0,0 +1,28 @@ +package net.frankheijden.serverutils.bukkit.reflection; + +import com.mojang.brigadier.tree.CommandNode; +import dev.frankheijden.minecraftreflection.ClassObject; +import dev.frankheijden.minecraftreflection.MinecraftReflection; + +public class RCommandNode { + + private static final MinecraftReflection reflection; + + static { + reflection = MinecraftReflection.of(CommandNode.class); + } + + public RCommandNode() {} + + public static void removeCommand(Object node, String name) { + reflection.invoke(node, "removeCommand", name); + } + + public static String getName(Object node) { + return reflection.invoke(node, "getName"); + } + + public static void addChild(Object parent, Object child) { + reflection.invoke(parent, "addChild", ClassObject.of(CommandNode.class, child)); + } +} diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCraftServer.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCraftServer.java index 5a3c916..6009f95 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCraftServer.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/reflection/RCraftServer.java @@ -3,12 +3,15 @@ package net.frankheijden.serverutils.bukkit.reflection; import dev.frankheijden.minecraftreflection.MinecraftReflection; import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion; import java.io.File; +import java.util.Collection; import java.util.Map; +import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Warning; import org.bukkit.command.Command; import org.bukkit.command.SimpleCommandMap; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; public class RCraftServer { @@ -41,8 +44,35 @@ public class RCraftServer { return reflection.get(Bukkit.getServer(), "commandMap"); } + /** + * Syncs and registers all commands, but keeping the old values that haven't been added. + */ + @SuppressWarnings({"rawtypes"}) public static void syncCommands() { - if (MinecraftReflectionVersion.MINOR >= 13) reflection.invoke(Bukkit.getServer(), "syncCommands"); + if (MinecraftReflectionVersion.MINOR < 13) return; + + Collection children = RCommandDispatcher.getDispatcher().getRoot().getChildren(); + reflection.invoke(Bukkit.getServer(), "syncCommands"); + Object root = RCommandDispatcher.getDispatcher().getRoot(); + + for (Object child : children) { + RCommandNode.removeCommand(root, RCommandNode.getName(child)); + RCommandNode.addChild(root, child); + } + updateCommands(); + } + + /** + * Updates commands for all online players. + */ + public static void updateCommands() { + if (MinecraftReflectionVersion.MINOR < 13) return; + Bukkit.getOnlinePlayers().forEach(RCraftServer::updateCommands); + } + + public static void updateCommands(Player player) { + if (MinecraftReflectionVersion.MINOR < 13) return; + player.updateCommands(); } public static Object getConsole() { @@ -89,7 +119,9 @@ public class RCraftServer { SimpleCommandMap commandMap = getCommandMap(); Map map = RCommandMap.getKnownCommands(commandMap); - for (String alias : Bukkit.getCommandAliases().keySet()) { + Set commandNames = Bukkit.getCommandAliases().keySet(); + RCommandDispatcher.removeCommands(commandNames); + for (String alias : commandNames) { Command aliasCommand = map.remove(alias); if (aliasCommand == null) continue;