package net.minecraft.network.protocol.game; import com.google.common.collect.Queues; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.tree.ArgumentCommandNode; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.RootCommandNode; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSets; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import java.util.Queue; import java.util.function.BiPredicate; import javax.annotation.Nullable; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.commands.synchronization.SuggestionProviders; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketType; import net.minecraft.resources.ResourceLocation; public class ClientboundCommandsPacket implements Packet { public static final StreamCodec STREAM_CODEC = Packet.codec( ClientboundCommandsPacket::write, ClientboundCommandsPacket::new ); private static final byte MASK_TYPE = 3; private static final byte FLAG_EXECUTABLE = 4; private static final byte FLAG_REDIRECT = 8; private static final byte FLAG_CUSTOM_SUGGESTIONS = 16; private static final byte TYPE_ROOT = 0; private static final byte TYPE_LITERAL = 1; private static final byte TYPE_ARGUMENT = 2; private final int rootIndex; private final List entries; public ClientboundCommandsPacket(RootCommandNode p_131861_) { Object2IntMap> object2intmap = enumerateNodes(p_131861_); this.entries = createEntries(object2intmap); this.rootIndex = object2intmap.getInt(p_131861_); } private ClientboundCommandsPacket(FriendlyByteBuf p_178805_) { this.entries = p_178805_.readList(ClientboundCommandsPacket::readNode); this.rootIndex = p_178805_.readVarInt(); validateEntries(this.entries); } private void write(FriendlyByteBuf p_131886_) { p_131886_.writeCollection(this.entries, (p_237642_, p_237643_) -> p_237643_.write(p_237642_)); p_131886_.writeVarInt(this.rootIndex); } private static void validateEntries(List p_237631_, BiPredicate p_237632_) { IntSet intset = new IntOpenHashSet(IntSets.fromTo(0, p_237631_.size())); while (!intset.isEmpty()) { boolean flag = intset.removeIf(p_237637_ -> p_237632_.test(p_237631_.get(p_237637_), intset)); if (!flag) { throw new IllegalStateException("Server sent an impossible command tree"); } } } private static void validateEntries(List p_237629_) { validateEntries(p_237629_, ClientboundCommandsPacket.Entry::canBuild); validateEntries(p_237629_, ClientboundCommandsPacket.Entry::canResolve); } private static Object2IntMap> enumerateNodes(RootCommandNode p_131863_) { Object2IntMap> object2intmap = new Object2IntOpenHashMap<>(); Queue> queue = Queues.newArrayDeque(); queue.add(p_131863_); CommandNode commandnode; while ((commandnode = queue.poll()) != null) { if (!object2intmap.containsKey(commandnode)) { int i = object2intmap.size(); object2intmap.put(commandnode, i); queue.addAll(commandnode.getChildren()); if (commandnode.getRedirect() != null) { queue.add(commandnode.getRedirect()); } } } return object2intmap; } private static List createEntries(Object2IntMap> p_237627_) { ObjectArrayList objectarraylist = new ObjectArrayList<>(p_237627_.size()); objectarraylist.size(p_237627_.size()); for (Object2IntMap.Entry> entry : Object2IntMaps.fastIterable(p_237627_)) { objectarraylist.set(entry.getIntValue(), createEntry(entry.getKey(), p_237627_)); } return objectarraylist; } private static ClientboundCommandsPacket.Entry readNode(FriendlyByteBuf p_131888_) { byte b0 = p_131888_.readByte(); int[] aint = p_131888_.readVarIntArray(); int i = (b0 & 8) != 0 ? p_131888_.readVarInt() : 0; ClientboundCommandsPacket.NodeStub clientboundcommandspacket$nodestub = read(p_131888_, b0); return new ClientboundCommandsPacket.Entry(clientboundcommandspacket$nodestub, b0, i, aint); } @Nullable private static ClientboundCommandsPacket.NodeStub read(FriendlyByteBuf p_237639_, byte p_237640_) { int i = p_237640_ & 3; if (i == 2) { String s1 = p_237639_.readUtf(); int j = p_237639_.readVarInt(); ArgumentTypeInfo argumenttypeinfo = BuiltInRegistries.COMMAND_ARGUMENT_TYPE.byId(j); if (argumenttypeinfo == null) { return null; } else { ArgumentTypeInfo.Template template = argumenttypeinfo.deserializeFromNetwork(p_237639_); ResourceLocation resourcelocation = (p_237640_ & 16) != 0 ? p_237639_.readResourceLocation() : null; return new ClientboundCommandsPacket.ArgumentNodeStub(s1, template, resourcelocation); } } else if (i == 1) { String s = p_237639_.readUtf(); return new ClientboundCommandsPacket.LiteralNodeStub(s); } else { return null; } } private static ClientboundCommandsPacket.Entry createEntry( CommandNode p_237622_, Object2IntMap> p_237623_ ) { int i = 0; int j; if (p_237622_.getRedirect() != null) { i |= 8; j = p_237623_.getInt(p_237622_.getRedirect()); } else { j = 0; } if (p_237622_.getCommand() != null) { i |= 4; } ClientboundCommandsPacket.NodeStub clientboundcommandspacket$nodestub; if (p_237622_ instanceof RootCommandNode) { i |= 0; clientboundcommandspacket$nodestub = null; } else if (p_237622_ instanceof ArgumentCommandNode argumentcommandnode) { clientboundcommandspacket$nodestub = new ClientboundCommandsPacket.ArgumentNodeStub(argumentcommandnode); i |= 2; if (argumentcommandnode.getCustomSuggestions() != null) { i |= 16; } } else { if (!(p_237622_ instanceof LiteralCommandNode literalcommandnode)) { throw new UnsupportedOperationException("Unknown node type " + p_237622_); } clientboundcommandspacket$nodestub = new ClientboundCommandsPacket.LiteralNodeStub(literalcommandnode.getLiteral()); i |= 1; } int[] aint = p_237622_.getChildren().stream().mapToInt(p_237623_::getInt).toArray(); return new ClientboundCommandsPacket.Entry(clientboundcommandspacket$nodestub, i, j, aint); } @Override public PacketType type() { return GamePacketTypes.CLIENTBOUND_COMMANDS; } public void handle(ClientGamePacketListener p_131878_) { p_131878_.handleCommands(this); } public RootCommandNode getRoot(CommandBuildContext p_237625_) { return (RootCommandNode)new ClientboundCommandsPacket.NodeResolver(p_237625_, this.entries).resolve(this.rootIndex); } static class ArgumentNodeStub implements ClientboundCommandsPacket.NodeStub { private final String id; private final ArgumentTypeInfo.Template argumentType; @Nullable private final ResourceLocation suggestionId; @Nullable private static ResourceLocation getSuggestionId(@Nullable SuggestionProvider p_237654_) { return p_237654_ != null ? SuggestionProviders.getName(p_237654_) : null; } ArgumentNodeStub(String p_237650_, ArgumentTypeInfo.Template p_237651_, @Nullable ResourceLocation p_237652_) { this.id = p_237650_; this.argumentType = p_237651_; this.suggestionId = p_237652_; } public ArgumentNodeStub(ArgumentCommandNode p_237648_) { this(p_237648_.getName(), ArgumentTypeInfos.unpack(p_237648_.getType()), getSuggestionId(p_237648_.getCustomSuggestions())); } @Override public ArgumentBuilder build(CommandBuildContext p_237656_) { ArgumentType argumenttype = this.argumentType.instantiate(p_237656_); RequiredArgumentBuilder requiredargumentbuilder = RequiredArgumentBuilder.argument(this.id, argumenttype); if (this.suggestionId != null) { requiredargumentbuilder.suggests(SuggestionProviders.getProvider(this.suggestionId)); } return requiredargumentbuilder; } @Override public void write(FriendlyByteBuf p_237658_) { p_237658_.writeUtf(this.id); serializeCap(p_237658_, this.argumentType); if (this.suggestionId != null) { p_237658_.writeResourceLocation(this.suggestionId); } } private static > void serializeCap(FriendlyByteBuf p_237660_, ArgumentTypeInfo.Template p_237661_) { serializeCap(p_237660_, p_237661_.type(), p_237661_); } private static , T extends ArgumentTypeInfo.Template> void serializeCap( FriendlyByteBuf p_237663_, ArgumentTypeInfo p_237664_, ArgumentTypeInfo.Template p_237665_ ) { p_237663_.writeVarInt(BuiltInRegistries.COMMAND_ARGUMENT_TYPE.getId(p_237664_)); p_237664_.serializeToNetwork((T)p_237665_, p_237663_); } } static class Entry { @Nullable final ClientboundCommandsPacket.NodeStub stub; final int flags; final int redirect; final int[] children; Entry(@Nullable ClientboundCommandsPacket.NodeStub p_237668_, int p_237669_, int p_237670_, int[] p_237671_) { this.stub = p_237668_; this.flags = p_237669_; this.redirect = p_237670_; this.children = p_237671_; } public void write(FriendlyByteBuf p_237675_) { p_237675_.writeByte(this.flags); p_237675_.writeVarIntArray(this.children); if ((this.flags & 8) != 0) { p_237675_.writeVarInt(this.redirect); } if (this.stub != null) { this.stub.write(p_237675_); } } public boolean canBuild(IntSet p_237673_) { return (this.flags & 8) != 0 ? !p_237673_.contains(this.redirect) : true; } public boolean canResolve(IntSet p_237677_) { for (int i : this.children) { if (p_237677_.contains(i)) { return false; } } return true; } } static class LiteralNodeStub implements ClientboundCommandsPacket.NodeStub { private final String id; LiteralNodeStub(String p_237680_) { this.id = p_237680_; } @Override public ArgumentBuilder build(CommandBuildContext p_237682_) { return LiteralArgumentBuilder.literal(this.id); } @Override public void write(FriendlyByteBuf p_237684_) { p_237684_.writeUtf(this.id); } } static class NodeResolver { private final CommandBuildContext context; private final List entries; private final List> nodes; NodeResolver(CommandBuildContext p_237689_, List p_237690_) { this.context = p_237689_; this.entries = p_237690_; ObjectArrayList> objectarraylist = new ObjectArrayList<>(); objectarraylist.size(p_237690_.size()); this.nodes = objectarraylist; } public CommandNode resolve(int p_237692_) { CommandNode commandnode = this.nodes.get(p_237692_); if (commandnode != null) { return commandnode; } else { ClientboundCommandsPacket.Entry clientboundcommandspacket$entry = this.entries.get(p_237692_); CommandNode commandnode1; if (clientboundcommandspacket$entry.stub == null) { commandnode1 = new RootCommandNode<>(); } else { ArgumentBuilder argumentbuilder = clientboundcommandspacket$entry.stub.build(this.context); if ((clientboundcommandspacket$entry.flags & 8) != 0) { argumentbuilder.redirect(this.resolve(clientboundcommandspacket$entry.redirect)); } if ((clientboundcommandspacket$entry.flags & 4) != 0) { argumentbuilder.executes(p_237694_ -> 0); } commandnode1 = argumentbuilder.build(); } this.nodes.set(p_237692_, commandnode1); for (int i : clientboundcommandspacket$entry.children) { CommandNode commandnode2 = this.resolve(i); if (!(commandnode2 instanceof RootCommandNode)) { commandnode1.addChild(commandnode2); } } return commandnode1; } } } interface NodeStub { ArgumentBuilder build(CommandBuildContext p_237695_); void write(FriendlyByteBuf p_237696_); } }