Update TileEntity optimizations (again again) ...

hopefully less often now
This commit is contained in:
Zach Brown 2014-08-11 23:07:39 -05:00
parent eefd5936bb
commit 20b21ebf3d
2 changed files with 114 additions and 70 deletions

View file

@ -1,6 +1,6 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <1254957+zachbr@users.noreply.github.com> From: Zach Brown <1254957+zachbr@users.noreply.github.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 Subject: [PATCH] Move sound handling out of the chest tick loop
This allows us to disable ticking chests and enderchests without any This allows us to disable ticking chests and enderchests without any
@ -151,21 +151,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java --- a/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
+++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java +++ b/src/main/java/org/github/paperspigot/ChunkTileEntityList.java
@@ -0,0 +0,0 @@ public class ChunkTileEntityList { @@ -0,0 +0,0 @@ public class ChunkTileEntityList {
TileEntityCommand.class, TileEntityCommand.class,
TileEntitySkull.class, TileEntitySkull.class,
TileEntityComparator.class, TileEntityComparator.class,
- TileEntityFlowerPot.class - TileEntityFlowerPot.class
+ TileEntityFlowerPot.class, + TileEntityFlowerPot.class,
+ TileEntityChest.class, + TileEntityChest.class,
+ TileEntityEnderChest.class + TileEntityEnderChest.class
}) { }) {
put(ignored, 0); put(ignored, 0);
} }
// does findPlayer lookup, so this helps performance to slow down // does findPlayer lookup, so this helps performance to slow down
- put(TileEntityChest.class, 20); - put(TileEntityChest.class, 20);
- put(TileEntityEnderChest.class, 20); - put(TileEntityEnderChest.class, 20);
put(TileEntityEnchantTable.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.
-- --

View file

@ -1,6 +1,6 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> 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 Subject: [PATCH] Optimize TileEntity ticking
Re-organizes the servers TileEntity Tick List to be bucketed by type. Re-organizes the servers TileEntity Tick List to be bucketed by type.
@ -39,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Spigot End // Spigot End
- this.world.a(tileentity); - 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) { for (int i = 0; i < this.entitySlices.length; ++i) {
@ -48,13 +48,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/TileEntity.java --- a/src/main/java/net/minecraft/server/TileEntity.java
+++ b/src/main/java/net/minecraft/server/TileEntity.java +++ b/src/main/java/net/minecraft/server/TileEntity.java
@@ -0,0 +0,0 @@ public class TileEntity { @@ -0,0 +0,0 @@ public class TileEntity {
}
// Spigot end
public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot + // PaperSpigot start - Optimized TileEntity Tick changes
private static final Logger a = LogManager.getLogger(); + private static int tileEntityCounter = 0;
+ public boolean isAdded = false; // PaperSpigot - optimize contains checks + public boolean isAdded = false;
private static Map i = new HashMap(); + public int tileId = tileEntityCounter++;
private static Map j = new HashMap(); + //PaperSpigot end
protected World world; +
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 diff --git a/src/main/java/net/minecraft/server/TileEntityBeacon.java b/src/main/java/net/minecraft/server/TileEntityBeacon.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/TileEntityBeacon.java --- a/src/main/java/net/minecraft/server/TileEntityBeacon.java
@ -94,7 +99,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public void h() { public void h() {
super.h(); super.h();
- if (++this.k % 20 * 4 == 0) { - 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); this.world.playBlockAction(this.x, this.y, this.z, Blocks.ENDER_CHEST, 1, this.j);
} }
@ -120,11 +125,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Spigot end // Spigot end
protected List f = new ArrayList(); protected List f = new ArrayList();
- public Set tileEntityList = new HashSet(); // CraftBukkit - ArrayList -> HashSet - 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 a = new ArrayList();
private List b = new ArrayList(); private List b = new ArrayList();
public List players = new ArrayList(); public List players = new ArrayList();
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { @@ -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()) { if (tileentity.r()) {
iterator.remove(); iterator.remove();
@ -150,50 +164,52 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap; +import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import net.minecraft.server.*; +import net.minecraft.server.*;
+import net.minecraft.util.gnu.trove.map.hash.TObjectIntHashMap; +import net.minecraft.util.gnu.trove.map.hash.TObjectIntHashMap;
+ +
+import java.util.Collection;
+import java.util.Iterator; +import java.util.Iterator;
+import java.util.List;
+import java.util.Map; +import java.util.Map;
+ +
+public class ChunkTileEntityList { +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>() {{ + private static final TObjectIntHashMap<Class<? extends TileEntity>> tileEntityTickIntervals =
+ // Use 0 for no ticking + new TObjectIntHashMap<Class<? extends TileEntity>>() {{
+ // These TE's have empty tick methods, doing nothing. Never bother ticking them. + // Use 0 for no ticking
+ for (Class<? extends TileEntity> ignored : new Class[]{ + // These TE's have empty tick methods, doing nothing. Never bother ticking them.
+ TileEntityRecordPlayer.class, + for (Class<? extends TileEntity> ignored : new Class[]{
+ TileEntityDispenser.class, + TileEntityRecordPlayer.class,
+ TileEntityDropper.class, + TileEntityDispenser.class,
+ TileEntitySign.class, + TileEntityDropper.class,
+ TileEntityNote.class, + TileEntitySign.class,
+ TileEntityEnderPortal.class, + TileEntityNote.class,
+ TileEntityCommand.class, + TileEntityEnderPortal.class,
+ TileEntitySkull.class, + TileEntityCommand.class,
+ TileEntityComparator.class, + TileEntitySkull.class,
+ TileEntityFlowerPot.class + TileEntityComparator.class,
+ }) { + TileEntityFlowerPot.class
+ put(ignored, 0); + }) {
+ } + put(ignored, 0);
+ }
+ +
+ // does findPlayer lookup, so this helps performance to slow down + // does findPlayer lookup, so this helps performance to slow down
+ put(TileEntityChest.class, 20); + put(TileEntityChest.class, 20);
+ put(TileEntityEnderChest.class, 20); + put(TileEntityEnderChest.class, 20);
+ put(TileEntityEnchantTable.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.
+ put(TileEntityFurnace.class, 10); + put(TileEntityFurnace.class, 10);
+ put(TileEntityBrewingStand.class, 10); + put(TileEntityBrewingStand.class, 10);
+ +
+ // Vanilla controlled values - These are checks already done in vanilla, so don't tick on ticks we know + // Vanilla controlled values - These are checks already done in vanilla, so don't tick on ticks we know
+ // won't do anything anyways + // won't do anything anyways
+ put(TileEntityBeacon.class, 80); + put(TileEntityBeacon.class, 80);
+ put(TileEntityLightDetector.class, 20); + put(TileEntityLightDetector.class, 20);
+ }}; + }};
+ +
+ public static Integer getInterval(Class cls) { + public static Integer getInterval(Class<? extends TileEntity> cls) {
+ Integer tickInterval = tileEntityTickIntervals.get(cls); + Integer tickInterval = tileEntityTickIntervals.get(cls);
+ return tickInterval != null ? tickInterval : 1; + return tickInterval != null ? tickInterval : 1;
+ } + }
@ -208,33 +224,63 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return new ChunkTileEntityIterator(); + return new ChunkTileEntityIterator();
+ } + }
+ +
+
+ public boolean add(TileEntity entity) { + public boolean add(TileEntity entity) {
+ entity.isAdded = true; + 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) { + public boolean remove(TileEntity entity) {
+ if (!entity.isAdded) {
+ return false;
+ }
+ entity.isAdded = 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 { + private class ChunkTileEntityIterator implements Iterator {
+ Iterator<Map.Entry<Class, Collection<TileEntity>>> typeIterator; + Iterator<Map.Entry<Class<? extends TileEntity>, ListMultimap<Integer, TileEntity>>> typeIterator;
+ Map.Entry<Class, Collection<TileEntity>> curType = null; + Map.Entry<Class <? extends TileEntity>, ListMultimap<Integer, TileEntity>> curType = null;
+ Iterator<TileEntity> listIterator = null; + Iterator<TileEntity> listIterator = null;
+ +
+ { + {
+ typeIterator = tickList.asMap().entrySet().iterator(); + typeIterator = tickList.entrySet().iterator();
+ nextType(); + nextType();
+ } + }
+ +
+ private boolean nextType() { + private boolean nextType() {
+ if (typeIterator.hasNext()) { + if (typeIterator.hasNext()) {
+ curType = typeIterator.next(); + curType = typeIterator.next();
+ final Integer interval = ChunkTileEntityList.getInterval(curType.getKey()); +
+ if (world.getTime() % interval != 0) { + final ListMultimap<Integer, TileEntity> buckets = curType.getValue();
+ listIterator = curType.getValue().iterator(); +
+ 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 { + } else {
+ listIterator = null; + listIterator = null;
+ } + }
@ -267,7 +313,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+} +}
\ 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 diff --git a/src/main/java/org/github/paperspigot/WorldTileEntityList.java b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -299,7 +344,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ */ + */
+ @Override + @Override
+ public boolean add(Object o) { + 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) { + private boolean add(TileEntity entity) {
@ -380,5 +425,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+} +}
\ No newline at end of file
-- --