mirror of
https://github.com/PaperMC/Paper.git
synced 2024-09-12 06:58:11 +02:00
Upstream has released updates that appears 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: 42d5a714 SPIGOT-5899: Hoglins API similar to Piglins 2c1ee10e SPIGOT-5887: ClickType doesn't include off hand swaps 5ff7c7ce SPIGOT-5886: Missing BlockData CraftBukkit Changes:7560f5f5
SPIGOT-5905: Fix hex colours not being allowed in MOTDd47c47ee
SPIGOT-5889: Villager using composter should call EntityChangeBlockEvent2fe6b4a3
SPIGOT-5899: Hoglins API similar to Piglinse09dbeca
SPIGOT-5887: ClickType doesn't include off hand swaps23aac2a5
SPIGOT-5903: EntityDismountEvent cannot be triggered asynchronously92cbf656
SPIGOT-5884: Tab completions lost on reloadData / minecraft:reloadfb4e54ad
SPIGOT-5902: PlayerRespawnEvent places player at spawn before event is calledaa8f3d5a
SPIGOT-5901: Structures are generated in all worlds based on the setting for the main worlda0c35937
SPIGOT-5895: PlayerChangedWorldEvent#getFrom is incorrect89c0a5c3
SPIGOT-5886: Missing BlockData Spigot Changes: 0287a20d SPIGOT-5903: EntityDismountEvent cannot be triggered asynchronously
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/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
index 76cd3ea9512f4355a055d9c683d939680dc5a1b7..ccf083fbfa97b2a24338a3c1fe18e9a8c850feaf 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
@@ -527,10 +527,10 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
|
|
|
@Override
|
|
public void a(PacketPlayInTabComplete packetplayintabcomplete) {
|
|
- PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer());
|
|
+ // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async
|
|
// CraftBukkit start
|
|
if (chatSpamField.addAndGet(this, 1) > 500 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) {
|
|
- this.disconnect(new ChatMessage("disconnect.spam", new Object[0]));
|
|
+ minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]))); // Paper
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
@@ -540,12 +540,35 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
|
stringreader.skip();
|
|
}
|
|
|
|
- ParseResults<CommandListenerWrapper> parseresults = this.minecraftServer.getCommandDispatcher().a().parse(stringreader, this.player.getCommandListener());
|
|
+ // Paper start - async tab completion
|
|
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
|
+ java.util.List<String> completions = new java.util.ArrayList<>();
|
|
+ String buffer = packetplayintabcomplete.c();
|
|
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getPlayer(), 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.minecraftServer.getCommandDispatcher().a().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.networkManager.sendPacket(new PacketPlayOutTabComplete(packetplayintabcomplete.b(), suggestions));
|
|
- });
|
|
+ this.minecraftServer.scheduleOnMain(() -> { // Paper - This needs to be on main
|
|
+ ParseResults<CommandListenerWrapper> parseresults = this.minecraftServer.getCommandDispatcher().a().parse(stringreader, this.player.getCommandListener());
|
|
+
|
|
+ this.minecraftServer.getCommandDispatcher().a().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.networkManager.sendPacket(new PacketPlayOutTabComplete(packetplayintabcomplete.b(), suggestions));
|
|
+ });
|
|
+ });
|
|
+ }
|
|
+ } else if (!completions.isEmpty()) {
|
|
+ com.mojang.brigadier.suggestion.SuggestionsBuilder builder = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packetplayintabcomplete.c(), stringreader.getTotalLength());
|
|
+
|
|
+ builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
|
+ completions.forEach(builder::suggest);
|
|
+ player.playerConnection.sendPacket(new PacketPlayOutTabComplete(packetplayintabcomplete.b(), 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 a77beb5b66923bcc35974a2dd51b671ba8bd0078..3954eb18bb28ad9033c957e05a13068b8751dbc9 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -1785,7 +1785,7 @@ public final class CraftServer implements Server {
|
|
offers = 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 BlockPosition(pos)) : null); // Paper
|
|
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 5510266fb114954322823b72e3199f33c4d7a9a7..a51202ed53d8ba99b364e8797fe32fa8aeb4fc87 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
|