From 679f34297e02703419d8c2eba92bbb7ae89a7527 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Mon, 5 Feb 2024 12:31:51 +0100 Subject: [PATCH] Improve tag parser handling, move hunks out of chunk system patch --- .../server/Add-PlayerKickEvent-causes.patch | 4 +- patches/server/AsyncTabCompleteEvent.patch | 79 +++++----- ...nd-make-tab-spam-limits-configurable.patch | 2 +- patches/server/Brigadier-Mojang-API.patch | 54 +++---- ...-ServerboundCommandSuggestionPacket-.patch | 4 +- ...te-namespaced-commands-if-send-names.patch | 20 +-- .../server/Improve-tag-parser-handling.patch | 143 ++++++++++++++++++ patches/server/Rewrite-chunk-system.patch | 31 ---- 8 files changed, 222 insertions(+), 115 deletions(-) create mode 100644 patches/server/Improve-tag-parser-handling.patch diff --git a/patches/server/Add-PlayerKickEvent-causes.patch b/patches/server/Add-PlayerKickEvent-causes.patch index 58d6a1da6d..6f78330fc1 100644 --- a/patches/server/Add-PlayerKickEvent-causes.patch +++ b/patches/server/Add-PlayerKickEvent-causes.patch @@ -261,8 +261,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async // CraftBukkit start if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper - configurable tab spam limits -- server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam"))); // Paper - AsyncTabCompleteEvent -+ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - AsyncTabCompleteEvent & kick event cause +- this.disconnect(Component.translatable("disconnect.spam")); ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause return; } // CraftBukkit end diff --git a/patches/server/AsyncTabCompleteEvent.patch b/patches/server/AsyncTabCompleteEvent.patch index 21970c4342..3048ac02ed 100644 --- a/patches/server/AsyncTabCompleteEvent.patch +++ b/patches/server/AsyncTabCompleteEvent.patch @@ -33,59 +33,52 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async // CraftBukkit start if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { -- this.disconnect(Component.translatable("disconnect.spam")); -+ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam"))); // Paper - AsyncTabCompleteEvent + this.disconnect(Component.translatable("disconnect.spam")); return; } // CraftBukkit end + // Paper start - AsyncTabCompleteEvent -+ TAB_COMPLETE_EXECUTOR.execute(() -> { ++ TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); ++ } ++ ++ private void handleCustomCommandSuggestions0(final ServerboundCommandSuggestionPacket packet) { StringReader stringreader = new StringReader(packet.getCommand()); if (stringreader.canRead() && stringreader.peek() == '/') { stringreader.skip(); } -- -- ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); -- -- this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer -- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); -+ final String command = packet.getCommand(); -+ final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), command, true, null); -+ event.callEvent(); -+ final java.util.List completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.completions(); -+ // If the event isn't handled, we can assume that we have no completions, and so we'll ask the server -+ if (!event.isHandled()) { -+ if (!event.isCancelled()) { -+ -+ this.server.scheduleOnMain(() -> { // This needs to be on main -+ ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); -+ -+ this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -+ if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer -+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); -+ }); -+ }); -+ } -+ } else if (!completions.isEmpty()) { -+ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(command, stringreader.getTotalLength()); -+ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder = builder0.createOffset(builder0.getInput().lastIndexOf(' ') + 1); -+ completions.forEach(completion -> { -+ final Integer intSuggestion = com.google.common.primitives.Ints.tryParse(completion.suggestion()); -+ if (intSuggestion != null) { -+ builder.suggest(intSuggestion, PaperAdventure.asVanilla(completion.tooltip())); -+ } else { -+ builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); -+ } -+ }); -+ player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join())); -+ } - }); -+ // Paper end - AsyncTabCompleteEvent - } - @Override ++ final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), packet.getCommand(), true, null); ++ event.callEvent(); ++ final List completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.completions(); ++ // If the event isn't handled, we can assume that we have no completions, and so we'll ask the server ++ if (!event.isHandled()) { ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ // This needs to be on main ++ this.server.scheduleOnMain(() -> this.sendServerSuggestions(packet, stringreader)); ++ } else if (!completions.isEmpty()) { ++ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringreader.getTotalLength()); ++ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder = builder0.createOffset(builder0.getInput().lastIndexOf(' ') + 1); ++ for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) { ++ final Integer intSuggestion = com.google.common.primitives.Ints.tryParse(completion.suggestion()); ++ if (intSuggestion != null) { ++ builder.suggest(intSuggestion, PaperAdventure.asVanilla(completion.tooltip())); ++ } else { ++ builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); ++ } ++ } ++ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join())); ++ } ++ } ++ ++ private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) { ++ // Paper end - AsyncTabCompleteEvent + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); + + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { 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 diff --git a/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch b/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch index 31e847c6eb..271c9e007f 100644 --- a/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch +++ b/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch @@ -47,6 +47,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { + if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper - configurable tab spam limits - server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam"))); // Paper - AsyncTabCompleteEvent + this.disconnect(Component.translatable("disconnect.spam")); return; } diff --git a/patches/server/Brigadier-Mojang-API.patch b/patches/server/Brigadier-Mojang-API.patch index f525d15bd4..e058995cd1 100644 --- a/patches/server/Brigadier-Mojang-API.patch +++ b/patches/server/Brigadier-Mojang-API.patch @@ -135,35 +135,37 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 extends ServerCommonPacketListenerImpl - ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); - - this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer -- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); -+ // Paper start - Brigadier API -+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, command); -+ suggestEvent.setCancelled(suggestions.isEmpty()); -+ if (!suggestEvent.callEvent()) return; -+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); -+ // Paper end - Brigadier API - }); - }); + builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); } -@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); - } - }); -- player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join())); -+ // Paper start - Brigadier API -+ com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join(); -+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, command); -+ suggestEvent.setCancelled(suggestions.isEmpty()); -+ if (!suggestEvent.callEvent()) return; -+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); -+ // Paper end - Brigadier API } +- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join())); ++ // Paper start - Brigadier API ++ com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join(); ++ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); ++ suggestEvent.setCancelled(suggestions.isEmpty()); ++ if (suggestEvent.callEvent()) { ++ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); ++ } ++ // Paper end - Brigadier API + } + } + +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); + + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { +- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer +- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); ++ // Paper start - Brigadier API ++ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); ++ suggestEvent.setCancelled(suggestions.isEmpty()); ++ if (suggestEvent.callEvent()) { ++ this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); ++ } ++ // Paper end - Brigadier API }); - // Paper end - AsyncTabCompleteEvent + } + diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java diff --git a/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch index f903a12e79..34a208bedd 100644 --- a/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch +++ b/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch @@ -19,5 +19,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - Don't suggest if tab-complete is disabled // Paper start - AsyncTabCompleteEvent - TAB_COMPLETE_EXECUTOR.execute(() -> { - StringReader stringreader = new StringReader(packet.getCommand()); + TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); + } diff --git a/patches/server/Don-t-tab-complete-namespaced-commands-if-send-names.patch b/patches/server/Don-t-tab-complete-namespaced-commands-if-send-names.patch index b35fd82657..eebf0f4ef6 100644 --- a/patches/server/Don-t-tab-complete-namespaced-commands-if-send-names.patch +++ b/patches/server/Don-t-tab-complete-namespaced-commands-if-send-names.patch @@ -15,14 +15,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 extends ServerCommonPacketListenerImpl - ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); - this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -+ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false -+ if (!org.spigotmc.SpigotConfig.sendNamespaced && suggestions.getRange().getStart() <= 1) { -+ suggestions.getList().removeIf(suggestion -> suggestion.getText().contains(":")); -+ } -+ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false - // Paper start - Brigadier API - com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, command); - suggestEvent.setCancelled(suggestions.isEmpty()); + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { ++ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false ++ if (!org.spigotmc.SpigotConfig.sendNamespaced && suggestions.getRange().getStart() <= 1) { ++ suggestions.getList().removeIf(suggestion -> suggestion.getText().contains(":")); ++ } ++ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false + // Paper start - Brigadier API + com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); + suggestEvent.setCancelled(suggestions.isEmpty()); diff --git a/patches/server/Improve-tag-parser-handling.patch b/patches/server/Improve-tag-parser-handling.patch new file mode 100644 index 0000000000..4d483370af --- /dev/null +++ b/patches/server/Improve-tag-parser-handling.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Mon, 5 Feb 2024 11:54:04 +0100 +Subject: [PATCH] Improve tag parser handling + + +diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java ++++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +@@ -0,0 +0,0 @@ public class CommandDispatcher { + try { + try { + child.parse(reader, context); ++ // Paper start - Handle non-reoverable exceptions; Rethrow NbtAccounterException so it can be caught properly and immediately ++ } catch (final net.minecraft.nbt.NbtAccounterException e) { ++ throw e; ++ // Paper end - Handle non-reoverable exceptions + } catch (final RuntimeException ex) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage()); + } +diff --git a/src/main/java/net/minecraft/nbt/TagParser.java b/src/main/java/net/minecraft/nbt/TagParser.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/nbt/TagParser.java ++++ b/src/main/java/net/minecraft/nbt/TagParser.java +@@ -0,0 +0,0 @@ public class TagParser { + } + }, CompoundTag::toString); + private final StringReader reader; ++ private int depth; // Paper + + public static CompoundTag parseTag(String string) throws CommandSyntaxException { + return (new TagParser(new StringReader(string))).readSingleStruct(); +@@ -0,0 +0,0 @@ public class TagParser { + + public CompoundTag readStruct() throws CommandSyntaxException { + this.expect('{'); ++ this.increaseDepth(); // Paper + CompoundTag compoundTag = new CompoundTag(); + this.reader.skipWhitespace(); + +@@ -0,0 +0,0 @@ public class TagParser { + } + + this.expect('}'); ++ this.depth--; // Paper + return compoundTag; + } + +@@ -0,0 +0,0 @@ public class TagParser { + if (!this.reader.canRead()) { + throw ERROR_EXPECTED_VALUE.createWithContext(this.reader); + } else { ++ this.increaseDepth(); // Paper + ListTag listTag = new ListTag(); + TagType tagType = null; + +@@ -0,0 +0,0 @@ public class TagParser { + } + + this.expect(']'); ++ this.depth--; // Paper + return listTag; + } + } +@@ -0,0 +0,0 @@ public class TagParser { + } + + if (typeReader == ByteTag.TYPE) { +- list.add((T)((NumericTag)tag).getAsByte()); ++ list.add((T)((NumericTag)tag).getAsNumber()); // Paper - decompile fix + } else if (typeReader == LongTag.TYPE) { +- list.add((T)((NumericTag)tag).getAsLong()); ++ list.add((T)((NumericTag)tag).getAsNumber()); // Paper - decompile fix + } else { +- list.add((T)((NumericTag)tag).getAsInt()); ++ list.add((T)((NumericTag)tag).getAsNumber()); // Paper - decompile fix + } + + if (this.hasElementSeparator()) { +@@ -0,0 +0,0 @@ public class TagParser { + this.reader.skipWhitespace(); + this.reader.expect(c); + } ++ ++ private void increaseDepth() { ++ this.depth++; ++ if (this.depth > 512) { ++ throw new net.minecraft.nbt.NbtAccounterException("NBT tag is too complex, depth > 512"); ++ } ++ } + } +diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java +@@ -0,0 +0,0 @@ public class ServerboundCommandSuggestionPacket implements Packet 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) { ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); ++ return; ++ } ++ // Paper end + // Paper start - AsyncTabCompleteEvent + TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); + } +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) { + // Paper end - AsyncTabCompleteEvent +- ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); ++ // Paper start - Handle non-reoverable exceptions ++ ParseResults parseresults; ++ try { ++ parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); ++ } catch (final Throwable e) { // This is fine:tm: ++ if (LOGGER.isDebugEnabled()) { ++ LOGGER.error("Exception parsing command", e); ++ } ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); ++ return; ++ } ++ // Paper end - Handle non-reoverable exceptions + + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { + // Paper start - Don't tab-complete namespaced commands if send-namespaced is false diff --git a/patches/server/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch index 6162c1c534..2789e64499 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -15506,19 +15506,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} -diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -@@ -0,0 +0,0 @@ public class ServerboundCommandSuggestionPacket implements Packet 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) { -+ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); -+ return; -+ } -+ // Paper end - rewrite chunk system - // Paper start - AsyncTabCompleteEvent - TAB_COMPLETE_EXECUTOR.execute(() -> { - StringReader stringreader = new StringReader(packet.getCommand()); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java