diff --git a/src/main/java/net/minecraftforge/client/ClientCommandHandler.java b/src/main/java/net/minecraftforge/client/ClientCommandHandler.java index 7deeb56ce9..0de8462468 100644 --- a/src/main/java/net/minecraftforge/client/ClientCommandHandler.java +++ b/src/main/java/net/minecraftforge/client/ClientCommandHandler.java @@ -35,6 +35,7 @@ import com.mojang.brigadier.tree.RootCommandNode; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.player.LocalPlayer; import net.minecraft.commands.CommandRuntimeException; import net.minecraft.commands.CommandSourceStack; @@ -46,6 +47,7 @@ import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.RegisterClientCommandsEvent; import net.minecraftforge.common.MinecraftForge; import org.apache.logging.log4j.LogManager; @@ -60,6 +62,22 @@ public class ClientCommandHandler private static final Logger LOGGER = LogManager.getLogger(); private static CommandDispatcher commands = null; + public static void init() + { + MinecraftForge.EVENT_BUS.addListener(ClientCommandHandler::handleClientPlayerLogin); + } + + private static void handleClientPlayerLogin(ClientPlayerNetworkEvent.LoggedInEvent event) + { + // some custom server implementations do not send ClientboundCommandsPacket, provide a fallback + var suggestionDispatcher = mergeServerCommands(new CommandDispatcher<>()); + if (event.getConnection().getPacketListener() instanceof ClientPacketListener listener) + { + // Must set this, so that suggestions for client-only commands work, if server never sends commands packet + listener.commands = suggestionDispatcher; + } + } + /* * For internal use * @@ -144,11 +162,17 @@ public class ClientCommandHandler */ private static void copy(CommandNode sourceNode, CommandNode resultNode) { + Map, CommandNode> newNodes = new IdentityHashMap<>(); + newNodes.put(sourceNode, resultNode); for (CommandNode child : sourceNode.getChildren()) { - ArgumentBuilder builder = child.createBuilder(); - CommandNode copy = builder.build(); - copy(child, copy); + CommandNode copy = newNodes.computeIfAbsent(child, innerChild -> + { + ArgumentBuilder builder = innerChild.createBuilder(); + CommandNode innerCopy = builder.build(); + copy(innerChild, innerCopy); + return innerCopy; + }); resultNode.addChild(copy); } } @@ -278,6 +302,11 @@ public class ClientCommandHandler } catch (CommandSyntaxException syntax)// Usually thrown by the CommandDispatcher { + if (syntax.getType() == CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand()) + { + // in case of unknown command, let the server try and handle it + return false; + } Minecraft.getInstance().player.sendMessage( new TextComponent("").append(ComponentUtils.fromMessage(syntax.getRawMessage())).withStyle(ChatFormatting.RED), Util.NIL_UUID); if (syntax.getInput() != null && syntax.getCursor() >= 0) diff --git a/src/main/java/net/minecraftforge/common/MinecraftForge.java b/src/main/java/net/minecraftforge/common/MinecraftForge.java index 91b5b605df..584eab102b 100644 --- a/src/main/java/net/minecraftforge/common/MinecraftForge.java +++ b/src/main/java/net/minecraftforge/common/MinecraftForge.java @@ -19,8 +19,11 @@ package net.minecraftforge.common; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.eventbus.api.BusBuilder; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.loading.FMLEnvironment; import net.minecraftforge.versions.forge.ForgeVersion; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -52,6 +55,7 @@ public class MinecraftForge UsernameCache.load(); TierSortingRegistry.init(); + if (FMLEnvironment.dist == Dist.CLIENT) ClientCommandHandler.init(); } /* diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 234e8db0f0..8c08cf5f46 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -71,6 +71,7 @@ public net.minecraft.client.gui.screens.Screen f_169369_ # renderables public net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent m_101404_(Lnet/minecraft/world/level/levelgen/WorldGenSettings;)V # updateSettings public net.minecraft.client.model.geom.LayerDefinitions f_171106_ # OUTER_ARMOR_DEFORMATION public net.minecraft.client.model.geom.LayerDefinitions f_171107_ # INNER_ARMOR_DEFORMATION +public net.minecraft.client.multiplayer.ClientPacketListener f_104899_ # commands public net.minecraft.client.particle.ParticleEngine m_107378_(Lnet/minecraft/core/particles/ParticleType;Lnet/minecraft/client/particle/ParticleEngine$SpriteParticleRegistration;)V # register public net.minecraft.client.particle.ParticleEngine m_107381_(Lnet/minecraft/core/particles/ParticleType;Lnet/minecraft/client/particle/ParticleProvider;)V # register public net.minecraft.client.particle.ParticleEngine$SpriteParticleRegistration