From 4a647dc40b08e7e5fbaf804448bd02f387132f86 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Sat, 24 Oct 2015 02:20:30 -0500 Subject: [PATCH] Remove TE/E Removal Optimizations Causes pistons to eat blocks in certain circumstances, double piston extenders most notably --- ...imize-Entity-and-Tile-Entity-Removal.patch | 233 ------------------ 1 file changed, 233 deletions(-) delete mode 100644 Spigot-Server-Patches/0071-Optimize-Entity-and-Tile-Entity-Removal.patch diff --git a/Spigot-Server-Patches/0071-Optimize-Entity-and-Tile-Entity-Removal.patch b/Spigot-Server-Patches/0071-Optimize-Entity-and-Tile-Entity-Removal.patch deleted file mode 100644 index b4357d2c85..0000000000 --- a/Spigot-Server-Patches/0071-Optimize-Entity-and-Tile-Entity-Removal.patch +++ /dev/null @@ -1,233 +0,0 @@ -From 397ba6e9dffea1e1a2541596adb6b037088b645f Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 16 Oct 2015 22:14:48 -0500 -Subject: [PATCH] Optimize Entity and Tile Entity Removal - -Java's implementation of List.removeAll is extremely slow. This is -currently causing lots of TPS loss when lots of chunk unload activity -occurs, as the process iterates the removal list for every entry in the -source list, resulting in O(n^2) performance. - -This change will switch the process to instead iterate over the -removal list, and marking a boolean that its removed. - -Then, we then iterate the source list and use a compaction technique -that skips any object marked for removal. - -After all live objects are compacted down, we do a range -removal to clear out any removed objects at the end of the current list. - -This gives us O(n) performance and a much cheaper overall operation. - -Compaction technique was originally used by CyberTiger in a different -implementation. - -Finally, we remove MOST single .remove() calls, and run a 2nd compaction -after ticking in order to remove the singles. - -This also fixes a bug with Tick Position in the Tick limiter, where -previously .removeAll would shift entity index order but the tick -position was never moved to its new location. - -diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index 68126c4..3b995c5 100644 ---- a/src/main/java/net/minecraft/server/Entity.java -+++ b/src/main/java/net/minecraft/server/Entity.java -@@ -32,7 +32,12 @@ import org.bukkit.event.entity.EntityPortalEvent; - import org.bukkit.plugin.PluginManager; - // CraftBukkit end - --public abstract class Entity implements ICommandListener { -+// PaperSpigot start - Optimized TE/E Removal -+public abstract class Entity implements ICommandListener, org.github.paperspigot.OptimizedRemoveAllArrayList.Marker { -+ private boolean needsRemoved = false; -+ public boolean isToBeRemoved() { return needsRemoved; } -+ public void setRemovalState(boolean removalState) { needsRemoved = removalState; } -+ // PaperSpigot End - - // CraftBukkit start - private static final int CURRENT_LEVEL = 2; -diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java -index 3fc6450..6d13a55 100644 ---- a/src/main/java/net/minecraft/server/TileEntity.java -+++ b/src/main/java/net/minecraft/server/TileEntity.java -@@ -9,7 +9,12 @@ import org.apache.logging.log4j.Logger; - import org.spigotmc.CustomTimingsHandler; // Spigot - import org.bukkit.inventory.InventoryHolder; // CraftBukkit - --public abstract class TileEntity { -+// PaperSpigot start - Optimized TE/E Removal -+public abstract class TileEntity implements org.github.paperspigot.OptimizedRemoveAllArrayList.Marker { -+ private boolean needsRemoved = false; -+ public boolean isToBeRemoved() { return needsRemoved; } -+ public void setRemovalState(boolean removalState) { needsRemoved = removalState; } -+ // PaperSpigot end - - public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot - private static final Logger a = LogManager.getLogger(); -@@ -126,7 +131,7 @@ public abstract class TileEntity { - } - - public boolean x() { -- return this.d; -+ return this.d && !isToBeRemoved(); // PaperSpigot - Optimize TE/E Removal - } - - public void y() { -diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 13ab789..0c1ed6c 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -32,7 +32,7 @@ public abstract class World implements IBlockAccess { - private int a = 63; - protected boolean e; - // Spigot start - guard entity list from removals -- public final List entityList = new java.util.ArrayList() -+ public final List entityList = new org.github.paperspigot.OptimizedRemoveAllArrayList() // PaperSpigot - Optimized TE/E Removal - { - @Override - public Entity remove(int index) -@@ -59,7 +59,7 @@ public abstract class World implements IBlockAccess { - // Spigot end - protected final List g = Lists.newArrayList(); - //public final List h = Lists.newArrayList(); // PaperSpigot - Remove unused list -- public final List tileEntityList = Lists.newArrayList(); -+ public final List tileEntityList = new org.github.paperspigot.OptimizedRemoveAllArrayList(); // PaperSpigot - Optimized TE/E Removal - private final List b = Lists.newArrayList(); - private final List c = Lists.newArrayList(); - public final List players = Lists.newArrayList(); -@@ -1462,13 +1462,14 @@ public abstract class World implements IBlockAccess { - } - - guardEntityList = false; // Spigot -- this.entityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable -+ this.entityList.remove(entity); // CraftBukkit - Use field for loop variable // PaperSpigot - Optimized TE/E Removal - guardEntityList = true; // Spigot - this.b(entity); - } - - this.methodProfiler.b(); - } -+ this.entityList.removeAll(null); // PaperSpigot - Optimize TE/E Removal - guardEntityList = false; // Spigot - - timings.entityTick.stopTiming(); // Spigot -@@ -1524,13 +1525,14 @@ public abstract class World implements IBlockAccess { - - if (tileentity.x()) { - tilesThisCycle--; -- this.tileEntityList.remove(tileTickPosition--); -+ this.tileEntityList.remove(tileentity); // PaperSpigot - Optimized TE/E Removal - //this.h.remove(tileentity); // PaperSpigot - Remove unused list - if (this.isLoaded(tileentity.getPosition())) { - this.getChunkAtWorldCoords(tileentity.getPosition()).e(tileentity.getPosition()); - } - } - } -+ this.tileEntityList.removeAll(null); // PaperSpigot - Optimized TE/E Removal - - timings.tileEntityTick.stopTiming(); // Spigot - timings.tileEntityPending.startTiming(); // Spigot -@@ -2619,6 +2621,7 @@ public abstract class World implements IBlockAccess { - - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); -+ if (entity.isToBeRemoved()) { continue; } // PaperSpigot - Optimized TE/E Removal - - if (oclass.isAssignableFrom(entity.getClass()) && predicate.apply((T) entity)) { // CraftBukkit - fix decompile error - arraylist.add(entity); -@@ -2703,6 +2706,7 @@ public abstract class World implements IBlockAccess { - - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); -+ if (entity.isToBeRemoved()) { continue; } // PaperSpigot - Optimized TE/E Removal - // CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; -diff --git a/src/main/java/org/github/paperspigot/OptimizedRemoveAllArrayList.java b/src/main/java/org/github/paperspigot/OptimizedRemoveAllArrayList.java -new file mode 100644 -index 0000000..6d4388a ---- /dev/null -+++ b/src/main/java/org/github/paperspigot/OptimizedRemoveAllArrayList.java -@@ -0,0 +1,78 @@ -+package org.github.paperspigot; -+ -+import org.github.paperspigot.OptimizedRemoveAllArrayList.Marker; -+ -+import java.util.ArrayList; -+import java.util.Collection; -+ -+/** -+ * Improved algorithim for bulk removing entries from a list -+ * -+ * WARNING: This system only works on Identity Based lists, -+ * unlike traditional .removeAll() that operates on object equality. -+ * -+ */ -+public class OptimizedRemoveAllArrayList extends ArrayList { -+ public OptimizedRemoveAllArrayList(int initialCapacity) { -+ super(initialCapacity); -+ } -+ -+ public OptimizedRemoveAllArrayList() { -+ } -+ -+ public OptimizedRemoveAllArrayList(Collection c) { -+ super(c); -+ } -+ -+ public OptimizedRemoveAllArrayList clone() { -+ return new OptimizedRemoveAllArrayList(this); -+ } -+ -+ @Override -+ public boolean addAll(Collection c) { -+ for (T t : c) { -+ t.setRemovalState(false); -+ } -+ return super.addAll(c); -+ } -+ -+ @Override -+ public boolean add(T t) { -+ t.setRemovalState(false); -+ return super.add(t); -+ } -+ -+ @Override -+ public boolean remove(Object o) { -+ ((Marker) o).setRemovalState(true); -+ return true; -+ } -+ -+ @Override -+ public boolean removeAll(Collection c) { -+ if (c != null) { -+ for (Object o : c) { -+ ((Marker) o).setRemovalState(true); -+ } -+ } -+ -+ int size = size(); -+ int insertAt = 0; -+ -+ for (int i = 0; i < size; i++) { -+ T el = get(i); -+ -+ if (el != null && !el.isToBeRemoved()) { -+ set(insertAt++, el); -+ } -+ } -+ subList(insertAt, size).clear(); -+ -+ return size() != size; -+ } -+ -+ public interface Marker { -+ boolean isToBeRemoved(); -+ void setRemovalState(boolean removalState); -+ } -+} --- -2.6.2 -