From 537b37247849b22c5058f77c9c5134fd7b25a5cf 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/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
index bc364ce371..80e13dfb2e 100644
--- a/src/main/java/net/minecraft/server/BlockPosition.java
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -387,6 +387,7 @@ public class BlockPosition extends BaseBlockPosition {
             this.c = i;
         }
 
+        public BlockPosition toBlockPosition() { return h(); } // Paper - OBFHELPER
         public BlockPosition h() {
             return new BlockPosition(this);
         }
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 82994db643..462f94ed18 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -592,6 +592,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
             this.recalcPosition();
         } else {
             if (enummovetype == EnumMoveType.PISTON) {
+                this.activatedTick = MinecraftServer.currentTick + 20; // Paper
                 long i = this.world.getTime();
 
                 if (i != this.aM) {
diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java
index 20b7c2c6dc..d659c57dbe 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
     private BlockPosition a;
     private float b;
 
diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java
index e5322de974..c530824596 100644
--- a/src/main/java/net/minecraft/server/EntityInsentient.java
+++ b/src/main/java/net/minecraft/server/EntityInsentient.java
@@ -105,6 +105,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() {
         return this.moveController;
     }
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index e8f2f11c4d..c0ef0c51f1 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -74,7 +74,7 @@ public abstract class EntityLiving extends Entity {
     public float aT;
     public float aU;
     public EntityHuman killer;
-    protected int lastDamageByPlayerTime;
+    public int lastDamageByPlayerTime; // Paper - public
     protected boolean killed;
     protected int ticksFarFromPlayer;
     protected float aZ;
diff --git a/src/main/java/net/minecraft/server/EntityLlama.java b/src/main/java/net/minecraft/server/EntityLlama.java
index b19bd2b99a..5e19768710 100644
--- a/src/main/java/net/minecraft/server/EntityLlama.java
+++ b/src/main/java/net/minecraft/server/EntityLlama.java
@@ -363,6 +363,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn
         return this.bR != null;
     }
 
+    public boolean inCaravan() { return this.em(); } // Paper - OBFHELPER
     public boolean em() {
         return this.bQ != null;
     }
diff --git a/src/main/java/net/minecraft/server/PathfinderGoal.java b/src/main/java/net/minecraft/server/PathfinderGoal.java
index a146a8b459..a19853463c 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoal.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoal.java
@@ -18,7 +18,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 d5c08aa7cb..756d63239c 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalGotoTarget.java
@@ -2,12 +2,12 @@ package net.minecraft.server;
 
 public abstract class PathfinderGoalGotoTarget extends PathfinderGoal {
 
-    private final EntityCreature f;
+    private final EntityCreature f;public EntityCreature getEntity() { return f; } // Paper - OBFHELPER
     public double a;
     protected int b;
     protected int c;
     private int g;
-    protected BlockPosition d;
+    protected BlockPosition d; public BlockPosition getTarget() { return d; } public void setTarget(BlockPosition pos) { this.d = pos; getEntity().movingTarget = pos != BlockPosition.ZERO ? pos : null; } // Paper - OBFHELPER
     private boolean h;
     private final int i;
     private final int j;
@@ -16,6 +16,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.d = BlockPosition.ZERO;
@@ -94,6 +101,7 @@ public abstract class PathfinderGoalGotoTarget extends PathfinderGoal {
                         blockposition_mutableblockposition.g(blockposition).d(i1, k - 1, j1);
                         if (this.f.f((BlockPosition) blockposition_mutableblockposition) && this.a(this.f.world, blockposition_mutableblockposition)) {
                             this.d = blockposition_mutableblockposition;
+                            setTarget(blockposition_mutableblockposition.toBlockPosition()); // Paper
                             return true;
                         }
                     }
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
index f3df91181f..3e2f9c749b 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
@@ -11,10 +11,10 @@ public class PathfinderGoalSelector {
 
     private static final Logger a = LogManager.getLogger();
     private final Set<PathfinderGoalSelector.PathfinderGoalSelectorItem> b = Sets.newLinkedHashSet();
-    private final Set<PathfinderGoalSelector.PathfinderGoalSelectorItem> c = Sets.newLinkedHashSet();
+    private final Set<PathfinderGoalSelector.PathfinderGoalSelectorItem> c = Sets.newLinkedHashSet();private Set<PathfinderGoalSelector.PathfinderGoalSelectorItem> getExecutingTasks() { return c; }// Paper - OBFHELPER
     private final MethodProfiler d;
-    private int e;
-    private int f = 3;
+    private int e;private int getCurRate() { return e; } private void incRate() { this.e++; }// Paper - OBFHELPER
+    private int f = 3;private int getTickRate() { return f; } // Paper - OBFHELPER
     private int g;
 
     public PathfinderGoalSelector(MethodProfiler methodprofiler) {
@@ -25,6 +25,20 @@ public class PathfinderGoalSelector {
         this.b.add(new PathfinderGoalSelector.PathfinderGoalSelectorItem(i, pathfindergoal));
     }
 
+    // Paper start
+    public boolean inactiveTick() {
+        if (getCurRate() % getTickRate() != 0) {
+            incRate();
+            return false;
+        } else {
+            return true;
+        }
+    }
+    public boolean hasTasks() {
+        return !getExecutingTasks().isEmpty();
+    }
+    // Paper end
+
     public void a(PathfinderGoal pathfindergoal) {
         Iterator iterator = this.b.iterator();
 
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 09df00e94b..d08ef3fe10 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -2,6 +2,8 @@ package org.spigotmc;
 
 import java.util.List;
 import java.util.Set;
+
+import co.aikar.timings.MinecraftTimings;
 import net.minecraft.server.AxisAlignedBB;
 import net.minecraft.server.Chunk;
 import net.minecraft.server.Entity;
@@ -13,25 +15,29 @@ import net.minecraft.server.EntityCreature;
 import net.minecraft.server.EntityCreeper;
 import net.minecraft.server.EntityEnderCrystal;
 import net.minecraft.server.EntityEnderDragon;
-import net.minecraft.server.EntityFallingBlock; // Paper
+import net.minecraft.server.EntityFallingBlock;
 import net.minecraft.server.EntityFireball;
 import net.minecraft.server.EntityFireworks;
+import net.minecraft.server.EntityFish;
 import net.minecraft.server.EntityHuman;
+import net.minecraft.server.EntityInsentient;
 import net.minecraft.server.EntityLiving;
+import net.minecraft.server.EntityLlama;
 import net.minecraft.server.EntityMonster;
 import net.minecraft.server.EntityProjectile;
 import net.minecraft.server.EntitySheep;
-import net.minecraft.server.EntitySlice;
 import net.minecraft.server.EntitySlime;
 import net.minecraft.server.EntityTNTPrimed;
 import net.minecraft.server.EntityThrownTrident;
 import net.minecraft.server.EntityVillager;
+import net.minecraft.server.EntityWaterAnimal;
 import net.minecraft.server.EntityWeather;
 import net.minecraft.server.EntityWither;
+import net.minecraft.server.MCUtil;
 import net.minecraft.server.MathHelper;
 import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.NavigationGuardian;
 import net.minecraft.server.World;
-import co.aikar.timings.MinecraftTimings;
 
 public class ActivationRange
 {
@@ -39,6 +45,7 @@ public class ActivationRange
     static AxisAlignedBB maxBB = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
     static AxisAlignedBB miscBB = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
     static AxisAlignedBB animalBB = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
+    static AxisAlignedBB waterBB = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 ); // Paper
     static AxisAlignedBB monsterBB = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
 
     /**
@@ -50,6 +57,7 @@ public class ActivationRange
      */
     public static byte initializeEntityActivationType(Entity entity)
     {
+        if (entity instanceof EntityWaterAnimal) { return 4; } // Paper
         if ( entity instanceof EntityMonster || entity instanceof EntitySlime )
         {
             return 1; // Monster
@@ -74,6 +82,7 @@ public class ActivationRange
         if ( ( entity.activationType == 3 && config.miscActivationRange == 0 )
                 || ( entity.activationType == 2 && config.animalActivationRange == 0 )
                 || ( entity.activationType == 1 && config.monsterActivationRange == 0 )
+                || ( entity.activationType == 4 && config.waterActivationRange == 0 ) // Paper
                 || entity instanceof EntityHuman
                 || entity instanceof EntityProjectile
                 || entity instanceof EntityEnderDragon
@@ -105,11 +114,13 @@ public class ActivationRange
         final int miscActivationRange = world.spigotConfig.miscActivationRange;
         final int animalActivationRange = world.spigotConfig.animalActivationRange;
         final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
+        final int waterActivationRange = world.spigotConfig.waterActivationRange; // Paper
 
         int maxRange = Math.max( monsterActivationRange, animalActivationRange );
         maxRange = Math.max( maxRange, miscActivationRange );
         //maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange ); Paper - Use player view distance API below instead
 
+        Chunk chunk; // Paper
         for ( EntityHuman player : world.players )
         {
             int playerMaxRange = maxRange = Math.min( ( player.getViewDistance() << 4 ) - 8, maxRange ); // Paper - Use player view distance API
@@ -117,6 +128,7 @@ public class ActivationRange
             maxBB = player.getBoundingBox().grow( playerMaxRange, 256, playerMaxRange ); // Paper - Use player view distance API
             miscBB = player.getBoundingBox().grow( miscActivationRange, 256, miscActivationRange );
             animalBB = player.getBoundingBox().grow( animalActivationRange, 256, animalActivationRange );
+            waterBB = player.getBoundingBox().grow( waterActivationRange, 256, waterActivationRange ); // Paper
             monsterBB = player.getBoundingBox().grow( monsterActivationRange, 256, monsterActivationRange );
 
             int i = MathHelper.floor( maxBB.minX / 16.0D );
@@ -128,9 +140,9 @@ public class ActivationRange
             {
                 for ( int j1 = k; j1 <= l; ++j1 )
                 {
-                    if ( world.getWorld().isChunkLoaded( i1, j1 ) )
+                    if ( (chunk = world.getChunkIfLoaded(i1, j1 )) != null ) // Paper
                     {
-                        activateChunkEntities( world.getChunkAt( i1, j1 ) );
+                        activateChunkEntities( chunk ); // Paper
                     }
                 }
             }
@@ -170,6 +182,14 @@ public class ActivationRange
                                 entity.activatedTick = MinecraftServer.currentTick;
                             }
                             break;
+                            // Paper start
+                        case 4:
+                            if ( waterBB.c( entity.getBoundingBox() ) )
+                            {
+                                entity.activatedTick = MinecraftServer.currentTick;
+                            }
+                            break;
+                            // Paper end
                         case 3:
                         default:
                             if ( miscBB.c( entity.getBoundingBox() ) )
@@ -191,11 +211,17 @@ public class ActivationRange
      */
     public static boolean checkEntityImmunities(Entity entity)
     {
-        // quick checks.
-        if ( entity.inWater || entity.fireTicks > 0 )
-        {
+        // Paper start - optimize Water cases
+        if (entity instanceof EntityFish) {
+            return false;
+        }
+        if (entity.inWater && (!(entity instanceof EntityInsentient) || !(((EntityInsentient) entity).getNavigation() instanceof NavigationGuardian))) {
             return true;
         }
+        if (entity.fireTicks > 0) {
+            return true;
+        }
+        // Paper end
         if ( !( entity instanceof EntityArrow ) )
         {
             if ( !entity.onGround || !entity.passengers.isEmpty() || entity.isPassenger() )
@@ -210,18 +236,29 @@ public class ActivationRange
         if ( entity instanceof EntityLiving )
         {
             EntityLiving living = (EntityLiving) entity;
-            if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTicks > 0 || living.effects.size() > 0 )
+            if ( living.lastDamageByPlayerTime > 0 || living.hurtTicks > 0 || living.effects.size() > 0 ) // Paper
             {
                 return true;
             }
-            if ( entity instanceof EntityCreature && ( (EntityCreature) entity ).getGoalTarget() != null )
+            if ( entity instanceof EntityCreature )
             {
-                return true;
+                // Paper start
+                EntityCreature creature = (EntityCreature) entity;
+                if (creature.getGoalTarget() != null || creature.getMovingTarget() != null) {
+                    return true;
+                }
+                // Paper end
             }
             if ( entity instanceof EntityVillager && ( (EntityVillager) entity ).isInLove() )
             {
                 return true;
             }
+            // Paper start
+            if ( entity instanceof EntityLlama && ( (EntityLlama ) entity ).inCaravan() )
+            {
+                return true;
+            }
+            // Paper end
             if ( entity instanceof EntityAnimal )
             {
                 EntityAnimal animal = (EntityAnimal) entity;
@@ -268,16 +305,20 @@ public class ActivationRange
                     entity.activatedTick = MinecraftServer.currentTick + 20;
                 }
                 isActive = true;
+                // Paper start
+            } else if (entity instanceof EntityInsentient && ((EntityInsentient) entity).targetSelector.hasTasks()) {
+                isActive = true;
             }
+            // Paper end
             // 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 && !(entity instanceof EntityInsentient && ((EntityInsentient) entity).targetSelector.hasTasks()) && !checkEntityImmunities( entity ) ) // Paper - add targetSelector.hasTasks
         {
             isActive = false;
         }
-        int x = MathHelper.floor( entity.locX );
-        int z = MathHelper.floor( entity.locZ );
+        //int x = MathHelper.floor( entity.locX ); // Paper
+        //int z = MathHelper.floor( entity.locZ ); // Paper
         // Make sure not on edge of unloaded chunk
-        Chunk chunk = entity.world.getChunkIfLoaded( x >> 4, z >> 4 );
+        Chunk chunk = entity.getChunkAtLocation(); // Paper
         if ( isActive && !( chunk != null && chunk.areNeighborsLoaded( 1 ) ) )
         {
             isActive = false;
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index d3c2abc398..1d222eaff7 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -150,12 +150,14 @@ public class SpigotWorldConfig
     public int animalActivationRange = 32;
     public int monsterActivationRange = 32;
     public int miscActivationRange = 16;
+    public int waterActivationRange = 16; // Paper
     public boolean tickInactiveVillagers = true;
     private void activationRange()
     {
         animalActivationRange = getInt( "entity-activation-range.animals", animalActivationRange );
         monsterActivationRange = getInt( "entity-activation-range.monsters", monsterActivationRange );
         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 + " / Mi " + miscActivationRange + " / Tiv " + tickInactiveVillagers );
     }
-- 
2.21.0

