mirror of
https://hub.spigotmc.org/stash/scm/spigot/craftbukkit.git
synced 2025-08-05 16:49:30 +00:00
Update to JLine 3
This commit is contained in:
parent
d257c87b12
commit
2ed8fab2ee
11 changed files with 148 additions and 228 deletions
|
@ -1,6 +1,6 @@
|
|||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -177,13 +177,39 @@
|
||||
@@ -177,13 +177,40 @@
|
||||
import net.minecraft.world.phys.Vec3D;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
|||
+import com.mojang.serialization.Lifecycle;
|
||||
+import java.io.File;
|
||||
+import java.util.Random;
|
||||
+import jline.console.ConsoleReader;
|
||||
+import joptsimple.OptionSet;
|
||||
+import net.minecraft.nbt.NbtException;
|
||||
+import net.minecraft.nbt.ReportedNbtException;
|
||||
|
@ -28,6 +27,8 @@
|
|||
+import org.bukkit.craftbukkit.Main;
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+import org.bukkit.event.server.ServerLoadEvent;
|
||||
+import org.jline.terminal.Terminal;
|
||||
+import org.jline.terminal.TerminalBuilder;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements ServerInfo, ChunkIOErrorReporter, ICommandListener {
|
||||
|
@ -41,7 +42,7 @@
|
|||
private static final int OVERLOADED_TICKS_THRESHOLD = 20;
|
||||
private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeRange.NANOSECONDS_PER_SECOND;
|
||||
private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100;
|
||||
@@ -274,6 +300,19 @@
|
||||
@@ -274,6 +301,19 @@
|
||||
private final SuppressedExceptionCollector suppressedExceptions;
|
||||
private final DiscontinuousFrame tickFrame;
|
||||
|
||||
|
@ -50,7 +51,7 @@
|
|||
+ public org.bukkit.craftbukkit.CraftServer server;
|
||||
+ public OptionSet options;
|
||||
+ public org.bukkit.command.ConsoleCommandSender console;
|
||||
+ public ConsoleReader reader;
|
||||
+ public Terminal terminal;
|
||||
+ public static int currentTick = (int) (System.currentTimeMillis() / 50);
|
||||
+ public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
+ public int autosavePeriod;
|
||||
|
@ -61,7 +62,7 @@
|
|||
public static <S extends MinecraftServer> S spin(Function<Thread, S> function) {
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
Thread thread = new Thread(() -> {
|
||||
@@ -294,7 +333,7 @@
|
||||
@@ -294,7 +334,7 @@
|
||||
return s0;
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@
|
|||
super("Server");
|
||||
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
|
||||
this.onMetricsRecordingStopped = (methodprofilerresults) -> {
|
||||
@@ -318,7 +357,7 @@
|
||||
@@ -318,7 +358,7 @@
|
||||
this.suppressedExceptions = new SuppressedExceptionCollector();
|
||||
this.registries = worldstem.registries();
|
||||
this.worldData = worldstem.worldData();
|
||||
|
@ -79,7 +80,7 @@
|
|||
throw new IllegalStateException("Missing Overworld dimension data");
|
||||
} else {
|
||||
this.proxy = proxy;
|
||||
@@ -346,6 +385,33 @@
|
||||
@@ -346,6 +386,30 @@
|
||||
this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures());
|
||||
this.tickFrame = TracyClient.createDiscontinuousFrame("Server Tick");
|
||||
}
|
||||
|
@ -88,22 +89,19 @@
|
|||
+ this.worldLoader = worldLoader;
|
||||
+ this.vanillaCommandDispatcher = worldstem.dataPackResources().commands; // CraftBukkit
|
||||
+ // 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");
|
||||
+ if (System.console() == null && System.getProperty(TerminalBuilder.PROP_PROVIDER) == null) {
|
||||
+ System.setProperty(TerminalBuilder.PROP_PROVIDER, Terminal.TYPE_DUMB);
|
||||
+ Main.useJline = false;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ reader = new ConsoleReader(System.in, System.out);
|
||||
+ reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators
|
||||
+ terminal = TerminalBuilder.builder().dumb(false).build();
|
||||
+ } catch (Throwable e) {
|
||||
+ try {
|
||||
+ // Try again with jline disabled for Windows users without C++ 2008 Redistributable
|
||||
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
|
||||
+ System.setProperty("user.language", "en");
|
||||
+ System.setProperty(TerminalBuilder.PROP_PROVIDER, Terminal.TYPE_DUMB);
|
||||
+ Main.useJline = false;
|
||||
+ reader = new ConsoleReader(System.in, System.out);
|
||||
+ reader.setExpandEvents(false);
|
||||
+ terminal = TerminalBuilder.builder().build();
|
||||
+ } catch (IOException ex) {
|
||||
+ LOGGER.warn((String) null, ex);
|
||||
+ }
|
||||
|
@ -113,7 +111,7 @@
|
|||
}
|
||||
|
||||
private void readScoreboard(WorldPersistentData worldpersistentdata) {
|
||||
@@ -354,7 +420,7 @@
|
||||
@@ -354,7 +418,7 @@
|
||||
|
||||
protected abstract boolean initServer() throws IOException;
|
||||
|
||||
|
@ -122,7 +120,7 @@
|
|||
if (!JvmProfiler.INSTANCE.isRunning()) {
|
||||
;
|
||||
}
|
||||
@@ -362,12 +428,8 @@
|
||||
@@ -362,12 +426,8 @@
|
||||
boolean flag = false;
|
||||
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted();
|
||||
|
||||
|
@ -136,7 +134,7 @@
|
|||
if (profiledduration != null) {
|
||||
profiledduration.finish(true);
|
||||
}
|
||||
@@ -384,23 +446,217 @@
|
||||
@@ -384,23 +444,217 @@
|
||||
|
||||
protected void forceDifficulty() {}
|
||||
|
||||
|
@ -368,7 +366,7 @@
|
|||
|
||||
if (!iworlddataserver.isInitialized()) {
|
||||
try {
|
||||
@@ -424,28 +680,8 @@
|
||||
@@ -424,28 +678,8 @@
|
||||
iworlddataserver.setInitialized(true);
|
||||
}
|
||||
|
||||
|
@ -398,7 +396,7 @@
|
|||
|
||||
private static void setInitialSpawn(WorldServer worldserver, IWorldDataServer iworlddataserver, boolean flag, boolean flag1) {
|
||||
if (flag1) {
|
||||
@@ -453,6 +689,21 @@
|
||||
@@ -453,6 +687,21 @@
|
||||
} else {
|
||||
ChunkProviderServer chunkproviderserver = worldserver.getChunkSource();
|
||||
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(chunkproviderserver.randomState().sampler().findSpawnPosition());
|
||||
|
@ -420,7 +418,7 @@
|
|||
int i = chunkproviderserver.getGenerator().getSpawnHeight(worldserver);
|
||||
|
||||
if (i < worldserver.getMinY()) {
|
||||
@@ -511,8 +762,11 @@
|
||||
@@ -511,8 +760,11 @@
|
||||
iworlddataserver.setGameType(EnumGamemode.SPECTATOR);
|
||||
}
|
||||
|
||||
|
@ -434,7 +432,7 @@
|
|||
|
||||
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location());
|
||||
BlockPosition blockposition = worldserver.getSharedSpawnPos();
|
||||
@@ -522,18 +776,21 @@
|
||||
@@ -522,18 +774,21 @@
|
||||
|
||||
this.nextTickTimeNanos = SystemUtils.getNanos();
|
||||
worldserver.setDefaultSpawnPos(blockposition, worldserver.getSharedSpawnAngle());
|
||||
|
@ -462,7 +460,7 @@
|
|||
TicketStorage ticketstorage = (TicketStorage) worldserver1.getDataStorage().get(TicketStorage.TYPE);
|
||||
|
||||
if (ticketstorage != null) {
|
||||
@@ -541,10 +798,17 @@
|
||||
@@ -541,10 +796,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,7 +481,7 @@
|
|||
}
|
||||
|
||||
public EnumGamemode getDefaultGameType() {
|
||||
@@ -573,12 +837,16 @@
|
||||
@@ -573,12 +835,16 @@
|
||||
flag3 = true;
|
||||
}
|
||||
|
||||
|
@ -500,7 +498,7 @@
|
|||
if (flag1) {
|
||||
for (WorldServer worldserver2 : this.getAllLevels()) {
|
||||
MinecraftServer.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", worldserver2.getChunkSource().chunkMap.getStorageName());
|
||||
@@ -609,18 +877,40 @@
|
||||
@@ -609,18 +875,40 @@
|
||||
this.stopServer();
|
||||
}
|
||||
|
||||
|
@ -541,7 +539,7 @@
|
|||
}
|
||||
|
||||
MinecraftServer.LOGGER.info("Saving worlds");
|
||||
@@ -700,7 +990,7 @@
|
||||
@@ -700,7 +988,7 @@
|
||||
}
|
||||
|
||||
this.nextTickTimeNanos = SystemUtils.getNanos();
|
||||
|
@ -550,7 +548,7 @@
|
|||
this.status = this.buildServerStatus();
|
||||
|
||||
while (this.running) {
|
||||
@@ -717,6 +1007,7 @@
|
||||
@@ -717,6 +1005,7 @@
|
||||
if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) {
|
||||
long k = j / i;
|
||||
|
||||
|
@ -558,7 +556,7 @@
|
|||
MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", j / TimeRange.NANOSECONDS_PER_MILLISECOND, k);
|
||||
this.nextTickTimeNanos += k * i;
|
||||
this.lastOverloadWarningNanos = this.nextTickTimeNanos;
|
||||
@@ -730,6 +1021,7 @@
|
||||
@@ -730,6 +1019,7 @@
|
||||
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(SystemUtils.getNanos(), this.tickCount);
|
||||
}
|
||||
|
||||
|
@ -566,20 +564,20 @@
|
|||
this.nextTickTimeNanos += i;
|
||||
|
||||
try {
|
||||
@@ -803,6 +1095,12 @@
|
||||
@@ -803,6 +1093,12 @@
|
||||
this.services.profileCache().clearExecutor();
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - Restore terminal to original settings
|
||||
+ try {
|
||||
+ reader.getTerminal().restore();
|
||||
+ terminal.close();
|
||||
+ } catch (Exception ignored) {
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.onServerExit();
|
||||
}
|
||||
|
||||
@@ -862,7 +1160,14 @@
|
||||
@@ -862,7 +1158,14 @@
|
||||
}
|
||||
|
||||
private boolean haveTime() {
|
||||
|
@ -595,7 +593,7 @@
|
|||
}
|
||||
|
||||
public static boolean throwIfFatalException() {
|
||||
@@ -876,7 +1181,7 @@
|
||||
@@ -876,7 +1179,7 @@
|
||||
}
|
||||
|
||||
public static void setFatalException(RuntimeException runtimeexception) {
|
||||
|
@ -604,7 +602,7 @@
|
|||
}
|
||||
|
||||
@Override
|
||||
@@ -946,7 +1251,7 @@
|
||||
@@ -946,7 +1249,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,7 +611,7 @@
|
|||
Profiler.get().incrementCounter("runTask");
|
||||
super.doRunTask(ticktask);
|
||||
}
|
||||
@@ -1010,6 +1315,7 @@
|
||||
@@ -1010,6 +1313,7 @@
|
||||
this.autoSave();
|
||||
}
|
||||
|
||||
|
@ -621,7 +619,7 @@
|
|||
this.tickConnection();
|
||||
return;
|
||||
}
|
||||
@@ -1024,7 +1330,7 @@
|
||||
@@ -1024,7 +1328,7 @@
|
||||
}
|
||||
|
||||
--this.ticksUntilAutosave;
|
||||
|
@ -630,7 +628,7 @@
|
|||
this.autoSave();
|
||||
}
|
||||
|
||||
@@ -1043,7 +1349,7 @@
|
||||
@@ -1043,7 +1347,7 @@
|
||||
}
|
||||
|
||||
private void autoSave() {
|
||||
|
@ -639,7 +637,7 @@
|
|||
MinecraftServer.LOGGER.debug("Autosave started");
|
||||
GameProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
|
||||
@@ -1123,21 +1429,38 @@
|
||||
@@ -1123,21 +1427,38 @@
|
||||
this.getPlayerList().getPlayers().forEach((entityplayer) -> {
|
||||
entityplayer.connection.suspendFlushing();
|
||||
});
|
||||
|
@ -678,7 +676,7 @@
|
|||
|
||||
gameprofilerfiller.push("tick");
|
||||
|
||||
@@ -1227,6 +1550,22 @@
|
||||
@@ -1227,6 +1548,22 @@
|
||||
return (WorldServer) this.levels.get(resourcekey);
|
||||
}
|
||||
|
||||
|
@ -701,7 +699,7 @@
|
|||
public Set<ResourceKey<World>> levelKeys() {
|
||||
return this.levels.keySet();
|
||||
}
|
||||
@@ -1256,7 +1595,7 @@
|
||||
@@ -1256,7 +1593,7 @@
|
||||
|
||||
@DontObfuscate
|
||||
public String getServerModName() {
|
||||
|
@ -710,7 +708,7 @@
|
|||
}
|
||||
|
||||
public SystemReport fillSystemReport(SystemReport systemreport) {
|
||||
@@ -1590,11 +1929,11 @@
|
||||
@@ -1590,11 +1927,11 @@
|
||||
|
||||
public CompletableFuture<Void> reloadResources(Collection<String> collection) {
|
||||
CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> {
|
||||
|
@ -724,7 +722,7 @@
|
|||
}, this).thenCompose((immutablelist) -> {
|
||||
IReloadableResourceManager ireloadableresourcemanager = new ResourceManager(EnumResourcePackType.SERVER_DATA, immutablelist);
|
||||
List<IRegistry.a<?>> list = TagDataPack.loadTagsForExistingRegistries(ireloadableresourcemanager, this.registries.compositeAccess());
|
||||
@@ -1610,6 +1949,7 @@
|
||||
@@ -1610,6 +1947,7 @@
|
||||
}).thenAcceptAsync((minecraftserver_reloadableresources) -> {
|
||||
this.resources.close();
|
||||
this.resources = minecraftserver_reloadableresources;
|
||||
|
@ -732,7 +730,7 @@
|
|||
this.packRepository.setSelected(collection);
|
||||
WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures());
|
||||
|
||||
@@ -1939,6 +2279,22 @@
|
||||
@@ -1939,6 +2277,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,7 +753,7 @@
|
|||
private GameProfilerFiller createProfiler() {
|
||||
if (this.willStartRecordingMetrics) {
|
||||
this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(SystemUtils.timeSource, this.isDedicatedServer()), SystemUtils.timeSource, SystemUtils.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> {
|
||||
@@ -2066,6 +2422,11 @@
|
||||
@@ -2066,6 +2420,11 @@
|
||||
|
||||
}
|
||||
|
||||
|
@ -767,7 +765,7 @@
|
|||
public ChatDecorator getChatDecorator() {
|
||||
return ChatDecorator.PLAIN;
|
||||
}
|
||||
@@ -2076,8 +2437,11 @@
|
||||
@@ -2076,8 +2435,11 @@
|
||||
|
||||
public void subscribeToDebugSample(EntityPlayer entityplayer, RemoteDebugSampleType remotedebugsampletype) {}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -59,6 +59,18 @@
|
||||
@@ -59,6 +59,21 @@
|
||||
import net.minecraft.world.level.storage.Convertable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -10,16 +10,19 @@
|
|||
+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;
|
||||
+import org.jline.reader.EndOfFileException;
|
||||
+import org.jline.reader.LineReader;
|
||||
+import org.jline.reader.LineReaderBuilder;
|
||||
+import org.jline.reader.UserInterruptException;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class DedicatedServer extends MinecraftServer implements IMinecraftServer {
|
||||
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -67,7 +79,7 @@
|
||||
@@ -67,7 +82,7 @@
|
||||
private final List<ServerCommand> consoleInput = Collections.synchronizedList(Lists.newArrayList());
|
||||
@Nullable
|
||||
private RemoteStatusListener queryThreadGs4;
|
||||
|
@ -28,7 +31,7 @@
|
|||
@Nullable
|
||||
private RemoteControlListener rconThread;
|
||||
public DedicatedServerSettings settings;
|
||||
@@ -81,10 +93,12 @@
|
||||
@@ -81,33 +96,93 @@
|
||||
private DebugSampleSubscriptionTracker debugSampleSubscriptionTracker;
|
||||
public ServerLinks serverLinks;
|
||||
|
||||
|
@ -44,8 +47,15 @@
|
|||
this.serverTextFilter = ServerTextFilter.createFromConfig(dedicatedserversettings.getProperties());
|
||||
this.serverLinks = createServerLinks(dedicatedserversettings);
|
||||
}
|
||||
@@ -93,13 +107,44 @@
|
||||
|
||||
@Override
|
||||
public boolean initServer() throws IOException {
|
||||
+ LineReader reader = LineReaderBuilder.builder()
|
||||
+ .terminal(terminal)
|
||||
+ .option(LineReader.Option.DISABLE_EVENT_EXPANSION, true)
|
||||
+ .completer(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter())
|
||||
+ .build();
|
||||
+
|
||||
Thread thread = new Thread("Server console handler") {
|
||||
public void run() {
|
||||
- BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
|
||||
|
@ -53,7 +63,6 @@
|
|||
+ if (!org.bukkit.craftbukkit.Main.useConsole) {
|
||||
+ return;
|
||||
+ }
|
||||
+ jline.console.ConsoleReader bufferedreader = reader;
|
||||
+
|
||||
+ // MC-33041, SPIGOT-5538: if System.in is not valid due to javaw, then return
|
||||
+ try {
|
||||
|
@ -70,29 +79,31 @@
|
|||
- DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
|
||||
+ // CraftBukkit start - JLine disabling compatibility
|
||||
+ while (!DedicatedServer.this.isStopped() && DedicatedServer.this.isRunning()) {
|
||||
+ if (org.bukkit.craftbukkit.Main.useJline) {
|
||||
+ s = bufferedreader.readLine(">", null);
|
||||
+ } else {
|
||||
+ s = bufferedreader.readLine();
|
||||
+ }
|
||||
+ try {
|
||||
+ if (org.bukkit.craftbukkit.Main.useJline) {
|
||||
+ s = reader.readLine(">", null);
|
||||
+ } else {
|
||||
+ s = reader.readLine();
|
||||
+ }
|
||||
+
|
||||
+ // SPIGOT-5220: Throttle if EOF (ctrl^d) or stdin is /dev/null
|
||||
+ if (s == null) {
|
||||
+ if (s.trim().length() > 0) { // Trim to filter lines which are just spaces
|
||||
+ DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
|
||||
+ }
|
||||
+ } catch (EndOfFileException | UserInterruptException eof) {
|
||||
+ // SPIGOT-5220: Throttle if EOF (ctrl^d) or stdin is /dev/null
|
||||
+ try {
|
||||
+ Thread.sleep(50L);
|
||||
+ } catch (InterruptedException ex) {
|
||||
+ Thread.currentThread().interrupt();
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (s.trim().length() > 0) { // Trim to filter lines which are just spaces
|
||||
+ DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
- } catch (IOException ioexception) {
|
||||
+ } catch (Throwable ioexception) {
|
||||
+ // CraftBukkit end
|
||||
DedicatedServer.LOGGER.error("Exception handling console input", ioexception);
|
||||
@@ -108,6 +153,29 @@
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -111,8 +122,7 @@
|
|||
+ }
|
||||
+ }
|
||||
+
|
||||
+ TerminalConsoleWriterThread writerThread = new TerminalConsoleWriterThread(System.out, this.reader);
|
||||
+ this.reader.setCompletionHandler(new TerminalCompletionHandler(writerThread, this.reader.getCompletionHandler()));
|
||||
+ TerminalConsoleWriterThread writerThread = new TerminalConsoleWriterThread(System.out, reader);
|
||||
+ writerThread.start();
|
||||
+
|
||||
+ System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream());
|
||||
|
@ -122,7 +132,7 @@
|
|||
thread.setDaemon(true);
|
||||
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
|
||||
thread.start();
|
||||
@@ -132,7 +200,7 @@
|
||||
@@ -132,7 +207,7 @@
|
||||
this.setMotd(dedicatedserverproperties.motd);
|
||||
super.setPlayerIdleTimeout((Integer) dedicatedserverproperties.playerIdleTimeout.get());
|
||||
this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist);
|
||||
|
@ -131,7 +141,7 @@
|
|||
DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode);
|
||||
InetAddress inetaddress = null;
|
||||
|
||||
@@ -156,6 +224,12 @@
|
||||
@@ -156,6 +231,12 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -144,7 +154,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.");
|
||||
@@ -170,7 +244,7 @@
|
||||
@@ -170,7 +251,7 @@
|
||||
if (!NameReferencingFileConverter.serverReadyAfterUserconversion(this)) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -153,7 +163,7 @@
|
|||
this.debugSampleSubscriptionTracker = new DebugSampleSubscriptionTracker(this.getPlayerList());
|
||||
this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSampleSubscriptionTracker, RemoteDebugSampleType.TICK_TIME);
|
||||
long i = SystemUtils.getNanos();
|
||||
@@ -178,13 +252,13 @@
|
||||
@@ -178,13 +259,13 @@
|
||||
TileEntitySkull.setup(this.services, this);
|
||||
UserCache.setUsesAuthentication(this.usesAuthentication());
|
||||
DedicatedServer.LOGGER.info("Preparing level \"{}\"", this.getLevelIdName());
|
||||
|
@ -169,7 +179,7 @@
|
|||
}
|
||||
|
||||
if (dedicatedserverproperties.enableQuery) {
|
||||
@@ -278,6 +352,7 @@
|
||||
@@ -278,6 +359,7 @@
|
||||
this.queryThreadGs4.stop();
|
||||
}
|
||||
|
||||
|
@ -177,7 +187,7 @@
|
|||
}
|
||||
|
||||
@Override
|
||||
@@ -299,7 +374,15 @@
|
||||
@@ -299,7 +381,15 @@
|
||||
while (!this.consoleInput.isEmpty()) {
|
||||
ServerCommand servercommand = (ServerCommand) this.consoleInput.remove(0);
|
||||
|
||||
|
@ -194,7 +204,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
@@ -524,16 +607,52 @@
|
||||
@@ -524,16 +614,52 @@
|
||||
|
||||
@Override
|
||||
public String getPluginNames() {
|
||||
|
@ -251,7 +261,7 @@
|
|||
}
|
||||
|
||||
public void storeUsingWhiteList(boolean flag) {
|
||||
@@ -643,4 +762,15 @@
|
||||
@@ -643,4 +769,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
public final WorldNBTStorage playerIo;
|
||||
private boolean doWhiteList;
|
||||
private final LayeredRegistryAccess<RegistryLayer> registries;
|
||||
@@ -131,13 +155,23 @@
|
||||
@@ -131,13 +155,22 @@
|
||||
private static final boolean ALLOW_LOGOUTIVATOR = false;
|
||||
private int sendAllPlayerInfoIn;
|
||||
|
||||
|
@ -59,7 +59,6 @@
|
|||
public PlayerList(MinecraftServer minecraftserver, LayeredRegistryAccess<RegistryLayer> layeredregistryaccess, WorldNBTStorage worldnbtstorage, int i) {
|
||||
+ this.cserver = minecraftserver.server = new CraftServer((DedicatedServer) minecraftserver, this);
|
||||
+ minecraftserver.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance();
|
||||
+ minecraftserver.reader.addCompleter(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter(minecraftserver.server));
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
this.bans = new GameProfileBanList(PlayerList.USERBANLIST_FILE);
|
||||
|
@ -75,7 +74,7 @@
|
|||
this.server = minecraftserver;
|
||||
this.registries = layeredregistryaccess;
|
||||
this.maxPlayers = i;
|
||||
@@ -160,9 +194,16 @@
|
||||
@@ -160,9 +193,16 @@
|
||||
|
||||
try (ProblemReporter.j problemreporter_j = new ProblemReporter.j(entityplayer.problemPath(), PlayerList.LOGGER)) {
|
||||
Optional<ValueInput> optional1 = this.load(entityplayer, problemreporter_j);
|
||||
|
@ -93,7 +92,7 @@
|
|||
WorldServer worldserver = this.server.getLevel(resourcekey);
|
||||
WorldServer worldserver1;
|
||||
|
||||
@@ -181,10 +222,11 @@
|
||||
@@ -181,10 +221,11 @@
|
||||
worldserver1.waitForChunkAndEntities(entityplayer.chunkPosition(), 1);
|
||||
String s1 = networkmanager.getLoggableAddress(this.server.logIPs());
|
||||
|
||||
|
@ -107,7 +106,7 @@
|
|||
PlayerConnection playerconnection = new PlayerConnection(this.server, networkmanager, entityplayer, commonlistenercookie);
|
||||
|
||||
networkmanager.setupInboundProtocol(GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()), playerconnection), playerconnection);
|
||||
@@ -194,6 +236,7 @@
|
||||
@@ -194,6 +235,7 @@
|
||||
boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING);
|
||||
|
||||
playerconnection.send(new PacketPlayOutLogin(entityplayer.getId(), worlddata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), this.viewDistance, this.simulationDistance, flag1, !flag, flag2, entityplayer.createCommonSpawnInfo(worldserver1), this.server.enforceSecureProfile()));
|
||||
|
@ -115,7 +114,7 @@
|
|||
playerconnection.send(new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
|
||||
playerconnection.send(new PacketPlayOutAbilities(entityplayer.getAbilities()));
|
||||
playerconnection.send(new PacketPlayOutHeldItemSlot(entityplayer.getInventory().getSelectedSlot()));
|
||||
@@ -212,8 +255,10 @@
|
||||
@@ -212,8 +254,10 @@
|
||||
} else {
|
||||
ichatmutablecomponent = IChatBaseComponent.translatable("multiplayer.player.joined.renamed", entityplayer.getDisplayName(), s);
|
||||
}
|
||||
|
@ -127,7 +126,7 @@
|
|||
playerconnection.teleport(entityplayer.getX(), entityplayer.getY(), entityplayer.getZ(), entityplayer.getYRot(), entityplayer.getXRot());
|
||||
ServerPing serverping = this.server.getStatus();
|
||||
|
||||
@@ -221,19 +266,72 @@
|
||||
@@ -221,19 +265,72 @@
|
||||
entityplayer.sendServerStatus(serverping);
|
||||
}
|
||||
|
||||
|
@ -204,7 +203,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
@@ -260,30 +358,31 @@
|
||||
@@ -260,30 +357,31 @@
|
||||
}
|
||||
|
||||
public void addWorldborderListener(WorldServer worldserver) {
|
||||
|
@ -241,7 +240,7 @@
|
|||
}
|
||||
|
||||
@Override
|
||||
@@ -312,14 +411,15 @@
|
||||
@@ -312,14 +410,15 @@
|
||||
}
|
||||
|
||||
protected void save(EntityPlayer entityplayer) {
|
||||
|
@ -259,7 +258,7 @@
|
|||
|
||||
if (advancementdataplayer != null) {
|
||||
advancementdataplayer.save();
|
||||
@@ -327,10 +427,24 @@
|
||||
@@ -327,10 +426,24 @@
|
||||
|
||||
}
|
||||
|
||||
|
@ -285,7 +284,7 @@
|
|||
this.save(entityplayer);
|
||||
if (entityplayer.isPassenger()) {
|
||||
Entity entity = entityplayer.getRootVehicle();
|
||||
@@ -339,7 +453,7 @@
|
||||
@@ -339,7 +452,7 @@
|
||||
PlayerList.LOGGER.debug("Removing player mount");
|
||||
entityplayer.stopRiding();
|
||||
entity.getPassengersAndSelf().forEach((entity1) -> {
|
||||
|
@ -294,7 +293,7 @@
|
|||
});
|
||||
}
|
||||
}
|
||||
@@ -347,7 +461,7 @@
|
||||
@@ -347,7 +460,7 @@
|
||||
entityplayer.unRide();
|
||||
|
||||
for (EntityEnderPearl entityenderpearl : entityplayer.getEnderPearls()) {
|
||||
|
@ -303,7 +302,7 @@
|
|||
}
|
||||
|
||||
worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
|
||||
@@ -359,15 +473,58 @@
|
||||
@@ -359,15 +472,58 @@
|
||||
|
||||
if (entityplayer1 == entityplayer) {
|
||||
this.playersByUUID.remove(uuid);
|
||||
|
@ -367,7 +366,7 @@
|
|||
if (this.bans.isBanned(gameprofile)) {
|
||||
GameProfileBanEntry gameprofilebanentry = (GameProfileBanEntry) this.bans.get(gameprofile);
|
||||
IChatMutableComponent ichatmutablecomponent = IChatBaseComponent.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason());
|
||||
@@ -376,9 +533,11 @@
|
||||
@@ -376,9 +532,11 @@
|
||||
ichatmutablecomponent.append((IChatBaseComponent) IChatBaseComponent.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires())));
|
||||
}
|
||||
|
||||
|
@ -381,7 +380,7 @@
|
|||
} else if (this.ipBans.isBanned(socketaddress)) {
|
||||
IpBanEntry ipbanentry = this.ipBans.get(socketaddress);
|
||||
IChatMutableComponent ichatmutablecomponent1 = IChatBaseComponent.translatable("multiplayer.disconnect.banned_ip.reason", ipbanentry.getReason());
|
||||
@@ -387,13 +546,25 @@
|
||||
@@ -387,13 +545,25 @@
|
||||
ichatmutablecomponent1.append((IChatBaseComponent) IChatBaseComponent.translatable("multiplayer.disconnect.banned_ip.expiration", PlayerList.BAN_DATE_FORMAT.format(ipbanentry.getExpires())));
|
||||
}
|
||||
|
||||
|
@ -410,7 +409,7 @@
|
|||
UUID uuid = gameprofile.getId();
|
||||
Set<EntityPlayer> set = Sets.newIdentityHashSet();
|
||||
|
||||
@@ -414,32 +585,66 @@
|
||||
@@ -414,32 +584,66 @@
|
||||
}
|
||||
|
||||
return !set.isEmpty();
|
||||
|
@ -479,7 +478,7 @@
|
|||
}
|
||||
|
||||
byte b0 = (byte) (flag ? 1 : 0);
|
||||
@@ -447,17 +652,19 @@
|
||||
@@ -447,17 +651,19 @@
|
||||
WorldData worlddata = worldserver1.getLevelData();
|
||||
|
||||
entityplayer1.connection.send(new PacketPlayOutRespawn(entityplayer1.createCommonSpawnInfo(worldserver1), b0));
|
||||
|
@ -504,7 +503,7 @@
|
|||
entityplayer1.setHealth(entityplayer1.getHealth());
|
||||
EntityPlayer.RespawnConfig entityplayer_respawnconfig = entityplayer1.getRespawnConfig();
|
||||
|
||||
@@ -473,6 +680,27 @@
|
||||
@@ -473,6 +679,27 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +531,7 @@
|
|||
|
||||
return entityplayer1;
|
||||
}
|
||||
@@ -497,7 +725,18 @@
|
||||
@@ -497,7 +724,18 @@
|
||||
|
||||
public void tick() {
|
||||
if (++this.sendAllPlayerInfoIn > 600) {
|
||||
|
@ -552,7 +551,7 @@
|
|||
this.sendAllPlayerInfoIn = 0;
|
||||
}
|
||||
|
||||
@@ -510,6 +749,25 @@
|
||||
@@ -510,6 +748,25 @@
|
||||
|
||||
}
|
||||
|
||||
|
@ -578,7 +577,7 @@
|
|||
public void broadcastAll(Packet<?> packet, ResourceKey<World> resourcekey) {
|
||||
for (EntityPlayer entityplayer : this.players) {
|
||||
if (entityplayer.level().dimension() == resourcekey) {
|
||||
@@ -604,6 +862,7 @@
|
||||
@@ -604,6 +861,7 @@
|
||||
entityplayer.connection.send(new PacketPlayOutEntityStatus(entityplayer, b0));
|
||||
}
|
||||
|
||||
|
@ -586,7 +585,7 @@
|
|||
this.server.getCommands().sendCommands(entityplayer);
|
||||
}
|
||||
|
||||
@@ -634,6 +893,12 @@
|
||||
@@ -634,6 +892,12 @@
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
EntityPlayer entityplayer = (EntityPlayer) this.players.get(i);
|
||||
|
||||
|
@ -599,7 +598,7 @@
|
|||
if (entityplayer != entityhuman && entityplayer.level().dimension() == resourcekey) {
|
||||
double d4 = d0 - entityplayer.getX();
|
||||
double d5 = d1 - entityplayer.getY();
|
||||
@@ -673,15 +938,19 @@
|
||||
@@ -673,15 +937,19 @@
|
||||
public void reloadWhiteList() {}
|
||||
|
||||
public void sendLevelInfo(EntityPlayer entityplayer, WorldServer worldserver) {
|
||||
|
@ -623,7 +622,7 @@
|
|||
}
|
||||
|
||||
entityplayer.connection.send(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.LEVEL_CHUNKS_LOAD_START, 0.0F));
|
||||
@@ -690,8 +959,16 @@
|
||||
@@ -690,8 +958,16 @@
|
||||
|
||||
public void sendAllPlayerInfo(EntityPlayer entityplayer) {
|
||||
entityplayer.inventoryMenu.sendAllDataToRemote();
|
||||
|
@ -641,7 +640,7 @@
|
|||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
@@ -744,11 +1021,21 @@
|
||||
@@ -744,11 +1020,21 @@
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
|
@ -665,7 +664,7 @@
|
|||
|
||||
public void broadcastSystemMessage(IChatBaseComponent ichatbasecomponent, boolean flag) {
|
||||
this.broadcastSystemMessage(ichatbasecomponent, (entityplayer) -> {
|
||||
@@ -803,16 +1090,23 @@
|
||||
@@ -803,16 +1089,23 @@
|
||||
return playerchatmessage.hasSignature() && !playerchatmessage.hasExpiredServer(Instant.now());
|
||||
}
|
||||
|
||||
|
@ -693,7 +692,7 @@
|
|||
Path path = file2.toPath();
|
||||
|
||||
if (FileUtils.isPathNormalized(path) && FileUtils.isPathPortable(path) && path.startsWith(file.getPath()) && file2.isFile()) {
|
||||
@@ -821,7 +1115,7 @@
|
||||
@@ -821,7 +1114,7 @@
|
||||
}
|
||||
|
||||
serverstatisticmanager = new ServerStatisticManager(this.server, file1);
|
||||
|
@ -702,7 +701,7 @@
|
|||
}
|
||||
|
||||
return serverstatisticmanager;
|
||||
@@ -829,13 +1123,13 @@
|
||||
@@ -829,13 +1122,13 @@
|
||||
|
||||
public AdvancementDataPlayer getPlayerAdvancements(EntityPlayer entityplayer) {
|
||||
UUID uuid = entityplayer.getUUID();
|
||||
|
@ -718,7 +717,7 @@
|
|||
}
|
||||
|
||||
advancementdataplayer.setPlayer(entityplayer);
|
||||
@@ -880,11 +1174,24 @@
|
||||
@@ -880,11 +1173,24 @@
|
||||
}
|
||||
|
||||
public void reloadResources() {
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -40,9 +40,9 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
<version>3.30.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -43,7 +43,6 @@ import java.util.logging.Level;
|
|||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
import jline.console.ConsoleReader;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.commands.CommandDispatcher;
|
||||
import net.minecraft.commands.CommandListenerWrapper;
|
||||
|
@ -264,6 +263,7 @@ import org.bukkit.scoreboard.Criteria;
|
|||
import org.bukkit.structure.StructureManager;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.bukkit.util.permissions.DefaultPermissions;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
@ -1334,8 +1334,8 @@ public final class CraftServer implements Server {
|
|||
return logger;
|
||||
}
|
||||
|
||||
public ConsoleReader getReader() {
|
||||
return console.reader;
|
||||
public Terminal getTerminal() {
|
||||
return console.terminal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,7 +13,8 @@ import java.util.logging.Logger;
|
|||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.util.PathConverter;
|
||||
import org.fusesource.jansi.AnsiConsole;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
|
||||
public class Main {
|
||||
public static boolean useJline = true;
|
||||
|
@ -169,22 +170,15 @@ public class Main {
|
|||
}
|
||||
|
||||
try {
|
||||
// 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'});
|
||||
|
||||
useJline = !(jline_UnsupportedTerminal).equals(System.getProperty(jline_terminal));
|
||||
useJline = !Terminal.TYPE_DUMB.equals(System.getProperty(TerminalBuilder.PROP_PROVIDER));
|
||||
|
||||
if (options.has("nojline")) {
|
||||
System.setProperty("user.language", "en");
|
||||
useJline = false;
|
||||
}
|
||||
|
||||
if (useJline) {
|
||||
AnsiConsole.systemInstall();
|
||||
} else {
|
||||
if (!useJline) {
|
||||
// This ensures the terminal literal will always match the jline implementation
|
||||
System.setProperty(jline.TerminalFactory.JLINE_TERMINAL, jline.UnsupportedTerminal.class.getName());
|
||||
System.setProperty(TerminalBuilder.PROP_PROVIDER, Terminal.TYPE_DUMB);
|
||||
}
|
||||
|
||||
if (options.has("noconsole")) {
|
||||
|
|
|
@ -5,27 +5,29 @@ import java.util.EnumMap;
|
|||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import jline.Terminal;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.fusesource.jansi.Ansi.Attribute;
|
||||
import org.jline.jansi.Ansi;
|
||||
import org.jline.jansi.Ansi.Attribute;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
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();
|
||||
private final boolean jansiPassthrough;
|
||||
private final boolean supportsAnsi;
|
||||
private static final char ANSI_ESC_CHAR = '\u001B';
|
||||
private static final String RGB_STRING = String.valueOf(ANSI_ESC_CHAR) + "[38;2;%d;%d;%dm";
|
||||
private static final Pattern RBG_TRANSLATE = Pattern.compile(String.valueOf(ChatColor.COLOR_CHAR) + "x(" + String.valueOf(ChatColor.COLOR_CHAR) + "[A-F0-9]){6}", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
protected ColouredConsoleSender() {
|
||||
super();
|
||||
this.terminal = ((CraftServer) getServer()).getReader().getTerminal();
|
||||
this.terminal = ((CraftServer) getServer()).getTerminal();
|
||||
this.jansiPassthrough = Boolean.getBoolean("jansi.passthrough");
|
||||
this.supportsAnsi = !Terminal.TYPE_DUMB.equals(terminal.getType());
|
||||
|
||||
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());
|
||||
|
@ -54,7 +56,7 @@ public class ColouredConsoleSender extends CraftConsoleCommandSender {
|
|||
@Override
|
||||
public void sendMessage(String message) {
|
||||
// support jansi passthrough VM option when jansi doesn't detect an ANSI supported terminal
|
||||
if (jansiPassthrough || terminal.isAnsiSupported()) {
|
||||
if (jansiPassthrough || supportsAnsi) {
|
||||
if (!conversationTracker.isConversingModaly()) {
|
||||
String result = convertRGBColors(message);
|
||||
for (ChatColor color : colors) {
|
||||
|
|
|
@ -4,20 +4,25 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import jline.console.completer.Completer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.util.Waitable;
|
||||
import org.bukkit.event.server.TabCompleteEvent;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.ParsedLine;
|
||||
|
||||
public class ConsoleCommandCompleter implements Completer {
|
||||
private final CraftServer server;
|
||||
|
||||
public ConsoleCommandCompleter(CraftServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
|
||||
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
CraftServer server = (CraftServer) Bukkit.getServer();
|
||||
if (server == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String buffer = line.line();
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
||||
@Override
|
||||
protected List<String> evaluate() {
|
||||
|
@ -29,25 +34,17 @@ public class ConsoleCommandCompleter implements Completer {
|
|||
return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
|
||||
}
|
||||
};
|
||||
this.server.getServer().processQueue.add(waitable);
|
||||
server.getServer().processQueue.add(waitable);
|
||||
try {
|
||||
List<String> offers = waitable.get();
|
||||
if (offers == null) {
|
||||
return cursor;
|
||||
}
|
||||
candidates.addAll(offers);
|
||||
|
||||
final int lastSpace = buffer.lastIndexOf(' ');
|
||||
if (lastSpace == -1) {
|
||||
return cursor - buffer.length();
|
||||
} else {
|
||||
return cursor - (buffer.length() - lastSpace - 1);
|
||||
return;
|
||||
}
|
||||
offers.stream().map(Candidate::new).forEach((candidate) -> candidates.add(candidate));
|
||||
} 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);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ public class ServerShutdownThread extends Thread {
|
|||
server.close();
|
||||
} finally {
|
||||
try {
|
||||
server.reader.getTerminal().restore();
|
||||
server.terminal.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -3,23 +3,16 @@ 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;
|
||||
import org.jline.reader.LineReader;
|
||||
|
||||
public class TerminalConsoleWriterThread extends Thread {
|
||||
private final ResourceBundle bundle = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
|
||||
private final ConsoleReader reader;
|
||||
private final LineReader reader;
|
||||
private final OutputStream output;
|
||||
private volatile int completion = -1;
|
||||
|
||||
public TerminalConsoleWriterThread(OutputStream output, ConsoleReader reader) {
|
||||
public TerminalConsoleWriterThread(OutputStream output, LineReader reader) {
|
||||
super("TerminalConsoleWriter");
|
||||
this.output = output;
|
||||
this.reader = reader;
|
||||
|
@ -40,23 +33,7 @@ public class TerminalConsoleWriterThread extends Thread {
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
reader.printAbove(message);
|
||||
} else {
|
||||
output.write(message.getBytes());
|
||||
output.flush();
|
||||
|
@ -66,8 +43,4 @@ public class TerminalConsoleWriterThread extends Thread {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setCompletion(int completion) {
|
||||
this.completion = completion;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue