Yatopia/patches/Tuinity/patches/server/0062-Optimise-WorldServer-n...

325 lines
17 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Thu, 9 Jul 2020 13:34:59 -0700
Subject: [PATCH] Optimise WorldServer#notify
Iterating over all of the navigators in the world is pretty expensive.
Instead, only iterate over navigators in the current region that are
eligible for repathing.
diff --git a/src/main/java/net/minecraft/server/NavigationAbstract.java b/src/main/java/net/minecraft/server/NavigationAbstract.java
index 1558c5f8256f50be6850f1d7f70eee3e8ec76496..6aec5098d346c1b7498fd8b800154cd31ce08a97 100644
--- a/src/main/java/net/minecraft/server/NavigationAbstract.java
+++ b/src/main/java/net/minecraft/server/NavigationAbstract.java
@@ -8,7 +8,7 @@ import javax.annotation.Nullable;
public abstract class NavigationAbstract {
- protected final EntityInsentient a; public Entity getEntity() { return a; } // Paper - OBFHELPER
+ protected final EntityInsentient a; public final EntityInsentient getEntity() { return a; } // Paper - OBFHELPER // Tuinity - match types
protected final World b;
@Nullable
protected PathEntity c; protected final PathEntity getCurrentPath() { return this.c; } // Paper - OBFHELPER
@@ -21,7 +21,7 @@ public abstract class NavigationAbstract {
protected long j;
protected double k;
protected float l;
- protected boolean m;
+ protected boolean m; protected final boolean needsPathRecalculation() { return this.m; } // Tuinity - OBFHELPER
protected long n;
protected PathfinderAbstract o;
private BlockPosition p;
@@ -30,6 +30,13 @@ public abstract class NavigationAbstract {
private final Pathfinder s; public Pathfinder getPathfinder() { return this.s; } // Paper - OBFHELPER
private boolean t;
+ // Tuinity start
+ public boolean isViableForPathRecalculationChecking() {
+ return !this.needsPathRecalculation() &&
+ (this.c != null && !this.c.c() && this.c.e() != 0);
+ }
+ // Tuinity end
+
public NavigationAbstract(EntityInsentient entityinsentient, World world) {
this.g = Vec3D.ORIGIN;
this.h = BaseBlockPosition.ZERO;
@@ -393,7 +400,7 @@ public abstract class NavigationAbstract {
}
public void b(BlockPosition blockposition) {
- if (this.c != null && !this.c.c() && this.c.e() != 0) {
+ if (this.c != null && !this.c.c() && this.c.e() != 0) { // Tuinity - diff on change - needed for isViableForPathRecalculationChecking()
PathPoint pathpoint = this.c.d();
Vec3D vec3d = new Vec3D(((double) pathpoint.a + this.a.locX()) / 2.0D, ((double) pathpoint.b + this.a.locY()) / 2.0D, ((double) pathpoint.c + this.a.locZ()) / 2.0D);
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index ff91f069e5f4a16c069c8a68d8cb55e9ad3627c8..58089180c730ce0bc423cdb20e86f11858543c25 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -299,17 +299,82 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
public static final class DataRegionData implements com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionData {
+ // Tuinity start - optimise notify()
+ private com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<EntityInsentient> navigators;
+ public com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<EntityInsentient> getNavigators() {
+ return this.navigators;
+ }
+
+ public boolean addToNavigators(final EntityInsentient navigator) {
+ if (this.navigators == null) {
+ this.navigators = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>();
+ }
+ return this.navigators.add(navigator);
+ }
+
+ public boolean removeFromNavigators(final EntityInsentient navigator) {
+ if (this.navigators == null) {
+ return false;
+ }
+ return this.navigators.remove(navigator);
+ }
+ // Tuinity end - optimise notify()
}
public static final class DataRegionSectionData implements com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSectionData {
+ // Tuinity start - optimise notify()
+ private com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<EntityInsentient> navigators;
+
+ public com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<EntityInsentient> getNavigators() {
+ return this.navigators;
+ }
+
+ public boolean addToNavigators(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, final EntityInsentient navigator) {
+ if (this.navigators == null) {
+ this.navigators = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>();
+ }
+ final boolean ret = this.navigators.add(navigator);
+ if (ret) {
+ final DataRegionData data = (DataRegionData)section.getRegion().regionData;
+ if (!data.addToNavigators(navigator)) {
+ throw new IllegalStateException();
+ }
+ }
+ return ret;
+ }
+
+ public boolean removeFromNavigators(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, final EntityInsentient navigator) {
+ if (this.navigators == null) {
+ return false;
+ }
+ final boolean ret = this.navigators.remove(navigator);
+ if (ret) {
+ final DataRegionData data = (DataRegionData)section.getRegion().regionData;
+ if (!data.removeFromNavigators(navigator)) {
+ throw new IllegalStateException();
+ }
+ }
+ return ret;
+ }
+ // Tuinity end - optimise notify()
+
@Override
public void removeFromRegion(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section,
final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region from) {
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
final DataRegionData fromData = (DataRegionData)from.regionData;
+ // Tuinity start - optimise notify()
+ if (sectionData.navigators != null) {
+ for (final Iterator<EntityInsentient> iterator = sectionData.navigators.unsafeIterator(com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
+ if (!fromData.removeFromNavigators(iterator.next())) {
+ throw new IllegalStateException();
+ }
+ }
+ }
+ // Tuinity end - optimise notify()
}
@Override
@@ -319,6 +384,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData;
final DataRegionData newRegionData = (DataRegionData)newRegion.regionData;
+ // Tuinity start - optimise notify()
+ if (sectionData.navigators != null) {
+ for (final Iterator<EntityInsentient> iterator = sectionData.navigators.unsafeIterator(com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
+ if (!newRegionData.addToNavigators(iterator.next())) {
+ throw new IllegalStateException();
+ }
+ }
+ }
+ // Tuinity end - optimise notify()
}
}
// Tuiniy end
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index ff9cbb830779b54af3fd3964d559b0d88376681d..c6d2ab318d711072507ce3667d07a9cdeb0d0fbe 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -970,6 +970,15 @@ public class WorldServer extends World implements GeneratorAccessSeed {
gameprofilerfiller.enter("checkDespawn");
if (!entity.dead) {
entity.checkDespawn();
+ // Tuinity start - optimise notify()
+ if (entity.inChunk && entity.valid) {
+ if (this.getChunkProvider().isInEntityTickingChunk(entity)) {
+ this.updateNavigatorsInRegion(entity);
+ }
+ } else {
+ this.removeNavigatorsFromData(entity);
+ }
+ // Tuinity end - optimise notify()
}
gameprofilerfiller.exit();
@@ -992,7 +1001,14 @@ public class WorldServer extends World implements GeneratorAccessSeed {
this.removeEntityFromChunk(entity);
this.entitiesById.remove(entity.getId()); // Tuinity
this.unregisterEntity(entity);
+ } else if (entity.inChunk && entity.valid) { // Tuinity start - optimise notify()
+ if (this.getChunkProvider().isInEntityTickingChunk(entity)) {
+ this.updateNavigatorsInRegion(entity);
+ }
+ } else {
+ this.removeNavigatorsFromData(entity);
}
+ // Tuinity end - optimise notify()
gameprofilerfiller.exit();
}
@@ -1403,6 +1419,12 @@ public class WorldServer extends World implements GeneratorAccessSeed {
int i = MathHelper.floor(entity.locX() / 16.0D);
int j = Math.min(15, Math.max(0, MathHelper.floor(entity.locY() / 16.0D))); // Paper - stay consistent with chunk add/remove behavior
int k = MathHelper.floor(entity.locZ() / 16.0D);
+ // Tuinity start
+ int oldRegionX = entity.chunkX >> this.getChunkProvider().playerChunkMap.dataRegionManager.regionChunkShift;
+ int oldRegionZ = entity.chunkZ >> this.getChunkProvider().playerChunkMap.dataRegionManager.regionChunkShift;
+ int newRegionX = i >> this.getChunkProvider().playerChunkMap.dataRegionManager.regionChunkShift;
+ int newRegionZ = k >> this.getChunkProvider().playerChunkMap.dataRegionManager.regionChunkShift;
+ // Tuinity end
if (!entity.inChunk || entity.chunkX != i || entity.chunkY != j || entity.chunkZ != k) {
// Paper start - remove entity if its in a chunk more correctly.
@@ -1412,6 +1434,12 @@ public class WorldServer extends World implements GeneratorAccessSeed {
}
// Paper end
+ // Tuinity start
+ if (oldRegionX != newRegionX || oldRegionZ != newRegionZ) {
+ this.removeNavigatorsFromData(entity);
+ }
+ // Tuinity end
+
if (entity.inChunk && this.isChunkLoaded(entity.chunkX, entity.chunkZ)) {
this.getChunkAt(entity.chunkX, entity.chunkZ).a(entity, entity.chunkY);
}
@@ -1425,6 +1453,11 @@ public class WorldServer extends World implements GeneratorAccessSeed {
} else {
this.getChunkAt(i, k).a(entity);
}
+ // Tuinity start
+ if (entity.inChunk && (oldRegionX != newRegionX || oldRegionZ != newRegionZ)) {
+ this.addNavigatorsIfPathingToRegion(entity);
+ }
+ // Tuinity end
}
this.getMethodProfiler().exit();
@@ -1887,9 +1920,64 @@ public class WorldServer extends World implements GeneratorAccessSeed {
// Tuinity end
}
new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
+ this.removeNavigatorsFromData(entity); // Tuinity - optimise notify()
entity.valid = false; // CraftBukkit
}
+ // Tuinity start - optimise notify()
+ void removeNavigatorsIfNotPathingFromRegion(Entity entity) {
+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section =
+ this.getChunkProvider().playerChunkMap.dataRegionManager.getRegionSection(entity.chunkX, entity.chunkZ);
+ if (section != null) {
+ PlayerChunkMap.DataRegionSectionData sectionData = (PlayerChunkMap.DataRegionSectionData)section.sectionData;
+ if (entity instanceof EntityInsentient) {
+ if (!((EntityInsentient)entity).getNavigation().isViableForPathRecalculationChecking()) {
+ sectionData.removeFromNavigators(section, (EntityInsentient)entity);
+ }
+ }
+ }
+ }
+
+ void removeNavigatorsFromData(Entity entity) {
+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section =
+ this.getChunkProvider().playerChunkMap.dataRegionManager.getRegionSection(entity.chunkX, entity.chunkZ);
+ if (section != null) {
+ PlayerChunkMap.DataRegionSectionData sectionData = (PlayerChunkMap.DataRegionSectionData)section.sectionData;
+ if (entity instanceof EntityInsentient) {
+ sectionData.removeFromNavigators(section, ((EntityInsentient)entity));
+ }
+ }
+ }
+
+ void addNavigatorsIfPathingToRegion(Entity entity) {
+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section =
+ this.getChunkProvider().playerChunkMap.dataRegionManager.getRegionSection(entity.chunkX, entity.chunkZ);
+ if (section != null) {
+ PlayerChunkMap.DataRegionSectionData sectionData = (PlayerChunkMap.DataRegionSectionData)section.sectionData;
+ if (entity instanceof EntityInsentient) {
+ if (((EntityInsentient)entity).getNavigation().isViableForPathRecalculationChecking()) {
+ sectionData.addToNavigators(section, ((EntityInsentient)entity));
+ }
+ }
+ }
+ }
+
+ void updateNavigatorsInRegion(Entity entity) {
+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section =
+ this.getChunkProvider().playerChunkMap.dataRegionManager.getRegionSection(entity.chunkX, entity.chunkZ);
+ if (section != null) {
+ PlayerChunkMap.DataRegionSectionData sectionData = (PlayerChunkMap.DataRegionSectionData)section.sectionData;
+ if (entity instanceof EntityInsentient) {
+ if (((EntityInsentient)entity).getNavigation().isViableForPathRecalculationChecking()) {
+ sectionData.addToNavigators(section, ((EntityInsentient)entity));
+ } else {
+ sectionData.removeFromNavigators(section, ((EntityInsentient)entity));
+ }
+ }
+ }
+ }
+ // Tuinity end - optimise notify()
+
private void registerEntity(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
// Paper start - don't double enqueue entity registration
@@ -2070,16 +2158,26 @@ public class WorldServer extends World implements GeneratorAccessSeed {
VoxelShape voxelshape1 = iblockdata1.getCollisionShape(this, blockposition);
if (VoxelShapes.c(voxelshape, voxelshape1, OperatorBoolean.NOT_SAME)) {
+ // Tuinity start - optimise notify()
+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region region = this.getChunkProvider().playerChunkMap.dataRegionManager.getRegion(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (region == null) {
+ return;
+ }
+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<EntityInsentient> navigatorsFromRegion = ((PlayerChunkMap.DataRegionData)region.regionData).getNavigators();
+ if (navigatorsFromRegion == null) {
+ return;
+ }
boolean wasTicking = this.tickingEntities; this.tickingEntities = true; // Paper
// Tuinity start
- com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator iterator = this.navigatorsForIteration.iterator();
+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<EntityInsentient> iterator = navigatorsFromRegion.iterator();
+ // Tuinity end - optimise notify()
try { // Tuinity end
while (iterator.hasNext()) {
// CraftBukkit start - fix SPIGOT-6362
NavigationAbstract navigationabstract;
try {
- navigationabstract = (NavigationAbstract) iterator.next();
+ navigationabstract = (NavigationAbstract) iterator.next().getNavigation(); // Tuinity - optimise notify
} catch (java.util.ConcurrentModificationException ex) {
// This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
// In this case we just run the update again across all the iterators as the chunk will then be loaded