diff --git a/Spigot-Server-Patches/Don-t-tick-chests.patch b/Spigot-Server-Patches/Don-t-tick-chests.patch new file mode 100644 index 0000000000..498f6aafb0 --- /dev/null +++ b/Spigot-Server-Patches/Don-t-tick-chests.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Iceee +Date: Fri, 11 Jul 2014 01:31:43 -0500 +Subject: [PATCH] Don't tick chests + + +diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/TileEntityChest.java ++++ b/src/main/java/net/minecraft/server/TileEntityChest.java +@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { + } + + public void h() { ++ // PaperSpigot start - Don't tick chests at all, period ++ /* + super.h(); + if (this.world == null) return; // CraftBukkit + this.i(); +@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { + this.m = 0.0F; + } + } ++ */ + } + + public boolean c(int i, int j) { +@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { + if (this.world == null) return; // CraftBukkit + this.world.playBlockAction(this.x, this.y, this.z, this.q(), 1, this.o); + ++ // PaperSpigot start - Move chest open sound handling down here ++ this.i(); ++ double d0; ++ ++ if (this.o > 0 && this.m == 0.0F && this.i == null && this.k == null) { ++ double d1 = (double) this.x + 0.5D; ++ ++ d0 = (double) this.z + 0.5D; ++ if (this.l != null) { ++ d0 += 0.5D; ++ } ++ ++ if (this.j != null) { ++ d1 += 0.5D; ++ } ++ ++ this.world.makeSound(d1, (double) this.y + 0.5D, d0, "random.chestopen", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); ++ } ++ // PaperSpigot end ++ + // CraftBukkit start - Call redstone event + if (this.q() == Blocks.TRAPPED_CHEST) { + int newPower = Math.max(0, Math.min(15, this.o)); +@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { + if (this.world == null) return; // CraftBukkit + this.world.playBlockAction(this.x, this.y, this.z, this.q(), 1, this.o); + ++ // PaperSpigot start - Move chest close sound handling down here ++ this.i(); ++ double d0; ++ ++ if (this.o == 0 && this.i == null && this.k == null) { ++ d0 = (double) this.x + 0.5D; ++ double d2 = (double) this.z + 0.5D; ++ ++ if (this.l != null) { ++ d2 += 0.5D; ++ } ++ ++ if (this.j != null) { ++ d0 += 0.5D; ++ } ++ ++ this.world.makeSound(d0, (double) this.y + 0.5D, d2, "random.chestclosed", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); ++ } ++ // PaperSpigot end ++ + // CraftBukkit start - Call redstone event + if (this.q() == Blocks.TRAPPED_CHEST) { + int newPower = Math.max(0, Math.min(15, this.o)); +-- \ No newline at end of file diff --git a/Spigot-Server-Patches/Move-sound-handling-out-of-the-chest-tick-loop.patch b/Spigot-Server-Patches/Move-sound-handling-out-of-the-chest-tick-loop.patch deleted file mode 100644 index a9c63f543e..0000000000 --- a/Spigot-Server-Patches/Move-sound-handling-out-of-the-chest-tick-loop.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown <1254957+zachbr@users.noreply.github.com> -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 -noticeable difference to players - -diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityChest.java -+++ b/src/main/java/net/minecraft/server/TileEntityChest.java -@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { - } - - this.n = this.m; -+ -+ // PaperSpigot start - Move chest sound handling out of the tick loop -+ /* - f = 0.1F; - double d0; - -@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { - this.m = 0.0F; - } - } -+ */ -+ // PaperSpigot end - } - - public boolean c(int i, int j) { -@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { - if (this.world == null) return; // CraftBukkit - this.world.playBlockAction(this.x, this.y, this.z, this.q(), 1, this.o); - -+ // PaperSpigot start - Move chest open sound handling down to here -+ this.i(); -+ double d0; -+ -+ if (this.o > 0 && this.m == 0.0F && this.i == null && this.k == null) { -+ double d1 = (double) this.x + 0.5D; -+ -+ d0 = (double) this.z + 0.5D; -+ if (this.l != null) { -+ d0 += 0.5D; -+ } -+ -+ if (this.j != null) { -+ d1 += 0.5D; -+ } -+ -+ this.world.makeSound(d1, (double) this.y + 0.5D, d0, "random.chestopen", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); -+ } -+ // PaperSpigot end -+ - // CraftBukkit start - Call redstone event - if (this.q() == Blocks.TRAPPED_CHEST) { - int newPower = Math.max(0, Math.min(15, this.o)); -@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { - if (this.world == null) return; // CraftBukkit - this.world.playBlockAction(this.x, this.y, this.z, this.q(), 1, this.o); - -+ // PaperSpigot start - Move chest close sound handling down to here -+ this.i(); -+ double d0; -+ -+ if (this.o == 0 && this.i == null && this.k == null) { -+ d0 = (double) this.x + 0.5D; -+ double d2 = (double) this.z + 0.5D; -+ -+ if (this.l != null) { -+ d2 += 0.5D; -+ } -+ -+ if (this.j != null) { -+ d0 += 0.5D; -+ } -+ -+ this.world.makeSound(d0, (double) this.y + 0.5D, d2, "random.chestclosed", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); -+ } -+ // PaperSpigot end -+ - // CraftBukkit start - Call redstone event - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityEnderChest.java -+++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java -@@ -0,0 +0,0 @@ public class TileEntityEnderChest extends TileEntity { - } - - this.i = this.a; -+ -+ // PaperSpigot start - Move chest sound handling out of the tick loop -+ /* - float f = 0.1F; - double d0; - -@@ -0,0 +0,0 @@ public class TileEntityEnderChest extends TileEntity { - this.a = 0.0F; - } - } -+ */ -+ // PaperSpigot end - } - - public boolean c(int i, int j) { -@@ -0,0 +0,0 @@ public class TileEntityEnderChest extends TileEntity { - public void a() { - ++this.j; - this.world.playBlockAction(this.x, this.y, this.z, Blocks.ENDER_CHEST, 1, this.j); -+ -+ // PaperSpigot start - Move chest open sound handling down to here -+ double d0; -+ -+ if (this.j > 0 && this.a == 0.0F) { -+ double d1 = (double) this.x + 0.5D; -+ -+ d0 = (double) this.z + 0.5D; -+ this.world.makeSound(d1, (double) this.y + 0.5D, d0, "random.chestopen", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); -+ } -+ // PaperSpigot end - } - - public void b() { - --this.j; - this.world.playBlockAction(this.x, this.y, this.z, Blocks.ENDER_CHEST, 1, this.j); -+ -+ // PaperSpigot start - Move chest close sound handling down to here -+ float f = 0.1F; -+ double d0; -+ -+ if (this.j == 0 && this.a == 0.0F || this.j > 0 && this.a < 1.0F) { -+ float f1 = this.a; -+ d0 = (double) this.x + 0.5D; -+ double d2 = (double) this.z + 0.5D; -+ -+ this.world.makeSound(d0, (double) this.y + 0.5D, d2, "random.chestclosed", 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); -+ -+ if (this.a < 0.0F) { -+ this.a = 0.0F; -+ } -+ } -+ // PaperSpigot end - } - - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java -+++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java -@@ -0,0 +0,0 @@ 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); - - // Slow things down that players won't notice due to craftbukkit "wall time" patches. --- \ No newline at end of file diff --git a/Spigot-Server-Patches/Optimize-TileEntity-ticking.patch b/Spigot-Server-Patches/Optimize-TileEntity-ticking.patch deleted file mode 100644 index 00bb3d8741..0000000000 --- a/Spigot-Server-Patches/Optimize-TileEntity-ticking.patch +++ /dev/null @@ -1,428 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -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. - -This allows the server to skip buckets of Tile Entities that is known to -not have any tick function (half of them), skipping time spent iterating -them and checking if they are valid and in a loaded chunk. In other words, -a lot of "meta" time wasted on tile entities that would never do anything anyways. - -This change also adds control into the interval of every TileEntity, giving -the server owner control on how fast a TileEntity ticks, slowing it down if they must -(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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/Chunk.java -+++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -0,0 +0,0 @@ public class Chunk { - public final int locX; - public final int locZ; - private boolean w; -+ public org.github.paperspigot.ChunkTileEntityList tileEntityTickList; // PaperSpigot - public Map tileEntities; - public List[] entitySlices; - public boolean done; -@@ -0,0 +0,0 @@ public class Chunk { - this.b = new int[256]; - this.c = new boolean[256]; - this.tileEntities = new HashMap(); -+ tileEntityTickList = new org.github.paperspigot.ChunkTileEntityList(world); // PaperSpigot - this.x = 4096; - this.entitySlices = new List[16]; - this.world = world; -@@ -0,0 +0,0 @@ public class Chunk { - } - // Spigot End - -- this.world.a(tileentity); -+ // 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntity.java -+++ b/src/main/java/net/minecraft/server/TileEntity.java -@@ -0,0 +0,0 @@ public class TileEntity { - } - // Spigot end - -+ // 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityBeacon.java -+++ b/src/main/java/net/minecraft/server/TileEntityBeacon.java -@@ -0,0 +0,0 @@ public class TileEntityBeacon extends TileEntity implements IInventory { - public TileEntityBeacon() {} - - public void h() { -- if (this.world.getTime() % 80L == 0L) { -+ // if (this.world.getTime() % 80L == 0L) { // PaperSpigot - controlled by Improved Tick handling - this.y(); - this.x(); -- } -+ // } // PaperSpigot - } - - private void x() { -diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityChest.java -+++ b/src/main/java/net/minecraft/server/TileEntityChest.java -@@ -0,0 +0,0 @@ public class TileEntityChest extends TileEntity implements IInventory { - ++this.ticks; - float f; - -- if (!this.world.isStatic && this.o != 0 && (this.ticks + this.x + this.y + this.z) % 200 == 0) { -+ if (!this.world.isStatic && this.o != 0 && (this.ticks + this.x + this.y + this.z) % 10 == 0) { // PaperSpigot Reduced 200 -> 10 interval due to reduced tick rate from Improved Tick Handling - this.o = 0; - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityEnderChest.java -+++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java -@@ -0,0 +0,0 @@ public class TileEntityEnderChest extends TileEntity { - - 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 - this.world.playBlockAction(this.x, this.y, this.z, Blocks.ENDER_CHEST, 1, this.j); - } - -diff --git a/src/main/java/net/minecraft/server/TileEntityLightDetector.java b/src/main/java/net/minecraft/server/TileEntityLightDetector.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/TileEntityLightDetector.java -+++ b/src/main/java/net/minecraft/server/TileEntityLightDetector.java -@@ -0,0 +0,0 @@ public class TileEntityLightDetector extends TileEntity { - public TileEntityLightDetector() {} - - public void h() { -- if (this.world != null && !this.world.isStatic && this.world.getTime() % 20L == 0L) { -+ if (this.world != null && !this.world.isStatic /*&& this.world.getTime() % 20L == 0L*/) { // PaperSpigot - interval controlled by Improved Tick Handling - this.h = this.q(); - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - }; - // Spigot end - protected List f = new ArrayList(); -- public Set tileEntityList = new HashSet(); // CraftBukkit - ArrayList -> HashSet -+ 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(); -@@ -0,0 +0,0 @@ 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(); -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - - if (tileentity.r()) { - iterator.remove(); -- if (this.isChunkLoaded(tileentity.x >> 4, tileentity.z >> 4)) { -+ // if (this.isChunkLoaded(tileentity.x >> 4, tileentity.z >> 4)) { // PaperSpigot - will always be loaded - Chunk chunk = this.getChunkAt(tileentity.x >> 4, tileentity.z >> 4); - - if (chunk != null) { - chunk.f(tileentity.x & 15, tileentity.y, tileentity.z & 15); - } -- } -+ // } // PaperSpigot - } - } - -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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java -@@ -0,0 +0,0 @@ -+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.Iterator; -+import java.util.List; -+import java.util.Map; -+ -+public class ChunkTileEntityList { -+ final Map, ListMultimap> tickList = Maps.newHashMap(); -+ -+ private static final TObjectIntHashMap> tileEntityTickIntervals = -+ new TObjectIntHashMap>() {{ -+ // Use 0 for no ticking -+ // These TE's have empty tick methods, doing nothing. Never bother ticking them. -+ for (Class 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); -+ -+ // 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); -+ }}; -+ -+ public static Integer getInterval(Class cls) { -+ Integer tickInterval = tileEntityTickIntervals.get(cls); -+ return tickInterval != null ? tickInterval : 1; -+ } -+ -+ private final World world; -+ -+ public ChunkTileEntityList(World world) { -+ this.world = world; -+ } -+ -+ public Iterator iterator() { -+ return new ChunkTileEntityIterator(); -+ } -+ -+ public boolean add(TileEntity entity) { -+ entity.isAdded = true; -+ int bucket = getBucketId(entity); -+ ListMultimap typeBucket = getBucket(entity); -+ return typeBucket.put(bucket, entity); -+ } -+ -+ public boolean remove(TileEntity entity) { -+ if (!entity.isAdded) { -+ return false; -+ } -+ entity.isAdded = false; -+ int bucket = getBucketId(entity); -+ ListMultimap typeBucket = getBucket(entity); -+ return typeBucket.remove(bucket, entity); -+ } -+ -+ private ListMultimap getBucket(TileEntity entity) { -+ final Class cls = entity.getClass(); -+ -+ ListMultimap 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, ListMultimap>> typeIterator; -+ Map.Entry, ListMultimap> curType = null; -+ Iterator listIterator = null; -+ -+ { -+ typeIterator = tickList.entrySet().iterator(); -+ nextType(); -+ } -+ -+ private boolean nextType() { -+ if (typeIterator.hasNext()) { -+ curType = typeIterator.next(); -+ -+ final ListMultimap buckets = curType.getValue(); -+ -+ final Integer interval = getInterval(curType.getKey()); -+ int bucket = (int) (world.getTime() % interval); -+ final List tileList = buckets.get(bucket); -+ if (tileList != null && !tileList.isEmpty()) { -+ listIterator = tileList.iterator(); -+ } else { -+ listIterator = null; -+ } -+ return true; -+ } else { -+ curType = null; -+ listIterator = null; -+ return false; -+ } -+ } -+ -+ @Override -+ public boolean hasNext() { -+ do { -+ if (listIterator != null && listIterator.hasNext()) { -+ return true; -+ } -+ } while (nextType()); -+ return false; -+ } -+ -+ @Override -+ public Object next() { -+ return listIterator.next(); -+ } -+ -+ @Override -+ public void remove() { -+ listIterator.remove(); -+ } -+ } -+} -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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/org/github/paperspigot/WorldTileEntityList.java -@@ -0,0 +0,0 @@ -+package org.github.paperspigot; -+ -+import com.google.common.collect.Sets; -+import net.minecraft.server.Chunk; -+import net.minecraft.server.TileEntity; -+import net.minecraft.server.World; -+import net.minecraft.server.WorldServer; -+ -+import java.util.HashSet; -+import java.util.Iterator; -+import java.util.Set; -+ -+public class WorldTileEntityList extends HashSet { -+ final Set tickList = Sets.newHashSet(); -+ private final WorldServer world; -+ -+ public WorldTileEntityList(World world) { -+ this.world = (WorldServer) world; -+ } -+ -+ /** -+ * Adds the TileEntity to the tick list only if it is expected to tick -+ */ -+ @Override -+ public boolean add(Object o) { -+ return o instanceof TileEntity && ChunkTileEntityList.getInterval(((TileEntity)o).getClass()) > 0 && add((TileEntity) o); -+ } -+ -+ private boolean add(TileEntity entity) { -+ if (entity.isAdded) { -+ return false; -+ } -+ -+ Chunk chunk = world.getChunkIfLoaded(entity.x >> 4, entity.z >> 4); -+ return chunk != null && chunk.tileEntityTickList.add(entity); -+ } -+ -+ @Override -+ public boolean remove(Object o) { -+ if (!(o instanceof TileEntity)) { -+ return false; -+ } -+ TileEntity entity = (TileEntity) o; -+ Chunk chunk = world.getChunkIfLoaded(entity.x >> 4, entity.z >> 4); -+ if (chunk != null) { -+ return chunk.tileEntityTickList.remove(entity); -+ } -+ return true; -+ } -+ -+ @Override -+ public Iterator iterator() { -+ return new WorldTileEntityIterator(); -+ } -+ -+ @Override -+ public boolean contains(Object o) { -+ return o instanceof TileEntity && ((TileEntity) o).isAdded; -+ } -+ -+ private class WorldTileEntityIterator implements Iterator { -+ Iterator chunkIterator; -+ Iterator chunkTileEntityListIterator; -+ -+ { -+ chunkIterator = world.chunkProviderServer.chunks.values().iterator(); -+ nextChunk(); -+ } -+ -+ private boolean nextChunk() { -+ if (chunkIterator.hasNext()) { -+ final Chunk chunk = chunkIterator.next(); -+ // Skip chunks queued for unload, and save isLoaded checks -+ if (!world.chunkProviderServer.unloadQueue.contains(chunk.locX, chunk.locZ)) { -+ chunkTileEntityListIterator = chunk.tileEntityTickList.iterator(); -+ } else { -+ chunkTileEntityListIterator = null; -+ } -+ return true; -+ } else { -+ chunkTileEntityListIterator = null; -+ return false; -+ } -+ } -+ -+ @Override -+ public boolean hasNext() { -+ do { -+ if (chunkTileEntityListIterator != null && chunkTileEntityListIterator.hasNext()) { -+ return true; -+ } -+ } while (nextChunk()); -+ return false; -+ } -+ -+ @Override -+ public Object next() { -+ return chunkTileEntityListIterator.next(); -+ } -+ -+ @Override -+ public void remove() { -+ chunkTileEntityListIterator.remove(); -+ } -+ } -+} --- \ No newline at end of file