From 5d149308c170326343337431e4c888a7b3284eb7 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 13 May 2016 01:38:06 -0400
Subject: [PATCH] Activation Range Improvements

Optimizes performance of Activation Range

Fixes and adds new Immunities to improve gameplay behavior

Adds water Mobs to activation range config and nerfs fish

diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index d522d7238d..3a248dbe37 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -192,6 +192,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
     public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
     public final boolean defaultActivationState;
     public long activatedTick = Integer.MIN_VALUE;
+    public boolean isTemporarilyActive = false; // Paper
     public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
     protected int numCollisions = 0; // Paper
     public void inactiveTick() { }
@@ -553,6 +554,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
             this.recalcPosition();
         } else {
             if (enummovetype == EnumMoveType.PISTON) {
+                this.activatedTick = MinecraftServer.currentTick + 20; // Paper
                 vec3d = this.a(vec3d);
                 if (vec3d.equals(Vec3D.a)) {
                     return;
@@ -565,6 +567,12 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
                 this.y = Vec3D.a;
                 this.setMot(Vec3D.a);
             }
+            // Paper start - ignore movement changes while inactive.
+            if (isTemporarilyActive && vec3d == getMot() && enummovetype == EnumMoveType.SELF) {
+                setMot(Vec3D.a);
+                return;
+            }
+            // Paper end
 
             vec3d = this.a(vec3d, enummovetype);
             Vec3D vec3d1 = this.e(vec3d);
@@ -2765,6 +2773,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
         return this.am;
     }
 
+    public boolean isPushedByWater() { return this.bM(); } // Paper - OBFHELPER - the below is not an obfhelper, don't use it!
     public boolean bM() {
         // Paper start
         return this.pushedByWater();
diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java
index b40c8d2f83..4eda130750 100644
--- a/src/main/java/net/minecraft/server/EntityCreature.java
+++ b/src/main/java/net/minecraft/server/EntityCreature.java
@@ -7,6 +7,7 @@ import org.bukkit.event.entity.EntityUnleashEvent;
 public abstract class EntityCreature extends EntityInsentient {
 
     public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
+    public BlockPosition movingTarget = null; public BlockPosition getMovingTarget() { return movingTarget; } // Paper
 
     protected EntityCreature(EntityTypes<? extends EntityCreature> entitytypes, World world) {
         super(entitytypes, world);
diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java
index 6d53254f83..1991cee43d 100644
--- a/src/main/java/net/minecraft/server/EntityInsentient.java
+++ b/src/main/java/net/minecraft/server/EntityInsentient.java
@@ -114,6 +114,17 @@ public abstract class EntityInsentient extends EntityLiving {
         return this.lookController;
     }
 
+    // Paper start
+    @Override
+    public void inactiveTick() {
+        super.inactiveTick();
+        this.goalSelector.inactiveTick();
+        if (this.targetSelector.inactiveTick()) {
+            this.targetSelector.doTick();
+        }
+    }
+    // Paper end
+
     public ControllerMove getControllerMove() {
         if (this.isPassenger() && this.getVehicle() instanceof EntityInsentient) {
             EntityInsentient entityinsentient = (EntityInsentient) this.getVehicle();
diff --git a/src/main/java/net/minecraft/server/EntityLlama.java b/src/main/java/net/minecraft/server/EntityLlama.java
index 6d4d41c88c..193dbfc5f6 100644
--- a/src/main/java/net/minecraft/server/EntityLlama.java
+++ b/src/main/java/net/minecraft/server/EntityLlama.java
@@ -382,6 +382,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn
         return this.bK != null;
     }
 
+    public boolean inCaravan() { return this.fd(); } // Paper - OBFHELPER
     public boolean fd() {
         return this.bJ != null;
     }
diff --git a/src/main/java/net/minecraft/server/PathfinderGoal.java b/src/main/java/net/minecraft/server/PathfinderGoal.java
index f22f12eeb0..bdb90a3466 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoal.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoal.java
@@ -20,7 +20,10 @@ public abstract class PathfinderGoal {
 
     public void c() {}
 
-    public void d() {}
+    public void d() {
+        onTaskReset(); // Paper
+    }
+    public void onTaskReset() {} // Paper
 
     public void e() {}
 
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java b/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java
index 41fb166ce0..e93129f0b2 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java
@@ -4,12 +4,12 @@ import java.util.EnumSet;
 
 public abstract class PathfinderGoalGotoTarget extends PathfinderGoal {
 
-    protected final EntityCreature a;
+    protected final EntityCreature a;public EntityCreature getEntity() { return a; } // Paper - OBFHELPER
     public final double b;
     protected int c;
     protected int d;
     private int g;
-    protected BlockPosition e;
+    protected BlockPosition e; public BlockPosition getTarget() { return e; } public void setTarget(BlockPosition pos) { this.e = pos; getEntity().movingTarget = pos != BlockPosition.ZERO ? pos : null; } // Paper - OBFHELPER
     private boolean h;
     private final int i;
     private final int j;
@@ -18,6 +18,13 @@ public abstract class PathfinderGoalGotoTarget extends PathfinderGoal {
     public PathfinderGoalGotoTarget(EntityCreature entitycreature, double d0, int i) {
         this(entitycreature, d0, i, 1);
     }
+    // Paper start - activation range improvements
+    @Override
+    public void onTaskReset() {
+        super.onTaskReset();
+        setTarget(BlockPosition.ZERO);
+    }
+    // Paper end
 
     public PathfinderGoalGotoTarget(EntityCreature entitycreature, double d0, int i, int j) {
         this.e = BlockPosition.ZERO;
@@ -100,6 +107,7 @@ public abstract class PathfinderGoalGotoTarget extends PathfinderGoal {
                         blockposition_mutableblockposition.g(blockposition).e(i1, k - 1, j1);
                         if (this.a.a((BlockPosition) blockposition_mutableblockposition) && this.a(this.a.world, blockposition_mutableblockposition)) {
                             this.e = blockposition_mutableblockposition;
+                            setTarget(blockposition_mutableblockposition.immutableCopy()); // Paper
                             return true;
                         }
                     }
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
index 44bb18c594..935136771e 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
@@ -24,10 +24,11 @@ public class PathfinderGoalSelector {
         }
     };
     private final Map<PathfinderGoal.Type, PathfinderGoalWrapped> c = new EnumMap(PathfinderGoal.Type.class);
-    private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet();
+    private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet();private Set<PathfinderGoalWrapped> getTasks() { return d; }// Paper - OBFHELPER
     private final GameProfilerFiller e;
     private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class);
-    private int g = 3;
+    private int g = 3;private int getTickRate() { return g; } // Paper - OBFHELPER
+    private int curRate;private int getCurRate() { return curRate; } private void incRate() { this.curRate++; } // Paper TODO
 
     public PathfinderGoalSelector(GameProfilerFiller gameprofilerfiller) {
         this.e = gameprofilerfiller;
@@ -37,6 +38,25 @@ public class PathfinderGoalSelector {
         this.d.add(new PathfinderGoalWrapped(i, pathfindergoal));
     }
 
+    // Paper start
+    public boolean inactiveTick() {
+        if (getCurRate() % getTickRate() != 0) {
+            incRate();
+            return false;
+        } else {
+            return true;
+        }
+    }
+    public boolean hasTasks() {
+        for (PathfinderGoalWrapped task : getTasks()) {
+            if (task.isRunning()) {
+                return true;
+            }
+        }
+        return false;
+    }
+    // Paper end
+
     public void a(PathfinderGoal pathfindergoal) {
         this.d.stream().filter((pathfindergoalwrapped) -> {
             return pathfindergoalwrapped.j() == pathfindergoal;
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
index 5a8c60ad90..29657fed75 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
@@ -64,6 +64,7 @@ public class PathfinderGoalWrapped extends PathfinderGoal {
         return this.a.i();
     }
 
+    public boolean isRunning() { return this.g(); } // Paper - OBFHELPER
     public boolean g() {
         return this.c;
     }
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 92601c581c..f4cb669740 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -3,11 +3,15 @@ package org.spigotmc;
 import java.util.Collection;
 import java.util.List;
 import net.minecraft.server.AxisAlignedBB;
+import net.minecraft.server.BehaviorController;
+import net.minecraft.server.BlockPosition;
 import net.minecraft.server.Chunk;
+import net.minecraft.server.ChunkProviderServer; // Paper
 import net.minecraft.server.Entity;
 import net.minecraft.server.EntityAmbient;
 import net.minecraft.server.EntityAnimal;
 import net.minecraft.server.EntityArrow;
+import net.minecraft.server.EntityBee;
 import net.minecraft.server.EntityComplexPart;
 import net.minecraft.server.EntityCreature;
 import net.minecraft.server.EntityCreeper;
@@ -16,10 +20,13 @@ import net.minecraft.server.EntityEnderDragon;
 import net.minecraft.server.EntityFallingBlock; // Paper
 import net.minecraft.server.EntityFireball;
 import net.minecraft.server.EntityFireworks;
+import net.minecraft.server.EntityFlying;
 import net.minecraft.server.EntityHuman;
 import net.minecraft.server.EntityLightning;
 import net.minecraft.server.EntityLiving;
 import net.minecraft.server.EntityMonster;
+import net.minecraft.server.EntityPillager;
+import net.minecraft.server.EntityPlayer;
 import net.minecraft.server.EntityProjectile;
 import net.minecraft.server.EntityRaider;
 import net.minecraft.server.EntitySheep;
@@ -30,15 +37,22 @@ import net.minecraft.server.EntityThrownTrident;
 import net.minecraft.server.EntityVillager;
 import net.minecraft.server.EntityWither;
 import net.minecraft.server.MathHelper;
+import net.minecraft.server.MemoryModuleType;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.server.World;
 import co.aikar.timings.MinecraftTimings;
+// Paper start
+import net.minecraft.server.EntityInsentient;
+import net.minecraft.server.EntityLlama;
+import net.minecraft.server.EntityWaterAnimal;
+// Paper end
 
 public class ActivationRange
 {
 
     public enum ActivationType
     {
+        WATER, // Paper
         MONSTER,
         ANIMAL,
         RAIDER,
@@ -58,6 +72,7 @@ public class ActivationRange
      */
     public static ActivationType initializeEntityActivationType(Entity entity)
     {
+        if (entity instanceof EntityWaterAnimal) { return ActivationType.WATER; } // Paper
         if ( entity instanceof EntityRaider )
         {
             return ActivationType.RAIDER;
@@ -86,6 +101,7 @@ public class ActivationRange
                 || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0 )
                 || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0 )
                 || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0 )
+                || ( entity.activationType == ActivationType.WATER && config.waterActivationRange == 0 ) // Paper
                 || entity instanceof EntityHuman
                 || entity instanceof EntityProjectile
                 || entity instanceof EntityEnderDragon
@@ -118,6 +134,8 @@ public class ActivationRange
         final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
         final int animalActivationRange = world.spigotConfig.animalActivationRange;
         final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
+        final int waterActivationRange = world.spigotConfig.waterActivationRange; // Paper
+        final ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider(); // Paper
 
         int maxRange = Math.max( monsterActivationRange, animalActivationRange );
         maxRange = Math.max( maxRange, raiderActivationRange );
@@ -133,6 +151,8 @@ public class ActivationRange
             ActivationType.RAIDER.boundingBox = player.getBoundingBox().grow( raiderActivationRange, 256, raiderActivationRange );
             ActivationType.ANIMAL.boundingBox = player.getBoundingBox().grow( animalActivationRange, 256, animalActivationRange );
             ActivationType.MONSTER.boundingBox = player.getBoundingBox().grow( monsterActivationRange, 256, monsterActivationRange );
+            ActivationType.WATER.boundingBox = player.getBoundingBox().grow( waterActivationRange, 256, waterActivationRange ); // Paper
+
 
             int i = MathHelper.floor( maxBB.minX / 16.0D );
             int j = MathHelper.floor( maxBB.maxX / 16.0D );
@@ -143,7 +163,7 @@ public class ActivationRange
             {
                 for ( int j1 = k; j1 <= l; ++j1 )
                 {
-                    Chunk chunk = (Chunk) world.getChunkIfLoadedImmediately( i1, j1 );
+                    Chunk chunk = chunkProvider.getChunkAtIfLoadedMainThreadNoCache( i1, j1 ); // Paper
                     if ( chunk != null )
                     {
                         activateChunkEntities( chunk );
@@ -161,19 +181,15 @@ public class ActivationRange
      */
     private static void activateChunkEntities(Chunk chunk)
     {
-        for ( List<Entity> slice : chunk.entitySlices )
-        {
-            for ( Entity entity : (Collection<Entity>) slice )
+        // Paper start
+        Entity[] rawData = chunk.entities.getRawData();
+        for (int i = 0; i < chunk.entities.size(); i++) {
+            Entity entity = rawData[i];
+            //for ( Entity entity : (Collection<Entity>) slice )
+            // Paper end
             {
-                if ( MinecraftServer.currentTick > entity.activatedTick )
-                {
-                    if ( entity.defaultActivationState )
-                    {
-                        entity.activatedTick = MinecraftServer.currentTick;
-                        continue;
-                    }
-                    if ( entity.activationType.boundingBox.c( entity.getBoundingBox() ) )
-                    {
+                if (MinecraftServer.currentTick > entity.activatedTick) {
+                    if (entity.defaultActivationState || entity.activationType.boundingBox.c(entity.getBoundingBox())) { // Paper
                         entity.activatedTick = MinecraftServer.currentTick;
                     }
                 }
@@ -188,22 +204,22 @@ public class ActivationRange
      * @param entity
      * @return
      */
-    public static boolean checkEntityImmunities(Entity entity)
+    public static int checkEntityImmunities(Entity entity) // Paper - return # of ticks to get immunity
     {
         // quick checks.
-        if ( entity.inWater || entity.fireTicks > 0 )
+        if ( (entity.activationType != ActivationType.WATER && entity.inWater && entity.pushedByWater()) || entity.fireTicks > 0 ) // Paper
         {
-            return true;
+            return 1; // Paper
         }
         if ( !( entity instanceof EntityArrow ) )
         {
-            if ( !entity.onGround || !entity.passengers.isEmpty() || entity.isPassenger() )
+            if ( (!entity.onGround && !(entity instanceof EntityFlying)) || !entity.passengers.isEmpty() || entity.isPassenger() ) // Paper
             {
-                return true;
+                return 10; // Paper
             }
         } else if ( !( (EntityArrow) entity ).inGround )
         {
-            return true;
+            return 1; // Paper
         }
         // special cases.
         if ( entity instanceof EntityLiving )
@@ -211,33 +227,63 @@ public class ActivationRange
             EntityLiving living = (EntityLiving) entity;
             if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTicks > 0 || living.effects.size() > 0 )
             {
-                return true;
+                return 1; // Paper
             }
-            if ( entity instanceof EntityCreature && ( (EntityCreature) entity ).getGoalTarget() != null )
+            if ( entity instanceof EntityInsentient && ((EntityInsentient) entity ).getGoalTarget() != null) // Paper
             {
-                return true;
+                return 20; // Paper
+            }
+            // Paper start
+            if (entity instanceof EntityBee) {
+                EntityBee bee = (EntityBee)entity;
+                BlockPosition movingTarget = bee.getMovingTarget();
+                if (bee.isAngry() ||
+                    (bee.getHivePos() != null && bee.getHivePos().equals(movingTarget)) ||
+                    (bee.getFlowerPos() != null && bee.getFlowerPos().equals(movingTarget))
+                ) {
+                    return 20;
+                }
             }
             if ( entity instanceof EntityVillager && ( (EntityVillager) entity ).canBreed() )
             {
-                return true;
+                BehaviorController<EntityVillager> behaviorController = ((EntityVillager) entity).getBehaviorController();
+                if (behaviorController.hasMemory(MemoryModuleType.BREED_TARGET)) {
+                    return 1;
+                }
+                // Paper end
             }
+            // Paper start
+            if ( entity instanceof EntityLlama && ( (EntityLlama ) entity ).inCaravan() )
+            {
+                return 0;
+            }
+            // Paper end
             if ( entity instanceof EntityAnimal )
             {
                 EntityAnimal animal = (EntityAnimal) entity;
                 if ( animal.isBaby() || animal.isInLove() )
                 {
-                    return true;
+                    return 1; // Paper
                 }
                 if ( entity instanceof EntitySheep && ( (EntitySheep) entity ).isSheared() )
                 {
-                    return true;
+                    return 1; // Paper
                 }
             }
             if (entity instanceof EntityCreeper && ((EntityCreeper) entity).isIgnited()) { // isExplosive
-                return true;
+                return 20; // Paper
+            }
+            // Paper start
+            if (entity instanceof EntityInsentient && ((EntityInsentient) entity).targetSelector.hasTasks() ) {
+                return 0;
             }
+            if (entity instanceof EntityPillager) {
+                EntityPillager pillager = (EntityPillager) entity;
+                // TODO:?
+            }
+            // Paper end
         }
-        return false;
+        return -1; // Paper
     }
 
     /**
@@ -254,6 +300,7 @@ public class ActivationRange
         }
 
         boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;
+        entity.isTemporarilyActive = false; // Paper
 
         // Should this entity tick?
         if ( !isActive )
@@ -261,15 +308,19 @@ public class ActivationRange
             if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 )
             {
                 // Check immunities every 20 ticks.
-                if ( checkEntityImmunities( entity ) )
-                {
-                    // Triggered some sort of immunity, give 20 full ticks before we check again.
-                    entity.activatedTick = MinecraftServer.currentTick + 20;
+                // Paper start
+                int immunity = checkEntityImmunities(entity);
+                if (immunity >= 0) {
+                    entity.activatedTick = MinecraftServer.currentTick + immunity;
+                } else {
+                    entity.isTemporarilyActive = true;
                 }
+                // Paper end
                 isActive = true;
+
             }
             // Add a little performance juice to active entities. Skip 1/4 if not immune.
-        } else if ( !entity.defaultActivationState && entity.ticksLived % 4 == 0 && !checkEntityImmunities( entity ) )
+        } else if ( !entity.defaultActivationState && entity.ticksLived % 4 == 0 && checkEntityImmunities( entity) < 0 ) // Paper
         {
             isActive = false;
         }
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 58767972a3..3ceeed3f99 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -180,6 +180,7 @@ public class SpigotWorldConfig
     public int monsterActivationRange = 32;
     public int raiderActivationRange = 48;
     public int miscActivationRange = 16;
+    public int waterActivationRange = 16; // Paper
     public boolean tickInactiveVillagers = true;
     private void activationRange()
     {
@@ -187,6 +188,7 @@ public class SpigotWorldConfig
         monsterActivationRange = getInt( "entity-activation-range.monsters", monsterActivationRange );
         raiderActivationRange = getInt( "entity-activation-range.raiders", raiderActivationRange );
         miscActivationRange = getInt( "entity-activation-range.misc", miscActivationRange );
+        waterActivationRange = getInt( "entity-activation-range.water", waterActivationRange ); // Paper
         tickInactiveVillagers = getBoolean( "entity-activation-range.tick-inactive-villagers", tickInactiveVillagers );
         log( "Entity Activation Range: An " + animalActivationRange + " / Mo " + monsterActivationRange + " / Ra " + raiderActivationRange + " / Mi " + miscActivationRange + " / Tiv " + tickInactiveVillagers );
     }
-- 
2.25.1