diff --git a/patches/server/Ensure-commands-are-not-ran-async.patch b/patches/server/Ensure-commands-are-not-ran-async.patch index bcc2d4fadb..e7dcba0768 100644 --- a/patches/server/Ensure-commands-are-not-ran-async.patch +++ b/patches/server/Ensure-commands-are-not-ran-async.patch @@ -13,40 +13,66 @@ This change will synchronize the command execution back to the main thread, caus big slowdown in execution but throwing an exception at same time to raise awareness that it is happening so that plugin authors can fix their code to stop executing commands async. +This also properly splits up the chat and command handling to reflect the server now +having separate packets for both, and the client always using the correct packet. Text +from a chat packet should never be parsed into a command, even if it starts with the `/` +character. + +Co-authored-by: Jake Potrebic + diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + return true; + } + +- private static boolean isChatMessageIllegal(String message) { ++ public static boolean isChatMessageIllegal(String message) { // Paper - private -> public + for (int i = 0; i < message.length(); ++i) { + if (!SharedConstants.isAllowedChatCharacter(message.charAt(i))) { + return true; +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + } OutgoingPlayerChatMessage outgoing = OutgoingPlayerChatMessage.create(original); - if (!async && s.startsWith("/")) { -+ // Paper Start -+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) { -+ final String fCommandLine = s; -+ LOGGER.error("Command Dispatched Async: " + fCommandLine); -+ LOGGER.error("Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); -+ Waitable wait = new Waitable() { -+ @Override -+ protected Object evaluate() { -+ chat(fCommandLine, original, false); -+ return null; -+ } -+ }; -+ server.processQueue.add(wait); -+ try { -+ wait.get(); -+ return; -+ } catch (InterruptedException e) { -+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on! -+ } catch (Exception e) { -+ throw new RuntimeException("Exception processing chat command", e.getCause()); -+ } -+ } -+ // Paper End +- if (!async && s.startsWith("/")) { ++ if (false && !async && s.startsWith("/")) { // Paper - don't handle commands in chat logic this.handleCommand(s); } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Do nothing, this is coming from a plugin +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + } + } + +- private void handleCommand(String s) { ++ public void handleCommand(String s) { // Paper - private -> public ++ // Paper Start ++ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) { ++ LOGGER.error("Command Dispatched Async: " + s); ++ LOGGER.error("Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); ++ Waitable wait = new Waitable<>() { ++ @Override ++ protected Void evaluate() { ++ ServerGamePacketListenerImpl.this.handleCommand(s); ++ return null; ++ } ++ }; ++ server.processQueue.add(wait); ++ try { ++ wait.get(); ++ return; ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on! ++ } catch (Exception e) { ++ throw new RuntimeException("Exception processing chat command", e.getCause()); ++ } ++ } ++ // Paper End + co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper + if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot + this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -80,6 +106,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.commandMap.dispatch(sender, commandLine)) { return true; } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + public void chat(String msg) { + if (this.getHandle().connection == null) return; + +- this.getHandle().connection.chat(msg, null, false); ++ // Paper start - improve chat handling ++ if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) { ++ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); ++ } else { ++ if (msg.startsWith("/")) { ++ this.getHandle().connection.handleCommand(msg); ++ } else { ++ // TODO text filtering ++ // TODO chat decorating ++ this.getHandle().connection.chat(msg, PlayerChatMessage.unsigned(net.minecraft.network.chat.MessageSigner.create(this.getUniqueId()), new net.minecraft.network.chat.ChatMessageContent(msg)), false); ++ } ++ } ++ // Paper end + } + + @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java