From 9ede1cf41673e987f77dae0f1965527d5f3868cd Mon Sep 17 00:00:00 2001 From: IzzelAliz Date: Fri, 12 Feb 2021 17:42:37 +0800 Subject: [PATCH] Use bukkit command dispatcher (#132) --- .../bridge/server/MinecraftServerBridge.java | 3 ++ .../common/mixin/bukkit/CraftServerMixin.java | 50 ------------------ .../advancements/FunctionManagerMixin.java | 24 +++++++++ .../mixin/core/command/CommandsMixin.java | 52 ++++++++++++++++--- .../play/ServerPlayNetHandlerMixin.java | 2 +- .../core/server/MinecraftServerMixin.java | 7 +++ .../dedicated/DedicatedServerMixin.java | 13 +++-- .../core/world/server/ServerWorldMixin.java | 10 ++-- .../common/mod/ArclightMixinPlugin.java | 1 + .../main/resources/mixins.arclight.core.json | 1 + 10 files changed, 93 insertions(+), 70 deletions(-) create mode 100644 arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/advancements/FunctionManagerMixin.java diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/bridge/server/MinecraftServerBridge.java b/arclight-common/src/main/java/io/izzel/arclight/common/bridge/server/MinecraftServerBridge.java index 25424d9d..c290aa95 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/bridge/server/MinecraftServerBridge.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/bridge/server/MinecraftServerBridge.java @@ -1,5 +1,6 @@ package io.izzel.arclight.common.bridge.server; +import net.minecraft.command.Commands; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.RemoteConsoleCommandSender; import org.bukkit.craftbukkit.v.CraftServer; @@ -21,4 +22,6 @@ public interface MinecraftServerBridge { void bridge$drainQueuedTasks(); boolean bridge$hasStopped(); + + Commands bridge$getVanillaCommands(); } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftServerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftServerMixin.java index 8b7fd4f1..4fce9eba 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftServerMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftServerMixin.java @@ -3,7 +3,6 @@ package io.izzel.arclight.common.mixin.bukkit; import io.izzel.arclight.common.bridge.bukkit.CraftServerBridge; import io.izzel.arclight.common.bridge.world.WorldBridge; import jline.console.ConsoleReader; -import net.minecraft.command.Commands; import net.minecraft.server.dedicated.DedicatedPlayerList; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.management.PlayerList; @@ -11,17 +10,12 @@ import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.world.WorldEvent; import org.bukkit.World; -import org.bukkit.command.Command; import org.bukkit.craftbukkit.v.CraftServer; import org.bukkit.craftbukkit.v.CraftWorld; -import org.bukkit.craftbukkit.v.command.BukkitCommandWrapper; import org.bukkit.craftbukkit.v.command.CraftCommandMap; import org.bukkit.craftbukkit.v.help.SimpleHelpMap; -import org.bukkit.craftbukkit.v.util.permissions.CraftDefaultPermissions; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginLoadOrder; import org.bukkit.plugin.SimplePluginManager; -import org.bukkit.util.permissions.DefaultPermissions; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; @@ -81,50 +75,6 @@ public abstract class CraftServerMixin implements CraftServerBridge { } } - /** - * @author IzzelAliz - * @reason - */ - @Overwrite(remap = false) - public void enablePlugins(PluginLoadOrder type) { - if (type == PluginLoadOrder.STARTUP) { - helpMap.clear(); - helpMap.initializeGeneralTopics(); - } - - Plugin[] plugins = pluginManager.getPlugins(); - - for (Plugin plugin : plugins) { - if ((!plugin.isEnabled()) && (plugin.getDescription().getLoad() == type)) { - enablePlugin(plugin); - } - } - - if (type == PluginLoadOrder.POSTWORLD) { - this.commandMap.setFallbackCommands(); - this.commandMap.registerServerAliases(); - DefaultPermissions.registerCorePermissions(); - CraftDefaultPermissions.registerCorePermissions(); - this.loadCustomPermissions(); - this.helpMap.initializeCommands(); - this.syncCommands(); - } - } - - /** - * @author IzzelAliz - * @reason - */ - @Overwrite(remap = false) - public void syncCommands() { - Commands dispatcher = this.console.getCommandManager(); - for (Map.Entry entry : this.commandMap.getKnownCommands().entrySet()) { - String label = entry.getKey(); - Command command = entry.getValue(); - new BukkitCommandWrapper((CraftServer) (Object) this, command).register(dispatcher.getDispatcher(), label); - } - } - @Override public void bridge$setPlayerList(PlayerList playerList) { this.playerList = (DedicatedPlayerList) playerList; diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/advancements/FunctionManagerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/advancements/FunctionManagerMixin.java new file mode 100644 index 00000000..0c261f8d --- /dev/null +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/advancements/FunctionManagerMixin.java @@ -0,0 +1,24 @@ +package io.izzel.arclight.common.mixin.core.advancements; + +import com.mojang.brigadier.CommandDispatcher; +import io.izzel.arclight.common.bridge.server.MinecraftServerBridge; +import net.minecraft.advancements.FunctionManager; +import net.minecraft.command.CommandSource; +import net.minecraft.server.MinecraftServer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(FunctionManager.class) +public class FunctionManagerMixin { + + @Shadow @Final private MinecraftServer server; + + @Inject(method = "getCommandDispatcher", cancellable = true, at = @At("HEAD")) + private void arclight$useVanillaDispatcher(CallbackInfoReturnable> cir) { + cir.setReturnValue(((MinecraftServerBridge) this.server).bridge$getVanillaCommands().getDispatcher()); + } +} diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/command/CommandsMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/command/CommandsMixin.java index ce03e42c..bce98b22 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/command/CommandsMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/command/CommandsMixin.java @@ -1,29 +1,66 @@ package io.izzel.arclight.common.mixin.core.command; +import com.google.common.collect.Maps; +import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.RootCommandNode; import io.izzel.arclight.common.bridge.command.CommandNodeBridge; import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge; +import io.izzel.arclight.common.bridge.server.MinecraftServerBridge; import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; import net.minecraft.command.ISuggestionProvider; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.play.server.SCommandListPacket; import org.bukkit.Bukkit; import org.bukkit.event.player.PlayerCommandSendEvent; +import org.spigotmc.SpigotConfig; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; import java.util.LinkedHashSet; import java.util.Map; @Mixin(Commands.class) -public class CommandsMixin { +public abstract class CommandsMixin { + + // @formatter:off + @Shadow public abstract int handleCommand(CommandSource source, String command); + @Shadow @Final private CommandDispatcher dispatcher; + // @formatter:on + + @Shadow + protected abstract void commandSourceNodesToSuggestionNodes(CommandNode rootCommandSource, CommandNode rootSuggestion, CommandSource source, Map, CommandNode> commandNodeToSuggestionNode); + + public void arclight$constructor() { + this.dispatcher = new CommandDispatcher<>(); + this.dispatcher.setConsumer((context, b, i) -> context.getSource().onCommandComplete(context, b, i)); + } + + public int a(CommandSource source, String command, String label) { + return this.handleCommand(source, command); + } + + /** + * @author IzzelAliz + * @reason + */ + @Overwrite + public void send(ServerPlayerEntity player) { + if (SpigotConfig.tabComplete < 0) return; + Map, CommandNode> map = Maps.newIdentityHashMap(); + + RootCommandNode vanillaRoot = new RootCommandNode<>(); + Commands vanillaCommands = ((MinecraftServerBridge) player.server).bridge$getVanillaCommands(); + map.put(vanillaCommands.getDispatcher().getRoot(), vanillaRoot); + this.commandSourceNodesToSuggestionNodes(vanillaCommands.getDispatcher().getRoot(), vanillaRoot, player.getCommandSource(), map); + + RootCommandNode node = new RootCommandNode<>(); + map.put(this.dispatcher.getRoot(), node); + this.commandSourceNodesToSuggestionNodes(this.dispatcher.getRoot(), node, player.getCommandSource(), map); - @Inject(method = "send", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/command/Commands;commandSourceNodesToSuggestionNodes(Lcom/mojang/brigadier/tree/CommandNode;Lcom/mojang/brigadier/tree/CommandNode;Lnet/minecraft/command/CommandSource;Ljava/util/Map;)V")) - private void arclight$playerCommandSend(ServerPlayerEntity player, CallbackInfo ci, Map, CommandNode> map , RootCommandNode node) { LinkedHashSet set = new LinkedHashSet<>(); for (CommandNode child : node.getChildren()) { set.add(child.getName()); @@ -35,5 +72,6 @@ public class CommandsMixin { ((CommandNodeBridge) node).bridge$removeCommand(s); } } + player.connection.sendPacket(new SCommandListPacket(node)); } } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/play/ServerPlayNetHandlerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/play/ServerPlayNetHandlerMixin.java index 0b596a12..80661ae9 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/play/ServerPlayNetHandlerMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/play/ServerPlayNetHandlerMixin.java @@ -1057,7 +1057,7 @@ public abstract class ServerPlayNetHandlerMixin implements ServerPlayNetHandlerB return; } try { - minecraftServer.getCommandManager().handleCommand(((CraftPlayer) event.getPlayer()).getHandle().getCommandSource(), event.getMessage()); + this.server.dispatchCommand(event.getPlayer(), event.getMessage().substring(1)); } catch (CommandException ex) { player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to perform this command"); java.util.logging.Logger.getLogger(ServerPlayNetHandler.class.getName()).log(Level.SEVERE, null, ex); diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/server/MinecraftServerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/server/MinecraftServerMixin.java index c40e7dcc..e3c333b6 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/server/MinecraftServerMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/server/MinecraftServerMixin.java @@ -135,6 +135,7 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); public int autosavePeriod; + public Commands vanillaCommandDispatcher; private boolean hasStopped = false; private final Object stopLock = new Object(); @@ -165,6 +166,7 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop