papermc/Spigot-Server-Patches/0077-Optimize-Navigation-Listener.patch
Aikar fec4578d74 Add comment to Navigation patch on why its done that way
to avoid accidently changing it in future and breaking things
2016-03-18 17:12:30 -04:00

105 lines
4.5 KiB
Diff

From 6b6ec7e713ac57a04dc7004e164eb3cd80d364ca Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 8 Mar 2016 19:13:54 -0500
Subject: [PATCH] Optimize Navigation Listener
Mojang was abusing a WeakHashMap to do clean up. However this has some
scary object life concerns as you could have a NavigationListener being
ticked even after the entity it was bound to was removed from world.
Switching this to an Array List gives superior iteration performance
at a slight cost to removal performance.
Additionally, change listener registration to be done upon world add
instead of immediate up creation.
This provides benefit of only registering and ticking REAL Navigation
objects, and not invalid entities (cancelled entity spawns for example)
Gives us a much leaner NavigationListener list.
diff --git a/src/main/java/net/minecraft/server/NavigationAbstract.java b/src/main/java/net/minecraft/server/NavigationAbstract.java
index 7d794b9..aa18f54 100644
--- a/src/main/java/net/minecraft/server/NavigationAbstract.java
+++ b/src/main/java/net/minecraft/server/NavigationAbstract.java
@@ -32,7 +32,7 @@ public abstract class NavigationAbstract {
this.b = world;
this.g = entityinsentient.getAttributeInstance(GenericAttributes.FOLLOW_RANGE);
this.s = this.a();
- this.b.C().a(this);
+ //this.b.C().a(this); // Paper - Optimized Nav Listener - registered on world add
}
protected abstract Pathfinder a();
diff --git a/src/main/java/net/minecraft/server/NavigationListener.java b/src/main/java/net/minecraft/server/NavigationListener.java
index 39a4032..3c277cb 100644
--- a/src/main/java/net/minecraft/server/NavigationListener.java
+++ b/src/main/java/net/minecraft/server/NavigationListener.java
@@ -1,16 +1,19 @@
package net.minecraft.server;
+import java.util.ArrayList; // Paper
+import java.util.List; // Paper
import java.util.WeakHashMap;
public class NavigationListener implements IWorldAccess {
private static final Object a = new Object();
- private final WeakHashMap<NavigationAbstract, Object> b = new WeakHashMap();
+ private final List<NavigationAbstract> navigators = new ArrayList<>(); // Paper
public NavigationListener() {}
public void a(NavigationAbstract navigationabstract) {
- this.b.put(navigationabstract, NavigationListener.a);
+ //this.b.put(navigationabstract, NavigationListener.a); // Paper
+ System.err.println("Unexpected NavigationListener add"); // Paper
}
public void a(World world, BlockPosition blockposition, IBlockData iblockdata, IBlockData iblockdata1, int i) {
@@ -19,10 +22,15 @@ public class NavigationListener implements IWorldAccess {
// NavigationAbstract[] anavigationabstract = (NavigationAbstract[]) this.b.keySet().toArray(new NavigationAbstract[0]);
// NavigationAbstract[] anavigationabstract1 = anavigationabstract;
// int j = anavigationabstract.length;
+ // Spigot end
- for (NavigationAbstract navigationabstract : this.b.keySet()) {
- // NavigationAbstract navigationabstract = anavigationabstract1[k];
- // Spigot end
+ // Paper start
+ // DO NOT USE AN ITERATOR! This must be a for (;;) to avoid CME.
+ // This is perfectly safe, as additions are ok to be done in this iteration
+ // And Removals are queued instead of immediate.
+ for (int k = 0; k < this.navigators.size(); ++k) {
+ NavigationAbstract navigationabstract = this.navigators.get(k);
+ // Paper end
if (navigationabstract != null && !navigationabstract.i()) {
PathEntity pathentity = navigationabstract.k();
@@ -57,9 +65,21 @@ public class NavigationListener implements IWorldAccess {
public void a(int i, boolean flag, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {}
- public void a(Entity entity) {}
+ public void a(Entity entity) {
+ // Paper start
+ if (entity instanceof EntityInsentient) {
+ this.navigators.add(((EntityInsentient) entity).navigation);
+ }
+ // Paper end
+ }
- public void b(Entity entity) {}
+ public void b(Entity entity) {
+ // Paper start
+ if (entity instanceof EntityInsentient) {
+ this.navigators.remove(((EntityInsentient) entity).navigation);
+ }
+ // Paper end
+ }
public void a(SoundEffect soundeffect, BlockPosition blockposition) {}
--
2.7.4