mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-23 09:27:45 +01:00
0fa2a949ae
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 8503c3c9 #621: Add HumanEntity#getItemInUse and Material#getSlipperiness 248deb09 #622: Add methods to check if item is the breed item for an entity 2ce691d8 Clarify Player#breakBlock only works for blocks in the same world 5dcdd48e SPIGOT-6514: Small Dripleaf block data is missing half property cc9610b7 #619: Add Player#breakBlock() 862bc475 Fix bad merge of SPIGOT-6502 fix 989bb0c1 Downgrade SnakeYAML due to issues with comments parsing 1dff62ae Fix inverted visual fire docs CraftBukkit Changes: 40caacc8 SPIGOT-6526: World entities are not populated when plugin onEnable is called c9a92ad0 SPIGOT-6536: Marker position not set on spawn 20d3e57c #855: Add HumanEntity#getItemInUse and Material#getSlipperiness d9c69b44 SPIGOT-6529: Fix BundleMeta#setItems 8bd43be5 SPIGOT-6535: PlayerGameModeChangeEvent event incorrectly reports old gamemode 4ece3ff3 #856: Add methods to check if item is the breed item for an entity dd4bec5f Add additional validation to Player#breakBlock bc835ae6 SPIGOT-6532: Fix Entity#setGlowing 384e116e Restore 1.16.5 behaviour of InventoryDragEvent being called even when a single item is 'dragged' to its own slot b42e708c Fix new map colors rendering as transparent cfe7fecf SPIGOT-6524: Inventory desync when InventoryClickEvent is cancelled eeae1b19 SPIGOT-6522: ItemStack on cursor is always AIR 7490724d Fix missing PlayerEditBookEvent 06875f76 SPIGOT-6513: Placing ItemStack in Inventory causes InventoryAction.NOTHING 27835bde SPIGOT-6519: Fix end gateway teleports 4ac634ad SPIGOT-6515: "Un-waterlogging" throws UnsupportedOperationException in some cases da425fa2 SPIGOT-6518: Anvils falling onto dripstone can sometimes crash server 50530da9 SPIGOT-6514: Small Dripleaf block data is missing half property 6fdecf20 #853: Implement Player#breakBlock() 4db9c49f SPIGOT-6510: Bukkit#createMap throws NullPointerException 89e2b127 SPIGOT-6517: Spider jockey crash on dripstone cbf2f678 SPIGOT-6508: Rename conflicted getServer 74575d48 SPIGOT-6506: Fix crash with custom inventories a3df386f Fix NPE with Entity.getNearbyEntities d747f8ed Fix NPE with World.getNearbyEntities 4d2c7800 Fix second usage of worldGenSettings just in case 5182f923 SPIGOT-6504: Fix generating fresh worlds Spigot Changes: 66f9d3c1 Rebuild patches 191e4971 Rebuild patches a09c0bb6 Restore Spigot experience merging
131 lines
8.1 KiB
Diff
131 lines
8.1 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Sun, 26 Nov 2017 13:19:58 -0500
|
|
Subject: [PATCH] AsyncTabCompleteEvent
|
|
|
|
Let plugins be able to control tab completion of commands and chat async.
|
|
|
|
This will be useful for frameworks like ACF so we can define async safe completion handlers,
|
|
and avoid going to main for tab completions.
|
|
|
|
Especially useful if you need to query a database in order to obtain the results for tab
|
|
completion, such as offline players.
|
|
|
|
Also adds isCommand and getLocation to the sync TabCompleteEvent
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
index 985736fc4e3d702a1fd787336db8ab18ee2a4783..5b426265d62063544f0104c8c9f8061d002bc56c 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -703,10 +703,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
|
|
@Override
|
|
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
|
|
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
|
+ // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async
|
|
// CraftBukkit start
|
|
if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
|
|
- this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]));
|
|
+ server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
@@ -716,12 +716,35 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
stringreader.skip();
|
|
}
|
|
|
|
- ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
|
+ // Paper start - async tab completion
|
|
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
|
+ java.util.List<String> completions = new java.util.ArrayList<>();
|
|
+ String buffer = packet.getCommand();
|
|
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), completions,
|
|
+ buffer, true, null);
|
|
+ event.callEvent();
|
|
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
|
+ // 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.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
|
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
|
|
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
|
|
- });
|
|
+ this.server.scheduleOnMain(() -> { // Paper - This needs to be on main
|
|
+ ParseResults<CommandSourceStack> 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 [<args>] from showing for plugins with nothing more to offer
|
|
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
|
|
+ });
|
|
+ });
|
|
+ }
|
|
+ } else if (!completions.isEmpty()) {
|
|
+ com.mojang.brigadier.suggestion.SuggestionsBuilder builder = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringreader.getTotalLength());
|
|
+
|
|
+ builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
|
+ completions.forEach(builder::suggest);
|
|
+ player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
|
|
+ }
|
|
+ // Paper end - async tab completion
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
index 754e10be4f62ee3efac34bea3c72e23b1b06053c..8e93f6398a5974676a479e17f31a8e77c461fb41 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -1851,7 +1851,7 @@ public final class CraftServer implements Server {
|
|
offers = this.tabCompleteChat(player, message);
|
|
}
|
|
|
|
- TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers);
|
|
+ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? net.minecraft.server.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper
|
|
this.getPluginManager().callEvent(tabEvent);
|
|
|
|
return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
index b996fde481cebbbcce80a6c267591136db7cc0bc..e5af155d75f717d33c23e22ff8b96bb3ff87844d 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
@@ -28,6 +28,39 @@ public class ConsoleCommandCompleter implements Completer {
|
|
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
|
final CraftServer server = this.server.server;
|
|
final String buffer = line.line();
|
|
+ // Async Tab Complete
|
|
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
|
+ java.util.List<String> completions = new java.util.ArrayList<>();
|
|
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(server.getConsoleSender(), completions,
|
|
+ buffer, true, null);
|
|
+ event.callEvent();
|
|
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
|
+
|
|
+ if (event.isCancelled() || event.isHandled()) {
|
|
+ // Still fire sync event with the provided completions, if someone is listening
|
|
+ if (!event.isCancelled() && TabCompleteEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
+ List<String> finalCompletions = completions;
|
|
+ Waitable<List<String>> syncCompletions = new Waitable<List<String>>() {
|
|
+ @Override
|
|
+ protected List<String> evaluate() {
|
|
+ org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(server.getConsoleSender(), buffer, finalCompletions);
|
|
+ return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of();
|
|
+ }
|
|
+ };
|
|
+ server.getServer().processQueue.add(syncCompletions);
|
|
+ try {
|
|
+ completions = syncCompletions.get();
|
|
+ } catch (InterruptedException | ExecutionException e1) {
|
|
+ e1.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!completions.isEmpty()) {
|
|
+ candidates.addAll(completions.stream().map(Candidate::new).collect(java.util.stream.Collectors.toList()));
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
// Paper end
|
|
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
|
@Override
|