From 31d35e76aca5f197cb900872bc0d879dd4c20c7b Mon Sep 17 00:00:00 2001
From: Zach Brown <Zbob750@live.com>
Date: Mon, 11 Aug 2014 23:07:39 -0500
Subject: [PATCH] Update TileEntity optimizations (again again) ... hopefully
 less often now

---
 .../0033-Optimize-TileEntity-ticking.patch    | 170 +++++++++++-------
 ...-handling-out-of-the-chest-tick-loop.patch |  40 ++---
 2 files changed, 127 insertions(+), 83 deletions(-)

diff --git a/Spigot-Server-Patches/0033-Optimize-TileEntity-ticking.patch b/Spigot-Server-Patches/0033-Optimize-TileEntity-ticking.patch
index 869d4f0e1..968c5cc71 100644
--- a/Spigot-Server-Patches/0033-Optimize-TileEntity-ticking.patch
+++ b/Spigot-Server-Patches/0033-Optimize-TileEntity-ticking.patch
@@ -1,6 +1,6 @@
-From fa5a4c6926b45e62616bef1069f593d5b88d2166 Mon Sep 17 00:00:00 2001
+From 85f6cf24d2cc67420285c6d695ddd33e5ff80f92 Mon Sep 17 00:00:00 2001
 From: Aikar <aikar@aikar.co>
-Date: Mon, 11 Aug 2014 21:46:33 -0500
+Date: Mon, 11 Aug 2014 23:00:13 -0500
 Subject: [PATCH] Optimize TileEntity ticking
 
 Re-organizes the servers TileEntity Tick List to be bucketed by type.
@@ -15,7 +15,7 @@ the server owner control on how fast a TileEntity ticks, slowing it down if they
 (Such as chest), to improve performance.
 
 diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
-index 0423ee9..09aa073 100644
+index 0423ee9..e0d34d9 100644
 --- a/src/main/java/net/minecraft/server/Chunk.java
 +++ b/src/main/java/net/minecraft/server/Chunk.java
 @@ -28,6 +28,7 @@ public class Chunk {
@@ -39,22 +39,27 @@ index 0423ee9..09aa073 100644
              // Spigot End
  
 -            this.world.a(tileentity);
-+            // this.world.a(tileentity); // Handled by Improved Tick List (Only loaded chunks iterate)
++            // this.world.a(tileentity); // PaperSpigot - Handled by Improved Tick List (Only loaded chunks iterate)
          }
  
          for (int i = 0; i < this.entitySlices.length; ++i) {
 diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
-index 3c5ec6f..50130ca 100644
+index 3c5ec6f..009a7fb 100644
 --- a/src/main/java/net/minecraft/server/TileEntity.java
 +++ b/src/main/java/net/minecraft/server/TileEntity.java
-@@ -14,6 +14,7 @@ public class TileEntity {
+@@ -58,6 +58,12 @@ public class TileEntity {
+     }
+     // Spigot end
  
-     public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot
-     private static final Logger a = LogManager.getLogger();
-+    public boolean isAdded = false; // PaperSpigot - optimize contains checks
-     private static Map i = new HashMap();
-     private static Map j = new HashMap();
-     protected World world;
++    // PaperSpigot start - Optimized TileEntity Tick changes
++    private static int tileEntityCounter = 0;
++    public boolean isAdded = false;
++    public int tileId = tileEntityCounter++;
++    //PaperSpigot end
++
+     public TileEntity() {}
+ 
+     private static void a(Class oclass, String s) {
 diff --git a/src/main/java/net/minecraft/server/TileEntityBeacon.java b/src/main/java/net/minecraft/server/TileEntityBeacon.java
 index 09313ea..86142f9 100644
 --- a/src/main/java/net/minecraft/server/TileEntityBeacon.java
@@ -86,7 +91,7 @@ index c900caf..e27716b 100644
              f = 5.0F;
              List list = this.world.a(EntityHuman.class, AxisAlignedBB.a((double) ((float) this.x - f), (double) ((float) this.y - f), (double) ((float) this.z - f), (double) ((float) (this.x + 1) + f), (double) ((float) (this.y + 1) + f), (double) ((float) (this.z + 1) + f)));
 diff --git a/src/main/java/net/minecraft/server/TileEntityEnderChest.java b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
-index b205ab7..d76a2b2 100644
+index b205ab7..c2b9e04 100644
 --- a/src/main/java/net/minecraft/server/TileEntityEnderChest.java
 +++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
 @@ -11,7 +11,7 @@ public class TileEntityEnderChest extends TileEntity {
@@ -94,7 +99,7 @@ index b205ab7..d76a2b2 100644
      public void h() {
          super.h();
 -        if (++this.k % 20 * 4 == 0) {
-+        if (++this.k % 4 == 0) { // PaperSpigot Reduced (20 * 4) -> 4 interval due to reduced tick rate from Improved Tick Handling
++        if (++this.k % 4 == 0) {  // PaperSpigot Reduced (20 * 4) -> 4 interval due to reduced tick rate from Improved Tick Handling
              this.world.playBlockAction(this.x, this.y, this.z, Blocks.ENDER_CHEST, 1, this.j);
          }
  
@@ -112,7 +117,7 @@ index 143cffb..de33df0 100644
              if (this.h instanceof BlockDaylightDetector) {
                  ((BlockDaylightDetector) this.h).e(this.world, this.x, this.y, this.z);
 diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
-index 33c228b..940e1c8 100644
+index 33c228b..fb0a6a8 100644
 --- a/src/main/java/net/minecraft/server/World.java
 +++ b/src/main/java/net/minecraft/server/World.java
 @@ -58,7 +58,7 @@ public abstract class World implements IBlockAccess {
@@ -120,10 +125,19 @@ index 33c228b..940e1c8 100644
      // Spigot end
      protected List f = new ArrayList();
 -    public Set tileEntityList = new HashSet(); // CraftBukkit - ArrayList -> HashSet
-+    public Set tileEntityList = new org.github.paperspigot.WorldTileEntityList(this); // CraftBukkit - ArrayList -> HashSet // PaperSpigot
++    public Set tileEntityList = new org.github.paperspigot.WorldTileEntityList(this); // PaperSpigot // CraftBukkit - ArrayList -> HashSet
      private List a = new ArrayList();
      private List b = new ArrayList();
      public List players = new ArrayList();
+@@ -1513,7 +1513,7 @@ public abstract class World implements IBlockAccess {
+             }
+             // Spigot end
+ 
+-            if (!tileentity.r() && tileentity.o() && this.isLoaded(tileentity.x, tileentity.y, tileentity.z)) {
++            if (!tileentity.r() && tileentity.o() /*&& this.isLoaded(tileentity.x, tileentity.y, tileentity.z)*/) { // PaperSpigot - remove isLoaded check - done by the iterator per chunk
+                 try {
+                     tileentity.tickTimer.startTiming(); // Spigot
+                     tileentity.h();
 @@ -1529,13 +1529,13 @@ public abstract class World implements IBlockAccess {
  
              if (tileentity.r()) {
@@ -142,58 +156,60 @@ index 33c228b..940e1c8 100644
  
 diff --git a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
 new file mode 100644
-index 0000000..e673ba9
+index 0000000..cb4a34e
 --- /dev/null
 +++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
-@@ -0,0 +1,121 @@
+@@ -0,0 +1,153 @@
 +package org.github.paperspigot;
 +
 +import com.google.common.collect.ArrayListMultimap;
 +import com.google.common.collect.ListMultimap;
++import com.google.common.collect.Maps;
 +import net.minecraft.server.*;
 +import net.minecraft.util.gnu.trove.map.hash.TObjectIntHashMap;
 +
-+import java.util.Collection;
 +import java.util.Iterator;
++import java.util.List;
 +import java.util.Map;
 +
 +public class ChunkTileEntityList {
-+    final ListMultimap<Class, TileEntity> tickList = ArrayListMultimap.create();
++    final Map<Class<? extends TileEntity>, ListMultimap<Integer, TileEntity>> tickList = Maps.newHashMap();
 +
-+    private static final TObjectIntHashMap<Class> tileEntityTickIntervals = new TObjectIntHashMap<Class>() {{
-+        // Use 0 for no ticking
-+        // These TE's have empty tick methods, doing nothing. Never bother ticking them.
-+        for (Class<? extends TileEntity> ignored : new Class[]{
-+                TileEntityRecordPlayer.class,
-+                TileEntityDispenser.class,
-+                TileEntityDropper.class,
-+                TileEntitySign.class,
-+                TileEntityNote.class,
-+                TileEntityEnderPortal.class,
-+                TileEntityCommand.class,
-+                TileEntitySkull.class,
-+                TileEntityComparator.class,
-+                TileEntityFlowerPot.class
-+        }) {
-+            put(ignored, 0);
-+        }
++    private static final TObjectIntHashMap<Class<? extends TileEntity>> tileEntityTickIntervals =
++            new TObjectIntHashMap<Class<? extends TileEntity>>() {{
++                // Use 0 for no ticking
++                // These TE's have empty tick methods, doing nothing. Never bother ticking them.
++                for (Class<? extends TileEntity> ignored : new Class[]{
++                        TileEntityRecordPlayer.class,
++                        TileEntityDispenser.class,
++                        TileEntityDropper.class,
++                        TileEntitySign.class,
++                        TileEntityNote.class,
++                        TileEntityEnderPortal.class,
++                        TileEntityCommand.class,
++                        TileEntitySkull.class,
++                        TileEntityComparator.class,
++                        TileEntityFlowerPot.class
++                }) {
++                    put(ignored, 0);
++                }
 +
-+        // does findPlayer lookup, so this helps performance to slow down
-+        put(TileEntityChest.class, 20);
-+        put(TileEntityEnderChest.class, 20);
-+        put(TileEntityEnchantTable.class, 20);
++                // does findPlayer lookup, so this helps performance to slow down
++                put(TileEntityChest.class, 20);
++                put(TileEntityEnderChest.class, 20);
++                put(TileEntityEnchantTable.class, 20);
 +
-+        // Slow things down that players won't notice due to craftbukkit "wall time" patches.
-+        put(TileEntityFurnace.class, 10);
-+        put(TileEntityBrewingStand.class, 10);
++                // Slow things down that players won't notice due to craftbukkit "wall time" patches.
++                put(TileEntityFurnace.class, 10);
++                put(TileEntityBrewingStand.class, 10);
 +
-+        // Vanilla controlled values - These are checks already done in vanilla, so don't tick on ticks we know
-+        // won't do anything anyways
-+        put(TileEntityBeacon.class, 80);
-+        put(TileEntityLightDetector.class, 20);
-+    }};
++                // Vanilla controlled values - These are checks already done in vanilla, so don't tick on ticks we know
++                // won't do anything anyways
++                put(TileEntityBeacon.class, 80);
++                put(TileEntityLightDetector.class, 20);
++            }};
 +
-+    public static Integer getInterval(Class cls) {
++    public static Integer getInterval(Class<? extends TileEntity> cls) {
 +        Integer tickInterval = tileEntityTickIntervals.get(cls);
 +        return tickInterval != null ? tickInterval : 1;
 +    }
@@ -208,33 +224,63 @@ index 0000000..e673ba9
 +        return new ChunkTileEntityIterator();
 +    }
 +
-+
 +    public boolean add(TileEntity entity) {
 +        entity.isAdded = true;
-+        return tickList.put(entity.getClass(), entity);
++        int bucket = getBucketId(entity);
++        ListMultimap<Integer, TileEntity> typeBucket = getBucket(entity);
++        return typeBucket.put(bucket, entity);
 +    }
 +
 +    public boolean remove(TileEntity entity) {
++        if (!entity.isAdded) {
++            return false;
++        }
 +        entity.isAdded = false;
-+        return tickList.remove(entity.getClass(), entity);
++        int bucket = getBucketId(entity);
++        ListMultimap<Integer, TileEntity> typeBucket = getBucket(entity);
++        return typeBucket.remove(bucket, entity);
++    }
++
++    private ListMultimap<Integer, TileEntity> getBucket(TileEntity entity) {
++        final Class<? extends TileEntity> cls = entity.getClass();
++
++        ListMultimap<Integer, TileEntity> typeBucket = tickList.get(cls);
++        if (typeBucket == null) {
++            typeBucket = ArrayListMultimap.create();
++            tickList.put(cls, typeBucket);
++        }
++        return typeBucket;
++    }
++
++    private static int getBucketId(TileEntity entity) {
++        Integer interval = getInterval(entity.getClass());
++        if (interval < 1) {
++            interval = 1; // Prevent divide by zero errors.
++        }
++        return entity.tileId % interval;
 +    }
 +
 +    private class ChunkTileEntityIterator implements Iterator {
-+        Iterator<Map.Entry<Class, Collection<TileEntity>>> typeIterator;
-+        Map.Entry<Class, Collection<TileEntity>> curType = null;
++        Iterator<Map.Entry<Class<? extends TileEntity>, ListMultimap<Integer, TileEntity>>> typeIterator;
++        Map.Entry<Class <? extends TileEntity>, ListMultimap<Integer, TileEntity>> curType = null;
 +        Iterator<TileEntity> listIterator = null;
 +
 +        {
-+            typeIterator = tickList.asMap().entrySet().iterator();
++            typeIterator = tickList.entrySet().iterator();
 +            nextType();
 +        }
 +
 +        private boolean nextType() {
 +            if (typeIterator.hasNext()) {
 +                curType = typeIterator.next();
-+                final Integer interval = ChunkTileEntityList.getInterval(curType.getKey());
-+                if (world.getTime() % interval != 0) {
-+                    listIterator = curType.getValue().iterator();
++
++                final ListMultimap<Integer, TileEntity> buckets = curType.getValue();
++
++                final Integer interval = getInterval(curType.getKey());
++                int bucket = (int) (world.getTime() % interval);
++                final List<TileEntity> tileList = buckets.get(bucket);
++                if (tileList != null && !tileList.isEmpty()) {
++                    listIterator = tileList.iterator();
 +                } else {
 +                    listIterator = null;
 +                }
@@ -267,10 +313,9 @@ index 0000000..e673ba9
 +        }
 +    }
 +}
-\ No newline at end of file
 diff --git a/src/main/java/org/github/paperspigot/WorldTileEntityList.java b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
 new file mode 100644
-index 0000000..d783741
+index 0000000..5f57c6d
 --- /dev/null
 +++ b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
 @@ -0,0 +1,106 @@
@@ -299,7 +344,7 @@ index 0000000..d783741
 +     */
 +    @Override
 +    public boolean add(Object o) {
-+        return o instanceof TileEntity && ChunkTileEntityList.getInterval(o.getClass()) > 0 && add((TileEntity) o);
++        return o instanceof TileEntity && ChunkTileEntityList.getInterval(((TileEntity)o).getClass()) > 0 && add((TileEntity) o);
 +    }
 +
 +    private boolean add(TileEntity entity) {
@@ -380,7 +425,6 @@ index 0000000..d783741
 +        }
 +    }
 +}
-\ No newline at end of file
 -- 
 1.9.1
 
diff --git a/Spigot-Server-Patches/0034-Move-sound-handling-out-of-the-chest-tick-loop.patch b/Spigot-Server-Patches/0034-Move-sound-handling-out-of-the-chest-tick-loop.patch
index 3b1d8f62a..681d9e5aa 100644
--- a/Spigot-Server-Patches/0034-Move-sound-handling-out-of-the-chest-tick-loop.patch
+++ b/Spigot-Server-Patches/0034-Move-sound-handling-out-of-the-chest-tick-loop.patch
@@ -1,6 +1,6 @@
-From 280e4f94a1b0fc4a599baaeaa854ee2321990e9f Mon Sep 17 00:00:00 2001
+From 8f5ed31e134327d8d6fffceacc0f873df8ea981a Mon Sep 17 00:00:00 2001
 From: Zach Brown <Zbob750@live.com>
-Date: Mon, 11 Aug 2014 19:30:19 -0500
+Date: Mon, 11 Aug 2014 23:03:47 -0500
 Subject: [PATCH] Move sound handling out of the chest tick loop
 
 This allows us to disable ticking chests and enderchests without any
@@ -84,7 +84,7 @@ index e27716b..69ffd30 100644
              if (this.q() == Blocks.TRAPPED_CHEST) {
                  int newPower = Math.max(0, Math.min(15, this.o));
 diff --git a/src/main/java/net/minecraft/server/TileEntityEnderChest.java b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
-index d76a2b2..339e133 100644
+index c2b9e04..7298c4f 100644
 --- a/src/main/java/net/minecraft/server/TileEntityEnderChest.java
 +++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
 @@ -16,6 +16,9 @@ public class TileEntityEnderChest extends TileEntity {
@@ -147,27 +147,27 @@ index d76a2b2..339e133 100644
  
      public boolean a(EntityHuman entityhuman) {
 diff --git a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
-index e673ba9..dac6463 100644
+index cb4a34e..128f5b2 100644
 --- a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
 +++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
-@@ -25,14 +25,14 @@ public class ChunkTileEntityList {
-                 TileEntityCommand.class,
-                 TileEntitySkull.class,
-                 TileEntityComparator.class,
--                TileEntityFlowerPot.class
-+                TileEntityFlowerPot.class,
-+                TileEntityChest.class,
-+                TileEntityEnderChest.class
-         }) {
-             put(ignored, 0);
-         }
+@@ -27,14 +27,14 @@ public class ChunkTileEntityList {
+                         TileEntityCommand.class,
+                         TileEntitySkull.class,
+                         TileEntityComparator.class,
+-                        TileEntityFlowerPot.class
++                        TileEntityFlowerPot.class,
++                        TileEntityChest.class,
++                        TileEntityEnderChest.class
+                 }) {
+                     put(ignored, 0);
+                 }
  
-         // does findPlayer lookup, so this helps performance to slow down
--        put(TileEntityChest.class, 20);
--        put(TileEntityEnderChest.class, 20);
-         put(TileEntityEnchantTable.class, 20);
+                 // does findPlayer lookup, so this helps performance to slow down
+-                put(TileEntityChest.class, 20);
+-                put(TileEntityEnderChest.class, 20);
+                 put(TileEntityEnchantTable.class, 20);
  
-         // Slow things down that players won't notice due to craftbukkit "wall time" patches.
+                 // Slow things down that players won't notice due to craftbukkit "wall time" patches.
 -- 
 1.9.1