aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0774-Optimise-WorldServer-notify.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0774-Optimise-WorldServer-notify.patch')
-rw-r--r--patches/server/0774-Optimise-WorldServer-notify.patch339
1 files changed, 339 insertions, 0 deletions
diff --git a/patches/server/0774-Optimise-WorldServer-notify.patch b/patches/server/0774-Optimise-WorldServer-notify.patch
new file mode 100644
index 0000000000..6cfd3dac52
--- /dev/null
+++ b/patches/server/0774-Optimise-WorldServer-notify.patch
@@ -0,0 +1,339 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Spottedleaf <[email protected]>
+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 9a269f0ab59b4ea2ce01957f89677d2f304ebf02..b6a17bb19a45ccd4bfc4be5f177a792a9a3727f5 100644
+--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
+@@ -301,15 +301,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
+@@ -319,6 +385,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 ea665ae89b0963e5605ff0bc87f906fdddeb2c9a..ae1de6544f488ff14202fd9df6267b2c98b81111 100644
+--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
+@@ -1096,6 +1096,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");
++ this.entityManager.updateNavigatorsInRegion(entity); // Paper - optimise notify
+ try {
+ if (currentlyTickingEntity.get() == null) {
+ currentlyTickingEntity.lazySet(entity);
+@@ -1548,9 +1549,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 {
+@@ -1572,16 +1582,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
+@@ -2381,10 +2398,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
+ }
+
+ public void onTrackingStart(Entity entity) {
+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 b47cd6d8ed02875bd9af54d27b7c1cda340e7f9f..d35032a8d2612d555c3dad1fe496d7ae1c5a285b 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
+@@ -27,7 +27,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;
+@@ -40,7 +40,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
+@@ -50,6 +50,13 @@ public abstract class PathNavigation {
+ public final PathFinder pathFinder;
+ private boolean isStuck;
+
++ // Paper start
++ public boolean isViableForPathRecalculationChecking() {
++ return !this.needsPathRecalculation() &&
++ (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0);
++ }
++ // Paper end
++
+ public PathNavigation(Mob mob, Level world) {
+ this.mob = mob;
+ this.level = world;
+@@ -413,7 +420,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()));
+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 5029ab81e3d7943a001b6367083eb511ce7d3572..db2ef605bccbb9024f787cd58f3cb93df03d5532 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);
+@@ -456,11 +515,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});
+@@ -472,6 +545,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());
+ }
+