diff --git a/Spigot-Server-Patches/Optimize-entity-list-iteration-requiring-entities-be.patch b/Spigot-Server-Patches/Optimize-entity-list-iteration-requiring-entities-be.patch deleted file mode 100644 index 22f015454..000000000 --- a/Spigot-Server-Patches/Optimize-entity-list-iteration-requiring-entities-be.patch +++ /dev/null @@ -1,232 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 5 May 2020 19:49:23 -0700 -Subject: [PATCH] Optimize entity list iteration requiring entities be in - loaded chunks - -We retain a list of loaded entities specifically for this usage - -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 implements IChunkAccess { - entity.chunkZ = this.loc.z; - this.entities.add(entity); // Paper - per chunk entity list - this.entitySlices[k].add(entity); if (entity.hardCollides()) this.hardCollidingEntities[k].add(entity); // Paper - optimise hard colliding entities -+ // Paper start - world loaded entity list -+ if (this.loadedTicketLevel) { -+ ((WorldServer)this.world).loadedEntities.add(entity); -+ } else { -+ ((WorldServer)this.world).loadedEntities.remove(entity); -+ } -+ // Paper end - world loaded entity list - // Paper start - if (entity instanceof EntityItem) { - itemCounts[k]++; -@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { - if (entity.hardCollides()) this.hardCollidingEntities[i].remove(entity); if (!this.entitySlices[i].remove(entity)) { // Paper - optimise hard colliding entities - return; - } -+ // Paper start - world loaded entity list -+ ((WorldServer)this.world).loadedEntities.remove(entity); -+ // Paper end - world loaded entity list - if (entity instanceof EntityItem) { - itemCounts[i]--; - } else if (entity instanceof IInventory) { -@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { - this.setNeighbourLoaded(0, 0, this); - this.loadedTicketLevel = true; - // Paper end - neighbour cache -+ ((WorldServer)this.world).onChunkLoad(this); // Paper - optimise entity list iteration - org.bukkit.Server server = this.world.getServer(); - ((WorldServer)this.world).getChunkProvider().addLoadedChunk(this); // Paper - if (server != null) { -@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { - this.loadedTicketLevel = false; - this.resetNeighbours(); - // Paper end -+ ((WorldServer)this.world).onChunkUnload(this); // Paper - optimise entity list iteration - } - // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/WorldServer.java -+++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - } - // Paper end - rewrite ticklistserver - -+ // Paper start - Optimize entity list iteration requiring entities be in loaded chunks -+ public final com.destroystokyo.paper.util.maplist.EntityList loadedEntities = new com.destroystokyo.paper.util.maplist.EntityList(); -+ void onChunkLoad(final Chunk chunk) { -+ final com.destroystokyo.paper.util.maplist.EntityList list = chunk.entities; -+ final Entity[] entities = list.getRawData(); -+ for (int i = 0, size = list.size(); i < size; ++i) { -+ this.loadedEntities.add(entities[i]); -+ } -+ } -+ -+ void onChunkUnload(final Chunk chunk) { -+ final com.destroystokyo.paper.util.maplist.EntityList list = chunk.entities; -+ final Entity[] entities = list.getRawData(); -+ for (int i = 0, size = list.size(); i < size; ++i) { -+ this.loadedEntities.remove(entities[i]); -+ } -+ } -+ // Paper end - Optimize entity list iteration requiring entities be in loaded chunks -+ - // Add env and gen to constructor - public WorldServer(MinecraftServer minecraftserver, Executor executor, WorldNBTStorage worldnbtstorage, WorldData worlddata, DimensionManager dimensionmanager, GameProfilerFiller gameprofilerfiller, WorldLoadListener worldloadlistener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { - super(worlddata, dimensionmanager, (world, worldprovider) -> { -@@ -0,0 +0,0 @@ public class WorldServer extends World { - - gameprofilerfiller.exitEnter("regular"); - this.tickingEntities = true; -- ObjectIterator objectiterator = this.entitiesById.int2ObjectEntrySet().iterator(); -+ Iterator entityiterator = this.loadedEntities.iterator(); // Paper - use loaded entity list - change var name to compile fail on usage change, we need to hook remove() calls here - - org.spigotmc.ActivationRange.activateEntities(this); // Spigot - timings.entityTick.startTiming(); // Spigot - TimingHistory.entityTicks += this.globalEntityList.size(); // Paper -- while (objectiterator.hasNext()) { -- Entry entry = (Entry) objectiterator.next(); -- Entity entity1 = (Entity) entry.getValue(); -+ while (entityiterator.hasNext()) { // Paper - use loaded entity list -+ Entity entity1 = entityiterator.next(); // Paper - use loaded entity list - Entity entity2 = entity1.getVehicle(); - - /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed -@@ -0,0 +0,0 @@ public class WorldServer extends World { - gameprofilerfiller.enter("remove"); - if (entity1.dead) { - this.removeEntityFromChunk(entity1); -- objectiterator.remove(); -+ entityiterator.remove(); this.entitiesById.remove(entity1.getId()); // Paper - use loaded entity list - this.unregisterEntity(entity1); - } - -@@ -0,0 +0,0 @@ public class WorldServer extends World { - if (entity instanceof EntityInsentient) { - this.navigators.remove(((EntityInsentient) entity).getNavigation()); - } -+ this.loadedEntities.remove(entity); // Paper - loaded entity list - new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid - entity.valid = false; // CraftBukkit - } -@@ -0,0 +0,0 @@ public class WorldServer extends World { - } - // Paper end - entity.shouldBeRemoved = false; // Paper - shouldn't be removed after being re-added -+ // Paper start - loaded entity list -+ if (this.isChunkLoaded(net.minecraft.server.MCUtil.getChunkCoordinate(entity.locX()), net.minecraft.server.MCUtil.getChunkCoordinate(entity.locZ()))) { -+ this.loadedEntities.add(entity); -+ } -+ // Paper end - loaded entity list - new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - - @Override - public List getEntities() { -- List list = new ArrayList(); -+ List list = new ArrayList(world.loadedEntities.size()); // Paper - optimize this call - -- for (Object o : world.entitiesById.values()) { -+ for (Object o : world.loadedEntities) { // Paper - optimize this call - if (o instanceof net.minecraft.server.Entity) { - net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o; - if (mcEnt.shouldBeRemoved) continue; // Paper - Entity bukkitEntity = mcEnt.getBukkitEntity(); - - // Assuming that bukkitEntity isn't null -- if (bukkitEntity != null && bukkitEntity.isValid()) { -+ if (bukkitEntity != null && CraftEntity.canBeSeenByPlugins(bukkitEntity)) { // Paper - optimize this call - list.add(bukkitEntity); - } - } -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - - @Override - public List getLivingEntities() { -- List list = new ArrayList(); -+ List list = new ArrayList(world.loadedEntities.size()); // Paper - optimize this call - -- for (Object o : world.entitiesById.values()) { -+ for (Object o : world.loadedEntities) { // Paper - optimize this call - if (o instanceof net.minecraft.server.Entity) { - net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o; - if (mcEnt.shouldBeRemoved) continue; // Paper - Entity bukkitEntity = mcEnt.getBukkitEntity(); - - // Assuming that bukkitEntity isn't null -- if (bukkitEntity != null && bukkitEntity instanceof LivingEntity && bukkitEntity.isValid()) { -+ if (bukkitEntity != null && bukkitEntity instanceof LivingEntity && CraftEntity.canBeSeenByPlugins(bukkitEntity)) { // Paper - optimize this call - list.add((LivingEntity) bukkitEntity); - } - } -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - public Collection getEntitiesByClass(Class clazz) { - Collection list = new ArrayList(); - -- for (Object entity: world.entitiesById.values()) { -+ for (Object entity: world.loadedEntities) { // Paper - optimize this call - if (entity instanceof net.minecraft.server.Entity) { - if (((net.minecraft.server.Entity) entity).shouldBeRemoved) continue; // Paper - Entity bukkitEntity = ((net.minecraft.server.Entity) entity).getBukkitEntity(); -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - - Class bukkitClass = bukkitEntity.getClass(); - -- if (clazz.isAssignableFrom(bukkitClass) && bukkitEntity.isValid()) { -+ if (clazz.isAssignableFrom(bukkitClass) && CraftEntity.canBeSeenByPlugins(bukkitEntity)) { // Paper - optimize this call - list.add((T) bukkitEntity); - } - } -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - public Collection getEntitiesByClasses(Class... classes) { - Collection list = new ArrayList(); - -- for (Object entity: world.entitiesById.values()) { -+ for (Object entity: world.loadedEntities) { // Paper - optimize this call - if (entity instanceof net.minecraft.server.Entity) { - if (((net.minecraft.server.Entity) entity).shouldBeRemoved) continue; // Paper - Entity bukkitEntity = ((net.minecraft.server.Entity) entity).getBukkitEntity(); -@@ -0,0 +0,0 @@ public class CraftWorld implements World { - - for (Class clazz : classes) { - if (clazz.isAssignableFrom(bukkitClass)) { -- if (bukkitEntity.isValid()) { -+ if (CraftEntity.canBeSeenByPlugins(bukkitEntity)) { // Paper - optimize this call - list.add(bukkitEntity); - } - break; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -0,0 +0,0 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - this.entity = entity; - } - -+ // Paper start -+ // note: this does not check isChunkLoaded, use Entity#isValid to do that -+ public static boolean canBeSeenByPlugins(org.bukkit.entity.Entity entity) { -+ Entity handle = ((CraftEntity)entity).getHandle(); -+ // TODO -+ // isAlive is a dumb choice, given living entities aren't alive (but are in the world) if health < 0 -+ // this needs to be brought up to spigot to fix though, we are NOT breaking api implementation, especially -+ // if no-one's complained. -+ return !handle.shouldBeRemoved && handle.isAlive() && handle.valid; -+ } -+ // Paper end -+ - @Override - public Chunk getChunk() { - net.minecraft.server.Chunk currentChunk = entity.getCurrentChunk(); diff --git a/Spigot-Server-Patches/Use-distance-map-to-optimise-entity-tracker.patch b/Spigot-Server-Patches/Use-distance-map-to-optimise-entity-tracker.patch index fef1ec5b3..b5c1702cd 100644 --- a/Spigot-Server-Patches/Use-distance-map-to-optimise-entity-tracker.patch +++ b/Spigot-Server-Patches/Use-distance-map-to-optimise-entity-tracker.patch @@ -181,15 +181,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private final void processTrackQueue() { + this.world.timings.tracker1.startTiming(); + try { -+ Entity[] entities = this.world.loadedEntities.getRawData(); -+ for (int i = 0, len = this.world.loadedEntities.size(); i < len; ++i) { -+ Entity tracked = entities[i]; ++ for (EntityTracker tracker : this.trackedEntities.values()) { + // update tracker entry -+ EntityTracker tracker = this.trackedEntities.get(tracked.getId()); -+ if (tracker == null) { -+ continue; -+ } -+ tracker.updatePlayers(tracked.getPlayersInTrackRange()); ++ tracker.updatePlayers(tracker.tracker.getPlayersInTrackRange()); + } + } finally { + this.world.timings.tracker1.stopTiming(); @@ -198,13 +192,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + this.world.timings.tracker2.startTiming(); + try { -+ Entity[] entities = this.world.loadedEntities.getRawData(); -+ for (int i = 0, len = this.world.loadedEntities.size(); i < len; ++i) { -+ Entity tracked = entities[i]; -+ EntityTracker tracker = this.trackedEntities.get(tracked.getId()); -+ if (tracker != null) { -+ tracker.trackerEntry.tick(); -+ } ++ for (EntityTracker tracker : this.trackedEntities.values()) { ++ tracker.trackerEntry.tick(); + } + } finally { + this.world.timings.tracker2.stopTiming();