From 2053af2fa33dc8104d6bd1ad6978a77535519a90 Mon Sep 17 00:00:00 2001 From: Riley Park Date: Wed, 15 Aug 2018 01:26:51 -0700 Subject: [PATCH 1/4] Allow disabling armour stand ticking --- ...Allow-disabling-armour-stand-ticking.patch | 33 +++++++++ ...Allow-disabling-armour-stand-ticking.patch | 71 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 Spigot-API-Patches/Allow-disabling-armour-stand-ticking.patch create mode 100644 Spigot-Server-Patches/Allow-disabling-armour-stand-ticking.patch diff --git a/Spigot-API-Patches/Allow-disabling-armour-stand-ticking.patch b/Spigot-API-Patches/Allow-disabling-armour-stand-ticking.patch new file mode 100644 index 000000000..67092293d --- /dev/null +++ b/Spigot-API-Patches/Allow-disabling-armour-stand-ticking.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Riley Park +Date: Wed, 15 Aug 2018 01:26:03 -0700 +Subject: [PATCH] Allow disabling armour stand ticking + + +diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java +index 099da6ce..859f166f 100644 +--- a/src/main/java/org/bukkit/entity/ArmorStand.java ++++ b/src/main/java/org/bukkit/entity/ArmorStand.java +@@ -0,0 +0,0 @@ public interface ArmorStand extends LivingEntity { + * @param move {@code true} if this armour stand can move, {@code false} otherwise + */ + void setCanMove(boolean move); ++ ++ /** ++ * Tests if this armor stand can tick. ++ * ++ *

The default value is defined in {@code paper.yml}.

++ * ++ * @return {@code true} if this armour stand can tick, {@code false} otherwise ++ */ ++ boolean canTick(); ++ ++ /** ++ * Sets if this armor stand can tick. ++ * ++ * @param tick {@code true} if this armour stand can tick, {@code false} otherwise ++ */ ++ void setCanTick(final boolean tick); + // Paper end + } +-- \ No newline at end of file diff --git a/Spigot-Server-Patches/Allow-disabling-armour-stand-ticking.patch b/Spigot-Server-Patches/Allow-disabling-armour-stand-ticking.patch new file mode 100644 index 000000000..effe2c23b --- /dev/null +++ b/Spigot-Server-Patches/Allow-disabling-armour-stand-ticking.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Riley Park +Date: Wed, 15 Aug 2018 01:26:09 -0700 +Subject: [PATCH] Allow disabling armour stand ticking + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index c3bd82692..ed1475351 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ public class PaperWorldConfig { + break; + } + } ++ ++ public boolean armorStandTick = true; ++ private void armorStandTick() { ++ this.armorStandTick = this.getBoolean("armor-stands-tick", this.armorStandTick); ++ log("ArmorStand ticking is " + (this.armorStandTick ? "enabled" : "disabled") + " by default"); ++ } + } +diff --git a/src/main/java/net/minecraft/server/EntityArmorStand.java b/src/main/java/net/minecraft/server/EntityArmorStand.java +index df0d66ad0..dca497072 100644 +--- a/src/main/java/net/minecraft/server/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/server/EntityArmorStand.java +@@ -0,0 +0,0 @@ public class EntityArmorStand extends EntityLiving { + public Vector3f leftLegPose; + public Vector3f rightLegPose; + public boolean canMove = true; // Paper ++ public boolean canTick = true; // Paper - armour stand ticking + + public EntityArmorStand(World world) { + super(world); +@@ -0,0 +0,0 @@ public class EntityArmorStand extends EntityLiving { + this.rightLegPose = EntityArmorStand.bw; + this.noclip = this.isNoGravity(); + this.setSize(0.5F, 1.975F); ++ if (world != null) this.canTick = world.paperConfig.armorStandTick; // Paper - armour stand ticking + } + + public EntityArmorStand(World world, double d0, double d1, double d2) { +@@ -0,0 +0,0 @@ public class EntityArmorStand extends EntityLiving { + } + + public void B_() { ++ if (!this.canTick) return;// Paper + super.B_(); + Vector3f vector3f = (Vector3f) this.datawatcher.get(EntityArmorStand.b); + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java +index 8a06cb165..91b7bc2ed 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java +@@ -0,0 +0,0 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand { + public void setCanMove(boolean move) { + getHandle().canMove = move; + } ++ ++ // Paper start ++ @Override ++ public boolean canTick() { ++ return this.getHandle().canTick; ++ } ++ ++ @Override ++ public void setCanTick(final boolean tick) { ++ this.getHandle().canTick = tick; ++ } ++ // Paper end + } +-- \ No newline at end of file From 29da1d351dec49d405c70a2df34c1669ac635293 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 12 Aug 2018 13:27:23 -0400 Subject: [PATCH 2/4] Improve Watchdog Early Warning Feature - Closes #1319 1) Don't kick in until server has started (the full crash will still kick in before full start) 2) Delay reporting until 10 seconds, then print every 5 3) Make the intervals configurable 4) Make it able to be disabled by setting every interval to <= 0 --- ...Add-5-second-short-dumps-to-watchdog.patch | 85 --------- ...dd-Early-Warning-Feature-to-WatchDog.patch | 164 ++++++++++++++++++ 2 files changed, 164 insertions(+), 85 deletions(-) delete mode 100644 Spigot-Server-Patches/Add-5-second-short-dumps-to-watchdog.patch create mode 100644 Spigot-Server-Patches/Add-Early-Warning-Feature-to-WatchDog.patch diff --git a/Spigot-Server-Patches/Add-5-second-short-dumps-to-watchdog.patch b/Spigot-Server-Patches/Add-5-second-short-dumps-to-watchdog.patch deleted file mode 100644 index 44147244e..000000000 --- a/Spigot-Server-Patches/Add-5-second-short-dumps-to-watchdog.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: miclebrick -Date: Wed, 8 Aug 2018 15:30:52 -0400 -Subject: [PATCH] Add 5 second short dumps to watchdog - - -diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index 57a4748a3..815c3e664 100644 ---- a/src/main/java/org/spigotmc/WatchdogThread.java -+++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread - - private static WatchdogThread instance; - private final long timeoutTime; -+ private final long shortTimeout; // Paper - Timeout time for just printing a dump but not restarting - private final boolean restart; - private volatile long lastTick; -+ private long lastShortDump; // Paper - Keep track of short dump times to avoid spamming console with short dumps - private volatile boolean stopping; - - private WatchdogThread(long timeoutTime, boolean restart) -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread - super( "Paper Watchdog Thread" ); - this.timeoutTime = timeoutTime; - this.restart = restart; -+ shortTimeout = Math.min(5000, timeoutTime); // Paper - Make short timeout the lower of 5 seconds, and timeout time - } - - public static void doStart(int timeoutTime, boolean restart) -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread - while ( !stopping ) - { - // -- if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable -+ long currentTime = System.currentTimeMillis(); // Paper - do we REALLY need to call this method multiple times? -+ if ( lastTick != 0 && currentTime > lastTick + shortTimeout && !Boolean.getBoolean("disable.watchdog") ) // Paper - Add property to disable and short timeout - { -+ // Paper start -+ boolean isLongTimeout = currentTime > lastTick + timeoutTime; -+ // Don't spam short dumps -+ if ( !isLongTimeout && currentTime < lastShortDump + shortTimeout ) continue; -+ lastShortDump = currentTime; -+ // Paper end - Logger log = Bukkit.getServer().getLogger(); -+ // Paper start - Different message when it's a short timeout -+ if ( isLongTimeout ) -+ { - log.log( Level.SEVERE, "The server has stopped responding!" ); - log.log( Level.SEVERE, "Please report this to https://github.com/PaperMC/Paper/issues" ); - log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" ); -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread - } - } - // Paper end -+ } else -+ { -+ log.log( Level.SEVERE, "The server has not responded for " + shortTimeout / 1000 + " seconds! Creating thread dump"); -+ } -+ // Paper end - Different message for short timeout - log.log( Level.SEVERE, "------------------------------" ); - log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); - dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE ), log ); - log.log( Level.SEVERE, "------------------------------" ); - // -+ // Paper start - Only print full dump on long timeouts -+ if ( isLongTimeout ) -+ { - log.log( Level.SEVERE, "Entire Thread Dump:" ); - ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true ); - for ( ThreadInfo thread : threads ) -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread - RestartCommand.restart(); - } - break; -+ } // Paper end - } - - try - { -- sleep( 10000 ); -+ sleep( 1000 ); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout - } catch ( InterruptedException ex ) - { - interrupt(); --- \ No newline at end of file diff --git a/Spigot-Server-Patches/Add-Early-Warning-Feature-to-WatchDog.patch b/Spigot-Server-Patches/Add-Early-Warning-Feature-to-WatchDog.patch new file mode 100644 index 000000000..d4ac52185 --- /dev/null +++ b/Spigot-Server-Patches/Add-Early-Warning-Feature-to-WatchDog.patch @@ -0,0 +1,164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: miclebrick +Date: Wed, 8 Aug 2018 15:30:52 -0400 +Subject: [PATCH] Add Early Warning Feature to WatchDog + +Detect when the server has been hung for a long duration, and start printing +thread dumps at an interval until the point of crash. + +This will help diagnose what was going on in that time before the crash. + +diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +index a5ff014e33..332e90f86b 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java +@@ -0,0 +0,0 @@ import org.bukkit.configuration.InvalidConfigurationException; + import org.bukkit.configuration.file.YamlConfiguration; + import co.aikar.timings.Timings; + import co.aikar.timings.TimingsManager; ++import org.spigotmc.SpigotConfig; ++import org.spigotmc.WatchdogThread; + + public class PaperConfig { + +@@ -0,0 +0,0 @@ public class PaperConfig { + } + } + ++ public static int watchdogPrintEarlyWarningEvery = 5000; ++ public static int watchdogPrintEarlyWarningDelay = 10000; ++ private static void watchdogEarlyWarning() { ++ watchdogPrintEarlyWarningEvery = getInt("settings.watchdog.early-warning-every", 5000); ++ watchdogPrintEarlyWarningDelay = getInt("settings.watchdog.early-warning-delay", 10000); ++ WatchdogThread.doStart(SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash ); ++ } ++ + public static int tabSpamIncrement = 10; + public static int tabSpamLimit = 500; + private static void tabSpamLimiters() { +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 0399a48e19..e0546e3dd2 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs + this.a(this.q); + + // Spigot start ++ org.spigotmc.WatchdogThread.hasStarted = true; + Arrays.fill( recentTps, 20 ); + long start = System.nanoTime(), lastTick = start - TICK_TIME, catchupTime = 0, curTime, wait, tickSection = start; // Paper - Further improve server tick loop + while (this.isRunning) { +diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java +index 4f9fd4bc60..2cdd9aaf81 100644 +--- a/src/main/java/org/spigotmc/SpigotConfig.java ++++ b/src/main/java/org/spigotmc/SpigotConfig.java +@@ -0,0 +0,0 @@ public class SpigotConfig + restartScript = getString( "settings.restart-script", restartScript ); + restartMessage = transform( getString( "messages.restart", "Server is restarting" ) ); + commands.put( "restart", new RestartCommand( "restart" ) ); +- WatchdogThread.doStart( timeoutTime, restartOnCrash ); ++ //WatchdogThread.doStart( timeoutTime, restartOnCrash ); // Paper - moved to PaperConfig + } + + public static boolean bungee; +diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java +index 57a4748a30..28a9e2b96f 100644 +--- a/src/main/java/org/spigotmc/WatchdogThread.java ++++ b/src/main/java/org/spigotmc/WatchdogThread.java +@@ -0,0 +0,0 @@ import java.lang.management.MonitorInfo; + import java.lang.management.ThreadInfo; + import java.util.logging.Level; + import java.util.logging.Logger; ++import com.destroystokyo.paper.PaperConfig; + import net.minecraft.server.MinecraftServer; + import org.bukkit.Bukkit; + +@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread + + private static WatchdogThread instance; + private final long timeoutTime; ++ private final long earlyWarningEvery; // Paper - Timeout time for just printing a dump but not restarting ++ private final long earlyWarningDelay; // Paper ++ public static volatile boolean hasStarted; // Paper ++ private long lastEarlyWarning; // Paper - Keep track of short dump times to avoid spamming console with short dumps + private final boolean restart; + private volatile long lastTick; + private volatile boolean stopping; +@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread + super( "Paper Watchdog Thread" ); + this.timeoutTime = timeoutTime; + this.restart = restart; ++ earlyWarningEvery = Math.min(PaperConfig.watchdogPrintEarlyWarningEvery, timeoutTime); // Paper ++ earlyWarningDelay = Math.min(PaperConfig.watchdogPrintEarlyWarningDelay, timeoutTime); // Paper + } + + public static void doStart(int timeoutTime, boolean restart) +@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread + while ( !stopping ) + { + // +- if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable ++ long currentTime = System.currentTimeMillis(); // Paper - do we REALLY need to call this method multiple times? ++ if ( lastTick != 0 && currentTime > lastTick + earlyWarningEvery && !Boolean.getBoolean("disable.watchdog") ) // Paper - Add property to disable and short timeout + { ++ // Paper start ++ boolean isLongTimeout = currentTime > lastTick + timeoutTime; ++ // Don't spam early warning dumps ++ if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue; ++ lastEarlyWarning = currentTime; ++ // Paper end + Logger log = Bukkit.getServer().getLogger(); ++ // Paper start - Different message when it's a short timeout ++ if ( isLongTimeout ) ++ { + log.log( Level.SEVERE, "The server has stopped responding!" ); + log.log( Level.SEVERE, "Please report this to https://github.com/PaperMC/Paper/issues" ); + log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" ); +@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread + } + } + // Paper end ++ } else ++ { ++ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---"); ++ log.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump"); ++ } ++ // Paper end - Different message for short timeout + log.log( Level.SEVERE, "------------------------------" ); + log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); + dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE ), log ); + log.log( Level.SEVERE, "------------------------------" ); + // ++ // Paper start - Only print full dump on long timeouts ++ if ( isLongTimeout ) ++ { + log.log( Level.SEVERE, "Entire Thread Dump:" ); + ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true ); + for ( ThreadInfo thread : threads ) + { + dumpThread( thread, log ); + } ++ } else { ++ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---"); ++ } ++ ++ + log.log( Level.SEVERE, "------------------------------" ); + + if ( restart ) + { + RestartCommand.restart(); + } ++ if (isLongTimeout) { + break; ++ } // Paper end + } + + try + { +- sleep( 10000 ); ++ sleep( 1000 ); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout + } catch ( InterruptedException ex ) + { + interrupt(); +-- \ No newline at end of file From 0661cf198ee1e7bf46b3112f7b744e28d9d77715 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 16 Aug 2018 17:46:38 -0400 Subject: [PATCH 3/4] Ensure chunks are always loaded on hard position sets Player Movement, Entity Creation and Teleportation move entities with a very "You are here, no debate" change, making the server register them as there, regardless if that chunk was loaded or not. It appears possible that with hack clients and lag, a player may be able to move fast enough to move into an unloaded chunk and get into a buggy state. To prevent this, we will ensure a chunk is always loaded, guaranteeing that the entity will be properly registered into its new home comfortably. Closes #1316 --- ...e-always-loaded-on-hard-position-set.patch | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch diff --git a/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch b/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch new file mode 100644 index 000000000..8ed6531ed --- /dev/null +++ b/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 16 Aug 2018 17:36:41 -0400 +Subject: [PATCH] Ensure chunks are always loaded on hard position sets + +Player Movement, Entity Creation and Teleportation move +entities with a very "You are here, no debate" change, making +the server register them as there, regardless if that chunk was +loaded or not. + +It appears possible that with hack clients and lag, a player +may be able to move fast enough to move into an unloaded +chunk and get into a buggy state. + +To prevent this, we will ensure a chunk is always loaded, +guaranteeing that the entity will be properly registered +into its new home comfortably. + +diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java +index 9b5f7fcf72..3c279d3fe8 100644 +--- a/src/main/java/net/minecraft/server/Entity.java ++++ b/src/main/java/net/minecraft/server/Entity.java +@@ -0,0 +0,0 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper + this.lastYaw -= 360.0F; + } + ++ world.getChunkAt((int) Math.floor(this.locX), (int) Math.floor(this.locZ)); // Paper - ensure chunk is always loaded + this.setPosition(this.locX, this.locY, this.locZ); + this.setYawPitch(f, f1); + } +-- \ No newline at end of file From 609d6bba6afd2f4e4156d9aa847ea57819cfcefe Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 16 Aug 2018 17:52:24 -0400 Subject: [PATCH 4/4] Fix bug in last patch --- ...Ensure-chunks-are-always-loaded-on-hard-position-set.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch b/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch index 8ed6531ed..f8c5e9bcf 100644 --- a/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch +++ b/Spigot-Server-Patches/Ensure-chunks-are-always-loaded-on-hard-position-set.patch @@ -17,14 +17,14 @@ guaranteeing that the entity will be properly registered into its new home comfortably. diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index 9b5f7fcf72..3c279d3fe8 100644 +index 9b5f7fcf72..48c9fbd9b3 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -0,0 +0,0 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper this.lastYaw -= 360.0F; } -+ world.getChunkAt((int) Math.floor(this.locX), (int) Math.floor(this.locZ)); // Paper - ensure chunk is always loaded ++ world.getChunkAt((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4); // Paper - ensure chunk is always loaded this.setPosition(this.locX, this.locY, this.locZ); this.setYawPitch(f, f1); }