From dfe57f34c404eaddcf3208b91dcbf21798843ccc Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Tue, 21 Nov 2023 17:08:58 -0300 Subject: [PATCH] Spooky month optimizations The quintessential patch that other performance forks also have for... some reason Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of mobs being spawned --- README.md | 4 + .../0013-Spooky-month-optimizations.patch | 207 ++++++++++++++++++ ...Track-how-much-MSPT-each-world-used.patch} | 4 +- ...atch => 0015-Parallel-world-ticking.patch} | 14 +- 4 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 patches/server/0013-Spooky-month-optimizations.patch rename patches/server/{0013-Track-how-much-MSPT-each-world-used.patch => 0014-Track-how-much-MSPT-each-world-used.patch} (97%) rename patches/server/{0014-Parallel-world-ticking.patch => 0015-Parallel-world-ticking.patch} (99%) diff --git a/README.md b/README.md index 65238fc..a05173e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,10 @@ SparklyPaper's config file is `sparklypaper.yml`, the file is, by default, place * Lazily create `LootContext` for criterions * For each player on each tick, enter block triggers are invoked, and these create loot contexts that are promptly thrown away since the trigger doesn't pass the predicate. * To avoid this, we now lazily create the LootContext if the criterion passes the predicate AND if any of the listener triggers require a loot context instance. +* Spooky month optimizations + * The quintessential patch that other performance forks also have for... some reason??? I thought that this optimization was too funny to not do it in SparklyPaper. + * Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends. The epoch is updated every 90 days. If your server is running for 90+ days straight without restarts, congratulations! + * Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of bats/zombies/skeletons spawning. * Check how much MSPT (milliseconds per tick) each world is using in `/mspt` * Useful to figure out which worlds are lagging your server. ![Per World MSPT](docs/per-world-mspt.png) diff --git a/patches/server/0013-Spooky-month-optimizations.patch b/patches/server/0013-Spooky-month-optimizations.patch new file mode 100644 index 0000000..9b686e3 --- /dev/null +++ b/patches/server/0013-Spooky-month-optimizations.patch @@ -0,0 +1,207 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Tue, 21 Nov 2023 16:50:04 -0300 +Subject: [PATCH] Spooky month optimizations + +The quintessential patch that other performance forks also have for... some reason??? I thought that this optimization was too funny to not do it in SparklyPaper. + +Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends. The epoch is updated every 90 days. If your server is running for 90+ days straight without restarts, congratulations! + +Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of bats/zombies/skeletons spawning. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 25367df06a8a6e8b0b3a56652a5fb1c70a15632d..a154182d4bab167086a644dc3907e0893af5adb6 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -308,6 +308,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { + AtomicReference atomicreference = new AtomicReference(); +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 9a6915a87ae8aa4ffefea575d7a7d5199c800799..7f90783254d4178e02baf6b5b0a60508a4ce2806 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -227,6 +227,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + } + net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this); + // SparklyPaper end ++ // SparklyPaper start - Spooky month optimizations ++ halloweenManager.startHalloweenEpochTask(); ++ halloweenManager.waitUntilEpochHasBeenUpdated(); ++ // SparklyPaper end + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now + io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider + // Paper end +diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +index 5beaa849a250ea005733250ad3edfa8382224667..02060f41c17dd22f27bdbf930ab7580984c5c841 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +@@ -227,7 +227,7 @@ public class Bat extends AmbientCreature { + int i = world.getMaxLocalRawBrightness(pos); + byte b0 = 4; + +- if (Bat.isHalloween()) { ++ if (world.getServer().halloweenManager.isSpookySeason()) { // SparklyPaper - Spooky month optimizations + b0 = 7; + } else if (random.nextBoolean()) { + return false; +@@ -237,6 +237,8 @@ public class Bat extends AmbientCreature { + } + } + ++ // SparklyPaper - Spooky month optimizations ++ /* + private static boolean isHalloween() { + LocalDate localdate = LocalDate.now(); + int i = localdate.get(ChronoField.DAY_OF_MONTH); +@@ -244,6 +246,7 @@ public class Bat extends AmbientCreature { + + return j == 10 && i >= 20 || j == 11 && i <= 3; + } ++ */ + + @Override + protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +index b319021b22c5dceba6199ed27814b2dcf47b8d50..4e7f19215bafc8ff6b06abc08076a154df5307aa 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -162,10 +162,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + LocalDate localdate = LocalDate.now(); +- int i = localdate.get(ChronoField.DAY_OF_MONTH); +- int j = localdate.get(ChronoField.MONTH_OF_YEAR); ++ // SparklyPaper start - Spooky month optimizations ++ // int i = localdate.get(ChronoField.DAY_OF_MONTH); ++ // int j = localdate.get(ChronoField.MONTH_OF_YEAR); + +- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) { ++ if (this.getServer().halloweenManager.isHalloween() /* j == 10 && i == 31 */&& randomsource.nextFloat() < 0.25F) { ++ // SparklyPaper end + this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); + this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +index 5fdad1600cc7a7c22d1d9a58b6b2dda605521b97..852be41caa3434c898ef2b0731e6f864e817c02b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -553,10 +553,11 @@ public class Zombie extends Monster { + + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + LocalDate localdate = LocalDate.now(); +- int i = localdate.get(ChronoField.DAY_OF_MONTH); +- int j = localdate.get(ChronoField.MONTH_OF_YEAR); ++ // SparklyPaper start - Spooky month optimizations ++ // int i = localdate.get(ChronoField.DAY_OF_MONTH); ++ // int j = localdate.get(ChronoField.MONTH_OF_YEAR); + +- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) { ++ if (this.getServer().halloweenManager.isHalloween() /* j == 10 && i == 31 */&& randomsource.nextFloat() < 0.25F) { + this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); + this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; + } +diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt b/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt +new file mode 100644 +index 0000000000000000000000000000000000000000..8dd82e727872c0d6c4d0827ac63d5fecb9218c61 +--- /dev/null ++++ b/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt +@@ -0,0 +1,93 @@ ++package net.sparklypower.sparklypaper ++ ++import com.mojang.logging.LogUtils ++import java.time.LocalDateTime ++import java.time.Month ++import java.time.ZoneOffset ++import java.util.concurrent.* ++ ++class HalloweenManager { ++ companion object { ++ private val LOGGER = LogUtils.getLogger() ++ } ++ private var spookySeasonStartEpoch = 0L ++ private var spookySeasonEndEpoch = 0L ++ private var halloweenStartEpoch = 0L ++ private var halloweenEndEpoch = 0L ++ private var executor = Executors.newSingleThreadScheduledExecutor(object: ThreadFactory { ++ override fun newThread(p0: Runnable): Thread { ++ val thread = Thread(p0) ++ thread.name = "halloween-timer-updater" ++ thread.priority = 1 // Minimum priority ++ return thread ++ } ++ }) ++ private var latch = CountDownLatch(1) ++ ++ fun startHalloweenEpochTask() { ++ var isFirst = true ++ executor.scheduleAtFixedRate({ ++ updateEpoch() ++ if (isFirst) ++ latch.countDown() ++ isFirst = false ++ }, 0L, 90L, TimeUnit.DAYS) // Every 90 days ++ } ++ ++ fun waitUntilEpochHasBeenUpdated() { ++ latch.await() ++ } ++ ++ fun updateEpoch() { ++ LOGGER.info("Updating Spooky Season and Halloween Time") ++ this.spookySeasonStartEpoch = getEpochMillisAtDate(20, Month.OCTOBER, false) ++ this.spookySeasonEndEpoch = getEpochMillisAtDate(3, Month.NOVEMBER, true) ++ this.halloweenStartEpoch = getEpochMillisAtDate(31, Month.OCTOBER, false) ++ this.halloweenEndEpoch = getEpochMillisAtDate(31, Month.OCTOBER, true) ++ LOGGER.info("Updated Spooky Season and Halloween Time!") ++ } ++ ++ fun isSpookySeason() = System.currentTimeMillis() in spookySeasonStartEpoch until spookySeasonEndEpoch ++ fun isHalloween() = System.currentTimeMillis() in halloweenStartEpoch until halloweenEndEpoch ++ ++ private fun getEpochMillisAtDate(dayOfMonth: Int, month: Month, isEnd: Boolean): Long { ++ // Get the current year ++ val currentYear = LocalDateTime.now().year ++ ++ // Define the target date (20/10/CurrentYear at midnight) ++ val targetDate = LocalDateTime.of( ++ currentYear, ++ month, ++ dayOfMonth, ++ if (isEnd) ++ 23 ++ else ++ 0, ++ if (isEnd) ++ 59 ++ else ++ 0, ++ if (isEnd) ++ 59 ++ else ++ 0, ++ if (isEnd) ++ 999_999_999 ++ else ++ 0, ++ ) ++ ++ // Check if the target date is in the past ++ val now = LocalDateTime.now() ++ val adjustedDate = if (now.isAfter(targetDate)) { ++ // If in the past, adjust to the same date in the next year ++ targetDate.plusYears(1) ++ } else { ++ // If in the future or today, use the original target date ++ targetDate ++ } ++ ++ // Convert the adjusted date to epoch time in milliseconds ++ return adjustedDate.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli() ++ } ++} +\ No newline at end of file diff --git a/patches/server/0013-Track-how-much-MSPT-each-world-used.patch b/patches/server/0014-Track-how-much-MSPT-each-world-used.patch similarity index 97% rename from patches/server/0013-Track-how-much-MSPT-each-world-used.patch rename to patches/server/0014-Track-how-much-MSPT-each-world-used.patch index cd0fa83..f1fda73 100644 --- a/patches/server/0013-Track-how-much-MSPT-each-world-used.patch +++ b/patches/server/0014-Track-how-much-MSPT-each-world-used.patch @@ -56,10 +56,10 @@ index 8b5293b0c696ef21d0101493ffa41b60bf0bc86b..601198a33adb29316b0617d5390d1620 } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 25367df06a8a6e8b0b3a56652a5fb1c70a15632d..a308b52c26c2bb1bfee9f50e03480676b53e602f 100644 +index a154182d4bab167086a644dc3907e0893af5adb6..4bdd8e58c7ad86b8ed839a5293e0b7442c05ad05 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1545,7 +1545,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); -@@ -1523,63 +1527,124 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop