77
88import com .mojang .brigadier .CommandDispatcher ;
99import com .mojang .brigadier .exceptions .CommandSyntaxException ;
10+ import meteordevelopment .meteorclient .MeteorClient ;
1011import meteordevelopment .meteorclient .commands .commands .*;
12+ import meteordevelopment .meteorclient .events .game .GameJoinedEvent ;
1113import meteordevelopment .meteorclient .pathing .PathManagers ;
1214import meteordevelopment .meteorclient .utils .PostInit ;
15+ import meteordevelopment .orbit .EventHandler ;
16+ import net .minecraft .client .network .ClientPlayNetworkHandler ;
17+ import net .minecraft .command .CommandRegistryAccess ;
1318import net .minecraft .command .CommandSource ;
1419
1520import java .util .ArrayList ;
1924import static meteordevelopment .meteorclient .MeteorClient .mc ;
2025
2126public class Commands {
22- public static final CommandDispatcher <CommandSource > DISPATCHER = new CommandDispatcher <>();
2327 public static final List <Command > COMMANDS = new ArrayList <>();
28+ public static CommandDispatcher <CommandSource > DISPATCHER = new CommandDispatcher <>();
2429
2530 @ PostInit (dependencies = PathManagers .class )
2631 public static void init () {
@@ -64,11 +69,12 @@ public static void init() {
6469 add (new LocateCommand ());
6570
6671 COMMANDS .sort (Comparator .comparing (Command ::getName ));
72+
73+ MeteorClient .EVENT_BUS .subscribe (Commands .class );
6774 }
6875
6976 public static void add (Command command ) {
7077 COMMANDS .removeIf (existing -> existing .getName ().equals (command .getName ()));
71- command .registerTo (DISPATCHER );
7278 COMMANDS .add (command );
7379 }
7480
@@ -85,4 +91,32 @@ public static Command get(String name) {
8591
8692 return null ;
8793 }
94+
95+ /**
96+ * Argument types that rely on Minecraft registries access those registries through a {@link CommandRegistryAccess}
97+ * object. Since dynamic registries are specific to each server, we need to make a new CommandRegistryAccess object
98+ * every time we join a server.
99+ * <p>
100+ * The command tree and by extension the {@link CommandDispatcher} also have to be rebuilt because:
101+ * <ol>
102+ * <li>Argument types that require registries use a registry wrapper object that is created and stored in the
103+ * argument type objects when the command tree is built.
104+ * <li>Registry entries and keys are compared using referential equality. Even if the data encoded is the same,
105+ * registry wrapper objects' dynamic data becomes stale after joining another server.
106+ * <li>The CommandDispatcher's node merging only adds missing children, it cannot replace stale argument type
107+ * objects.
108+ * </ol>
109+ *
110+ * @author Crosby
111+ */
112+ @ EventHandler
113+ private static void onJoin (GameJoinedEvent event ) {
114+ ClientPlayNetworkHandler networkHandler = mc .getNetworkHandler ();
115+ Command .REGISTRY_ACCESS = CommandRegistryAccess .of (networkHandler .getRegistryManager (), networkHandler .getEnabledFeatures ());
116+
117+ DISPATCHER = new CommandDispatcher <>();
118+ for (Command command : COMMANDS ) {
119+ command .registerTo (DISPATCHER );
120+ }
121+ }
88122}
0 commit comments