Fix CraftServer#syncCommands breaking commodore

This commit is contained in:
Frank van der Heijden 2022-03-02 22:58:10 +01:00
parent 1632da717b
commit 814a41da93
No known key found for this signature in database
GPG key ID: B808721C2DD5B5B8
4 changed files with 141 additions and 7 deletions

View file

@ -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<Plugin, BukkitPlu
Map<String, Command> knownCommands = getKnownCommands();
if (knownCommands == null) return;
knownCommands.values().removeIf(c -> {
List<String> 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<Plugin, BukkitPlu
return false;
});
RCraftServer.syncCommands();
RCommandDispatcher.removeCommands(unregisteredCommands);
RCraftServer.updateCommands();
}
/**
@ -263,7 +269,8 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin, BukkitPlu
return false;
});
RCraftServer.syncCommands();
RCommandDispatcher.removeCommands(commands);
RCraftServer.updateCommands();
}
/**
@ -282,7 +289,8 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin, BukkitPlu
map.remove(command);
}
RCraftServer.syncCommands();
RCommandDispatcher.removeCommands(Arrays.asList(commands));
RCraftServer.updateCommands();
}
/**
@ -294,7 +302,8 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin, BukkitPlu
if (knownCommands == null) return;
knownCommands.values().removeAll(commands);
RCraftServer.syncCommands();
RCommandDispatcher.removeCommands(commands.stream().map(Command::getName).collect(Collectors.toList()));
RCraftServer.updateCommands();
}
/**

View file

@ -0,0 +1,65 @@
package net.frankheijden.serverutils.bukkit.reflection;
import com.mojang.brigadier.CommandDispatcher;
import dev.frankheijden.minecraftreflection.MinecraftReflection;
import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import dev.frankheijden.minecraftreflection.exceptions.MinecraftReflectionException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
public class RCommandDispatcher {
private static final MinecraftReflection reflection;
private static final Method getCommandDispatcherMethod;
private static final Method getDispatcherMethod;
static {
if (MinecraftReflectionVersion.MINOR < 13) {
reflection = null;
getCommandDispatcherMethod = null;
getDispatcherMethod = null;
} else {
if (MinecraftReflectionVersion.MINOR >= 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()))
.distinct()
.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<? extends String> commands) {
if (MinecraftReflectionVersion.MINOR < 13) return;
CommandDispatcher<?> dispatcher = getDispatcher();
for (String command : commands) {
RCommandNode.removeCommand(dispatcher.getRoot(), command);
}
}
}

View file

@ -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));
}
}

View file

@ -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<String, Command> map = RCommandMap.getKnownCommands(commandMap);
for (String alias : Bukkit.getCommandAliases().keySet()) {
Set<String> commandNames = Bukkit.getCommandAliases().keySet();
RCommandDispatcher.removeCommands(commandNames);
for (String alias : commandNames) {
Command aliasCommand = map.remove(alias);
if (aliasCommand == null) continue;