ef0e5a642d
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: 9ae3f10f SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API 48c0c547 PR-786: Add methods to get sounds from entities CraftBukkit Changes: 5cc9c022a SPIGOT-7152: Handle hand item changing during air interact event 4ffa1acf6 SPIGOT-7154: Players get kicked when interacting with a conversation 4daa21123 SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API e5d6a9bbf PR-1100: Add methods to get sounds from entities b7e9f1c8b SPIGOT-7146: Reduce use of Material switch in ItemMeta Spigot Changes: 4c157bb4 Rebuild patches
296 Zeilen
14 KiB
Diff
296 Zeilen
14 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
|
Date: Tue, 30 Mar 2021 16:06:08 -0700
|
|
Subject: [PATCH] Enhance console tab completions for brigadier commands
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
index a4070b59e261f0f1ac4beec47b11492f4724bf27..c5d5648f4ca603ef2b1df723b58f9caf4dd3c722 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
@@ -16,11 +16,15 @@ public final class PaperConsole extends SimpleTerminalConsole {
|
|
|
|
@Override
|
|
protected LineReader buildReader(LineReaderBuilder builder) {
|
|
- return super.buildReader(builder
|
|
+ builder
|
|
.appName("Paper")
|
|
.variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history"))
|
|
.completer(new ConsoleCommandCompleter(this.server))
|
|
- );
|
|
+ .option(LineReader.Option.COMPLETE_IN_WORD, true);
|
|
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) {
|
|
+ builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server));
|
|
+ }
|
|
+ return super.buildReader(builder);
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0627c98cae0b5ebdd71a849ae1299d7d3d581850
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
|
|
@@ -0,0 +1,99 @@
|
|
+package io.papermc.paper.console;
|
|
+
|
|
+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion;
|
|
+import com.google.common.base.Suppliers;
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import com.mojang.brigadier.ParseResults;
|
|
+import com.mojang.brigadier.StringReader;
|
|
+import com.mojang.brigadier.suggestion.Suggestion;
|
|
+import io.papermc.paper.adventure.PaperAdventure;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.function.Supplier;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.network.chat.ComponentUtils;
|
|
+import net.minecraft.server.dedicated.DedicatedServer;
|
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
|
+import org.jline.reader.Candidate;
|
|
+import org.jline.reader.LineReader;
|
|
+import org.jline.reader.ParsedLine;
|
|
+
|
|
+import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion;
|
|
+
|
|
+public final class BrigadierCommandCompleter {
|
|
+ private final Supplier<CommandSourceStack> commandSourceStack;
|
|
+ private final DedicatedServer server;
|
|
+
|
|
+ public BrigadierCommandCompleter(final @NonNull DedicatedServer server) {
|
|
+ this.server = server;
|
|
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
|
|
+ }
|
|
+
|
|
+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List<Candidate> candidates, final @NonNull List<Completion> existing) {
|
|
+ //noinspection ConstantConditions
|
|
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
|
|
+ return;
|
|
+ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) {
|
|
+ this.addCandidates(candidates, Collections.emptyList(), existing);
|
|
+ return;
|
|
+ }
|
|
+ final CommandDispatcher<CommandSourceStack> dispatcher = this.server.getCommands().getDispatcher();
|
|
+ final ParseResults<CommandSourceStack> results = dispatcher.parse(prepareStringReader(line.line()), this.commandSourceStack.get());
|
|
+ this.addCandidates(
|
|
+ candidates,
|
|
+ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(),
|
|
+ existing
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private void addCandidates(
|
|
+ final @NonNull List<Candidate> candidates,
|
|
+ final @NonNull List<Suggestion> brigSuggestions,
|
|
+ final @NonNull List<Completion> existing
|
|
+ ) {
|
|
+ final List<Completion> completions = new ArrayList<>();
|
|
+ brigSuggestions.forEach(it -> completions.add(toCompletion(it)));
|
|
+ for (final Completion completion : existing) {
|
|
+ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) {
|
|
+ continue;
|
|
+ }
|
|
+ completions.add(completion);
|
|
+ }
|
|
+ for (final Completion completion : completions) {
|
|
+ if (completion.suggestion().isEmpty()) {
|
|
+ continue;
|
|
+ }
|
|
+ candidates.add(toCandidate(completion));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) {
|
|
+ final String suggestionText = completion.suggestion();
|
|
+ final String suggestionTooltip = PaperAdventure.PLAIN.serializeOr(completion.tooltip(), null);
|
|
+ return new Candidate(
|
|
+ suggestionText,
|
|
+ suggestionText,
|
|
+ null,
|
|
+ suggestionTooltip,
|
|
+ null,
|
|
+ null,
|
|
+ false
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static @NonNull Completion toCompletion(final @NonNull Suggestion suggestion) {
|
|
+ if (suggestion.getTooltip() == null) {
|
|
+ return completion(suggestion.getText());
|
|
+ }
|
|
+ return completion(suggestion.getText(), PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip())));
|
|
+ }
|
|
+
|
|
+ static @NonNull StringReader prepareStringReader(final @NonNull String line) {
|
|
+ final StringReader stringReader = new StringReader(line);
|
|
+ if (stringReader.canRead() && stringReader.peek() == '/') {
|
|
+ stringReader.skip();
|
|
+ }
|
|
+ return stringReader;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..dd9d77d7c7f1a5a130a1f4c15e5b1e68ae3753e1
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
|
|
@@ -0,0 +1,70 @@
|
|
+package io.papermc.paper.console;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+import com.mojang.brigadier.ParseResults;
|
|
+import com.mojang.brigadier.context.ParsedCommandNode;
|
|
+import com.mojang.brigadier.tree.LiteralCommandNode;
|
|
+import java.util.function.Supplier;
|
|
+import java.util.regex.Pattern;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.server.dedicated.DedicatedServer;
|
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
|
+import org.jline.reader.Highlighter;
|
|
+import org.jline.reader.LineReader;
|
|
+import org.jline.utils.AttributedString;
|
|
+import org.jline.utils.AttributedStringBuilder;
|
|
+import org.jline.utils.AttributedStyle;
|
|
+
|
|
+public final class BrigadierCommandHighlighter implements Highlighter {
|
|
+ private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, /* Client uses GOLD here, not BLUE, however there is no GOLD AttributedStyle. */ AttributedStyle.BLUE};
|
|
+ private final Supplier<CommandSourceStack> commandSourceStack;
|
|
+ private final DedicatedServer server;
|
|
+
|
|
+ public BrigadierCommandHighlighter(final @NonNull DedicatedServer server) {
|
|
+ this.server = server;
|
|
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public AttributedString highlight(final @NonNull LineReader reader, final @NonNull String buffer) {
|
|
+ //noinspection ConstantConditions
|
|
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
|
|
+ return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
|
+ }
|
|
+ final AttributedStringBuilder builder = new AttributedStringBuilder();
|
|
+ final ParseResults<CommandSourceStack> results = this.server.getCommands().getDispatcher().parse(BrigadierCommandCompleter.prepareStringReader(buffer), this.commandSourceStack.get());
|
|
+ int pos = 0;
|
|
+ if (buffer.startsWith("/")) {
|
|
+ builder.append("/", AttributedStyle.DEFAULT);
|
|
+ pos = 1;
|
|
+ }
|
|
+ int component = -1;
|
|
+ for (final ParsedCommandNode<CommandSourceStack> node : results.getContext().getLastChild().getNodes()) {
|
|
+ if (node.getRange().getStart() >= buffer.length()) {
|
|
+ break;
|
|
+ }
|
|
+ final int start = node.getRange().getStart();
|
|
+ final int end = Math.min(node.getRange().getEnd(), buffer.length());
|
|
+ builder.append(buffer.substring(pos, start), AttributedStyle.DEFAULT);
|
|
+ if (node.getNode() instanceof LiteralCommandNode) {
|
|
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT);
|
|
+ } else {
|
|
+ if (++component >= COLORS.length) {
|
|
+ component = 0;
|
|
+ }
|
|
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component]));
|
|
+ }
|
|
+ pos = end;
|
|
+ }
|
|
+ if (pos < buffer.length()) {
|
|
+ builder.append((buffer.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
|
+ }
|
|
+ return builder.toAttributedString();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setErrorPattern(final Pattern errorPattern) {}
|
|
+
|
|
+ @Override
|
|
+ public void setErrorIndex(final int errorIndex) {}
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index ef02ceba53943d34bd45070297c72beedd6e1883..f812b0a2d5534a7c443361bd69cfc2fe2110ba9a 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -178,7 +178,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
|
|
thread.setDaemon(true);
|
|
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
|
|
- thread.start();
|
|
+ // thread.start(); // Paper - moved down
|
|
DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName());
|
|
if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) {
|
|
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
|
@@ -210,6 +210,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames
|
|
// Paper end - moved up
|
|
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash);
|
|
+ thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized
|
|
io.papermc.paper.command.PaperCommands.registerCommands(this);
|
|
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics();
|
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
index 14cd8ae69d9b25dc5edad4ff96ff4a9acb1f22cb..cd4ad8261e56365850068db1d83d6a8454026737 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
@@ -18,9 +18,11 @@ import org.bukkit.event.server.TabCompleteEvent;
|
|
|
|
public class ConsoleCommandCompleter implements Completer {
|
|
private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer
|
|
+ private final io.papermc.paper.console.BrigadierCommandCompleter brigadierCompleter; // Paper
|
|
|
|
public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer
|
|
this.server = server;
|
|
+ this.brigadierCompleter = new io.papermc.paper.console.BrigadierCommandCompleter(this.server); // Paper
|
|
}
|
|
|
|
// Paper start - Change method signature for JLine update
|
|
@@ -64,7 +66,7 @@ public class ConsoleCommandCompleter implements Completer {
|
|
}
|
|
}
|
|
|
|
- if (!completions.isEmpty()) {
|
|
+ if (false && !completions.isEmpty()) {
|
|
for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) {
|
|
if (completion.suggestion().isEmpty()) {
|
|
continue;
|
|
@@ -80,6 +82,7 @@ public class ConsoleCommandCompleter implements Completer {
|
|
));
|
|
}
|
|
}
|
|
+ this.addCompletions(reader, line, candidates, completions);
|
|
return;
|
|
}
|
|
|
|
@@ -99,10 +102,12 @@ public class ConsoleCommandCompleter implements Completer {
|
|
try {
|
|
List<String> offers = waitable.get();
|
|
if (offers == null) {
|
|
+ this.addCompletions(reader, line, candidates, Collections.emptyList()); // Paper
|
|
return; // Paper - Method returns void
|
|
}
|
|
|
|
// Paper start - JLine update
|
|
+ /*
|
|
for (String completion : offers) {
|
|
if (completion.isEmpty()) {
|
|
continue;
|
|
@@ -110,6 +115,8 @@ public class ConsoleCommandCompleter implements Completer {
|
|
|
|
candidates.add(new Candidate(completion));
|
|
}
|
|
+ */
|
|
+ this.addCompletions(reader, line, candidates, offers.stream().map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::completion).collect(java.util.stream.Collectors.toList()));
|
|
// Paper end
|
|
|
|
// Paper start - JLine handles cursor now
|
|
@@ -138,5 +145,9 @@ public class ConsoleCommandCompleter implements Completer {
|
|
}
|
|
return false;
|
|
}
|
|
+
|
|
+ private void addCompletions(final LineReader reader, final ParsedLine line, final List<Candidate> candidates, final List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> existing) {
|
|
+ this.brigadierCompleter.complete(reader, line, candidates, existing);
|
|
+ }
|
|
// Paper end
|
|
}
|