some more patches
This commit is contained in:
parent
78a003ee89
commit
2bc818efd4
14 changed files with 94 additions and 96 deletions
|
@ -1,547 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 12 Apr 2020 15:50:48 -0400
|
||||
Subject: [PATCH] Improved Watchdog Support
|
||||
|
||||
Forced Watchdog Crash support and Improve Async Shutdown
|
||||
|
||||
If the request to shut down the server is received while we are in
|
||||
a watchdog hang, immediately treat it as a crash and begin the shutdown
|
||||
process. Shutdown process is now improved to also shutdown cleanly when
|
||||
not using restart scripts either.
|
||||
|
||||
If a server is deadlocked, a server owner can send SIGUP (or any other signal
|
||||
the JVM understands to shut down as it currently does) and the watchdog
|
||||
will no longer need to wait until the full timeout, allowing you to trigger
|
||||
a close process and try to shut the server down gracefully, saving player and
|
||||
world data.
|
||||
|
||||
Previously there was no way to trigger this outside of waiting for a full watchdog
|
||||
timeout, which may be set to a really long time...
|
||||
|
||||
Additionally, fix everything to do with shutting the server down asynchronously.
|
||||
|
||||
Previously, nearly everything about the process was fragile and unsafe. Main might
|
||||
not have actually been frozen, and might still be manipulating state.
|
||||
|
||||
Or, some reuest might ask main to do something in the shutdown but main is dead.
|
||||
|
||||
Or worse, other things might start closing down items such as the Console or Thread Pool
|
||||
before we are fully shutdown.
|
||||
|
||||
This change tries to resolve all of these issues by moving everything into the stop
|
||||
method and guaranteeing only one thread is stopping the server.
|
||||
|
||||
We then issue Thread Death to the main thread of another thread initiates the stop process.
|
||||
We have to ensure Thread Death propagates correctly though to stop main completely.
|
||||
|
||||
This is to ensure that if main isn't truely stuck, it's not manipulating state we are trying to save.
|
||||
|
||||
This also moves all plugins who register "delayed init" tasks to occur just before "Done" so they
|
||||
are properly accounted for and wont trip watchdog on init.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
index 6aaed8e8bf8c721fc834da5c76ac72a4c3e92458..4b002e8b75d117b726b0de274a76d3596fce015b 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
@@ -92,7 +92,12 @@ public class Metrics {
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
- final Runnable submitTask = this::submitData;
|
||||
+ final Runnable submitTask = () -> {
|
||||
+ if (MinecraftServer.getServer().hasStopped()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ submitData();
|
||||
+ };
|
||||
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay.
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 336795dff742b7c6957fbd3476aff31d25a5e659..30a58229aa6dac5039511d0c0df5f2912ea7de9f 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -230,6 +230,7 @@ public class CrashReport {
|
||||
}
|
||||
|
||||
public static CrashReport forThrowable(Throwable cause, String title) {
|
||||
+ if (cause instanceof ThreadDeath) com.destroystokyo.paper.util.SneakyThrow.sneaky(cause); // Paper
|
||||
while (cause instanceof CompletionException && cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 498f06aa1d8b2c20f5bf31d6751f08cf1eb4240f..047562e1df93347f629b529ca0647697e22ecf48 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -296,7 +296,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
public int autosavePeriod;
|
||||
public Commands vanillaCommandDispatcher;
|
||||
- private boolean forceTicks;
|
||||
+ public boolean forceTicks; // Paper
|
||||
// CraftBukkit end
|
||||
// Spigot start
|
||||
public static final int TPS = 20;
|
||||
@@ -307,6 +307,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations;
|
||||
public static long currentTickLong = 0L; // Paper
|
||||
|
||||
+ public volatile Thread shutdownThread; // Paper
|
||||
+ public volatile boolean abnormalExit = false; // Paper
|
||||
+
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system
|
||||
@@ -883,6 +886,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
+ public volatile boolean hasFullyShutdown = false; // Paper
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -897,6 +901,19 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (this.hasStopped) return;
|
||||
this.hasStopped = true;
|
||||
}
|
||||
+ // Paper start - kill main thread, and kill it hard
|
||||
+ shutdownThread = Thread.currentThread();
|
||||
+ org.spigotmc.WatchdogThread.doStop(); // Paper
|
||||
+ if (!isSameThread()) {
|
||||
+ MinecraftServer.LOGGER.info("Stopping main thread (Ignore any thread death message you see! - DO NOT REPORT THREAD DEATH TO PAPER)");
|
||||
+ while (this.getRunningThread().isAlive()) {
|
||||
+ this.getRunningThread().stop();
|
||||
+ try {
|
||||
+ Thread.sleep(1);
|
||||
+ } catch (InterruptedException e) {}
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
if (this.metricsRecorder.isRecording()) {
|
||||
this.cancelRecordingMetrics();
|
||||
@@ -953,7 +970,19 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.getProfileCache().save(false); // Paper
|
||||
}
|
||||
// Spigot end
|
||||
+
|
||||
+ // Paper start - move final shutdown items here
|
||||
+ LOGGER.info("Flushing Chunk IO");
|
||||
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
|
||||
+ LOGGER.info("Closing Thread Pool");
|
||||
+ Util.shutdownExecutors(); // Paper
|
||||
+ LOGGER.info("Closing Server");
|
||||
+ try {
|
||||
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ } catch (Exception e) {
|
||||
+ }
|
||||
+ this.onServerExit();
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public String getLocalIp() {
|
||||
@@ -1048,6 +1077,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void runServer() {
|
||||
try {
|
||||
+ long serverStartTime = Util.getNanos(); // Paper
|
||||
if (!this.initServer()) {
|
||||
throw new IllegalStateException("Failed to initialize server");
|
||||
}
|
||||
@@ -1057,6 +1087,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.status = this.buildServerStatus();
|
||||
|
||||
// Spigot start
|
||||
+ // Paper start - move done tracking
|
||||
+ LOGGER.info("Running delayed init tasks");
|
||||
+ this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // run all 1 tick delay tasks during init,
|
||||
+ // this is going to be the first thing the tick process does anyways, so move done and run it after
|
||||
+ // everything is init before watchdog tick.
|
||||
+ // anything at 3+ won't be caught here but also will trip watchdog....
|
||||
+ // tasks are default scheduled at -1 + delay, and first tick will tick at 1
|
||||
+ String doneTime = String.format(java.util.Locale.ROOT, "%.3fs", (double) (Util.getNanos() - serverStartTime) / 1.0E9D);
|
||||
+ LOGGER.info("Done ({})! For help, type \"help\"", doneTime);
|
||||
+ // Paper end
|
||||
+
|
||||
+ org.spigotmc.WatchdogThread.tick(); // Paper
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
|
||||
Arrays.fill( recentTps, 20 );
|
||||
long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
|
||||
@@ -1117,6 +1159,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
JvmProfiler.INSTANCE.onServerTick(this.averageTickTime);
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
+ // Paper start
|
||||
+ if (throwable instanceof ThreadDeath) {
|
||||
+ MinecraftServer.LOGGER.error("Main thread terminated by WatchDog due to hard crash", throwable);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable);
|
||||
// Spigot Start
|
||||
if ( throwable.getCause() != null )
|
||||
@@ -1147,14 +1195,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.services.profileCache().clearExecutor();
|
||||
}
|
||||
|
||||
- org.spigotmc.WatchdogThread.doStop(); // Spigot
|
||||
+ //org.spigotmc.WatchdogThread.doStop(); // Spigot // Paper - move into stop
|
||||
// CraftBukkit start - Restore terminal to original settings
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// CraftBukkit end
|
||||
- this.onServerExit();
|
||||
+ //this.onServerExit(); // Paper - moved into stop
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1223,6 +1271,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public TickTask wrapRunnable(Runnable runnable) {
|
||||
+ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog
|
||||
+ if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) {
|
||||
+ runnable.run();
|
||||
+ runnable = () -> {};
|
||||
+ }
|
||||
+ // Paper end
|
||||
return new TickTask(this.tickCount, runnable);
|
||||
}
|
||||
|
||||
@@ -1458,6 +1512,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
||||
} catch (Throwable t) {
|
||||
+ if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
|
||||
throw new RuntimeException("Error generating crash report", t);
|
||||
}
|
||||
// Spigot End
|
||||
@@ -1958,7 +2013,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.worldData.setDataConfiguration(worlddataconfiguration);
|
||||
this.resources.managers.updateRegistryTags(this.registryAccess());
|
||||
- this.getPlayerList().saveAll();
|
||||
+ // Paper start
|
||||
+ if (Thread.currentThread() != this.serverThread) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements
|
||||
+ for (ServerPlayer player : this.getPlayerList().getPlayers()) {
|
||||
+ player.getAdvancements().save();
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 56b17a1ce545ec43bf588d4ab438440fb829bc97..ba75c854faed13c60ae5464c4685373b99ef42c2 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -269,7 +269,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
long j = Util.getNanos() - i;
|
||||
String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D);
|
||||
|
||||
- DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s);
|
||||
+ //DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s); // Paper moved to after init
|
||||
if (dedicatedserverproperties.announcePlayerAchievements != null) {
|
||||
((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this);
|
||||
}
|
||||
@@ -397,7 +397,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
// this.remoteStatusListener.stop(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
- System.exit(0); // CraftBukkit
|
||||
+ hasFullyShutdown = true; // Paper
|
||||
+ System.exit(this.abnormalExit ? 70 : 0); // CraftBukkit // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -770,7 +771,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@Override
|
||||
public void stopServer() {
|
||||
super.stopServer();
|
||||
- Util.shutdownExecutors();
|
||||
+ //Util.shutdownExecutors(); // Paper - moved into super
|
||||
SkullBlockEntity.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 5b8b345ade30012371bdda744ba82c585f74db07..0d100788312a234616c1401656f09835458e79f6 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -547,7 +547,7 @@ public abstract class PlayerList {
|
||||
this.cserver.getPluginManager().callEvent(playerQuitEvent);
|
||||
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
||||
|
||||
- entityplayer.doTick(); // SPIGOT-924
|
||||
+ if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
|
||||
// CraftBukkit end
|
||||
|
||||
// Paper start - Remove from collideRule team if needed
|
||||
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
index f5829ae484d93b547a5437b85a9621346384a11b..83701fbfaa56a232593ee8f11a3afb8941238bfa 100644
|
||||
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
@@ -152,6 +152,7 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception var3) {
|
||||
+ if (var3.getCause() instanceof ThreadDeath) throw var3; // Paper
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Error executing task on {}", this.name(), var3);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 7a1886585bd00dc8213ce22130b8b6fea52c5cf6..52a44510d0499df56d2ebef0963fe8164eda7301 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -904,6 +904,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
MinecraftServer.LOGGER.error(msg, throwable);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index c3760f22fcc56ccb25e3315823054416c2172386..246606164117e8140ab0892ec1326503b414a1ab 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1180,6 +1180,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
|
||||
gameprofilerfiller.pop();
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 2badebc0d7954c6d343bfd66dd14dc2d2d4661d7..f847527bf22fa34817dee79e61a47545b1e1f7bc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -178,6 +178,36 @@ public class Main {
|
||||
|
||||
OptionSet options = null;
|
||||
|
||||
+ // Paper start - preload logger classes to avoid plugins mixing versions
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Core");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.appender.AsyncAppender");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Appender");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.ContextDataInjector");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Filter");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.ErrorHandler");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Logger");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LoggerContext");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LogEventListener");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.AbstractLogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.AsynchronouslyFormattable");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.FormattedMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.ParameterizedMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.Message");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.MessageFactory");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.TimestampMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.SimpleMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLogger");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerContext");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncQueueFullPolicy");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerDisruptor");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.DisruptorUtil");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEventHandler");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ThrowableProxy");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedClassInfo");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedStackTraceElement");
|
||||
+ // Paper end
|
||||
try {
|
||||
options = parser.parse(args);
|
||||
} catch (joptsimple.OptionException ex) {
|
||||
@@ -288,8 +318,64 @@ public class Main {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
+ // Paper start
|
||||
+ // load some required classes to avoid errors during shutdown if jar is replaced
|
||||
+ // also to guarantee our version loads over plugins
|
||||
+ tryPreloadClass("com.destroystokyo.paper.util.SneakyThrow");
|
||||
+ tryPreloadClass("com.google.common.collect.Iterators$PeekingImpl");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$Values");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$ValueIterator");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$WriteThroughEntry");
|
||||
+ tryPreloadClass("com.google.common.collect.Iterables");
|
||||
+ for (int i = 1; i <= 15; i++) {
|
||||
+ tryPreloadClass("com.google.common.collect.Iterables$" + i, false);
|
||||
+ }
|
||||
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableBoolean");
|
||||
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableInt");
|
||||
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport");
|
||||
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport$1");
|
||||
+ tryPreloadClass("org.jline.terminal.Terminal$MouseTracking");
|
||||
+ tryPreloadClass("co.aikar.timings.TimingHistory");
|
||||
+ tryPreloadClass("co.aikar.timings.TimingHistory$MinuteReport");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext$11");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext$12");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannel$AbstractUnsafe$8");
|
||||
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise");
|
||||
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise$1");
|
||||
+ tryPreloadClass("io.netty.util.internal.PromiseNotificationUtil");
|
||||
+ tryPreloadClass("io.netty.util.internal.SystemPropertyUtil");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$1");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$2");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$3");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$4");
|
||||
+ tryPreloadClass("org.slf4j.helpers.MessageFormatter");
|
||||
+ tryPreloadClass("org.slf4j.helpers.FormattingTuple");
|
||||
+ tryPreloadClass("org.slf4j.helpers.BasicMarker");
|
||||
+ tryPreloadClass("org.slf4j.helpers.Util");
|
||||
+ tryPreloadClass("com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent");
|
||||
+ tryPreloadClass("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent");
|
||||
+ // Minecraft, seen during saving
|
||||
+ tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.DummyLightLayerEventListener.class.getName());
|
||||
+ tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.class.getName());
|
||||
+ tryPreloadClass(net.minecraft.util.ExceptionCollector.class.getName());
|
||||
+ // Paper end
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Paper start
|
||||
+ private static void tryPreloadClass(String className) {
|
||||
+ tryPreloadClass(className, true);
|
||||
+ }
|
||||
+ private static void tryPreloadClass(String className, boolean printError) {
|
||||
+ try {
|
||||
+ Class.forName(className);
|
||||
+ } catch (ClassNotFoundException e) {
|
||||
+ if (printError) System.err.println("An expected class " + className + " was not found for preloading: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
private static List<String> asList(String... params) {
|
||||
return Arrays.asList(params);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
index c6e8441e299f477ddb22c1ce2618710763978f1a..e8e93538dfd71de86515d9405f728db1631e949a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
@@ -12,11 +12,27 @@ public class ServerShutdownThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
+ // Paper start - try to shutdown on main
|
||||
+ server.safeShutdown(false, false);
|
||||
+ for (int i = 1000; i > 0 && !server.hasStopped(); i -= 100) {
|
||||
+ Thread.sleep(100);
|
||||
+ }
|
||||
+ if (server.hasStopped()) {
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Looks stalled, close async
|
||||
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
|
||||
+ server.forceTicks = true;
|
||||
this.server.close();
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ // Paper end
|
||||
} finally {
|
||||
+ org.apache.logging.log4j.LogManager.shutdown(); // Paper
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
index 14eadb0f81dfad072d82d7793cce1a4dd3f2c5f0..29b39dff0aceaa902f701162a42d3f2f881d6d5a 100644
|
||||
--- a/src/main/java/org/spigotmc/RestartCommand.java
|
||||
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
@@ -138,7 +138,7 @@ public class RestartCommand extends Command
|
||||
// Paper end
|
||||
|
||||
// Paper start - copied from above and modified to return if the hook registered
|
||||
- private static boolean addShutdownHook(String restartScript)
|
||||
+ public static boolean addShutdownHook(String restartScript)
|
||||
{
|
||||
String[] split = restartScript.split( " " );
|
||||
if ( split.length > 0 && new File( split[0] ).isFile() )
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index b47d043144c499b1499f6b4be5a16a3f75c9fcb8..a9bd33b58a6a3296b70eaaaea3adbee74724e448 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -11,6 +11,7 @@ import org.bukkit.Bukkit;
|
||||
public final class WatchdogThread extends io.papermc.paper.util.TickThread // Paper - rewrite chunk system
|
||||
{
|
||||
|
||||
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@@ -39,6 +40,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
{
|
||||
if ( WatchdogThread.instance == null )
|
||||
{
|
||||
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
|
||||
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
||||
WatchdogThread.instance.start();
|
||||
} else
|
||||
@@ -70,12 +72,13 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
// Paper start
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
long currentTime = WatchdogThread.monotonicMillis();
|
||||
- if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.hasStarted && (!server.isRunning() || (currentTime > this.lastTick + this.earlyWarningEvery && !DISABLE_WATCHDOG) )) // Paper - add property to disable
|
||||
{
|
||||
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
|
||||
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
|
||||
// Don't spam early warning dumps
|
||||
if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
|
||||
- if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
+ if ( !isLongTimeout && server.hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
lastEarlyWarning = currentTime;
|
||||
if (isLongTimeout) {
|
||||
// Paper end
|
||||
@@ -137,9 +140,24 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
|
||||
if ( isLongTimeout )
|
||||
{
|
||||
- if ( this.restart && !MinecraftServer.getServer().hasStopped() )
|
||||
+ if ( !server.hasStopped() )
|
||||
{
|
||||
- RestartCommand.restart();
|
||||
+ AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
||||
+ server.forceTicks = true;
|
||||
+ if (restart) {
|
||||
+ RestartCommand.addShutdownHook( SpigotConfig.restartScript );
|
||||
+ }
|
||||
+ // try one last chance to safe shutdown on main incase it 'comes back'
|
||||
+ server.abnormalExit = true;
|
||||
+ server.safeShutdown(false, restart);
|
||||
+ try {
|
||||
+ Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ }
|
||||
+ if (!server.hasStopped()) {
|
||||
+ server.close();
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
} // Paper end
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index ea4e2161c0bd43884055cc6b8d70b2139f70e720..266b4e6fb3988b5848021c83fdc68e342c70b188 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
-<Configuration status="WARN" packages="com.mojang.util">
|
||||
+<Configuration status="WARN" packages="com.mojang.util" shutdownHook="disable">
|
||||
<Appenders>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 02:02:07 -0600
|
||||
Subject: [PATCH] Optimize Pathfinding
|
||||
|
||||
Prevents pathfinding from spamming failures for things such as
|
||||
arrow attacks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 03cc97b13b1b8eb591b563c1eb52355b00ea3bf1..b376670d11088e524ce246f667e580e90cd119a3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -192,9 +192,29 @@ public abstract class PathNavigation {
|
||||
return this.moveTo(this.createPath(x, y, z, 1), speed);
|
||||
}
|
||||
|
||||
+ // Paper start - optimise pathfinding
|
||||
+ private int lastFailure = 0;
|
||||
+ private int pathfindFailures = 0;
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean moveTo(Entity entity, double speed) {
|
||||
+ // Paper start - Pathfinding optimizations
|
||||
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
Path path = this.createPath(entity, 1);
|
||||
- return path != null && this.moveTo(path, speed);
|
||||
+ // Paper start - Pathfinding optimizations
|
||||
+ if (path != null && this.moveTo(path, speed)) {
|
||||
+ this.lastFailure = 0;
|
||||
+ this.pathfindFailures = 0;
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ this.pathfindFailures++;
|
||||
+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public boolean moveTo(@Nullable Path path, double speed) {
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 18:35:09 -0700
|
||||
Subject: [PATCH] Reduce Either Optional allocation
|
||||
|
||||
In order to get chunk values, we shouldn't need to create
|
||||
an optional each time.
|
||||
|
||||
diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
index de524d485fada3c3cca8c2fe6c63db0e0b33dad8..6eb0c94965a6e96ec8ae112125e98c6c4809805b 100644
|
||||
--- a/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
+++ b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
@@ -22,7 +22,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Left<L, R> extends Either<L, R> {
|
||||
- private final L value;
|
||||
+ private final L value; private Optional<L> valueOptional; // Paper - reduce the optional allocation...
|
||||
|
||||
public Left(final L value) {
|
||||
this.value = value;
|
||||
@@ -51,7 +51,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<L> left() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation...
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,7 +83,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Right<L, R> extends Either<L, R> {
|
||||
- private final R value;
|
||||
+ private final R value; private Optional<R> valueOptional; // Paper - reduce the optional allocation...
|
||||
|
||||
public Right(final R value) {
|
||||
this.value = value;
|
||||
@@ -117,7 +117,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<R> right() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation...
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:39:25 -0700
|
||||
Subject: [PATCH] Reduce memory footprint of NBTTagCompound
|
||||
|
||||
Fastutil maps are going to have a lower memory footprint - which
|
||||
is important because we clone chunk data after reading it for safety.
|
||||
So, reduce the impact of the clone on GC.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
index 64765dab6fed87ffdf4af197d8d5f28a04544db0..1d13bc15c56faa69699fb3ad39210233d6b6934d 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -36,7 +36,7 @@ public class CompoundTag implements Tag {
|
||||
if (i > 512) {
|
||||
throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512");
|
||||
} else {
|
||||
- Map<String, Tag> map = Maps.newHashMap();
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound
|
||||
|
||||
byte b;
|
||||
while((b = CompoundTag.readNamedTagType(dataInput, nbtAccounter)) != 0) {
|
||||
@@ -130,7 +130,7 @@ public class CompoundTag implements Tag {
|
||||
}
|
||||
|
||||
public CompoundTag() {
|
||||
- this(Maps.newHashMap());
|
||||
+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - reduce memory footprint of NBTTagCompound
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -449,8 +449,16 @@ public class CompoundTag implements Tag {
|
||||
|
||||
@Override
|
||||
public CompoundTag copy() {
|
||||
- Map<String, Tag> map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy));
|
||||
- return new CompoundTag(map);
|
||||
+ // Paper start - reduce memory footprint of NBTTagCompound
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f);
|
||||
+ java.util.Iterator<java.util.Map.Entry<String, Tag>> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator();
|
||||
+ while (iterator.hasNext()) {
|
||||
+ Map.Entry<String, Tag> entry = iterator.next();
|
||||
+ ret.put(entry.getKey(), entry.getValue().copy());
|
||||
+ }
|
||||
+
|
||||
+ return new CompoundTag(ret);
|
||||
+ // Paper end - reduce memory footprint of NBTTagCompound
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Mon, 13 Apr 2020 07:31:44 +0100
|
||||
Subject: [PATCH] Prevent opening inventories when frozen
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index c7d4341642df2fc847e139cf03992b13645afa3e..0e7f5d780d8c17a68a6d3cf98febad94f63e3f81 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -693,7 +693,7 @@ public class ServerPlayer extends Player {
|
||||
containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
|
||||
}
|
||||
// Paper end
|
||||
- if (!this.level().isClientSide && !this.containerMenu.stillValid(this)) {
|
||||
+ if (!this.level().isClientSide && this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - auto close while frozen
|
||||
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
|
||||
this.containerMenu = this.inventoryMenu;
|
||||
}
|
||||
@@ -1542,7 +1542,7 @@ public class ServerPlayer extends Player {
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
this.containerMenu = container;
|
||||
- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle()));
|
||||
+ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper
|
||||
// CraftBukkit end
|
||||
this.initMenu(container);
|
||||
return OptionalInt.of(this.containerCounter);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index 552fb0be2f31bd52a5ae43526d55aa29828f786e..ec7ea1ef632bea761ca8b9603059a12fb72dfa47 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -325,7 +325,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper
|
||||
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
||||
@@ -399,7 +399,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 15 Apr 2020 17:56:07 -0700
|
||||
Subject: [PATCH] Don't run entity collision code if not needed
|
||||
|
||||
Will not run if:
|
||||
Max entity cramming is disabled and the max collisions per entity is less than or equal to 0.
|
||||
Entity#isPushable() returns false, meaning all entities will not be able to collide with this
|
||||
entity anyways.
|
||||
The entity's current team collision rule causes them to NEVER collide.
|
||||
|
||||
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 11e84ea16177f11b834bcf13e9b36985ac4cfd4e..fe5995a79929fb46ae5d9d9056993a6e37b670e7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3370,10 +3370,24 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
if (this.level().isClientSide()) {
|
||||
this.level().getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush);
|
||||
} else {
|
||||
+ // Paper start - don't run getEntities if we're not going to use its result
|
||||
+ if (!this.isPushable()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ net.minecraft.world.scores.Team team = this.getTeam();
|
||||
+ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - don't run getEntities if we're not going to use its result
|
||||
List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this));
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ // Paper - moved up
|
||||
int j;
|
||||
|
||||
if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) {
|
|
@ -1,174 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Mon, 20 Jan 2020 21:38:15 +0100
|
||||
Subject: [PATCH] Implement Player Client Options API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabba57885e1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
@@ -0,0 +1,74 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import com.google.common.base.Objects;
|
||||
+
|
||||
+import java.util.StringJoiner;
|
||||
+
|
||||
+public class PaperSkinParts implements SkinParts {
|
||||
+
|
||||
+ private final int raw;
|
||||
+
|
||||
+ public PaperSkinParts(int raw) {
|
||||
+ this.raw = raw;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasCapeEnabled() {
|
||||
+ return (raw & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasJacketEnabled() {
|
||||
+ return (raw >> 1 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftSleeveEnabled() {
|
||||
+ return (raw >> 2 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightSleeveEnabled() {
|
||||
+ return (raw >> 3 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftPantsEnabled() {
|
||||
+ return (raw >> 4 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightPantsEnabled() {
|
||||
+ return (raw >> 5 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasHatsEnabled() {
|
||||
+ return (raw >> 6 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getRaw() {
|
||||
+ return raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || getClass() != o.getClass()) return false;
|
||||
+ PaperSkinParts that = (PaperSkinParts) o;
|
||||
+ return raw == that.raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return Objects.hashCode(raw);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]")
|
||||
+ .add("raw=" + raw)
|
||||
+ .add("cape=" + hasCapeEnabled())
|
||||
+ .add("jacket=" + hasJacketEnabled())
|
||||
+ .add("leftSleeve=" + hasLeftSleeveEnabled())
|
||||
+ .add("rightSleeve=" + hasRightSleeveEnabled())
|
||||
+ .add("leftPants=" + hasLeftPantsEnabled())
|
||||
+ .add("rightPants=" + hasRightPantsEnabled())
|
||||
+ .add("hats=" + hasHatsEnabled())
|
||||
+ .toString();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0e7f5d780d8c17a68a6d3cf98febad94f63e3f81..f4a8491d6b6333030cecee3920da060d6b96a309 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1949,9 +1949,24 @@ public class ServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Client option API
|
||||
+ private java.util.Map<com.destroystokyo.paper.ClientOption<?>, ?> getClientOptionMap(String locale, int viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility chatVisibility, boolean chatColors, com.destroystokyo.paper.PaperSkinParts skinParts, org.bukkit.inventory.MainHand mainHand, boolean allowsServerListing, boolean textFilteringEnabled) {
|
||||
+ java.util.Map<com.destroystokyo.paper.ClientOption<?>, Object> map = new java.util.HashMap<>();
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, locale);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, viewDistance);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, chatVisibility);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, chatColors);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, skinParts);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, mainHand);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, allowsServerListing);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, textFilteringEnabled);
|
||||
+ return map;
|
||||
+ }
|
||||
+ // Paper end
|
||||
public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
|
||||
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
||||
public void updateOptions(ServerboundClientInformationPacket packet) {
|
||||
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), getClientOptionMap(packet.language, packet.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packet.chatVisibility().name()), packet.chatColors(), new com.destroystokyo.paper.PaperSkinParts(packet.modelCustomisation()), packet.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT, packet.allowsListing(), packet.textFilteringEnabled())).callEvent(); // Paper - settings event
|
||||
// CraftBukkit start
|
||||
if (getMainArm() != packet.mainHand()) {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 08404472a89192fb0cbae0192793c4c4ae63a9bb..cb9482240de0d5d56be4ec591b4fbb23006767c1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -602,6 +602,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public <T> T getClientOption(com.destroystokyo.paper.ClientOption<T> type) {
|
||||
+ if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) {
|
||||
+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION)));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().canChatInColor());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) {
|
||||
+ return type.getType().cast(getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(getHandle().getChatVisibility().name()));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) {
|
||||
+ return type.getType().cast(getLocale());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) {
|
||||
+ return type.getType().cast(getMainHand());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) {
|
||||
+ return type.getType().cast(getClientViewDistance());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) {
|
||||
+ return type.getType().cast(getHandle().allowsListing());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().isTextFilteringEnabled());
|
||||
+ }
|
||||
+ throw new RuntimeException("Unknown settings type");
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fab3063fffa959ac7f0eb5937f2fae94d11b6591
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+package io.papermc.paper.world;
|
||||
+
|
||||
+import com.destroystokyo.paper.ClientOption;
|
||||
+import net.minecraft.world.entity.player.ChatVisiblity;
|
||||
+import org.bukkit.Difficulty;
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+public class TranslationKeyTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testChatVisibilityKeys() {
|
||||
+ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) {
|
||||
+ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue;
|
||||
+ Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 18 Apr 2020 15:59:41 -0400
|
||||
Subject: [PATCH] Don't crash if player is attempted to be removed from
|
||||
untracked chunk.
|
||||
|
||||
I suspect it deals with teleporting as it uses players current x/y/z
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index c716047fefb51a77ce18df243c517d80c78b6853..0a926afa06a5e37cf2650afa1b5099a2a9ffa659 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -147,8 +147,8 @@ public abstract class DistanceManager {
|
||||
ObjectSet<ServerPlayer> objectset = (ObjectSet) this.playersPerChunk.get(i);
|
||||
if (objectset == null) return; // CraftBukkit - SPIGOT-6208
|
||||
|
||||
- objectset.remove(player);
|
||||
- if (objectset.isEmpty()) {
|
||||
+ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
||||
+ if (objectset == null || objectset.isEmpty()) { // Paper
|
||||
this.playersPerChunk.remove(i);
|
||||
this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
|
@ -1,113 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 00:05:46 -0400
|
||||
Subject: [PATCH] Fix Longstanding Broken behavior of PlayerJoinEvent
|
||||
|
||||
For years, plugin developers have had to delay many things they do
|
||||
inside of the PlayerJoinEvent by 1 tick to make it actually work.
|
||||
|
||||
This all boiled down to 1 reason why: The event fired before the
|
||||
player was fully ready and joined to the world!
|
||||
|
||||
Additionally, if that player logged out on a vehicle, the event
|
||||
fired before the vehicle was even loaded, so that plugins had no
|
||||
access to the vehicle during this event either.
|
||||
|
||||
This change finally fixes this issue, fully preparing the player
|
||||
into the world as a fully ready entity, vehicle included.
|
||||
|
||||
There should be no plugins that break because of this change, but might
|
||||
improve consistency with other plugins instead.
|
||||
|
||||
For example, if 2 plugins listens to this event, and the first one
|
||||
teleported the player in the event, then the 2nd plugin actually
|
||||
would be getting a valid player!
|
||||
|
||||
This was very non deterministic. This change will ensure every plugin
|
||||
receives a deterministic result, and should no longer require 1 tick
|
||||
delays anymore.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index a8c4c7298e127e5b60a3b43ad168976d29901bc5..48586780da5d260894fe59efaa97cb1facfe73fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1037,6 +1037,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
+ ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
|
||||
return;
|
||||
}
|
||||
+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets
|
||||
// Paper end
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index f4a8491d6b6333030cecee3920da060d6b96a309..15a70bad66eb2508f58ff184061c2d19e45297e1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -267,6 +267,7 @@ public class ServerPlayer extends Player {
|
||||
public double maxHealthCache;
|
||||
public boolean joining = true;
|
||||
public boolean sentListPacket = false;
|
||||
+ public boolean supressTrackerForLogin = false; // Paper
|
||||
public Integer clientViewDistance;
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0d100788312a234616c1401656f09835458e79f6..97199ae30edfaaacb9ea9d29846ee131395815e6 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -311,6 +311,12 @@ public abstract class PlayerList {
|
||||
this.playersByUUID.put(player.getUUID(), player);
|
||||
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below
|
||||
|
||||
+ // Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
|
||||
+ player.supressTrackerForLogin = true;
|
||||
+ worldserver1.addNewPlayer(player);
|
||||
+ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer);
|
||||
+ mountSavedVehicle(player, worldserver1, nbttagcompound);
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
CraftPlayer bukkitPlayer = player.getBukkitEntity();
|
||||
|
||||
@@ -349,6 +355,8 @@ public abstract class PlayerList {
|
||||
player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1)));
|
||||
}
|
||||
player.sentListPacket = true;
|
||||
+ player.supressTrackerForLogin = false; // Paper
|
||||
+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now
|
||||
// CraftBukkit end
|
||||
|
||||
player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
|
||||
@@ -374,6 +382,11 @@ public abstract class PlayerList {
|
||||
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect));
|
||||
}
|
||||
|
||||
+ // Paper start - move vehicle into method so it can be called above - short circuit around that code
|
||||
+ onPlayerJoinFinish(player, worldserver1, s1);
|
||||
+ }
|
||||
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) {
|
||||
+ // Paper end
|
||||
if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) {
|
||||
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
||||
// CraftBukkit start
|
||||
@@ -422,6 +435,10 @@ public abstract class PlayerList {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ }
|
||||
+ public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) {
|
||||
+ // Paper end
|
||||
player.initInventoryMenu();
|
||||
// CraftBukkit - Moved from above, added world
|
||||
// Paper start - Add to collideRule team if needed
|
||||
@@ -431,6 +448,7 @@ public abstract class PlayerList {
|
||||
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
||||
}
|
||||
// Paper end
|
||||
+ // CraftBukkit - Moved from above, added world
|
||||
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: 2277 <38501234+2277@users.noreply.github.com>
|
||||
Date: Tue, 31 Mar 2020 10:33:55 +0100
|
||||
Subject: [PATCH] Move player to spawn point if spawn in unloaded world
|
||||
|
||||
The code following this has better support for null worlds to move
|
||||
them back to the world spawn.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 70d1d664efa323cbb0c07fd5aa746122261b6bfa..d7cf9ca3a1002463b09ed709f3003d0528a3ff0b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2319,9 +2319,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
bworld = server.getWorld(worldName);
|
||||
}
|
||||
|
||||
- if (bworld == null) {
|
||||
- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld();
|
||||
- }
|
||||
+ // Paper start - Move player to spawn point if spawn in unloaded world
|
||||
+// if (bworld == null) {
|
||||
+// bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(World.OVERWORLD).getWorld();
|
||||
+// }
|
||||
+ // Paper end - Move player to spawn point if spawn in unloaded world
|
||||
|
||||
((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: nossr50 <nossr50@gmail.com>
|
||||
Date: Thu, 26 Mar 2020 19:44:50 -0700
|
||||
Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index fe5995a79929fb46ae5d9d9056993a6e37b670e7..1cae4bcd7d5d310ead65342af063a4617d24c694 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2162,7 +2162,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption);
|
||||
if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) {
|
||||
- ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired
|
||||
+ // Paper start - PlayerAttackEntityCooldownResetEvent
|
||||
+ if (damagesource.getEntity() instanceof ServerPlayer) {
|
||||
+ ServerPlayer player = (ServerPlayer) damagesource.getEntity();
|
||||
+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) {
|
||||
+ player.resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ } else {
|
||||
+ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 23 Apr 2020 01:36:39 -0400
|
||||
Subject: [PATCH] Don't fire BlockFade on worldgen threads
|
||||
|
||||
Caused a deadlock
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
index 945d8b0f58f6a5b2281f136d3afbba3b34e0e6b5..8c6edd032c927f7d1e04e944b4ce5598d71cdd81 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
@@ -101,6 +101,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
// CraftBukkit start
|
||||
+ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation
|
||||
if (!this.canSurvive(state, world, pos)) {
|
||||
// Suppress during worldgen
|
||||
if (!(world instanceof Level)) {
|
||||
@@ -116,7 +117,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
return blockState.getHandle();
|
||||
}
|
||||
}
|
||||
- return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE));
|
||||
+ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - diff on change, see "don't fire events in world generation"
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 25 Apr 2020 15:13:41 -0500
|
||||
Subject: [PATCH] Add phantom creative and insomniac controls
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
index 668a7c3f36cdbe48e472cb810b27ae4ab39a65d6..d15e62da0307728a7c2be191a27f87da1bb29f49 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -27,6 +27,7 @@ public final class EntitySelector {
|
||||
return !entity.isSpectator();
|
||||
};
|
||||
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
|
||||
+ public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
|
||||
|
||||
private EntitySelector() {}
|
||||
// Paper start
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
index 9bd6e71ea38bf050832f0f7bbed4a5db6ddcef71..ab639cb2faaafaeb33be91bfe99ffad6d23088db 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
@@ -563,6 +563,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) {
|
||||
+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper
|
||||
Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
index 94ee9c399f59e0198b4d9bc2a4255e8b821bcd36..b1fc786970b5288a02cc3a46e3fe7784ac566c07 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
@@ -49,7 +49,7 @@ public class PhantomSpawner implements CustomSpawner {
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
|
||||
- if (!entityplayer.isSpectator()) {
|
||||
+ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper
|
||||
BlockPos blockposition = entityplayer.blockPosition();
|
||||
|
||||
if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
|
|
@ -1,167 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 25 Apr 2020 06:46:35 -0400
|
||||
Subject: [PATCH] Fix numerous item duplication issues and teleport issues
|
||||
|
||||
This notably fixes the newest "Donkey Dupe", but also fixes a lot
|
||||
of dupe bugs in general around nether portals and entity world transfer
|
||||
|
||||
We also fix item duplication generically by anytime we clone an item
|
||||
to drop it on the ground, destroy the source item.
|
||||
|
||||
This avoid an itemstack ever existing twice in the world state pre
|
||||
clean up stage.
|
||||
|
||||
So even if something NEW comes up, it would be impossible to drop the
|
||||
same item twice because the source was destroyed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index d7cf9ca3a1002463b09ed709f3003d0528a3ff0b..ce4b2ec2ad6138b754ced976521d1c73eb4193a8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2449,11 +2449,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
} else {
|
||||
// CraftBukkit start - Capture drops for death event
|
||||
if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
|
||||
- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack));
|
||||
+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later
|
||||
return null;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack);
|
||||
+ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original
|
||||
+ stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
|
||||
|
||||
entityitem.setDefaultPickUpDelay();
|
||||
// CraftBukkit start
|
||||
@@ -3227,6 +3228,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@Nullable
|
||||
public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
|
||||
// CraftBukkit end
|
||||
+ // Paper start - fix bad state entities causing dupes
|
||||
+ if (!this.isAlive() || !this.valid) {
|
||||
+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable());
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (this.level() instanceof ServerLevel && !this.isRemoved()) {
|
||||
this.level().getProfiler().push("changeDimension");
|
||||
// CraftBukkit start
|
||||
@@ -3253,6 +3260,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit end
|
||||
|
||||
this.level().getProfiler().popPush("reloading");
|
||||
+ // Paper start - Change lead drop timing to prevent dupe
|
||||
+ if (this instanceof Mob) {
|
||||
+ ((Mob) this).dropLeash(true, true); // Paper drop lead
|
||||
+ }
|
||||
+ // Paper end
|
||||
Entity entity = this.getType().create(worldserver);
|
||||
|
||||
if (entity != null) {
|
||||
@@ -3266,10 +3278,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
this.getBukkitEntity().setHandle(entity);
|
||||
entity.bukkitEntity = this.getBukkitEntity();
|
||||
-
|
||||
- if (this instanceof Mob) {
|
||||
- ((Mob) this).dropLeash(true, false); // Unleash to prevent duping of leads.
|
||||
- }
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
@@ -3390,7 +3398,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public boolean canChangeDimensions() {
|
||||
- return !this.isPassenger() && !this.isVehicle();
|
||||
+ return !this.isPassenger() && !this.isVehicle() && isAlive() && valid; // Paper
|
||||
}
|
||||
|
||||
public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 1cae4bcd7d5d310ead65342af063a4617d24c694..3ec6243f831330a8096e209a00e0164dea2ef9d0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1678,9 +1678,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
// Paper start
|
||||
org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource);
|
||||
if (deathEvent == null || !deathEvent.isCancelled()) {
|
||||
- if (this.deathScore >= 0 && entityliving != null) {
|
||||
- entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
- }
|
||||
+ // if (this.deathScore >= 0 && entityliving != null) { // Paper moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent
|
||||
+ // entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
+ // }
|
||||
// Paper start - clear equipment if event is not cancelled
|
||||
if (this instanceof Mob) {
|
||||
for (EquipmentSlot slot : this.clearedEquipmentSlots) {
|
||||
@@ -1781,8 +1781,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.dropCustomDeathLoot(source, i, flag);
|
||||
this.clearEquipmentSlots = prev; // Paper
|
||||
}
|
||||
- // CraftBukkit start - Call death event
|
||||
- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper
|
||||
+ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
|
||||
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops, () -> {
|
||||
+ final LivingEntity entityliving = this.getKillCredit();
|
||||
+ if (this.deathScore >= 0 && entityliving != null) {
|
||||
+ entityliving.awardKillScore(this, this.deathScore, source);
|
||||
+ }
|
||||
+ }); // Paper end
|
||||
this.postDeathDropItems(deathEvent); // Paper
|
||||
this.drops = new ArrayList<>();
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
index a35a0952ce8e1fc42e92734786d531c7e10b34d7..498c6664fcfb028111031691348bfa2eb21d605b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -624,7 +624,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.handItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.handItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.handItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
@@ -632,7 +632,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.armorItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.armorItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.armorItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index ee7a7b80f96712830ea92daefb4454df70def170..81c77354a856956283fc149980a9a09e99b544f5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -866,6 +866,11 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
|
||||
+ // Paper start
|
||||
+ return CraftEventFactory.callEntityDeathEvent(victim, drops, com.google.common.util.concurrent.Runnables.doNothing());
|
||||
+ }
|
||||
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
|
||||
+ // Paper end
|
||||
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
|
||||
EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
|
||||
populateFields(victim, event); // Paper - make cancellable
|
||||
@@ -879,11 +884,13 @@ public class CraftEventFactory {
|
||||
playDeathSound(victim, event);
|
||||
// Paper end
|
||||
victim.expToDrop = event.getDroppedExp();
|
||||
+ lootCheck.run(); // Paper - advancement triggers before destroying items
|
||||
|
||||
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
|
||||
if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
|
||||
|
||||
- world.dropItem(entity.getLocation(), stack);
|
||||
+ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
|
||||
+ if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items
|
||||
}
|
||||
|
||||
return event;
|
Loading…
Add table
Add a link
Reference in a new issue