338 lines
19 KiB
Diff
338 lines
19 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/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index aa1b6b692f9107ef1b5091714f1ecc8b29da9897..69b8f5dcae4ea75ea9d63c36b3f5b4383fe232f9 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -302,15 +302,81 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
public final io.papermc.paper.chunk.SingleThreadChunkRegionManager dataRegionManager;
|
|
|
|
public static final class DataRegionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionData {
|
|
+ // Paper start - optimise notify()
|
|
+ private io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigators;
|
|
+
|
|
+ public io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> getNavigators() {
|
|
+ return this.navigators;
|
|
+ }
|
|
+
|
|
+ public boolean addToNavigators(final Mob navigator) {
|
|
+ if (this.navigators == null) {
|
|
+ this.navigators = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>();
|
|
+ }
|
|
+ return this.navigators.add(navigator);
|
|
+ }
|
|
+
|
|
+ public boolean removeFromNavigators(final Mob navigator) {
|
|
+ if (this.navigators == null) {
|
|
+ return false;
|
|
+ }
|
|
+ return this.navigators.remove(navigator);
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
}
|
|
|
|
public static final class DataRegionSectionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSectionData {
|
|
|
|
+ // Paper start - optimise notify()
|
|
+ private io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigators;
|
|
+
|
|
+ public io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> getNavigators() {
|
|
+ return this.navigators;
|
|
+ }
|
|
+
|
|
+ public boolean addToNavigators(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob navigator) {
|
|
+ if (this.navigators == null) {
|
|
+ this.navigators = new io.papermc.paper.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 io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob 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;
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
+
|
|
@Override
|
|
public void removeFromRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section,
|
|
final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region from) {
|
|
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
|
|
final DataRegionData fromData = (DataRegionData)from.regionData;
|
|
+ // Paper start - optimise notify()
|
|
+ if (sectionData.navigators != null) {
|
|
+ for (final Iterator<Mob> iterator = sectionData.navigators.unsafeIterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
|
|
+ if (!fromData.removeFromNavigators(iterator.next())) {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
}
|
|
|
|
@Override
|
|
@@ -320,6 +386,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
|
|
final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData;
|
|
final DataRegionData newRegionData = (DataRegionData)newRegion.regionData;
|
|
+ // Paper start - optimise notify()
|
|
+ if (sectionData.navigators != null) {
|
|
+ for (final Iterator<Mob> iterator = sectionData.navigators.unsafeIterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
|
|
+ if (!newRegionData.addToNavigators(iterator.next())) {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 25149dde919738859f6fb6b2d0405e90d1732f2b..a7a403d34551453a1e0502fe1f7bc139f645d917 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -1122,6 +1122,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
public void tickNonPassenger(Entity entity) {
|
|
// Paper start - log detailed entity tick information
|
|
io.papermc.paper.util.TickThread.ensureTickThread("Cannot tick an entity off-main");
|
|
+ if (!entity.isRemoved()) this.entityManager.updateNavigatorsInRegion(entity); // Paper - optimise notify
|
|
try {
|
|
if (currentlyTickingEntity.get() == null) {
|
|
currentlyTickingEntity.lazySet(entity);
|
|
@@ -1639,9 +1640,18 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
|
|
if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
|
|
List<PathNavigation> list = new ObjectArrayList();
|
|
- Iterator iterator = this.navigatingMobs.iterator();
|
|
+ // Paper start - optimise notify()
|
|
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region region = this.getChunkSource().chunkMap.dataRegionManager.getRegion(pos.getX() >> 4, pos.getZ() >> 4);
|
|
+ if (region == null) {
|
|
+ return;
|
|
+ }
|
|
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigatorsFromRegion = ((ChunkMap.DataRegionData)region.regionData).getNavigators();
|
|
+ if (navigatorsFromRegion == null) {
|
|
+ return;
|
|
+ }
|
|
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Mob> iterator = navigatorsFromRegion.iterator();
|
|
|
|
- while (iterator.hasNext()) {
|
|
+ try { while (iterator.hasNext()) { // Paper end - optimise notify()
|
|
// CraftBukkit start - fix SPIGOT-6362
|
|
Mob entityinsentient;
|
|
try {
|
|
@@ -1663,16 +1673,23 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
|
|
try {
|
|
this.isUpdatingNavigations = true;
|
|
- iterator = list.iterator();
|
|
+ // Paper start - optimise notify()
|
|
+ Iterator<PathNavigation> navigationIterator = list.iterator();
|
|
|
|
- while (iterator.hasNext()) {
|
|
- PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
|
|
+ while (navigationIterator.hasNext()) {
|
|
+ PathNavigation navigationabstract1 = navigationIterator.next();
|
|
+ // Paper end - optimise notify()
|
|
|
|
navigationabstract1.recomputePath();
|
|
}
|
|
} finally {
|
|
this.isUpdatingNavigations = false;
|
|
}
|
|
+ // Paper start - optimise notify()
|
|
+ } finally {
|
|
+ iterator.finishedIterating();
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
|
|
}
|
|
} // Paper
|
|
@@ -2470,10 +2487,12 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
|
|
public void onTickingStart(Entity entity) {
|
|
ServerLevel.this.entityTickList.add(entity);
|
|
+ ServerLevel.this.entityManager.addNavigatorsIfPathingToRegion(entity); // Paper - optimise notify
|
|
}
|
|
|
|
public void onTickingEnd(Entity entity) {
|
|
ServerLevel.this.entityTickList.remove(entity);
|
|
+ ServerLevel.this.entityManager.removeNavigatorsFromData(entity); // Paper - optimise notify
|
|
// Paper start - Reset pearls when they stop being ticked
|
|
if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) {
|
|
pearl.cachedOwner = null;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
index c1781c92ff59f0c9eb47cbbef01e3252c5e1a1bf..02653adc591d390ca8b4ee13289510d4652c8894 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
|
@@ -28,7 +28,7 @@ import net.minecraft.world.phys.Vec3;
|
|
|
|
public abstract class PathNavigation {
|
|
private static final int MAX_TIME_RECOMPUTE = 20;
|
|
- protected final Mob mob;
|
|
+ protected final Mob mob; public final Mob getEntity() { return this.mob; } // Paper - public accessor
|
|
protected final Level level;
|
|
@Nullable
|
|
protected Path path;
|
|
@@ -41,7 +41,7 @@ public abstract class PathNavigation {
|
|
protected long lastTimeoutCheck;
|
|
protected double timeoutLimit;
|
|
protected float maxDistanceToWaypoint = 0.5F;
|
|
- protected boolean hasDelayedRecomputation;
|
|
+ protected boolean hasDelayedRecomputation; protected final boolean needsPathRecalculation() { return this.hasDelayedRecomputation; } // Paper - public accessor
|
|
protected long timeLastRecompute;
|
|
protected NodeEvaluator nodeEvaluator;
|
|
@Nullable
|
|
@@ -419,7 +419,7 @@ public abstract class PathNavigation {
|
|
public boolean shouldRecomputePath(BlockPos pos) {
|
|
if (this.hasDelayedRecomputation) {
|
|
return false;
|
|
- } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) {
|
|
+ } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) { // Paper - diff on change - needed for isViableForPathRecalculationChecking()
|
|
Node node = this.path.getEndNode();
|
|
Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D);
|
|
return pos.closerToCenterThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex()));
|
|
@@ -435,4 +435,11 @@ public abstract class PathNavigation {
|
|
public boolean isStuck() {
|
|
return this.isStuck;
|
|
}
|
|
+
|
|
+ // Paper start
|
|
+ public boolean isViableForPathRecalculationChecking() {
|
|
+ return !this.needsPathRecalculation() &&
|
|
+ (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0);
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
|
index f635b610e68d129aa0ae60c54b83da6943946436..1f0eddb0f3ded42bf312f8933def2f5c9a964651 100644
|
|
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
|
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
|
@@ -71,6 +71,65 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
|
}
|
|
// CraftBukkit end
|
|
|
|
+ // Paper start - optimise notify()
|
|
+ public final void removeNavigatorsFromData(Entity entity, final int chunkX, final int chunkZ) {
|
|
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
|
+ return;
|
|
+ }
|
|
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
|
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(chunkX, chunkZ);
|
|
+ if (section != null) {
|
|
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
|
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public final void removeNavigatorsFromData(Entity entity) {
|
|
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
|
+ return;
|
|
+ }
|
|
+ BlockPos entityPos = entity.blockPosition();
|
|
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
|
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
|
+ if (section != null) {
|
|
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
|
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public final void addNavigatorsIfPathingToRegion(Entity entity) {
|
|
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
|
+ return;
|
|
+ }
|
|
+ BlockPos entityPos = entity.blockPosition();
|
|
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
|
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
|
+ if (section != null) {
|
|
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
|
+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) {
|
|
+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public final void updateNavigatorsInRegion(Entity entity) {
|
|
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
|
+ return;
|
|
+ }
|
|
+ BlockPos entityPos = entity.blockPosition();
|
|
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
|
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
|
+ if (section != null) {
|
|
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
|
+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) {
|
|
+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
|
+ } else {
|
|
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimise notify()
|
|
+
|
|
void removeSectionIfEmpty(long sectionPos, EntitySection<T> section) {
|
|
if (section.isEmpty()) {
|
|
this.sectionStorage.remove(sectionPos);
|
|
@@ -468,11 +527,25 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
|
@Override
|
|
public void onMove() {
|
|
BlockPos blockposition = this.entity.blockPosition();
|
|
- long i = SectionPos.asLong(blockposition);
|
|
+ long i = SectionPos.asLong(blockposition); final long newSectionPos = i; // Paper - diff on change, new position section
|
|
|
|
if (i != this.currentSectionKey) {
|
|
PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Paper
|
|
- Visibility visibility = this.currentSection.getStatus();
|
|
+ Visibility visibility = this.currentSection.getStatus(); final Visibility oldVisibility = visibility; // Paper - diff on change - this should be OLD section visibility
|
|
+ // Paper start
|
|
+ int shift = PersistentEntitySectionManager.this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.regionChunkShift;
|
|
+ int oldChunkX = io.papermc.paper.util.CoordinateUtils.getChunkSectionX(this.currentSectionKey);
|
|
+ int oldChunkZ = io.papermc.paper.util.CoordinateUtils.getChunkSectionZ(this.currentSectionKey);
|
|
+ int oldRegionX = oldChunkX >> shift;
|
|
+ int oldRegionZ = oldChunkZ >> shift;
|
|
+
|
|
+ int newRegionX = io.papermc.paper.util.CoordinateUtils.getChunkSectionX(newSectionPos) >> shift;
|
|
+ int newRegionZ = io.papermc.paper.util.CoordinateUtils.getChunkSectionZ(newSectionPos) >> shift;
|
|
+
|
|
+ if (oldRegionX != newRegionX || oldRegionZ != newRegionZ) {
|
|
+ PersistentEntitySectionManager.this.removeNavigatorsFromData((Entity)this.entity, oldChunkX, oldChunkZ);
|
|
+ }
|
|
+ // Paper end
|
|
|
|
if (!this.currentSection.remove(this.entity)) {
|
|
PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), i});
|
|
@@ -484,6 +557,11 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
|
entitysection.add(this.entity);
|
|
this.currentSection = entitysection;
|
|
this.currentSectionKey = i;
|
|
+ // Paper start
|
|
+ if ((oldRegionX != newRegionX || oldRegionZ != newRegionZ) && oldVisibility.isTicking() && entitysection.getStatus().isTicking()) {
|
|
+ PersistentEntitySectionManager.this.addNavigatorsIfPathingToRegion((Entity)this.entity);
|
|
+ }
|
|
+ // Paper end
|
|
this.updateStatus(visibility, entitysection.getStatus());
|
|
}
|
|
|