From 4e105d3f9f5da3a4315203631c42ecaa111fc001 Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Tue, 31 Oct 2023 00:53:33 -0300 Subject: [PATCH] Let's start from scratch, shall we? --- README.md | 2 - gradle.properties | 2 +- ...ering-once-per-world-instead-for-eve.patch | 0 ...ntityLookup.ArrayIterable.-init-call.patch | 0 ...ve-iterators-from-inventory-contains.patch | 38 ------- ...reams-and-iterators-from-range-check.patch | 49 --------- ...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 ------- 16 files changed, 1 insertion(+), 601 deletions(-) rename patches/{ => removed}/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch (100%) rename patches/{ => removed}/server/0017-Optimize-heavy-EntityLookup.ArrayIterable.-init-call.patch (100%) delete mode 100644 patches/server/0003-Remove-iterators-from-inventory-contains.patch delete mode 100644 patches/server/0004-Remove-streams-and-iterators-from-range-check.patch delete mode 100644 patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch delete mode 100644 patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch delete mode 100644 patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch delete mode 100644 patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch delete mode 100644 patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch delete mode 100644 patches/server/0010-Reduce-chunk-loading-lookups.patch delete mode 100644 patches/server/0011-Early-return-optimization-for-target-finding.patch delete mode 100644 patches/server/0012-Optimize-entity-coordinate-key.patch delete mode 100644 patches/server/0013-Remove-lambda-from-ticking-guard.patch delete mode 100644 patches/server/0014-Reduce-entity-allocations.patch diff --git a/README.md b/README.md index b762812..175075e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,5 @@ While our fork is mostly cherry-picked patches from other forks, we do have some * 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 53633d4..cef13af 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=5bb30ce95b14293f5bfebf10be2fdf929eabcc01 +paperRef=1865625d958b94d82e0bd601d6d860318980c4c4 org.gradle.caching=true org.gradle.parallel=true diff --git a/patches/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch b/patches/removed/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch similarity index 100% rename from patches/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch rename to patches/removed/server/0016-Only-check-thundering-once-per-world-instead-for-eve.patch diff --git a/patches/server/0017-Optimize-heavy-EntityLookup.ArrayIterable.-init-call.patch b/patches/removed/server/0017-Optimize-heavy-EntityLookup.ArrayIterable.-init-call.patch similarity index 100% rename from patches/server/0017-Optimize-heavy-EntityLookup.ArrayIterable.-init-call.patch rename to patches/removed/server/0017-Optimize-heavy-EntityLookup.ArrayIterable.-init-call.patch diff --git a/patches/server/0003-Remove-iterators-from-inventory-contains.patch b/patches/server/0003-Remove-iterators-from-inventory-contains.patch deleted file mode 100644 index 549002f..0000000 --- a/patches/server/0003-Remove-iterators-from-inventory-contains.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index daa3120..0000000 --- a/patches/server/0004-Remove-streams-and-iterators-from-range-check.patch +++ /dev/null @@ -1,49 +0,0 @@ -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-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch b/patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch deleted file mode 100644 index 8e03833..0000000 --- a/patches/server/0005-Simpler-ShapelessRecipes-comparison-for-Vanilla.patch +++ /dev/null @@ -1,84 +0,0 @@ -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 96d772eb02f79f8c478f5e6f065e387aa7665b18..c5ce412f321b8b4f31cc042893659e213b081f29 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, this.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 deleted file mode 100644 index 3b59c7a..0000000 --- a/patches/server/0006-Only-check-for-spooky-season-once-an-hour.patch +++ /dev/null @@ -1,49 +0,0 @@ -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 deleted file mode 100644 index f661252..0000000 --- a/patches/server/0007-Move-ThreadUnsafeRandom-Initialization.patch +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index f956509..0000000 --- a/patches/server/0008-Use-thread-unsafe-random-for-mob-spawning.patch +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 67818af..0000000 --- a/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch +++ /dev/null @@ -1,101 +0,0 @@ -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 8c33a12ca879c46893150d6adfb8aa4d397c6b4c..b384a9ed3f072d2fbf08d2fd8d8ef9a18fdf1e3e 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 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % this.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 1c73235e071cfd713972a2485c8dbaf995f0512f..93b6e92e490025f8ef3c154e7534bf6c278eae2a 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 fa170cc1ce7011d201295b89718292d696c7fc24..7fd68d4aba72b15b2e21e5c88b44e677b794fe57 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 deleted file mode 100644 index 7c29aad..0000000 --- a/patches/server/0010-Reduce-chunk-loading-lookups.patch +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 548d806..0000000 --- a/patches/server/0011-Early-return-optimization-for-target-finding.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 6c90688..0000000 --- a/patches/server/0012-Optimize-entity-coordinate-key.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index e5caa30..0000000 --- a/patches/server/0013-Remove-lambda-from-ticking-guard.patch +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index 4108ecd..0000000 --- a/patches/server/0014-Reduce-entity-allocations.patch +++ /dev/null @@ -1,36 +0,0 @@ -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