From c4a67b640b058d29e5cceb12fb8af61c9b78ee6e Mon Sep 17 00:00:00 2001
From: md_5 <md_5@live.com.au>
Date: Tue, 11 Jun 2013 12:56:24 +1000
Subject: [PATCH] Let the PAIN begin

---
 .../0004-Spigot-Configuration.patch           |  50 ++++-
 .../0005-Better-Chunk-Tick-Selection.patch    | 184 ++++++++++++++++++
 2 files changed, 233 insertions(+), 1 deletion(-)
 create mode 100644 CraftBukkit-Patches/0005-Better-Chunk-Tick-Selection.patch

diff --git a/CraftBukkit-Patches/0004-Spigot-Configuration.patch b/CraftBukkit-Patches/0004-Spigot-Configuration.patch
index c05d989567..4b64eab6ae 100644
--- a/CraftBukkit-Patches/0004-Spigot-Configuration.patch
+++ b/CraftBukkit-Patches/0004-Spigot-Configuration.patch
@@ -1,4 +1,4 @@
-From 1dd9dbc277e2a8afd185b7acab193b6913da26e7 Mon Sep 17 00:00:00 2001
+From 23604895a4c7e1eeb6ae4dc364ba42630403f2d9 Mon Sep 17 00:00:00 2001
 From: md_5 <md_5@live.com.au>
 Date: Tue, 14 May 2013 12:06:27 +1000
 Subject: [PATCH] Spigot Configuration
@@ -25,6 +25,54 @@ index 7261dc9..10ce69d 100644
  
          if (!this.getOnlineMode()) {
              this.getLogger().warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+index 6cb50b7..2956e75 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+@@ -145,7 +145,7 @@ public final class CraftServer implements Server {
+     protected final MinecraftServer console;
+     protected final DedicatedPlayerList playerList;
+     private final Map<String, World> worlds = new LinkedHashMap<String, World>();
+-    private YamlConfiguration configuration;
++    public YamlConfiguration configuration; // Spigot
+     private final Yaml yaml = new Yaml(new SafeConstructor());
+     private final Map<String, OfflinePlayer> offlinePlayers = new MapMaker().softValues().makeMap();
+     private final AutoUpdater updater;
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+index c0fb528..430a9c0 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+@@ -77,6 +77,30 @@ public class CraftWorld implements World {
+         if (server.chunkGCPeriod > 0) {
+             chunkGCTickCount = rand.nextInt(server.chunkGCPeriod);
+         }
++        // Spigot start
++        org.bukkit.configuration.file.YamlConfiguration configuration = server.configuration;
++        String name;
++        if ( world.worldData == null || world.worldData.getName() == null )
++        {
++            name = "default";
++        } else
++        {
++            name = world.worldData.getName().replaceAll( " ", "_" );
++        }
++
++        // Load defaults first
++        boolean info = configuration.getBoolean( "world-settings.default.info", true );
++
++        // Override defaults with world specific, if they exist
++        info = configuration.getBoolean( "world-settings." + name + ".info", info );
++
++        if ( info )
++        {
++            server.getLogger().info( "-------------- Spigot ----------------" );
++            server.getLogger().info( "-------- World Settings For [" + name + "] --------" );
++            server.getLogger().info( "-------------------------------------------------" );
++        }
++        // Spigot end
+     }
+ 
+     public Block getBlockAt(int x, int y, int z) {
 -- 
 1.8.1.2
 
diff --git a/CraftBukkit-Patches/0005-Better-Chunk-Tick-Selection.patch b/CraftBukkit-Patches/0005-Better-Chunk-Tick-Selection.patch
new file mode 100644
index 0000000000..8a071065ab
--- /dev/null
+++ b/CraftBukkit-Patches/0005-Better-Chunk-Tick-Selection.patch
@@ -0,0 +1,184 @@
+From b50024fe4c26652f55fcb2aa4f395130838e7a49 Mon Sep 17 00:00:00 2001
+From: md_5 <md_5@live.com.au>
+Date: Tue, 11 Jun 2013 12:56:02 +1000
+Subject: [PATCH] Better Chunk Tick Selection
+
+
+diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
+index 3a4ddea..ddf84f8 100644
+--- a/src/main/java/net/minecraft/server/World.java
++++ b/src/main/java/net/minecraft/server/World.java
+@@ -66,13 +66,35 @@ public abstract class World implements IBlockAccess {
+     // CraftBukkit start - public, longhashset
+     public boolean allowMonsters = true;
+     public boolean allowAnimals = true;
+-    protected LongHashSet chunkTickList = new LongHashSet();
+     public long ticksPerAnimalSpawns;
+     public long ticksPerMonsterSpawns;
+     // CraftBukkit end
+     private int O;
+     int[] H;
+     public boolean isStatic;
++    // Spigot start
++    protected final gnu.trove.map.hash.TLongShortHashMap chunkTickList;
++    protected float growthOdds = 100;
++    protected float modifiedOdds = 100;
++    private final byte chunkTickRadius;
++
++    public static long chunkToKey(int x, int z)
++    {
++        long k = ( ( ( (long) x ) & 0xFFFF0000L ) << 16 ) | ( ( ( (long) x ) & 0x0000FFFFL ) << 0 );
++        k     |= ( ( ( (long) z ) & 0xFFFF0000L ) << 32 ) | ( ( ( (long) z ) & 0x0000FFFFL ) << 16 );
++        return k;
++    }
++
++    public static int keyToX(long k)
++    {
++        return (int) ( ( ( k >> 16 ) & 0xFFFF0000 ) | ( k & 0x0000FFFF ) );
++    }
++
++    public static int keyToZ(long k)
++    {
++        return (int) ( ( ( k >> 32 ) & 0xFFFF0000L ) | ( ( k >> 16 ) & 0x0000FFFF ) );
++    }
++    // Spigot end
+ 
+     public BiomeBase getBiome(int i, int j) {
+         if (this.isLoaded(i, 0, j)) {
+@@ -115,6 +137,11 @@ public abstract class World implements IBlockAccess {
+         this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit
+         this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns(); // CraftBukkit
+         // CraftBukkit end
++        // Spigot start
++        this.chunkTickRadius = (byte) ( ( this.getServer().getViewDistance() < 7 ) ? this.getServer().getViewDistance() : 7 );
++        this.chunkTickList = new gnu.trove.map.hash.TLongShortHashMap( world.growthPerTick * 5, 0.7f, Long.MIN_VALUE, Short.MIN_VALUE );
++        this.chunkTickList.setAutoCompactionFactor( 0 );
++        // Spigot end
+ 
+         this.O = this.random.nextInt(12000);
+         this.H = new int['\u8000'];
+@@ -1954,24 +1981,44 @@ public abstract class World implements IBlockAccess {
+         int j;
+         int k;
+ 
++        // Spigot start
++        int optimalChunks = this.getWorld().growthPerTick;
++        // Quick conditions to allow us to exist early
++        if ( optimalChunks <= 0 || players.isEmpty() )
++        {
++            return;
++        }
++        // Keep chunks with growth inside of the optimal chunk range
++        int chunksPerPlayer = Math.min( 200, Math.max( 1, (int) ( ( ( optimalChunks - players.size() ) / (double) players.size() ) + 0.5 ) ) );
++        int randRange = 3 + chunksPerPlayer / 30;
++        // Limit to normal tick radius - including view distance
++        randRange = ( randRange > chunkTickRadius ) ? chunkTickRadius : randRange;
++        // odds of growth happening vs growth happening in vanilla
++        this.growthOdds = this.modifiedOdds = Math.max( 35, Math.min( 100, ( ( chunksPerPlayer + 1 ) * 100F ) / 15F ) );
++        // Spigot end
+         for (i = 0; i < this.players.size(); ++i) {
+             entityhuman = (EntityHuman) this.players.get(i);
+             j = MathHelper.floor(entityhuman.locX / 16.0D);
+             k = MathHelper.floor(entityhuman.locZ / 16.0D);
+             byte b0 = 7;
+ 
+-            for (int l = -b0; l <= b0; ++l) {
+-                for (int i1 = -b0; i1 <= b0; ++i1) {
+-                    // CraftBukkit start - Don't tick chunks queued for unload
+-                    ChunkProviderServer chunkProviderServer = ((WorldServer) entityhuman.world).chunkProviderServer;
+-                    if (chunkProviderServer.unloadQueue.contains(l + j, i1 + k)) {
+-                        continue;
+-                    }
+-                    // CraftBukkit end
+-
+-                    this.chunkTickList.add(org.bukkit.craftbukkit.util.LongHash.toLong(l + j, i1 + k)); // CraftBukkit
++            // Spigot start - Always update the chunk the player is on
++            long key = chunkToKey( j, k );
++            int existingPlayers = Math.max( 0, chunkTickList.get( key ) ); // filter out -1
++            chunkTickList.put(key, (short) (existingPlayers + 1));
++
++            // Check and see if we update the chunks surrounding the player this tick
++            for ( int chunk = 0; chunk < chunksPerPlayer; chunk++ )
++            {
++                int dx = ( random.nextBoolean() ? 1 : -1 ) * random.nextInt( randRange );
++                int dz = ( random.nextBoolean() ? 1 : -1 ) * random.nextInt( randRange );
++                long hash = chunkToKey( dx + j, dz + k );
++                if ( !chunkTickList.contains( hash ) && this.isChunkLoaded( dx + j, dz + k ) )
++                {
++                    chunkTickList.put( hash, (short) -1 ); // no players
+                 }
+             }
++            // Spigot End
+         }
+ 
+         this.methodProfiler.b();
+diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
+index 49360c1..6c3fcf1 100644
+--- a/src/main/java/net/minecraft/server/WorldServer.java
++++ b/src/main/java/net/minecraft/server/WorldServer.java
+@@ -301,9 +301,19 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
+         // CraftBukkit start
+         // Iterator iterator = this.chunkTickList.iterator();
+ 
+-        for (long chunkCoord : this.chunkTickList.popAll()) {
+-            int chunkX = LongHash.msw(chunkCoord);
+-            int chunkZ = LongHash.lsw(chunkCoord);
++        // Spigot start
++        for (gnu.trove.iterator.TLongShortIterator iter = chunkTickList.iterator(); iter.hasNext();) {
++            iter.advance();
++            long chunkCoord = iter.key();
++            int chunkX = World.keyToX(chunkCoord);
++            int chunkZ = World.keyToZ(chunkCoord);
++            // If unloaded, or in procedd of being unloaded, drop it
++            if ( ( !this.isChunkLoaded( chunkX, chunkZ ) ) || ( this.chunkProviderServer.unloadQueue.contains( chunkX, chunkZ ) ) )
++            {
++                iter.remove();
++                continue;
++            }
++            // Spigot end
+             // ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next();
+             int k = chunkX * 16;
+             int l = chunkZ * 16;
+@@ -401,6 +411,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
+ 
+                         if (block != null && block.isTicking()) {
+                             ++i;
++                            this.growthOdds = (iter.value() < 1) ? this.modifiedOdds : 100; // Spigot - grow fast if no players are in this chunk (value = player count)
+                             block.a(this, k2 + k, i3 + chunksection.getYPosition(), l2 + l, this.random);
+                         }
+                     }
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+index 430a9c0..d28a4c8 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+@@ -67,6 +67,9 @@ public class CraftWorld implements World {
+     private int chunkGCTickCount;
+ 
+     private static final Random rand = new Random();
++    // Spigot start
++    public int growthPerTick = 650;
++    // Spigot end
+ 
+     public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) {
+         this.world = world;
+@@ -90,14 +93,17 @@ public class CraftWorld implements World {
+ 
+         // Load defaults first
+         boolean info = configuration.getBoolean( "world-settings.default.info", true );
++        growthPerTick = configuration.getInt( "world-settings.default.growth-chunks-per-tick", growthPerTick );
+ 
+         // Override defaults with world specific, if they exist
+         info = configuration.getBoolean( "world-settings." + name + ".info", info );
++        growthPerTick = configuration.getInt( "world-settings." + name + ".growth-chunks-per-tick", growthPerTick );
+ 
+         if ( info )
+         {
+             server.getLogger().info( "-------------- Spigot ----------------" );
+             server.getLogger().info( "-------- World Settings For [" + name + "] --------" );
++            server.getLogger().info( "Growth Per Tick: " + growthPerTick );
+             server.getLogger().info( "-------------------------------------------------" );
+         }
+         // Spigot end
+-- 
+1.8.1.2
+