From 3b9106c7d138f5ae99eb51834e768f1441a41bb2 Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Mon, 17 Feb 2025 23:51:52 +0100 Subject: [PATCH] Readd dead redirect recovery (#12136) While the paper command system no longer uses redirects for namespaced registration, vanilla still does. This means that removal of vanilla redirecting target nodes still causes issues, e.g. the removal of the vanilla 'msg' node in favour of a command alias one. Redirecting nodes like tell, minecraft:msg and minecraft:tell are broken by this and need to by flattened before sending them to the client. --- .../minecraft/commands/Commands.java.patch | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch index b5fdc04cca..dff5340ad3 100644 --- a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch @@ -144,7 +144,7 @@ } return null; -@@ -360,26 +_,85 @@ +@@ -360,26 +_,120 @@ } public void sendCommands(ServerPlayer player) { @@ -226,6 +226,41 @@ + if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot if (commandNode.canUse(source)) { ArgumentBuilder argumentBuilder = (ArgumentBuilder) commandNode.createBuilder(); ++ // Paper start ++ /* ++ Because of how commands can be yeeted right left and center due to bad bukkit practices ++ we need to be able to ensure that ALL commands are registered (even redirects). ++ ++ What this will do is IF the redirect seems to be "dead" it will create a builder and essentially populate (flatten) ++ all the children from the dead redirect to the node. ++ ++ So, if minecraft:msg redirects to msg but the original msg node has been overriden minecraft:msg will now act as msg and will explicilty inherit its children. ++ ++ The only way to fix this is to either: ++ - Send EVERYTHING flattened, don't use redirects ++ - Don't allow command nodes to be deleted ++ - Do this :) ++ */ ++ // Is there an invalid command redirect? ++ if (argumentBuilder.getRedirect() != null && commandNodeToSuggestionNode.get(argumentBuilder.getRedirect()) == null) { ++ // Create the argument builder with the same values as the specified node, but with a different literal and populated children ++ ++ final CommandNode redirect = argumentBuilder.getRedirect(); ++ // Diff copied from LiteralCommand#createBuilder ++ final com.mojang.brigadier.builder.LiteralArgumentBuilder builder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(commandNode.getName()); ++ builder.requires(redirect.getRequirement()); ++ // builder.forward(redirect.getRedirect(), redirect.getRedirectModifier(), redirect.isFork()); We don't want to migrate the forward, since it's invalid. ++ if (redirect.getCommand() != null) { ++ builder.executes(redirect.getCommand()); ++ } ++ // Diff copied from LiteralCommand#createBuilder ++ for (final CommandNode child : redirect.getChildren()) { ++ builder.then(child); ++ } ++ ++ argumentBuilder = builder; ++ } ++ // Paper end argumentBuilder.requires(suggestions -> true); - if (argumentBuilder.getCommand() != null) { - argumentBuilder.executes(commandContext -> 0);