From aa295c78bc0181027c97528fd8ebbe46e340a7f6 Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Mon, 23 Oct 2023 00:33:25 -0300 Subject: [PATCH] Update upstream, add new cherry-picked patches from other forks --- BORKED_PATCHES.md | 16 +++ README.md | 11 +- gradle.properties | 2 +- ...ve-iterators-from-inventory-contains.patch | 38 +++++++ ...reams-and-iterators-from-range-check.patch | 49 +++++++++ ...-an-iterator-in-getEffectiveRange-if.patch | 20 ---- ...pelessRecipes-comparison-for-Vanilla.patch | 84 +++++++++++++++ ...check-for-spooky-season-once-an-hour.patch | 49 +++++++++ ...ve-ThreadUnsafeRandom-Initialization.patch | 35 ++++++ ...hread-unsafe-random-for-mob-spawning.patch | 40 +++++++ ...timize-random-calls-in-chunk-ticking.patch | 101 ++++++++++++++++++ .../0010-Reduce-chunk-loading-lookups.patch | 45 ++++++++ ...turn-optimization-for-target-finding.patch | 31 ++++++ .../0012-Optimize-entity-coordinate-key.patch | 38 +++++++ ...013-Remove-lambda-from-ticking-guard.patch | 52 +++++++++ .../0014-Reduce-entity-allocations.patch | 36 +++++++ ...-Land-moisture-tick-rate-when-the-b.patch} | 0 ...ring-once-per-world-instead-for-eve.patch} | 8 +- 18 files changed, 629 insertions(+), 26 deletions(-) create mode 100644 BORKED_PATCHES.md create mode 100644 patches/server/0003-Remove-iterators-from-inventory-contains.patch create mode 100644 patches/server/0004-Remove-streams-and-iterators-from-range-check.patch delete mode 100644 patches/server/0005-Avoid-allocating-an-iterator-in-getEffectiveRange-if.patch create mode 100644 patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch create mode 100644 patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch create mode 100644 patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch create mode 100644 patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch create mode 100644 patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch create mode 100644 patches/server/0010-Reduce-chunk-loading-lookups.patch create mode 100644 patches/server/0011-Early-return-optimization-for-target-finding.patch create mode 100644 patches/server/0012-Optimize-entity-coordinate-key.patch create mode 100644 patches/server/0013-Remove-lambda-from-ticking-guard.patch create mode 100644 patches/server/0014-Reduce-entity-allocations.patch rename patches/server/{0003-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch => 0015-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch} (100%) rename patches/server/{0004-Only-check-thundering-once-per-world-instead-for-eve.patch => 0016-Only-check-thundering-once-per-world-instead-for-eve.patch} (88%) diff --git a/BORKED_PATCHES.md b/BORKED_PATCHES.md new file mode 100644 index 0000000..7cb947f --- /dev/null +++ b/BORKED_PATCHES.md @@ -0,0 +1,16 @@ +# Borked Patches + +List of *maybe* borked and *maybe* useless patches that I found in other fork's that may be borked or not do anything useful, so I annoted them here to remember about why I didn't cherry-pick them to SparklyPaper. + +Keep in mind that I'm very naive when it comes to Minecraft Server internals, so I may be wrong! + +## (Pufferfish) `Reduce-entity-allocations` + +While not useless, the patch adds a `cachedBlockPos` variable that is never used by any other patch. Heck, not even in Airplane it was used! +## (Pufferfish) `Skip-cloning-loot-parameters` + +Unnnecessarily wraps `parameters` and `dynamicDrops` into a unmodifiable map, causing unnecessary allocations. + +This was useful back in 1.17 days, where the patch DID bring a meaningful benefit, since vanilla used `ImmutableMap.copyOf` instead. + +As a reference, here's Airplane's original patch: https://github.com/TECHNOVE/Airplane/blob/af3563c98bdd8b27123e3a656de261ed96652b3e/patches/server/0030-Skip-cloning-loot-parameters.patch#L21 \ No newline at end of file diff --git a/README.md b/README.md index 0f23a70..b762812 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,13 @@

✨ SparklyPaper ✨

-SparklyPower's Paper fork, with a mix of weird & crazy patches from other forks! \ No newline at end of file +SparklyPower's Paper fork, with a mix of weird & crazy patches from other forks! + +While our fork is mostly cherry-picked patches from other forks, we do have some handmade patches too to add and optimize some of the things that we have in our server! + +* Configurable Farm Land moisture tick rate when the block is already moisturised + * The isNearWater check is costly, especially if you have a lot of farm lands. If the block is already moistured, we can change the tick rate of it to avoid these expensive isNearWater checks. +* Only check thundering once per world instead for every chunk + * For some reason the isThundering check is consuming ~3% of CPU time when profiled so, instead of checking the thunder every chunk, we can cache the result and reuse on the same chunk tick. + +We don't cherry-pick *everything* from other forks, only patches that I can see and think "yeah, I can see how this would improve performance" or patches that target specific performance/feature pain points in our server are cherry-picked! In fact, some patches that are used in other forks [may be actually borked](BORKED_PATCHES.md)... \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 16203b0..95dce08 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group=net.sparklypower.sparklypaper version=1.20.2-R0.1-SNAPSHOT mcVersion=1.20.2 -paperRef=3a5c6f8cee7e1379fff1908e87af9fd5448eda0e +paperRef=90fe0d58a5945c31f2c1b138799f64f2fe3475d8 org.gradle.caching=true org.gradle.parallel=true diff --git a/patches/server/0003-Remove-iterators-from-inventory-contains.patch b/patches/server/0003-Remove-iterators-from-inventory-contains.patch new file mode 100644 index 0000000..549002f --- /dev/null +++ b/patches/server/0003-Remove-iterators-from-inventory-contains.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Sat, 13 Mar 2021 12:24:41 -0600 +Subject: [PATCH] Remove iterators from inventory contains + + +diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java +index 96d664c28738d6090f7067761c2978dd1aa0fd0e..b1c24a02b87aca7b180a6efbce177f2300db49c1 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java ++++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java +@@ -687,6 +687,8 @@ public class Inventory implements Container, Nameable { + } + + public boolean contains(ItemStack stack) { ++ // Pufferfish start - don't allocate iterators ++ /* + Iterator iterator = this.compartments.iterator(); + + while (iterator.hasNext()) { +@@ -701,6 +703,18 @@ public class Inventory implements Container, Nameable { + } + } + } ++ */ ++ for (int i = 0; i < this.compartments.size(); i++) { ++ List list = this.compartments.get(i); ++ for (int j = 0; j < list.size(); j++) { ++ ItemStack itemstack1 = list.get(j); ++ ++ if (!itemstack1.isEmpty() && ItemStack.isSameItemSameTags(itemstack1, stack)) { ++ return true; ++ } ++ } ++ } ++ // Pufferfish end + + return false; + } diff --git a/patches/server/0004-Remove-streams-and-iterators-from-range-check.patch b/patches/server/0004-Remove-streams-and-iterators-from-range-check.patch new file mode 100644 index 0000000..daa3120 --- /dev/null +++ b/patches/server/0004-Remove-streams-and-iterators-from-range-check.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Tue, 22 Jun 2021 15:08:21 -0500 +Subject: [PATCH] Remove streams and iterators from range check + + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 28c6ec04750daca3d77a0cee2b9f17f2508662cc..219393390fcef956b0694ff597436249901b3e17 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1330,8 +1330,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + return ChunkMap.this.level.getServer().getScaledTrackingDistance(initialDistance); + } + ++ private static int getHighestRange(Entity parent, int highest) { ++ List passengers = parent.getPassengers(); ++ ++ for (int i = 0, size = passengers.size(); i < size; i++) { ++ Entity entity = passengers.get(i); ++ int range = entity.getType().clientTrackingRange() * 16; ++ range = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, range); // Paper ++ ++ if (range > highest) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic // Tuinity - not anymore! ++ highest = range; ++ } ++ ++ highest = getHighestRange(entity, highest); ++ } ++ ++ return highest; ++ } ++ + private int getEffectiveRange() { + int i = this.range; ++ // Pufferfish start - remove iterators and streams ++ /* + Iterator iterator = this.entity.getIndirectPassengers().iterator(); + + while (iterator.hasNext()) { +@@ -1343,6 +1363,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + i = j; + } + } ++ */ ++ i = getHighestRange(this.entity, i); ++ // Pufferfish end + + return this.scaledRange(i); + } diff --git a/patches/server/0005-Avoid-allocating-an-iterator-in-getEffectiveRange-if.patch b/patches/server/0005-Avoid-allocating-an-iterator-in-getEffectiveRange-if.patch deleted file mode 100644 index f07fb3f..0000000 --- a/patches/server/0005-Avoid-allocating-an-iterator-in-getEffectiveRange-if.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrPowerGamerBR -Date: Sun, 22 Oct 2023 12:47:38 -0300 -Subject: [PATCH] Avoid allocating an iterator in getEffectiveRange if the - entity does not have any passengers - - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 28c6ec04750daca3d77a0cee2b9f17f2508662cc..841e2458548aa7ba3e29e693161f31f17344dfbe 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1332,6 +1332,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - private int getEffectiveRange() { - int i = this.range; -+ if (this.entity.passengers.isEmpty()) return this.scaledRange(i); // SparklyPaper - Avoid allocating an iterator if the entity does not have any passengers -+ - Iterator iterator = this.entity.getIndirectPassengers().iterator(); - - while (iterator.hasNext()) { diff --git a/patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch b/patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch new file mode 100644 index 0000000..e37786b --- /dev/null +++ b/patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Sat, 31 Oct 2020 18:51:38 -0500 +Subject: [PATCH] Simpler ShapelessRecipes comparison for Vanilla + +Paper added a fancy sorting comparison due to Bukkit recipes breaking +the vanilla one, however this is far more advanced than what you need +for all the vanilla recipes. + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java +index 38f7d1ece27ec1a3deda21fb6a6f0e788c8ed718..252fc22844682c0f67dc02a87478e01e49b6430d 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java ++++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java +@@ -26,8 +26,13 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo + final CraftingBookCategory category; + final ItemStack result; + final NonNullList ingredients; ++ private final boolean isBukkit; // Pufferfish + ++ // Pufferfish start + public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients) { ++ this(group, category, result, ingredients, false); ++ } ++ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients, boolean isBukkit) { this.isBukkit = isBukkit; // Pufferfish end + this.group = group; + this.category = category; + this.result = result; +@@ -77,6 +82,28 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo + } + + public boolean matches(CraftingContainer inventory, Level world) { ++ // Pufferfish start ++ if (!this.isBukkit) { ++ java.util.List ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0])); ++ ++ inventory: for (int index = 0; index < inventory.getContainerSize(); index++) { ++ ItemStack itemStack = inventory.getItem(index); ++ ++ if (!itemStack.isEmpty()) { ++ for (int i = 0; i < ingredients.size(); i++) { ++ if (ingredients.get(i).test(itemStack)) { ++ ingredients.remove(i); ++ continue inventory; ++ } ++ } ++ return false; ++ } ++ } ++ ++ return ingredients.isEmpty(); ++ } ++ // Pufferfish end ++ + StackedContents autorecipestackmanager = new StackedContents(); + autorecipestackmanager.initialize(this); // Paper - better exact choice recipes + int i = 0; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +index acfe2676b840d4edc70507aa139f7db212ed90b7..ef89684b5e8ab20744ba02a71fe0465d197f627d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +@@ -45,6 +45,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe + data.set(i, toNMS(ingred.get(i), true)); + } + +- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); ++ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data, true))); // Pufferfish + } + } diff --git a/patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch b/patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch new file mode 100644 index 0000000..3b59c7a --- /dev/null +++ b/patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Sun, 13 Dec 2020 17:53:08 -0600 +Subject: [PATCH] Only check for spooky season once an hour + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +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..2c91fe46355c9a201507de5577f693ed4f5fb974 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +@@ -237,13 +237,22 @@ public class Bat extends AmbientCreature { + } + } + ++ // Pufferfish start - only check for spooky season once an hour ++ private static boolean isSpookySeason = false; ++ private static final int ONE_HOUR = 20 * 60 * 60; ++ private static int lastSpookyCheck = -ONE_HOUR; + private static boolean isHalloween() { ++ if (net.minecraft.server.MinecraftServer.currentTick - lastSpookyCheck > ONE_HOUR) { + LocalDate localdate = LocalDate.now(); + int i = localdate.get(ChronoField.DAY_OF_MONTH); + int j = localdate.get(ChronoField.MONTH_OF_YEAR); + +- return j == 10 && i >= 20 || j == 11 && i <= 3; ++ isSpookySeason = j == 10 && i >= 20 || j == 11 && i <= 3; ++ lastSpookyCheck = net.minecraft.server.MinecraftServer.currentTick; ++ } ++ return isSpookySeason; + } ++ // Pufferfish end + + @Override + protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { diff --git a/patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch b/patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch new file mode 100644 index 0000000..f661252 --- /dev/null +++ b/patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Raneri +Date: Sun, 12 Jun 2022 22:19:37 -0500 +Subject: [PATCH] Move ThreadUnsafeRandom Initialization + +ThreadUnsafeRandom is initialized too late and some of our patches +require it to be initialized earlier. By moving it to the superclass, we +initialize it earlier, ensuring that it is available sooner. + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 17610196db7a1c6feb2cf74a02479a8691aa323f..715a622a11b295badb0821376fec721f9c6ecaed 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -962,7 +962,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + // Paper start - optimise random block ticking + private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); +- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); ++ // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super + // Paper end + + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index aa9c56fb95d5e438e85aced984631493b84c8556..33b81d637bb5fe2a864f4313ad8796e42a5d2ad8 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -211,6 +211,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + public abstract ResourceKey getTypeKey(); + ++ protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); // Pufferfish - move thread unsafe random initialization ++ + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper diff --git a/patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch b/patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch new file mode 100644 index 0000000..f956509 --- /dev/null +++ b/patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Tue, 22 Jun 2021 15:04:37 -0500 +Subject: [PATCH] Use thread unsafe random for mob spawning + + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 33b81d637bb5fe2a864f4313ad8796e42a5d2ad8..e357223bcaa27a668e7e95cf54e183fed13920aa 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -211,7 +211,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + public abstract ResourceKey getTypeKey(); + +- protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); // Pufferfish - move thread unsafe random initialization ++ protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter + + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot +diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +index 3cdddda9c0618e95288b81b975d499c8dd30c05f..9c2d62feff1816f5729060c6192269a5b2d34153 100644 +--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java ++++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +@@ -429,12 +429,12 @@ public final class NaturalSpawner { + } + } + +- private static BlockPos getRandomPosWithin(Level world, LevelChunk chunk) { ++ private static BlockPos getRandomPosWithin(ServerLevel world, LevelChunk chunk) { // Pufferfish - accept serverlevel + ChunkPos chunkcoordintpair = chunk.getPos(); +- int i = chunkcoordintpair.getMinBlockX() + world.random.nextInt(16); +- int j = chunkcoordintpair.getMinBlockZ() + world.random.nextInt(16); ++ int i = chunkcoordintpair.getMinBlockX() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish - use thread unsafe random ++ int j = chunkcoordintpair.getMinBlockZ() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish + int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; +- int l = Mth.randomBetweenInclusive(world.random, world.getMinBuildHeight(), k); ++ int l = Mth.randomBetweenInclusive(world.getThreadUnsafeRandom(), world.getMinBuildHeight(), k); // Pufferfish + + return new BlockPos(i, l, j); + } diff --git a/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch b/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch new file mode 100644 index 0000000..155c557 --- /dev/null +++ b/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 7 Jan 2021 11:49:36 -0600 +Subject: [PATCH] Optimize random calls in chunk ticking + +Especially at over 30,000 chunks these random calls are fairly heavy. We +use a different method here for checking lightning, and for checking +ice. + +Lightning: Each chunk now keeps an int of how many ticks until the +lightning should strike. This int is a random number from 0 to 100000 * 2, +the multiplication is required to keep the probability the same. + +Ice and snow: We just generate a single random number 0-16 and increment +it, while checking if it's 0 for the current chunk. + +Depending on configuration for things that tick in a chunk, this is a +5-10% improvement. + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 17b6925b46f8386dcfc561483693de516465ec12..c02ffd419236980cd063741612e99d739d97ec94 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -521,6 +521,7 @@ public class ServerChunkCache extends ChunkSource { + ProfilerFiller gameprofilerfiller = this.level.getProfiler(); + + gameprofilerfiller.push("pollingChunks"); ++ this.level.resetIceAndSnowTick(); // Pufferfish - reset ice & snow tick random + int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + boolean flag1 = level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 715a622a11b295badb0821376fec721f9c6ecaed..2192db61ced4434c2c643599b5d2dcc11fcfb45c 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -965,6 +965,8 @@ public class ServerLevel extends Level implements WorldGenLevel { + // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super + // Paper end + ++ private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Pufferfish ++ + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + ChunkPos chunkcoordintpair = chunk.getPos(); + boolean flag = this.isRaining(); +@@ -975,7 +977,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + gameprofilerfiller.push("thunder"); + final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change + +- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder ++ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && /*this.random.nextInt(this.spigotConfig.thunderChance) == 0 &&*/ chunk.shouldDoLightning(this.random)) { // Spigot // Paper - disable thunder // Pufferfish - replace random with shouldDoLightning + blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper + + if (this.isRainingAt(blockposition)) { +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 3e9758fa40bf93fe3d315cc66389193bd57bc393..b78476223637722efe12520d3c2e301603abd8a1 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -86,6 +86,18 @@ public class LevelChunk extends ChunkAccess { + private final LevelChunkTicks fluidTicks; + public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system + ++ // Pufferfish start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively ++ private int lightningTick; ++ // shouldDoLightning compiles down to 29 bytes, which with the default of 35 byte inlining should guarantee an inline ++ public final boolean shouldDoLightning(net.minecraft.util.RandomSource random) { ++ if (this.lightningTick-- <= 0) { ++ this.lightningTick = random.nextInt(this.level.spigotConfig.thunderChance) << 1; ++ return true; ++ } ++ return false; ++ } ++ // Pufferfish end ++ + public LevelChunk(Level world, ChunkPos pos) { + this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null); + } +@@ -109,6 +121,8 @@ public class LevelChunk extends ChunkAccess { + this.postLoad = entityLoader; + this.blockTicks = blockTickScheduler; + this.fluidTicks = fluidTickScheduler; ++ ++ this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; // Pufferfish - initialize lightning tick + } + + // CraftBukkit start diff --git a/patches/server/0010-Reduce-chunk-loading-lookups.patch b/patches/server/0010-Reduce-chunk-loading-lookups.patch new file mode 100644 index 0000000..7c29aad --- /dev/null +++ b/patches/server/0010-Reduce-chunk-loading-lookups.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 4 Feb 2021 23:33:52 -0600 +Subject: [PATCH] Reduce chunk loading & lookups + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +index b0a97679157a18a3c623ce3b2ae315789772c254..9fc3db543a0c9df502df5fb85012c6aa590e887d 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +@@ -333,11 +333,17 @@ public class EnderMan extends Monster implements NeutralMob { + private boolean teleport(double x, double y, double z) { + BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, y, z); + +- while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !this.level().getBlockState(blockposition_mutableblockposition).blocksMotion()) { ++ // Pufferfish start - single chunk lookup ++ net.minecraft.world.level.chunk.LevelChunk chunk = this.level().getChunkIfLoaded(blockposition_mutableblockposition); ++ if (chunk == null) { ++ return false; ++ } ++ // Pufferfish end ++ while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !chunk.getBlockState(blockposition_mutableblockposition).blocksMotion()) { // Pufferfish + blockposition_mutableblockposition.move(Direction.DOWN); + } + +- BlockState iblockdata = this.level().getBlockState(blockposition_mutableblockposition); ++ BlockState iblockdata = chunk.getBlockState(blockposition_mutableblockposition); // Pufferfish + boolean flag = iblockdata.blocksMotion(); + boolean flag1 = iblockdata.getFluidState().is(FluidTags.WATER); + diff --git a/patches/server/0011-Early-return-optimization-for-target-finding.patch b/patches/server/0011-Early-return-optimization-for-target-finding.patch new file mode 100644 index 0000000..548d806 --- /dev/null +++ b/patches/server/0011-Early-return-optimization-for-target-finding.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Sat, 13 Mar 2021 15:05:28 -0600 +Subject: [PATCH] Early return optimization for target finding + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +index c157309ac78e7af084d3acb6e8b2bcd469a39d5e..ac5e5676b194a2a99e5cf53eb89c1152cac963b8 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java ++++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +@@ -75,9 +75,18 @@ public class TargetingConditions { + } + + if (this.range > 0.0D) { +- double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D; +- double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper ++ // Pufferfish start - check range before getting visibility ++ // d = invisibility percent, e = follow range adjusted for invisibility, f = distance + double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); ++ double followRangeRaw = this.useFollowRange ? this.getFollowRange(baseEntity) : this.range; ++ ++ if (f > followRangeRaw * followRangeRaw) { // the actual follow range will always be this value or smaller, so if the distance is larger then it never will return true after getting invis ++ return false; ++ } ++ ++ double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D; ++ double e = Math.max((followRangeRaw) * d, 2.0D); // Paper ++ // Pufferfish end + if (f > e * e) { + return false; + } diff --git a/patches/server/0012-Optimize-entity-coordinate-key.patch b/patches/server/0012-Optimize-entity-coordinate-key.patch new file mode 100644 index 0000000..6c90688 --- /dev/null +++ b/patches/server/0012-Optimize-entity-coordinate-key.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Raneri +Date: Tue, 9 Nov 2021 14:33:16 -0500 +Subject: [PATCH] Optimize entity coordinate key + +When executing getCoordinateKey for entities (a hotpath), the JVM is +required to repeatedly cast doubles to longs. The performance impact of +this depends on the CPU architecture, but generally switching between +FPU and ALU incurs a significant performance hit. The casted/rounded +data is already available in the blockPosition struct, so we use that +instead of re-doing the casting. + +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index d02546b18cb689724887b4e85e8d32a18828a4ad..91eaff58bb422ba188e6cfaa9c20b45bec211edd 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -213,7 +213,7 @@ public final class MCUtil { + } + + public static long getCoordinateKey(final Entity entity) { +- return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); ++ return ((long)(entity.blockPosition.getZ() >> 4) << 32) | ((entity.blockPosition.getX() >> 4) & 0xFFFFFFFFL); // Pufferfish - eliminate double->long cast in hotpath + } + + public static long getCoordinateKey(final ChunkPos pair) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index f20ae9153b7098980ce6c0e75fcbbb4da652661b..4b551df667bb1aeca7ba78a063f7f0e0f1e11c5e 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -305,7 +305,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + public double yo; + public double zo; + private Vec3 position; +- private BlockPos blockPosition; ++ public BlockPos blockPosition; // Pufferfish - private->public + private ChunkPos chunkPosition; + private Vec3 deltaMovement; + private float yRot; diff --git a/patches/server/0013-Remove-lambda-from-ticking-guard.patch b/patches/server/0013-Remove-lambda-from-ticking-guard.patch new file mode 100644 index 0000000..e5caa30 --- /dev/null +++ b/patches/server/0013-Remove-lambda-from-ticking-guard.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul +Date: Fri, 2 Jul 2021 18:27:12 -0500 +Subject: [PATCH] Remove lambda from ticking guard + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 2192db61ced4434c2c643599b5d2dcc11fcfb45c..008a4cd92932024af8ced4e33100570d2ded3552 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -897,7 +897,20 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.push("tick"); +- this.guardEntityTick(this::tickNonPassenger, entity); ++ // Pufferfish start - copied from this.guardEntityTick ++ try { ++ this.tickNonPassenger(entity); // Pufferfish - changed ++ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick ++ } 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); ++ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); ++ entity.discard(); ++ // Paper end ++ } ++ // Pufferfish end + gameprofilerfiller.pop(); + } + } +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index e357223bcaa27a668e7e95cf54e183fed13920aa..9388dd9b34bb8148ce8b5f7e24122fa4bd1bafa8 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -1312,13 +1312,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + try { + tickConsumer.accept(entity); + MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick +- } catch (Throwable throwable) { ++ } catch (Throwable throwable) { // Pufferfish - diff on change ServerLevel.tick + 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); + getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable))); +- entity.discard(); ++ entity.discard(); // Pufferfish - diff on change ServerLevel.tick + // Paper end + } + } diff --git a/patches/server/0014-Reduce-entity-allocations.patch b/patches/server/0014-Reduce-entity-allocations.patch new file mode 100644 index 0000000..4108ecd --- /dev/null +++ b/patches/server/0014-Reduce-entity-allocations.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul +Date: Fri, 2 Jul 2021 18:25:18 -0500 +Subject: [PATCH] Reduce entity allocations + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +index 7204b973c3ad9239e82355513f6d538107102e48..3087f8359b098682a345399c85395de8a15b6eed 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +@@ -23,9 +23,11 @@ public class AttributeMap { + private final Map attributes = Maps.newHashMap(); + private final Set dirtyAttributes = Sets.newHashSet(); + private final AttributeSupplier supplier; ++ private final java.util.function.Function createInstance; // Pufferfish + + public AttributeMap(AttributeSupplier defaultAttributes) { + this.supplier = defaultAttributes; ++ this.createInstance = attribute -> this.supplier.createInstance(this::onAttributeModified, attribute); // Pufferfish + } + + private void onAttributeModified(AttributeInstance instance) { +@@ -45,11 +47,10 @@ public class AttributeMap { + }).collect(Collectors.toList()); + } + ++ + @Nullable + public AttributeInstance getInstance(Attribute attribute) { +- return this.attributes.computeIfAbsent(attribute, (attributex) -> { +- return this.supplier.createInstance(this::onAttributeModified, attributex); +- }); ++ return this.attributes.computeIfAbsent(attribute, this.createInstance); // Pufferfish - cache lambda, as for some reason java allocates it anyways + } + + @Nullable diff --git a/patches/server/0003-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch b/patches/server/0015-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch similarity index 100% rename from patches/server/0003-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch rename to patches/server/0015-Configurable-Farm-Land-moisture-tick-rate-when-the-b.patch diff --git a/patches/server/0004-Only-check-thundering-once-per-world-instead-for-eve.patch b/patches/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch similarity index 88% rename from patches/server/0004-Only-check-thundering-once-per-world-instead-for-eve.patch rename to patches/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch index 9e5edb6..de6fada 100644 --- a/patches/server/0004-Only-check-thundering-once-per-world-instead-for-eve.patch +++ b/patches/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Only check thundering once per world instead for every chunk For some reason the isThundering check is consuming ~3% of CPU time when profiled so, instead of checking the thunder every chunk, we can cache the result and reuse on the same chunk tick diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 17b6925b46f8386dcfc561483693de516465ec12..8f57bf4fffae352b1f81220b94def01c81af7f5e 100644 +index c02ffd419236980cd063741612e99d739d97ec94..daa5948cc7b86a719a313ea595f135cd00b6a3cc 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -598,6 +598,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -599,6 +599,7 @@ public class ServerChunkCache extends ChunkSource { } // Paper end - optimise chunk tick iteration @@ -18,7 +18,7 @@ index 17b6925b46f8386dcfc561483693de516465ec12..8f57bf4fffae352b1f81220b94def01c // Paper start - optimise chunk tick iteration io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = this.chunkMap.getNearbyPlayers(); // Paper - optimise chunk tick iteration diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index aa9c56fb95d5e438e85aced984631493b84c8556..10adb0b41b4140c1361572f868b2595b0511590d 100644 +index 9388dd9b34bb8148ce8b5f7e24122fa4bd1bafa8..0210226d2185803a18c0020d7985c1fccb798953 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -184,6 +184,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -29,7 +29,7 @@ index aa9c56fb95d5e438e85aced984631493b84c8556..10adb0b41b4140c1361572f868b2595b // Paper start - fix and optimise world upgrading // copied from below -@@ -1612,7 +1613,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1614,7 +1615,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.rainLevel = f1; }