Temporarily remove optimized tile entity code

Potential CME's and issues with pistons, we'll work through this on a separate branch and re-add it when appropriate
This commit is contained in:
Zach Brown 2014-08-13 16:50:24 -05:00
parent 20b21ebf3d
commit 8567c11cb9
3 changed files with 82 additions and 599 deletions

View file

@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Iceee <andrew@opticgaming.tv>
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));
--

View file

@ -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.
--

View file

@ -1,428 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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<Class<? extends TileEntity>, ListMultimap<Integer, TileEntity>> tickList = Maps.newHashMap();
+
+ 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);
+
+ // 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<? extends TileEntity> 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<Integer, TileEntity> 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<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<? extends TileEntity>, ListMultimap<Integer, TileEntity>>> typeIterator;
+ Map.Entry<Class <? extends TileEntity>, ListMultimap<Integer, TileEntity>> curType = null;
+ Iterator<TileEntity> listIterator = null;
+
+ {
+ typeIterator = tickList.entrySet().iterator();
+ nextType();
+ }
+
+ private boolean nextType() {
+ if (typeIterator.hasNext()) {
+ curType = typeIterator.next();
+
+ 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;
+ }
+ 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<ChunkTileEntityList> 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<Chunk> chunkIterator;
+ Iterator<ChunkTileEntityList> 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();
+ }
+ }
+}
--