From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
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.

Lighting: 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 <http://www.gnu.org/licenses/>.

diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
index fe040615ff03478a20cdf8376f89a6b7d100ba61..207a9c3928aad7c6e89a120b54d87e003ebd232c 100644
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
@@ -1000,6 +1000,7 @@ public class ChunkProviderServer extends IChunkProvider {
             }
             // Paper end - optimize isOutisdeRange
             this.world.getMethodProfiler().enter("pollingChunks");
+            this.world.resetIceAndSnowTick(); // Airplane - reset ice & snow tick random
             int k = this.world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED);
             boolean flag2 = world.ticksPerAnimalSpawns != 0L && worlddata.getTime() % world.ticksPerAnimalSpawns == 0L; // CraftBukkit
 
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
index 9e71e6c331c60d55220399cee4381367113f596a..ab1cf52d7faa93feba9dd2efd9479b2d72771778 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -1202,6 +1202,8 @@ public class WorldServer extends World implements GeneratorAccessSeed {
     private final BiomeBase[] biomeBaseCache = new BiomeBase[1];
     // Tuinity end - optimise chunk ice snow ticking
 
+    private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane
+
     public void a(Chunk chunk, int i) { final int randomTickSpeed = i; // Paper
         ChunkCoordIntPair chunkcoordintpair = chunk.getPos();
         boolean flag = this.isRaining();
@@ -1212,7 +1214,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
         gameprofilerfiller.enter("thunder");
         final BlockPosition.MutableBlockPosition blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change
 
-        if (!this.paperConfig.disableThunder && flag && this.random.nextInt(100000) == 0 && this.W()) { // Paper - Disable thunder // Airplane - check this.W last
+        if (!this.paperConfig.disableThunder && flag && chunk.shouldDoLightning(this.random) && this.W()) { // Paper - Disable thunder // Airplane - check this.W last // Airplane - replace random with shouldDoLighting
             blockposition.setValues(this.a(this.a(j, 0, k, 15))); // Paper
             if (this.isRainingAt(blockposition)) {
                 DifficultyDamageScaler difficultydamagescaler = this.getDamageScaler(blockposition);
@@ -1236,7 +1238,7 @@ 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
+        if (!this.paperConfig.disableIceAndSnow && (this.currentIceAndSnowTick++ & 15) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking // Airplane - optimize further random ticking
             // Paper start - optimise chunk ticking
             // Tuinity start - optimise chunk ice snow ticking
             BiomeBase[] biomeCache = this.biomeBaseCache;
diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
index fc07e2014e961da5d97095c4ee6f972e2ece3ec3..8f5809756b4fb358f1207c1d61c5cbe6df3fff00 100644
--- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
@@ -99,6 +99,18 @@ public class Chunk implements IChunkAccess {
     private final ChunkCoordIntPair loc; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
     private volatile boolean x;
 
+    // Airplane 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(java.util.Random random) {
+        if (this.lightningTick-- <= 0) {
+            this.lightningTick = random.nextInt(100000) << 1;
+            return true;
+        }
+        return false;
+    }
+    // Airplane end
+
     public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage) {
         this(world, chunkcoordintpair, biomestorage, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, (ChunkSection[]) null, (Consumer) null);
     }
@@ -333,6 +345,7 @@ public class Chunk implements IChunkAccess {
         // CraftBukkit start
         this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
         this.entitySlicesManager = new com.tuinity.tuinity.world.ChunkEntitySlices(this.world, this.loc.x, this.loc.z, 0, 15); // TODO update for 1.17 // Tuinity
+        this.lightningTick = this.world.random.nextInt(100000) << 1; // Airplane - initialize lightning tick
     }
 
     public org.bukkit.Chunk bukkitChunk;
