aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMinecrell <[email protected]>2017-06-09 19:05:12 +0200
committerMinecrell <[email protected]>2017-06-11 14:31:21 +0200
commitde2af506f35c415345189814a08f867a70f76a4b (patch)
treea763f32c2f357de3ff17947713ab52f8046d5c5b
parentfe4678c414341f7e13f533019d0fb042ffdef16b (diff)
downloadPaper-de2af506f35c415345189814a08f867a70f76a4b.tar.gz
Paper-de2af506f35c415345189814a08f867a70f76a4b.zip
Improve console implementation
Rewrite console improvements (console colors, tab completion, persistent input line, ...) using JLine 3.x and TerminalConsoleAppender. New features: - Support console colors for Vanilla commands - Add console colors for warnings and errors - Server can now be turned off safely using CTRL + C. JLine catches the signal and the implementation shuts down the server cleanly. - Support console colors and persistent input line when running in IntelliJ IDEA Other changes: - Update JLine to 3.3.1 (from 2.12.1) - Server starts 1-2 seconds faster thanks to optimizations in Log4j configuration
-rw-r--r--.gitignore4
-rw-r--r--Spigot-Server-Patches/0211-Add-configuration-option-to-prevent-player-names-fro.patch (renamed from Spigot-Server-Patches/0212-Add-configuration-option-to-prevent-player-names-fro.patch)0
-rw-r--r--Spigot-Server-Patches/0211-Workaround-for-jansi-bug-with-Windows.patch29
-rw-r--r--Spigot-Server-Patches/0212-Use-TerminalConsoleAppender-for-console-improvements.patch614
-rw-r--r--pom.xml5
5 files changed, 622 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index 321af62064..a8596ddd67 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,11 +42,13 @@ work/test-server
*.ipr
*.iws
.idea/
+out/
# Linux temp files
*~
# other stuff
+run/
Paper-Server
Paper-API
@@ -55,4 +57,4 @@ PaperSpigot-API
Paperclip.jar
paperclip.jar
paperclip-*.jar
-paperclip.properties \ No newline at end of file
+paperclip.properties
diff --git a/Spigot-Server-Patches/0212-Add-configuration-option-to-prevent-player-names-fro.patch b/Spigot-Server-Patches/0211-Add-configuration-option-to-prevent-player-names-fro.patch
index 09d8cb77eb..09d8cb77eb 100644
--- a/Spigot-Server-Patches/0212-Add-configuration-option-to-prevent-player-names-fro.patch
+++ b/Spigot-Server-Patches/0211-Add-configuration-option-to-prevent-player-names-fro.patch
diff --git a/Spigot-Server-Patches/0211-Workaround-for-jansi-bug-with-Windows.patch b/Spigot-Server-Patches/0211-Workaround-for-jansi-bug-with-Windows.patch
deleted file mode 100644
index 2fd2250eea..0000000000
--- a/Spigot-Server-Patches/0211-Workaround-for-jansi-bug-with-Windows.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 6e358e579628685730d344c55695e30694525cc0 Mon Sep 17 00:00:00 2001
-From: Shane Freeder <[email protected]>
-Date: Wed, 17 May 2017 17:45:19 -0500
-Subject: [PATCH] Workaround for jansi bug with Windows
-
-When jansi attempts to extract its natives, by default it tries to extract a specific version
-using the loading class's implementation version. Normally this works completely fine
-however when on Windows certain characters such as - and : can trigger special behaviour.
-
-Furthermore this behaviour only occurs in specific combinations due to the parsing done by jansi.
-For example test-test works fine, but test-test-test does not! In order to avoid this all together but
-still keep our versions the same as they were, we set the override property to the essentially garbage version
-Paper. This version is only used when extracting the libraries to their temp folder.
-
-diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
-index 1cbcc3dfa..98e27fa25 100644
---- a/src/main/java/org/bukkit/craftbukkit/Main.java
-+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
-@@ -182,6 +182,7 @@ public class Main {
- }
-
- if (useJline) {
-+ System.setProperty( "library.jansi.version", "Paper" ); // Paper - set jansi library version to avoid crash
- AnsiConsole.systemInstall();
- } else {
- // This ensures the terminal literal will always match the jline implementation
---
-2.13.0.windows.1
-
diff --git a/Spigot-Server-Patches/0212-Use-TerminalConsoleAppender-for-console-improvements.patch b/Spigot-Server-Patches/0212-Use-TerminalConsoleAppender-for-console-improvements.patch
new file mode 100644
index 0000000000..5b28c22118
--- /dev/null
+++ b/Spigot-Server-Patches/0212-Use-TerminalConsoleAppender-for-console-improvements.patch
@@ -0,0 +1,614 @@
+From 3d69c48006f75e45b053b2d626a1829f71d1a7d6 Mon Sep 17 00:00:00 2001
+From: Minecrell <[email protected]>
+Date: Fri, 9 Jun 2017 19:03:43 +0200
+Subject: [PATCH] Use TerminalConsoleAppender for console improvements
+
+Rewrite console improvements (console colors, tab completion,
+persistent input line, ...) using JLine 3.x and TerminalConsoleAppender.
+
+New features:
+ - Support console colors for Vanilla commands
+ - Add console colors for warnings and errors
+ - Server can now be turned off safely using CTRL + C. JLine catches
+ the signal and the implementation shuts down the server cleanly.
+ - Support console colors and persistent input line when running in
+ IntelliJ IDEA
+
+Other changes:
+ - Update JLine to 3.3.1 (from 2.12.1)
+ - Server starts 1-2 seconds faster thanks to optimizations in Log4j
+ configuration
+
+diff --git a/pom.xml b/pom.xml
+index b2aa10ff..0ae2c9c6 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -47,12 +47,6 @@
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+- <groupId>jline</groupId>
+- <artifactId>jline</artifactId>
+- <version>2.12.1</version>
+- <scope>compile</scope>
+- </dependency>
+- <dependency>
+ <groupId>org.xerial</groupId>
+ <artifactId>sqlite-jdbc</artifactId>
+ <version>3.18.0</version>
+@@ -69,6 +63,38 @@
+ <artifactId>trove4j</artifactId>
+ <version>3.0.3</version>
+ </dependency>
++
++ <dependency>
++ <groupId>net.minecrell</groupId>
++ <artifactId>terminalconsoleappender</artifactId>
++ <version>1.0.0-SNAPSHOT</version>
++ </dependency>
++ <dependency>
++ <groupId>org.jline</groupId>
++ <artifactId>jline-terminal-jna</artifactId>
++ <version>3.3.1</version>
++ <scope>runtime</scope>
++ </dependency>
++ <dependency>
++ <groupId>net.java.dev.jna</groupId>
++ <artifactId>jna</artifactId>
++ <version>4.4.0</version>
++ <scope>runtime</scope>
++ </dependency>
++
++ <!--
++ Required to add the missing Log4j2Plugins.dat file from log4j-core
++ which has been removed by Mojang. Without it, log4j has to classload
++ all its classes to check if they are plugins.
++ Scanning takes about 1-2 seconds so adding this speeds up the server start.
++ -->
++ <dependency>
++ <groupId>org.apache.logging.log4j</groupId>
++ <artifactId>log4j-core</artifactId>
++ <version>2.8.1</version>
++ <scope>runtime</scope>
++ </dependency>
++
+ <!-- testing -->
+ <dependency>
+ <groupId>junit</groupId>
+@@ -216,10 +242,18 @@
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>META-INF/services/java.sql.Driver</resource>
+ </transformer>
++ <transformer implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer" />
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
++ <dependencies>
++ <dependency>
++ <groupId>com.github.edwgiz</groupId>
++ <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
++ <version>2.8.1</version>
++ </dependency>
++ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+diff --git a/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java
+new file mode 100644
+index 00000000..24f30efb
+--- /dev/null
++++ b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java
+@@ -0,0 +1,13 @@
++package com.destroystokyo.paper.console;
++
++import org.bukkit.craftbukkit.command.CraftConsoleCommandSender;
++
++public class TerminalConsoleCommandSender extends CraftConsoleCommandSender {
++
++ @Override
++ public void sendRawMessage(String message) {
++ // Print message with colors
++ System.out.println(message);
++ }
++
++}
+diff --git a/src/main/java/com/destroystokyo/paper/console/TerminalHandler.java b/src/main/java/com/destroystokyo/paper/console/TerminalHandler.java
+new file mode 100644
+index 00000000..dcd31fbc
+--- /dev/null
++++ b/src/main/java/com/destroystokyo/paper/console/TerminalHandler.java
+@@ -0,0 +1,53 @@
++package com.destroystokyo.paper.console;
++
++import net.minecraft.server.DedicatedServer;
++import net.minecrell.terminalconsole.TerminalConsoleAppender;
++import org.bukkit.craftbukkit.command.ConsoleCommandCompleter;
++import org.jline.reader.LineReader;
++import org.jline.reader.LineReaderBuilder;
++import org.jline.reader.UserInterruptException;
++import org.jline.terminal.Terminal;
++
++public class TerminalHandler {
++
++ private TerminalHandler() {
++ }
++
++ public static boolean handleCommands(DedicatedServer server) {
++ final Terminal terminal = TerminalConsoleAppender.getTerminal();
++ if (terminal == null) {
++ return false;
++ }
++
++ LineReader reader = LineReaderBuilder.builder()
++ .appName("Paper")
++ .terminal(terminal)
++ .completer(new ConsoleCommandCompleter(server))
++ .build();
++ reader.unsetOpt(LineReader.Option.INSERT_TAB);
++
++ TerminalConsoleAppender.setReader(reader);
++
++ try {
++ String line;
++ while (!server.isStopped() && server.isRunning()) {
++ line = reader.readLine("> ");
++ if (line == null) {
++ break;
++ }
++
++ line = line.trim();
++ if (!line.isEmpty()) {
++ server.issueCommand(line, server);
++ }
++ }
++ } catch (UserInterruptException e) {
++ server.safeShutdown();
++ } finally {
++ TerminalConsoleAppender.setReader(null);
++ }
++
++ return true;
++ }
++
++}
+diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
+index 2feeb855..db9ace0c 100644
+--- a/src/main/java/net/minecraft/server/DedicatedServer.java
++++ b/src/main/java/net/minecraft/server/DedicatedServer.java
+@@ -73,7 +73,10 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
+ if (!org.bukkit.craftbukkit.Main.useConsole) {
+ return;
+ }
+- jline.console.ConsoleReader bufferedreader = reader;
++ // Paper start - Use TerminalConsoleAppender implementation
++ if (com.destroystokyo.paper.console.TerminalHandler.handleCommands(DedicatedServer.this)) return;
++ BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
++ // Paper end
+ // CraftBukkit end
+
+ String s;
+@@ -81,11 +84,17 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
+ try {
+ // CraftBukkit start - JLine disabling compatibility
+ while (!isStopped() && isRunning()) {
++ // Paper start - code is not used for jline
++ /*
+ if (org.bukkit.craftbukkit.Main.useJline) {
+ s = bufferedreader.readLine(">", null);
+ } else {
+ s = bufferedreader.readLine();
+ }
++ */
++ s = bufferedreader.readLine();
++ // Paper end
++
+ if (s != null && s.trim().length() > 0) { // Trim to filter lines which are just spaces
+ issueCommand(s, DedicatedServer.this);
+ }
+@@ -113,8 +122,6 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
+ }
+ }
+
+- new Thread(new org.bukkit.craftbukkit.util.TerminalConsoleWriterThread(System.out, this.reader)).start();
+-
+ System.setOut(new PrintStream(new LoggerOutputStream(logger, Level.INFO), true));
+ System.setErr(new PrintStream(new LoggerOutputStream(logger, Level.WARN), true));
+ // CraftBukkit end
+diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
+index d84f59da..8ca8fdce 100644
+--- a/src/main/java/net/minecraft/server/MinecraftServer.java
++++ b/src/main/java/net/minecraft/server/MinecraftServer.java
+@@ -41,7 +41,6 @@ import org.apache.commons.lang3.Validate;
+ import org.apache.logging.log4j.LogManager;
+ import org.apache.logging.log4j.Logger;
+ // CraftBukkit start
+-import jline.console.ConsoleReader;
+ import joptsimple.OptionSet;
+ import org.bukkit.Bukkit;
+ import org.bukkit.craftbukkit.CraftServer;
+@@ -114,7 +113,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
+ public OptionSet options;
+ public org.bukkit.command.ConsoleCommandSender console;
+ public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
+- public ConsoleReader reader;
++ //public ConsoleReader reader; // Paper
+ public static int currentTick = 0; // Paper - Further improve tick loop
+ public final Thread primaryThread;
+ public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
+@@ -140,7 +139,9 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
+ this.dataConverterManager = dataconvertermanager;
+ // CraftBukkit start
+ this.options = options;
++ // Paper start - Handled by TerminalConsoleAppender
+ // Try to see if we're actually running in a terminal, disable jline if not
++ /*
+ if (System.console() == null && System.getProperty("jline.terminal") == null) {
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
+ Main.useJline = false;
+@@ -161,6 +162,8 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
+ LOGGER.warn((String) null, ex);
+ }
+ }
++ */
++ // Paper end
+ Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
+
+ this.serverThread = primaryThread = new Thread(this, "Server thread"); // Moved from main
+@@ -700,7 +703,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
+ } finally {
+ // CraftBukkit start - Restore terminal to original settings
+ try {
+- reader.getTerminal().restore();
++ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
+ } catch (Exception ignored) {
+ }
+ // CraftBukkit end
+@@ -1226,7 +1229,8 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
+ }
+
+ public void sendMessage(IChatBaseComponent ichatbasecomponent) {
+- MinecraftServer.LOGGER.info(ichatbasecomponent.toPlainText());
++ // Paper - Log message with colors
++ MinecraftServer.LOGGER.info(org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(ichatbasecomponent, net.minecraft.server.EnumChatFormat.WHITE));
+ }
+
+ public boolean a(int i, String s) {
+diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
+index 0c328782..ed0a749e 100644
+--- a/src/main/java/net/minecraft/server/PlayerList.java
++++ b/src/main/java/net/minecraft/server/PlayerList.java
+@@ -76,8 +76,7 @@ public abstract class PlayerList {
+
+ public PlayerList(MinecraftServer minecraftserver) {
+ this.cserver = minecraftserver.server = new CraftServer(minecraftserver, this);
+- minecraftserver.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance();
+- minecraftserver.reader.addCompleter(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter(minecraftserver.server));
++ minecraftserver.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper
+ // CraftBukkit end
+
+ this.k = new GameProfileBanList(PlayerList.a);
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+index 463f5890..df6a75b0 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+@@ -127,7 +127,6 @@ import io.netty.buffer.ByteBuf;
+ import io.netty.buffer.ByteBufOutputStream;
+ import io.netty.buffer.Unpooled;
+ import io.netty.handler.codec.base64.Base64;
+-import jline.console.ConsoleReader;
+ import org.apache.commons.lang.StringUtils;
+ import org.bukkit.NamespacedKey;
+ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+@@ -1088,9 +1087,13 @@ public final class CraftServer implements Server {
+ return logger;
+ }
+
++ // Paper start - JLine update
++ /*
+ public ConsoleReader getReader() {
+ return console.reader;
+ }
++ */
++ // Paper end
+
+ @Override
+ public PluginCommand getPluginCommand(String name) {
+diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
+index 1cbcc3df..c3b2413a 100644
+--- a/src/main/java/org/bukkit/craftbukkit/Main.java
++++ b/src/main/java/org/bukkit/craftbukkit/Main.java
+@@ -14,7 +14,7 @@ import java.util.logging.Logger;
+ import joptsimple.OptionParser;
+ import joptsimple.OptionSet;
+ import net.minecraft.server.MinecraftServer;
+-import org.fusesource.jansi.AnsiConsole;
++import net.minecrell.terminalconsole.TerminalConsoleAppender; // Paper
+
+ public class Main {
+ public static boolean useJline = true;
+@@ -170,6 +170,8 @@ public class Main {
+ }
+
+ try {
++ // Paper start - Handled by TerminalConsoleAppender
++ /*
+ // This trick bypasses Maven Shade's clever rewriting of our getProperty call when using String literals
+ String jline_UnsupportedTerminal = new String(new char[] {'j','l','i','n','e','.','U','n','s','u','p','p','o','r','t','e','d','T','e','r','m','i','n','a','l'});
+ String jline_terminal = new String(new char[] {'j','l','i','n','e','.','t','e','r','m','i','n','a','l'});
+@@ -187,10 +189,18 @@ public class Main {
+ // This ensures the terminal literal will always match the jline implementation
+ System.setProperty(jline.TerminalFactory.JLINE_TERMINAL, jline.UnsupportedTerminal.class.getName());
+ }
++ */
+
++ if (options.has("nojline")) {
++ System.setProperty(TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false");
++ useJline = false;
++ }
++ // Paper end
+
+ if (options.has("noconsole")) {
+ useConsole = false;
++ useJline = false; // Paper
++ System.setProperty(TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
+ }
+
+ if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
+diff --git a/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java b/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java
+deleted file mode 100644
+index 26a2fb89..00000000
+--- a/src/main/java/org/bukkit/craftbukkit/command/ColouredConsoleSender.java
++++ /dev/null
+@@ -1,74 +0,0 @@
+-package org.bukkit.craftbukkit.command;
+-
+-import java.util.EnumMap;
+-import java.util.Map;
+-
+-import org.fusesource.jansi.Ansi;
+-import org.fusesource.jansi.Ansi.Attribute;
+-import jline.Terminal;
+-
+-import org.bukkit.Bukkit;
+-import org.bukkit.ChatColor;
+-import org.bukkit.command.ConsoleCommandSender;
+-import org.bukkit.craftbukkit.CraftServer;
+-
+-public class ColouredConsoleSender extends CraftConsoleCommandSender {
+- private final Terminal terminal;
+- private final Map<ChatColor, String> replacements = new EnumMap<ChatColor, String>(ChatColor.class);
+- private final ChatColor[] colors = ChatColor.values();
+-
+- protected ColouredConsoleSender() {
+- super();
+- this.terminal = ((CraftServer) getServer()).getReader().getTerminal();
+-
+- replacements.put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString());
+- replacements.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString());
+- replacements.put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString());
+- replacements.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString());
+- replacements.put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString());
+- replacements.put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString());
+- replacements.put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString());
+- replacements.put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString());
+- replacements.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString());
+- replacements.put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString());
+- replacements.put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString());
+- replacements.put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString());
+- replacements.put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString());
+- replacements.put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString());
+- replacements.put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString());
+- replacements.put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString());
+- replacements.put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString());
+- replacements.put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString());
+- replacements.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString());
+- replacements.put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString());
+- replacements.put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString());
+- replacements.put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString());
+- }
+-
+- @Override
+- public void sendMessage(String message) {
+- if (terminal.isAnsiSupported()) {
+- if (!conversationTracker.isConversingModaly()) {
+- String result = message;
+- for (ChatColor color : colors) {
+- if (replacements.containsKey(color)) {
+- result = result.replaceAll("(?i)" + color.toString(), replacements.get(color));
+- } else {
+- result = result.replaceAll("(?i)" + color.toString(), "");
+- }
+- }
+- System.out.println(result + Ansi.ansi().reset().toString());
+- }
+- } else {
+- super.sendMessage(message);
+- }
+- }
+-
+- public static ConsoleCommandSender getInstance() {
+- if (Bukkit.getConsoleSender() != null) {
+- return Bukkit.getConsoleSender();
+- } else {
+- return new ColouredConsoleSender();
+- }
+- }
+-}
+diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
+index 33e8ea02..1e3aae3b 100644
+--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
++++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
+@@ -8,17 +8,27 @@ import java.util.logging.Level;
+ import org.bukkit.craftbukkit.CraftServer;
+ import org.bukkit.craftbukkit.util.Waitable;
+
+-import jline.console.completer.Completer;
++// Paper start - JLine update
++import net.minecraft.server.DedicatedServer; // Paper
++import org.jline.reader.Candidate;
++import org.jline.reader.Completer;
++import org.jline.reader.LineReader;
++import org.jline.reader.ParsedLine;
++// Paper end
+ import org.bukkit.event.server.TabCompleteEvent;
+
+ public class ConsoleCommandCompleter implements Completer {
+- private final CraftServer server;
++ private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer
+
+- public ConsoleCommandCompleter(CraftServer server) {
++ public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer
+ this.server = server;
+ }
+
+- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
++ // Paper start - Change method signature for JLine update
++ public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
++ final CraftServer server = this.server.server;
++ final String buffer = line.line();
++ // Paper end
+ Waitable<List<String>> waitable = new Waitable<List<String>>() {
+ @Override
+ protected List<String> evaluate() {
+@@ -30,25 +40,37 @@ public class ConsoleCommandCompleter implements Completer {
+ return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
+ }
+ };
+- this.server.getServer().processQueue.add(waitable);
++ server.getServer().processQueue.add(waitable); // Paper - Remove "this."
+ try {
+ List<String> offers = waitable.get();
+ if (offers == null) {
+- return cursor;
++ return; // Paper - Method returns void
+ }
+- candidates.addAll(offers);
+
++ // Paper start - JLine update
++ for (String completion : offers) {
++ if (completion.isEmpty()) {
++ continue;
++ }
++
++ candidates.add(new Candidate(completion));
++ }
++ // Paper end
++
++ // Paper start - JLine handles cursor now
++ /*
+ final int lastSpace = buffer.lastIndexOf(' ');
+ if (lastSpace == -1) {
+ return cursor - buffer.length();
+ } else {
+ return cursor - (buffer.length() - lastSpace - 1);
+ }
++ */
++ // Paper end
+ } catch (ExecutionException e) {
+- this.server.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e);
++ server.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e); // Paper - Remove "this."
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+- return cursor;
+ }
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+index ae3481ba..6a38025e 100644
+--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
++++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+@@ -18,7 +18,7 @@ public class ServerShutdownThread extends Thread {
+ ex.printStackTrace();
+ } finally {
+ try {
+- server.reader.getTerminal().restore();
++ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
+ } catch (Exception e) {
+ }
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java b/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java
+deleted file mode 100644
+index b6409711..00000000
+--- a/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java
++++ /dev/null
+@@ -1,54 +0,0 @@
+-package org.bukkit.craftbukkit.util;
+-
+-import java.io.IOException;
+-import java.io.OutputStream;
+-import java.util.logging.Level;
+-import java.util.logging.Logger;
+-import jline.console.ConsoleReader;
+-import com.mojang.util.QueueLogAppender;
+-import org.bukkit.craftbukkit.Main;
+-import org.fusesource.jansi.Ansi;
+-import org.fusesource.jansi.Ansi.Erase;
+-
+-public class TerminalConsoleWriterThread implements Runnable {
+- final private ConsoleReader reader;
+- final private OutputStream output;
+-
+- public TerminalConsoleWriterThread(OutputStream output, ConsoleReader reader) {
+- this.output = output;
+- this.reader = reader;
+- }
+-
+- public void run() {
+- String message;
+-
+- // Using name from log4j config in vanilla jar
+- while (true) {
+- message = QueueLogAppender.getNextLogEvent("TerminalConsole");
+- if (message == null) {
+- continue;
+- }
+-
+- try {
+- if (Main.useJline) {
+- reader.print(Ansi.ansi().eraseLine(Erase.ALL).toString() + ConsoleReader.RESET_LINE);
+- reader.flush();
+- output.write(message.getBytes());
+- output.flush();
+-
+- try {
+- reader.drawLine();
+- } catch (Throwable ex) {
+- reader.getCursorBuffer().clear();
+- }
+- reader.flush();
+- } else {
+- output.write(message.getBytes());
+- output.flush();
+- }
+- } catch (IOException ex) {
+- Logger.getLogger(TerminalConsoleWriterThread.class.getName()).log(Level.SEVERE, null, ex);
+- }
+- }
+- }
+-}
+diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
+index 5cee8f00..f248d05f 100644
+--- a/src/main/resources/log4j2.xml
++++ b/src/main/resources/log4j2.xml
+@@ -1,12 +1,12 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+-<Configuration status="WARN" packages="com.mojang.util">
++<Configuration status="WARN">
+ <Appenders>
+ <Console name="WINDOWS_COMPAT" target="SYSTEM_OUT"></Console>
+- <Queue name="TerminalConsole">
+- <PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
+- </Queue>
++ <TerminalConsole name="TerminalConsole">
++ <PatternLayout pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx}" />
++ </TerminalConsole>
+ <RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
+- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
++ <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n" />
+ <Policies>
+ <TimeBasedTriggeringPolicy />
+ <OnStartupTriggeringPolicy />
+--
+2.13.1
+
diff --git a/pom.xml b/pom.xml
index 90d310c38a..d428c63b80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,11 @@
<id>aikar</id>
<url>http://ci.emc.gs/nexus/content/groups/aikar/</url>
</repository>
+ <repository>
+ <!-- TODO: Remove when TerminalConsoleAppender is released -->
+ <id>oss-snapshots</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </repository>
</repositories>
<distributionManagement>