From 31d35e76aca5f197cb900872bc0d879dd4c20c7b Mon Sep 17 00:00:00 2001 From: Zach Brown 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 -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 tickList = ArrayListMultimap.create(); ++ 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); -+ } ++ 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); ++ // 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 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 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 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>> typeIterator; -+ Map.Entry> curType = null; ++ Iterator, ListMultimap>> typeIterator; ++ Map.Entry, ListMultimap> curType = null; + Iterator 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 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; + } @@ -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 -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