diff --git a/build.gradle b/build.gradle index 70de947fc..d6c733786 100644 --- a/build.gradle +++ b/build.gradle @@ -151,6 +151,9 @@ dependencies { // SLF4J is the base logger for most libraries, therefore we can hook it into log4j2. api 'org.apache.logging.log4j:log4j-slf4j-impl:2.14.0' + // https://mvnrepository.com/artifact/org.jline/jline + implementation group: 'org.jline', name: 'jline', version: '3.19.0' + // Guava 21.0+ required for Mixin, but Authlib imports 17.0 api 'com.google.guava:guava:30.1-jre' api 'com.mojang:authlib:1.5.21' diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 639ca5e36..da39e4732 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -42,6 +42,7 @@ import net.minestom.server.sound.SoundEvent; import net.minestom.server.stat.StatisticType; import net.minestom.server.storage.StorageLocation; import net.minestom.server.storage.StorageManager; +import net.minestom.server.terminal.MinestomTerminal; import net.minestom.server.timer.SchedulerManager; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.PacketUtils; @@ -775,7 +776,7 @@ public final class MinecraftServer { LOGGER.info("Minestom server started successfully."); - commandManager.startConsoleThread(); + MinestomTerminal.start(); } /** @@ -805,7 +806,7 @@ public final class MinecraftServer { extensionManager.shutdown(); LOGGER.info("Shutting down all thread pools."); benchmarkManager.disable(); - commandManager.stopConsoleThread(); + MinestomTerminal.stop(); MinestomThread.shutdownAll(); LOGGER.info("Minestom server stopped successfully."); } diff --git a/src/main/java/net/minestom/server/command/CommandManager.java b/src/main/java/net/minestom/server/command/CommandManager.java index 6543ee426..fccc96118 100644 --- a/src/main/java/net/minestom/server/command/CommandManager.java +++ b/src/main/java/net/minestom/server/command/CommandManager.java @@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; -import net.minestom.server.MinecraftServer; import net.minestom.server.command.builder.*; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.minecraft.SuggestionType; @@ -24,14 +23,11 @@ import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; import java.util.*; import java.util.stream.Collectors; /** - * Manager used to register {@link Command} and {@link CommandProcessor}. + * Manager used to register {@link Command commands}. *
* It is also possible to simulate a command using {@link #execute(CommandSender, String)}. */ @@ -39,8 +35,6 @@ public final class CommandManager { public static final String COMMAND_PREFIX = "/"; - private volatile boolean running = true; - private final ServerSender serverSender = new ServerSender(); private final ConsoleSender consoleSender = new ConsoleSender(); @@ -52,15 +46,6 @@ public final class CommandManager { public CommandManager() { } - /** - * Stops the console responsible for the console commands processing. - *
- * WARNING: it cannot be re-run later. - */ - public void stopConsoleThread() { - running = false; - } - /** * Registers a {@link Command}. * @@ -246,43 +231,6 @@ public final class CommandManager { return consoleSender; } - /** - * Starts the thread responsible for executing commands from the console. - */ - public void startConsoleThread() { - Thread consoleThread = new Thread(() -> { - BufferedReader bi = new BufferedReader(new InputStreamReader(System.in)); - while (running) { - - try { - - if (bi.ready()) { - final String command = bi.readLine(); - execute(consoleSender, command); - } - } catch (IOException e) { - MinecraftServer.getExceptionManager().handleException(e); - continue; - } - - // Prevent permanent looping - try { - Thread.sleep(200); - } catch (InterruptedException e) { - MinecraftServer.getExceptionManager().handleException(e); - } - - } - try { - bi.close(); - } catch (IOException e) { - MinecraftServer.getExceptionManager().handleException(e); - } - }, "ConsoleCommand-Thread"); - consoleThread.setDaemon(true); - consoleThread.start(); - } - /** * Gets the {@link DeclareCommandsPacket} for a specific player. *
diff --git a/src/main/java/net/minestom/server/terminal/MinestomTerminal.java b/src/main/java/net/minestom/server/terminal/MinestomTerminal.java new file mode 100644 index 000000000..b0123f899 --- /dev/null +++ b/src/main/java/net/minestom/server/terminal/MinestomTerminal.java @@ -0,0 +1,52 @@ +package net.minestom.server.terminal; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.command.CommandManager; +import org.jetbrains.annotations.ApiStatus; +import org.jline.reader.EndOfFileException; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; + +import java.io.IOException; + +public class MinestomTerminal { + + private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager(); + private static final String PROMPT = "> "; + + private static volatile boolean running = false; + + @ApiStatus.Internal + public static void start() { + Terminal terminal = null; + try { + terminal = TerminalBuilder.terminal(); + } catch (IOException e) { + e.printStackTrace(); + } + LineReader reader = LineReaderBuilder.builder() + .terminal(terminal) + .build(); + running = true; + while (running) { + String command; + try { + command = reader.readLine(PROMPT); + COMMAND_MANAGER.execute(COMMAND_MANAGER.getConsoleSender(), command); + } catch (UserInterruptException e) { + // Ignore + } catch (EndOfFileException e) { + return; + } + } + } + + @ApiStatus.Internal + public static void stop() { + running = false; + } + +}