From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 19 Feb 2021 19:27:34 -0800
Subject: [PATCH] Optimise snow & ice in chunk ticking

Avoid the biome lookups most of the time by
hiding them behind the snow/air checks. The biome
checks take up the most here, followed by the block gets.
Soften some of the block gets by passing the chunk to
the biome methods, removing the need to invoke a chunk
lookup.

diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
index 2d207dbad7752526c9a0b212979043c009e66386..84b4b7524064a4f0c175f34778e4e0d8004888ea 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -1198,6 +1198,9 @@ public class WorldServer extends World implements GeneratorAccessSeed {
     private final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition();
     private final com.destroystokyo.paper.util.math.ThreadUnsafeRandom randomTickRandom = new com.destroystokyo.paper.util.math.ThreadUnsafeRandom();
     // Paper end
+    // Tuinity start - optimise chunk ice snow ticking
+    private final BiomeBase[] biomeBaseCache = new BiomeBase[1];
+    // Tuinity end - optimise chunk ice snow ticking
 
     public void a(Chunk chunk, int i) { final int randomTickSpeed = i; // Paper
         ChunkCoordIntPair chunkcoordintpair = chunk.getPos();
@@ -1235,28 +1238,32 @@ public class WorldServer extends World implements GeneratorAccessSeed {
         gameprofilerfiller.exitEnter("iceandsnow");
         if (!this.paperConfig.disableIceAndSnow && this.randomTickRandom.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking
             // Paper start - optimise chunk ticking
+            // Tuinity start - optimise chunk ice snow ticking
+            BiomeBase[] biomeCache = this.biomeBaseCache;
+            biomeCache[0] = null;
+            // Tuinity start - optimise chunk ice snow ticking
             this.getRandomBlockPosition(j, 0, k, 15, blockposition);
             int normalY = chunk.getHighestBlockY(HeightMap.Type.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15);
             int downY = normalY - 1;
             blockposition.setY(normalY);
             // Paper end
-            BiomeBase biomebase = this.getBiome(blockposition);
+            //BiomeBase biomebase = this.getBiome(blockposition); // Tuinity - lazily-get biome
 
             // Paper start - optimise chunk ticking
             blockposition.setY(downY);
-            if (biomebase.a(this, blockposition)) {
+            if (BiomeBase.canTurnWaterIntoIce(this, blockposition, true, chunk, biomeCache)) { // Tuinity - add chunk parameter, avoid biome lookup
                 org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.ICE.getBlockData(), null); // CraftBukkit
                 // Paper end
             }
 
             blockposition.setY(normalY); // Paper
-            if (flag && biomebase.b(this, blockposition)) {
+            if (flag && BiomeBase.canTurnAirIntoSnow(this, blockposition, chunk, biomeCache)) {
                 org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.getBlockData(), null); // CraftBukkit
             }
 
             // Paper start - optimise chunk ticking
             blockposition.setY(downY);
-            if (flag && this.getBiome(blockposition).c() == BiomeBase.Precipitation.RAIN) {
+            if (flag && chunk.getType(blockposition).getBlock() instanceof net.minecraft.world.level.block.BlockCauldron && this.getBiome(blockposition).c() == BiomeBase.Precipitation.RAIN) { // Tuinity - only cauldron uses that method, and it's not likely to hit. So, avoid the expensive biome lookup and replace it with a block lookup TODO check on update for overrides
                 chunk.getType(blockposition).getBlock().c((World) this, blockposition);
                 // Paper end
             }
diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
index 15096a9c2719b8b4c099f62d0a1c808e56b63a8e..9bbd175f7e20591bbefdbddcb5e998e7098c5adb 100644
--- a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
+++ b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
@@ -175,14 +175,33 @@ public final class BiomeBase {
     }
 
     public boolean a(IWorldReader iworldreader, BlockPosition blockposition, boolean flag) {
-        if (this.getAdjustedTemperature(blockposition) >= 0.15F) {
+        // Tuinity start - add chunk parameter and lazily get biome
+        return canTurnWaterIntoIce(iworldreader, blockposition, flag, null, new BiomeBase[] { this });
+    }
+    public static boolean canTurnWaterIntoIce(IWorldReader iworldreader, BlockPosition blockposition, boolean flag, IChunkAccess chunk, BiomeBase[] biomeAbove) {
+        // Tuinity end - add chunk parameter and lazily get biome
+        if (false && biomeAbove[0].getAdjustedTemperature(blockposition) >= 0.15F) { // Tuinity - move this down, this check is expensive
             return false;
         } else {
             if (blockposition.getY() >= 0 && blockposition.getY() < 256 && iworldreader.getBrightness(EnumSkyBlock.BLOCK, blockposition) < 10) {
-                IBlockData iblockdata = iworldreader.getType(blockposition);
-                Fluid fluid = iworldreader.getFluid(blockposition);
+                // Tuinity start - add chunk parameter
+                if (chunk == null) {
+                    chunk = iworldreader.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+                }
+                // Tuinity end - add chunk parameter
+                IBlockData iblockdata = chunk.getType(blockposition); // Tuinity - skip chunk lookup, we got the chunk
+                Fluid fluid = iblockdata.getFluid(); // Tuinity - skip another block lookup, we have the blockdata
 
                 if (fluid.getType() == FluidTypes.WATER && iblockdata.getBlock() instanceof BlockFluids) {
+                    // Tuinity start - moved down from top, only run when we actually encounter water
+                    if (biomeAbove[0] == null) {
+                        // lazily-get biome
+                        biomeAbove[0] = iworldreader.getBiome(blockposition.up()); // TODO - avoid blockpos alloc
+                    }
+                    if (biomeAbove[0].getAdjustedTemperature(blockposition) >= 0.15F) {
+                        return false;
+                    }
+                    // Tuinity end - moved down from top, only run when we actually encounter water
                     if (!flag) {
                         return true;
                     }
@@ -200,13 +219,32 @@ public final class BiomeBase {
     }
 
     public boolean b(IWorldReader iworldreader, BlockPosition blockposition) {
-        if (this.getAdjustedTemperature(blockposition) >= 0.15F) {
+        // Tuinity start - add chunk parameter and lazily get biome
+        return canTurnAirIntoSnow(iworldreader, blockposition, null, new BiomeBase[]{ this });
+    }
+    public static boolean canTurnAirIntoSnow(IWorldReader iworldreader, BlockPosition blockposition, IChunkAccess chunk, BiomeBase[] biomeAbove) {
+        // Tuinity end - add chunk parameter and lazily get biome
+        if (false && biomeAbove[0].getAdjustedTemperature(blockposition) >= 0.15F) { // Tuinity - move this down, this check is expensive
             return false;
         } else {
             if (blockposition.getY() >= 0 && blockposition.getY() < 256 && iworldreader.getBrightness(EnumSkyBlock.BLOCK, blockposition) < 10) {
-                IBlockData iblockdata = iworldreader.getType(blockposition);
+                // Tuinity start - add chunk parameter
+                if (chunk == null) {
+                    chunk = iworldreader.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+                }
+                // Tuinity end - add chunk parameter
+                IBlockData iblockdata = chunk.getType(blockposition); // Tuinity - skip chunk lookup, we got the chunk
 
                 if (iblockdata.isAir() && Blocks.SNOW.getBlockData().canPlace(iworldreader, blockposition)) {
+                    // Tuinity start - moved down from top, only run when we actually encounter water
+                    if (biomeAbove[0] == null) {
+                        // lazily-get biome
+                        biomeAbove[0] = iworldreader.getBiome(blockposition.up()); // TODO - avoid blockpos alloc
+                    }
+                    if (biomeAbove[0].getAdjustedTemperature(blockposition) >= 0.15F) {
+                        return false;
+                    }
+                    // Tuinity end - moved down from top, only run when we actually encounter water
                     return true;
                 }
             }
