SPIGOT-6705: Re-print tab completion "Display all" message in console, when another message is being logged

By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2024-04-07 11:54:28 +10:00
parent 84d43ef379
commit d54bcadd91
3 changed files with 85 additions and 13 deletions

View file

@ -1,6 +1,6 @@
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -53,6 +53,16 @@
@@ -53,6 +53,18 @@
import net.minecraft.world.level.storage.Convertable;
import org.slf4j.Logger;
@ -10,6 +10,8 @@
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.io.IoBuilder;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.util.TerminalCompletionHandler;
+import org.bukkit.craftbukkit.util.TerminalConsoleWriterThread;
+import org.bukkit.event.server.ServerCommandEvent;
+import org.bukkit.event.server.RemoteServerCommandEvent;
+// CraftBukkit end
@ -17,7 +19,7 @@
public class DedicatedServer extends MinecraftServer implements IMinecraftServer {
static final Logger LOGGER = LogUtils.getLogger();
@@ -61,7 +71,7 @@
@@ -61,7 +73,7 @@
private final List<ServerCommand> consoleInput = Collections.synchronizedList(Lists.newArrayList());
@Nullable
private RemoteStatusListener queryThreadGs4;
@ -26,7 +28,7 @@
@Nullable
private RemoteControlListener rconThread;
public DedicatedServerSettings settings;
@@ -70,10 +80,12 @@
@@ -70,10 +82,12 @@
@Nullable
private final TextFilter textFilterClient;
@ -42,7 +44,7 @@
this.textFilterClient = TextFilter.createFromConfig(dedicatedserversettings.getProperties().textFilteringConfig);
}
@@ -81,13 +93,44 @@
@@ -81,13 +95,44 @@
public boolean initServer() throws IOException {
Thread thread = new Thread("Server console handler") {
public void run() {
@ -90,7 +92,7 @@
}
} catch (IOException ioexception) {
DedicatedServer.LOGGER.error("Exception handling console input", ioexception);
@@ -96,6 +139,27 @@
@@ -96,6 +141,29 @@
}
};
@ -109,7 +111,9 @@
+ }
+ }
+
+ new org.bukkit.craftbukkit.util.TerminalConsoleWriterThread(System.out, this.reader).start();
+ TerminalConsoleWriterThread writerThread = new TerminalConsoleWriterThread(System.out, this.reader);
+ this.reader.setCompletionHandler(new TerminalCompletionHandler(writerThread, this.reader.getCompletionHandler()));
+ writerThread.start();
+
+ System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream());
+ System.setErr(IoBuilder.forLogger(logger).setLevel(Level.WARN).buildPrintStream());
@ -118,7 +122,7 @@
thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
thread.start();
@@ -120,7 +184,7 @@
@@ -120,7 +188,7 @@
this.setMotd(dedicatedserverproperties.motd);
super.setPlayerIdleTimeout((Integer) dedicatedserverproperties.playerIdleTimeout.get());
this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist);
@ -127,7 +131,7 @@
DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode);
InetAddress inetaddress = null;
@@ -144,6 +208,12 @@
@@ -144,6 +212,12 @@
return false;
}
@ -140,7 +144,7 @@
if (!this.usesAuthentication()) {
DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
@@ -158,19 +228,19 @@
@@ -158,19 +232,19 @@
if (!NameReferencingFileConverter.serverReadyAfterUserconversion(this)) {
return false;
} else {
@ -163,7 +167,7 @@
}
if (dedicatedserverproperties.enableQuery) {
@@ -296,6 +366,7 @@
@@ -296,6 +370,7 @@
this.queryThreadGs4.stop();
}
@ -171,7 +175,7 @@
}
@Override
@@ -317,7 +388,15 @@
@@ -317,7 +392,15 @@
while (!this.consoleInput.isEmpty()) {
ServerCommand servercommand = (ServerCommand) this.consoleInput.remove(0);
@ -188,7 +192,7 @@
}
}
@@ -544,16 +623,52 @@
@@ -544,16 +627,52 @@
@Override
public String getPluginNames() {
@ -245,7 +249,7 @@
}
public void storeUsingWhiteList(boolean flag) {
@@ -604,4 +719,15 @@
@@ -604,4 +723,15 @@
public Optional<MinecraftServer.ServerResourcePackInfo> getServerResourcePack() {
return this.settings.getProperties().serverResourcePackInfo;
}

View file

@ -0,0 +1,53 @@
package org.bukkit.craftbukkit.util;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jline.console.ConsoleReader;
import jline.console.completer.CompletionHandler;
/**
* SPIGOT-6705: Make sure we print the display line again on tab completion, so that the user does not get stuck on it
* e.g. The user needs to press y / n to continue
*/
public class TerminalCompletionHandler implements CompletionHandler {
private final TerminalConsoleWriterThread writerThread;
private final CompletionHandler delegate;
public TerminalCompletionHandler(TerminalConsoleWriterThread writerThread, CompletionHandler delegate) {
this.writerThread = writerThread;
this.delegate = delegate;
}
@Override
public boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException {
// First check normal list, so that we do not unnecessarily create a new HashSet if the not distinct list is already lower
if (candidates.size() <= reader.getAutoprintThreshold()) {
return delegate.complete(reader, candidates, position);
}
Set<CharSequence> distinct = new HashSet<>(candidates);
if (distinct.size() <= reader.getAutoprintThreshold()) {
return delegate.complete(reader, candidates, position);
}
writerThread.setCompletion(distinct.size());
// FIXME: Potential concurrency issue, when terminal writer prints the display message before the delegate does it
// resulting in two display message being present, until a new message gets logged or the user presses y / n
// But the probability of this happening are probably lower than the effort needed to fix this
// And seeing the display message at all should be a higher priority than seeing it two times in rare cases.
boolean result = delegate.complete(reader, candidates, position);
writerThread.setCompletion(-1);
// draw line to prevent concurrency issue,
// where terminal write would print the display message between delegate#complete finished and the completion set back to -1
// Resulting in the display message being present even after pressing y / n
reader.drawLine();
reader.flush();
return result;
}
}

View file

@ -3,16 +3,21 @@ package org.bukkit.craftbukkit.util;
import com.mojang.logging.LogQueues;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import jline.console.ConsoleReader;
import jline.console.completer.CandidateListCompletionHandler;
import org.bukkit.craftbukkit.Main;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Erase;
public class TerminalConsoleWriterThread extends Thread {
private final ResourceBundle bundle = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
private final ConsoleReader reader;
private final OutputStream output;
private volatile int completion = -1;
public TerminalConsoleWriterThread(OutputStream output, ConsoleReader reader) {
super("TerminalConsoleWriter");
@ -45,6 +50,12 @@ public class TerminalConsoleWriterThread extends Thread {
} catch (Throwable ex) {
reader.getCursorBuffer().clear();
}
if (completion > -1) {
// SPIGOT-6705: Make sure we print the display line again on tab completion, so that the user does not get stuck on it
reader.print(String.format(bundle.getString("DISPLAY_CANDIDATES"), completion));
}
reader.flush();
} else {
output.write(message.getBytes());
@ -55,4 +66,8 @@ public class TerminalConsoleWriterThread extends Thread {
}
}
}
void setCompletion(int completion) {
this.completion = completion;
}
}