aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0345-Entity-Activation-Range-2.0.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0345-Entity-Activation-Range-2.0.patch')
-rw-r--r--patches/server/0345-Entity-Activation-Range-2.0.patch808
1 files changed, 808 insertions, 0 deletions
diff --git a/patches/server/0345-Entity-Activation-Range-2.0.patch b/patches/server/0345-Entity-Activation-Range-2.0.patch
new file mode 100644
index 0000000000..a17d561fe8
--- /dev/null
+++ b/patches/server/0345-Entity-Activation-Range-2.0.patch
@@ -0,0 +1,808 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Fri, 13 May 2016 01:38:06 -0400
+Subject: [PATCH] Entity Activation Range 2.0
+
+Optimizes performance of Activation Range
+
+Adds many new configurations and a new wake up inactive system
+
+Fixes and adds new Immunities to improve gameplay behavior
+
+Adds water Mobs to activation range config and nerfs fish
+Adds flying monsters to control ghast and phantoms
+Adds villagers as separate config
+
+diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
+index faee1edda215fa72f5b7e1bdbbeb01004d019b0d..4a06da72c8b769c683e9eb03817bd9381a0cf099 100644
+--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
+@@ -2,7 +2,6 @@ package net.minecraft.server.level;
+
+ import com.google.common.annotations.VisibleForTesting;
+ import co.aikar.timings.TimingHistory; // Paper
+-import co.aikar.timings.Timings; // Paper
+ import com.google.common.collect.Lists;
+ import com.mojang.datafixers.DataFixer;
+ import com.mojang.datafixers.util.Pair;
+@@ -1026,17 +1025,17 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ ++TimingHistory.entityTicks; // Paper - timings
+ // Spigot start
+ co.aikar.timings.Timing timer; // Paper
+- if (!org.spigotmc.ActivationRange.checkIfActive(entity)) {
++ /*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out - EAR 2, reimplement below
+ entity.tickCount++;
+ timer = entity.getType().inactiveTickTimer.startTiming(); try { // Paper - timings
+ entity.inactiveTick();
+ } finally { timer.stopTiming(); } // Paper
+ return;
+- }
++ }*/ // Paper - comment out EAR 2
+ // Spigot end
+ // Paper start- timings
+- TimingHistory.activatedEntityTicks++;
+- timer = entity.getVehicle() != null ? entity.getType().passengerTickTimer.startTiming() : entity.getType().tickTimer.startTiming();
++ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity);
++ timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper
+ try {
+ // Paper end - timings
+ entity.setOldPosAndRot();
+@@ -1047,9 +1046,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ return Registry.ENTITY_TYPE.getKey(entity.getType()).toString();
+ });
+ gameprofilerfiller.incrementCounter("tickNonPassenger");
++ if (isActive) { // Paper - EAR 2
++ TimingHistory.activatedEntityTicks++;
+ entity.tick();
+ entity.postTick(); // CraftBukkit
++ } else { entity.inactiveTick(); } // Paper - EAR 2
+ this.getProfiler().pop();
++ } finally { timer.stopTiming(); } // Paper - timings
+ Iterator iterator = entity.getPassengers().iterator();
+
+ while (iterator.hasNext()) {
+@@ -1057,13 +1060,18 @@ public class ServerLevel extends Level implements WorldGenLevel {
+
+ this.tickPassenger(entity, entity1);
+ }
+- } finally { timer.stopTiming(); } // Paper - timings
++ // } finally { timer.stopTiming(); } // Paper - timings - move up
+
+ }
+
+ private void tickPassenger(Entity vehicle, Entity passenger) {
+ if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) {
+ if (passenger instanceof Player || this.entityTickList.contains(passenger)) {
++ // Paper - EAR 2
++ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(passenger);
++ co.aikar.timings.Timing timer = isActive ? passenger.getType().passengerTickTimer.startTiming() : passenger.getType().passengerInactiveTickTimer.startTiming(); // Paper
++ try {
++ // Paper end
+ passenger.setOldPosAndRot();
+ ++passenger.tickCount;
+ ProfilerFiller gameprofilerfiller = this.getProfiler();
+@@ -1072,8 +1080,17 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ return Registry.ENTITY_TYPE.getKey(passenger.getType()).toString();
+ });
+ gameprofilerfiller.incrementCounter("tickPassenger");
++ // Paper start - EAR 2
++ if (isActive) {
+ passenger.rideTick();
+ passenger.postTick(); // CraftBukkit
++ } else {
++ passenger.setDeltaMovement(Vec3.ZERO);
++ passenger.inactiveTick();
++ // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary
++ vehicle.positionRider(passenger);
++ }
++ // Paper end - EAR 2
+ gameprofilerfiller.pop();
+ Iterator iterator = passenger.getPassengers().iterator();
+
+@@ -1083,6 +1100,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ this.tickPassenger(passenger, entity2);
+ }
+
++ } finally { timer.stopTiming(); }// Paper - EAR2 timings
+ }
+ } else {
+ passenger.stopRiding();
+diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
+index fa128e7f8089339f932e19edf95a8d5c0cc14046..c5b1d2e4b577a3f4ad352dc6a8436c04411efa8b 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -384,6 +384,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ public void inactiveTick() { }
+ // Spigot end
+ // Paper start
++ public long activatedImmunityTick = Integer.MIN_VALUE; // Paper
++ public boolean isTemporarilyActive = false; // Paper
+ protected int numCollisions = 0; // Paper
+ public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
+ @javax.annotation.Nullable
+@@ -909,6 +911,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ } else {
+ this.wasOnFire = this.isOnFire();
+ if (movementType == MoverType.PISTON) {
++ this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); // Paper
++ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); // Paper
+ movement = this.limitPistonMovement(movement);
+ if (movement.equals(Vec3.ZERO)) {
+ return;
+@@ -921,6 +925,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ this.stuckSpeedMultiplier = Vec3.ZERO;
+ this.setDeltaMovement(Vec3.ZERO);
+ }
++ // Paper start - ignore movement changes while inactive.
++ if (isTemporarilyActive && !(this instanceof ItemEntity || this instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) && movement == getDeltaMovement() && movementType == MoverType.SELF) {
++ setDeltaMovement(Vec3.ZERO);
++ this.level.getProfiler().pop();
++ return;
++ }
++ // Paper end
+
+ movement = this.maybeBackOffFromEdge(movement, movementType);
+ Vec3 vec3d1 = this.collide(movement);
+diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
+index 7b3ce253e76cf411768af4961abd148f242f4bb4..2ae973d77d0b088cf7dc7a2338b8b7461e585dca 100644
+--- a/src/main/java/net/minecraft/world/entity/Mob.java
++++ b/src/main/java/net/minecraft/world/entity/Mob.java
+@@ -210,6 +210,19 @@ public abstract class Mob extends LivingEntity {
+ return this.lookControl;
+ }
+
++ // Paper start
++ @Override
++ public void inactiveTick() {
++ super.inactiveTick();
++ if (this.goalSelector.inactiveTick()) {
++ this.goalSelector.tick();
++ }
++ if (this.targetSelector.inactiveTick()) {
++ this.targetSelector.tick();
++ }
++ }
++ // Paper end
++
+ public MoveControl getMoveControl() {
+ if (this.isPassenger() && this.getVehicle() instanceof Mob) {
+ Mob entityinsentient = (Mob) this.getVehicle();
+diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
+index 2df5b50be11297941d13ec9d17001f488af11750..3db309e709cd72e3aae184ff2f8b1a7b98f2c7a8 100644
+--- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java
++++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
+@@ -19,6 +19,7 @@ public abstract class PathfinderMob extends Mob {
+ }
+
+ public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
++ public BlockPos movingTarget = null; public BlockPos getMovingTarget() { return movingTarget; } // Paper
+
+ public float getWalkTargetValue(BlockPos pos) {
+ return this.getWalkTargetValue(pos, this.level);
+diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+index 3e981fbf81f21b40652f7a05d4a7a37065db4b00..19ee04dd92b39a775260f832ca8880335d24988b 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+@@ -32,6 +32,7 @@ public class GoalSelector {
+ private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
+ private int tickCount;
+ private int newGoalRate = 3;
++ private int curRate;
+
+ public GoalSelector(Supplier<ProfilerFiller> profiler) {
+ this.profiler = profiler;
+@@ -46,6 +47,20 @@ public class GoalSelector {
+ this.availableGoals.clear();
+ }
+
++ // Paper start
++ public boolean inactiveTick() {
++ this.curRate++;
++ return this.curRate % this.newGoalRate == 0;
++ }
++ public boolean hasTasks() {
++ for (WrappedGoal task : this.availableGoals) {
++ if (task.isRunning()) {
++ return true;
++ }
++ }
++ return false;
++ }
++ // Paper end
+ public void removeGoal(Goal goal) {
+ this.availableGoals.stream().filter((wrappedGoal) -> {
+ return wrappedGoal.getGoal() == goal;
+diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+index 6efba52c2e5d7811ee329ed22c1c76f75d7ddbe1..26bf383caea68834c654b25653ced9017f1b1b22 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+@@ -14,7 +14,7 @@ public abstract class MoveToBlockGoal extends Goal {
+ protected int nextStartTick;
+ protected int tryTicks;
+ private int maxStayTicks;
+- protected BlockPos blockPos = BlockPos.ZERO; @Deprecated public final BlockPos getTargetPosition() { return this.blockPos; } // Paper - OBFHELPER
++ protected BlockPos blockPos = BlockPos.ZERO; @Deprecated public final BlockPos getTargetPosition() { return this.blockPos; } @Deprecated public void setTargetPosition(BlockPos pos) { this.blockPos = pos; mob.movingTarget = pos != BlockPos.ZERO ? pos : null; } // Paper - OBFHELPER
+ private boolean reachedTarget;
+ private final int searchRange;
+ private final int verticalSearchRange;
+@@ -23,6 +23,13 @@ public abstract class MoveToBlockGoal extends Goal {
+ public MoveToBlockGoal(PathfinderMob mob, double speed, int range) {
+ this(mob, speed, range, 1);
+ }
++ // Paper start - activation range improvements
++ @Override
++ public void stop() {
++ super.stop();
++ setTargetPosition(BlockPos.ZERO);
++ }
++ // Paper end
+
+ public MoveToBlockGoal(PathfinderMob mob, double speed, int range, int maxYDifference) {
+ this.mob = mob;
+@@ -114,6 +121,7 @@ public abstract class MoveToBlockGoal extends Goal {
+ mutableBlockPos.setWithOffset(blockPos, m, k - 1, n);
+ if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level, mutableBlockPos)) {
+ this.blockPos = mutableBlockPos;
++ setTargetPosition(mutableBlockPos.immutable()); // Paper
+ return true;
+ }
+ }
+diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
+index f957c0aca36b7228ac3a33ca04c948b1d10642d1..39fc94b1e1555fd6706391223dd2783139b16016 100644
+--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
++++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
+@@ -225,17 +225,29 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ @Override
+ public void inactiveTick() {
+ // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
+- if (level.spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) {
+- this.customServerAiStep();
++ // Paper start
++ if (this.getUnhappyCounter() > 0) {
++ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
++ }
++ if (this.isEffectiveAi()) {
++ if (level.spigotConfig.tickInactiveVillagers) {
++ this.customServerAiStep();
++ } else {
++ this.mobTick(true);
++ }
+ }
++ maybeDecayGossip();
++ // Paper end
++
+ super.inactiveTick();
+ }
+ // Spigot End
+
+ @Override
+- protected void customServerAiStep() {
++ protected void customServerAiStep() { mobTick(false); }
++ protected void mobTick(boolean inactive) {
+ this.level.getProfiler().push("villagerBrain");
+- this.getBrain().tick((ServerLevel) this.level, this);
++ if (!inactive) this.getBrain().tick((ServerLevel) this.level, this); // Paper
+ this.level.getProfiler().pop();
+ if (this.assignProfessionWhenSpawned) {
+ this.assignProfessionWhenSpawned = false;
+@@ -259,7 +271,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ this.lastTradedPlayer = null;
+ }
+
+- if (!this.isNoAi() && this.random.nextInt(100) == 0) {
++ if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper
+ Raid raid = ((ServerLevel) this.level).getRaidAt(this.blockPosition());
+
+ if (raid != null && raid.isActive() && !raid.isOver()) {
+@@ -270,6 +282,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.isTrading()) {
+ this.stopTrading();
+ }
++ if (inactive) return; // Paper
+
+ super.customServerAiStep();
+ }
+diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
+index 540c23f6297c34cf8e7bf8312ceaa5fc868f414c..2866385a64b22b7dc82b6122c62bcea6b0908a60 100644
+--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
++++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
+@@ -57,6 +57,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
+ if (bl != this.isEnabled()) {
+ this.setEnabled(bl);
+ }
++ this.immunize(); // Paper
+
+ }
+
+@@ -107,11 +108,13 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
+
+ public boolean suckInItems() {
+ if (HopperBlockEntity.suckInItems(this.level, this)) {
++ this.immunize(); // Paper
+ return true;
+ } else {
+ List<ItemEntity> list = this.level.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25D, 0.0D, 0.25D), EntitySelector.ENTITY_STILL_ALIVE);
+ if (!list.isEmpty()) {
+ HopperBlockEntity.addItem(this, list.get(0));
++ this.immunize(); // Paper
+ }
+
+ return false;
+@@ -149,4 +152,11 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
+ public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) {
+ return new HopperMenu(syncId, playerInventory, this);
+ }
++
++ // Paper start
++ public void immunize() {
++ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 20);
++ }
++ // Paper end
++
+ }
+diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
+index cb7e92f2694cefeecebc840959a01e1e1945061a..10a5315c6a2f872d88c080910eeca140ac6fbbc4 100644
+--- a/src/main/java/net/minecraft/world/level/Level.java
++++ b/src/main/java/net/minecraft/world/level/Level.java
+@@ -158,6 +158,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ public Map<BlockPos, BlockEntity> capturedTileEntities = new HashMap<>();
+ public List<ItemEntity> captureDrops;
+ public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<SpawnCategory> ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>();
++ // Paper start
++ public int wakeupInactiveRemainingAnimals;
++ public int wakeupInactiveRemainingFlying;
++ public int wakeupInactiveRemainingMonsters;
++ public int wakeupInactiveRemainingVillagers;
++ // Paper end
+ public boolean populating;
+ public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
+ // Paper start
+diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+index 4b55b667eebfe50dfeda89015112e275e71b9777..dda0b32a4989bbead35a2219a969a30ba0e975b0 100644
+--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+@@ -140,6 +140,10 @@ public class PistonMovingBlockEntity extends BlockEntity {
+ }
+
+ entity.setDeltaMovement(e, g, h);
++ // Paper - EAR items stuck in in slime pushed by a piston
++ entity.activatedTick = Math.max(entity.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 10);
++ entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 10);
++ // Paper end
+ break;
+ }
+ }
+diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
+index 2861c585710eaa00541ff417a29f1f6a2fb5b46a..b1ed97618d08d7691d24f89e9e9b0ed0f2bddd09 100644
+--- a/src/main/java/org/spigotmc/ActivationRange.java
++++ b/src/main/java/org/spigotmc/ActivationRange.java
+@@ -1,39 +1,52 @@
+ package org.spigotmc;
+
++import net.minecraft.core.BlockPos;
+ import net.minecraft.server.MinecraftServer;
++import net.minecraft.server.level.ServerChunkCache;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.ExperienceOrb;
++import net.minecraft.world.entity.FlyingMob;
+ import net.minecraft.world.entity.LightningBolt;
+ import net.minecraft.world.entity.LivingEntity;
++import net.minecraft.world.entity.Mob;
+ import net.minecraft.world.entity.PathfinderMob;
++import net.minecraft.world.entity.ai.Brain;
+ import net.minecraft.world.entity.ambient.AmbientCreature;
+ import net.minecraft.world.entity.animal.Animal;
++import net.minecraft.world.entity.animal.Bee;
+ import net.minecraft.world.entity.animal.Sheep;
++import net.minecraft.world.entity.animal.WaterAnimal;
++import net.minecraft.world.entity.animal.horse.Llama;
+ import net.minecraft.world.entity.boss.EnderDragonPart;
+ import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
+ import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
+ import net.minecraft.world.entity.boss.wither.WitherBoss;
+ import net.minecraft.world.entity.item.PrimedTnt;
+ import net.minecraft.world.entity.monster.Creeper;
+-import net.minecraft.world.entity.monster.Monster;
+-import net.minecraft.world.entity.monster.Slime;
++import net.minecraft.world.entity.monster.Enemy;
++import net.minecraft.world.entity.monster.Pillager;
+ import net.minecraft.world.entity.npc.Villager;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.AbstractArrow;
+ import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
++import net.minecraft.world.entity.projectile.EyeOfEnder;
+ import net.minecraft.world.entity.projectile.FireworkRocketEntity;
+ import net.minecraft.world.entity.projectile.ThrowableProjectile;
+ import net.minecraft.world.entity.projectile.ThrownTrident;
+ import net.minecraft.world.entity.raid.Raider;
++import co.aikar.timings.MinecraftTimings;
++import net.minecraft.world.entity.schedule.Activity;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.phys.AABB;
+-import co.aikar.timings.MinecraftTimings;
+
+ public class ActivationRange
+ {
+
+ public enum ActivationType
+ {
++ WATER, // Paper
++ FLYING_MONSTER, // Paper
++ VILLAGER, // Paper
+ MONSTER,
+ ANIMAL,
+ RAIDER,
+@@ -41,6 +54,43 @@ public class ActivationRange
+
+ AABB boundingBox = new AABB( 0, 0, 0, 0, 0, 0 );
+ }
++ // Paper start
++
++ static Activity[] VILLAGER_PANIC_IMMUNITIES = {
++ Activity.HIDE,
++ Activity.PRE_RAID,
++ Activity.RAID,
++ Activity.PANIC
++ };
++
++ private static int checkInactiveWakeup(Entity entity) {
++ Level world = entity.level;
++ SpigotWorldConfig config = world.spigotConfig;
++ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
++ if (entity.activationType == ActivationType.VILLAGER) {
++ if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) {
++ world.wakeupInactiveRemainingVillagers--;
++ return config.wakeUpInactiveVillagersFor;
++ }
++ } else if (entity.activationType == ActivationType.ANIMAL) {
++ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) {
++ world.wakeupInactiveRemainingAnimals--;
++ return config.wakeUpInactiveAnimalsFor;
++ }
++ } else if (entity.activationType == ActivationType.FLYING_MONSTER) {
++ if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) {
++ world.wakeupInactiveRemainingFlying--;
++ return config.wakeUpInactiveFlyingFor;
++ }
++ } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) {
++ if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) {
++ world.wakeupInactiveRemainingMonsters--;
++ return config.wakeUpInactiveMonstersFor;
++ }
++ }
++ return -1;
++ }
++ // Paper end
+
+ static AABB maxBB = new AABB( 0, 0, 0, 0, 0, 0 );
+
+@@ -53,10 +103,13 @@ public class ActivationRange
+ */
+ public static ActivationType initializeEntityActivationType(Entity entity)
+ {
++ if (entity instanceof WaterAnimal) { return ActivationType.WATER; } // Paper
++ else if (entity instanceof Villager) { return ActivationType.VILLAGER; } // Paper
++ else if (entity instanceof FlyingMob && entity instanceof Enemy) { return ActivationType.FLYING_MONSTER; } // Paper - doing & Monster incase Flying no longer includes monster in future
+ if ( entity instanceof Raider )
+ {
+ return ActivationType.RAIDER;
+- } else if ( entity instanceof Monster || entity instanceof Slime )
++ } else if ( entity instanceof Enemy ) // Paper - correct monster check
+ {
+ return ActivationType.MONSTER;
+ } else if ( entity instanceof PathfinderMob || entity instanceof AmbientCreature )
+@@ -77,10 +130,14 @@ public class ActivationRange
+ */
+ public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config)
+ {
+- if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange == 0 )
+- || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0 )
+- || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0 )
+- || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0 )
++ if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange <= 0 )
++ || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange <= 0 )
++ || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange <= 0 )
++ || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange <= 0 )
++ || ( entity.activationType == ActivationType.VILLAGER && config.villagerActivationRange <= 0 ) // Paper
++ || ( entity.activationType == ActivationType.WATER && config.waterActivationRange <= 0 ) // Paper
++ || ( entity.activationType == ActivationType.FLYING_MONSTER && config.flyingMonsterActivationRange <= 0 ) // Paper
++ || entity instanceof EyeOfEnder // Paper
+ || entity instanceof Player
+ || entity instanceof ThrowableProjectile
+ || entity instanceof EnderDragon
+@@ -113,10 +170,25 @@ public class ActivationRange
+ final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
+ final int animalActivationRange = world.spigotConfig.animalActivationRange;
+ final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
++ // Paper start
++ final int waterActivationRange = world.spigotConfig.waterActivationRange;
++ final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange;
++ final int villagerActivationRange = world.spigotConfig.villagerActivationRange;
++ world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals);
++ world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers);
++ world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters);
++ world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying);
++ final ServerChunkCache chunkProvider = (ServerChunkCache) world.getChunkSource();
++ // Paper end
+
+ int maxRange = Math.max( monsterActivationRange, animalActivationRange );
+ maxRange = Math.max( maxRange, raiderActivationRange );
+ maxRange = Math.max( maxRange, miscActivationRange );
++ // Paper start
++ maxRange = Math.max( maxRange, flyingActivationRange );
++ maxRange = Math.max( maxRange, waterActivationRange );
++ maxRange = Math.max( maxRange, villagerActivationRange );
++ // Paper end
+ maxRange = Math.min( ( world.spigotConfig.simulationDistance << 4 ) - 8, maxRange );
+
+ for ( Player player : world.players() )
+@@ -127,11 +199,17 @@ public class ActivationRange
+ continue;
+ }
+
+- ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, 256, maxRange );
+- ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, 256, miscActivationRange );
+- ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange );
+- ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, 256, animalActivationRange );
+- ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, 256, monsterActivationRange );
++ // Paper start
++ int worldHeight = world.getHeight();
++ ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange );
++ ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, worldHeight, miscActivationRange );
++ ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, worldHeight, raiderActivationRange );
++ ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, worldHeight, animalActivationRange );
++ ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, worldHeight, monsterActivationRange );
++ ActivationType.WATER.boundingBox = player.getBoundingBox().inflate( waterActivationRange, worldHeight, waterActivationRange );
++ ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate( flyingActivationRange, worldHeight, flyingActivationRange );
++ ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange );
++ // Paper end
+
+ // Paper start
+ java.util.List<Entity> entities = world.getEntities((Entity)null, maxBB, null);
+@@ -172,60 +250,118 @@ 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
+ {
++ // Paper start
++ SpigotWorldConfig config = entity.level.spigotConfig;
++ int inactiveWakeUpImmunity = checkInactiveWakeup(entity);
++ if (inactiveWakeUpImmunity > -1) {
++ return inactiveWakeUpImmunity;
++ }
++ if (entity.remainingFireTicks > 0) {
++ return 2;
++ }
++ if (entity.activatedImmunityTick >= MinecraftServer.currentTick) {
++ return 1;
++ }
++ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
++ // Paper end
+ // quick checks.
+- if ( entity.wasTouchingWater || entity.remainingFireTicks > 0 )
++ if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper
+ {
+- return true;
++ return 100; // Paper
++ }
++ // Paper start
++ if ( !entity.isOnGround() || entity.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D )
++ {
++ return 100;
+ }
++ // Paper end
+ if ( !( entity instanceof AbstractArrow ) )
+ {
+- if ( !entity.isOnGround() || !entity.passengers.isEmpty() || entity.isPassenger() )
++ if ( (!entity.isOnGround() && !(entity instanceof FlyingMob)) ) // Paper - remove passengers logic
+ {
+- return true;
++ return 10; // Paper
+ }
+ } else if ( !( (AbstractArrow) entity ).inGround )
+ {
+- return true;
++ return 1; // Paper
+ }
+ // special cases.
+ if ( entity instanceof LivingEntity )
+ {
+ LivingEntity living = (LivingEntity) entity;
+- if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTime > 0 || living.activeEffects.size() > 0 )
++ if ( living.onClimbable() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 ) // Paper
+ {
+- return true;
++ return 1; // Paper
+ }
+- if ( entity instanceof PathfinderMob && ( (PathfinderMob) entity ).getTarget() != null )
++ if ( entity instanceof Mob && ((Mob) entity ).getTarget() != null) // Paper
+ {
+- return true;
++ return 20; // Paper
++ }
++ // Paper start
++ if (entity instanceof Bee) {
++ Bee bee = (Bee)entity;
++ BlockPos movingTarget = bee.getMovingTarget();
++ if (bee.isAngry() ||
++ (bee.getHivePos() != null && bee.getHivePos().equals(movingTarget)) ||
++ (bee.getSavedFlowerPos() != null && bee.getSavedFlowerPos().equals(movingTarget))
++ ) {
++ return 20;
++ }
++ }
++ if ( entity instanceof Villager ) {
++ Brain<Villager> behaviorController = ((Villager) entity).getBrain();
++
++ if (config.villagersActiveForPanic) {
++ for (Activity activity : VILLAGER_PANIC_IMMUNITIES) {
++ if (behaviorController.isActive(activity)) {
++ return 20*5;
++ }
++ }
++ }
++
++ if (config.villagersWorkImmunityAfter > 0 && inactiveFor >= config.villagersWorkImmunityAfter) {
++ if (behaviorController.isActive(Activity.WORK)) {
++ return config.villagersWorkImmunityFor;
++ }
++ }
+ }
+- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() )
++ if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() )
+ {
+- return true;
++ return 1;
+ }
++ // Paper end
+ if ( entity instanceof Animal )
+ {
+ Animal animal = (Animal) entity;
+ if ( animal.isBaby() || animal.isInLove() )
+ {
+- return true;
++ return 5; // Paper
+ }
+ if ( entity instanceof Sheep && ( (Sheep) entity ).isSheared() )
+ {
+- return true;
++ return 1; // Paper
+ }
+ }
+ if (entity instanceof Creeper && ((Creeper) entity).isIgnited()) { // isExplosive
+- return true;
++ return 20; // Paper
++ }
++ // Paper start
++ if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) {
++ return 0;
+ }
++ if (entity instanceof Pillager) {
++ Pillager pillager = (Pillager) entity;
++ // TODO:?
++ }
++ // Paper end
+ }
+ // SPIGOT-6644: Otherwise the target refresh tick will be missed
+ if (entity instanceof ExperienceOrb) {
+- return true;
++ return 20; // Paper
+ }
+- return false;
++ return -1; // Paper
+ }
+
+ /**
+@@ -240,8 +376,19 @@ public class ActivationRange
+ if ( entity instanceof FireworkRocketEntity ) {
+ return true;
+ }
++ // Paper start - special case always immunities
++ // immunize brand new entities, dead entities, and portal scenarios
++ if (entity.defaultActivationState || entity.tickCount < 20*10 || !entity.isAlive() || entity.isInsidePortal || entity.portalCooldown > 0) {
++ return true;
++ }
++ // immunize leashed entities
++ if (entity instanceof Mob && ((Mob)entity).leashHolder instanceof Player) {
++ return true;
++ }
++ // Paper end
+
+- boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;
++ boolean isActive = entity.activatedTick >= MinecraftServer.currentTick;
++ entity.isTemporarilyActive = false; // Paper
+
+ // Should this entity tick?
+ if ( !isActive )
+@@ -249,15 +396,19 @@ public class ActivationRange
+ if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 )
+ {
+ // Check immunities every 20 ticks.
+- if ( ActivationRange.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.tickCount + entity.getId() + 1 % 4 == 0 && !ActivationRange.checkEntityImmunities( entity ) ) // Paper - Ensure checking item movement is offset from Spigot's entity activation range check
++ } else if ( entity.tickCount + entity.getId() + 1 % 4 == 0 && ActivationRange.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 d4d2d11cf19167410ec6ad3417495e7130330d11..9c9723e13b5440d4803a7268057d63cbdc973b77 100644
+--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+@@ -199,14 +199,60 @@ public class SpigotWorldConfig
+ public int monsterActivationRange = 32;
+ public int raiderActivationRange = 48;
+ public int miscActivationRange = 16;
++ // Paper start
++ public int flyingMonsterActivationRange = 32;
++ public int waterActivationRange = 16;
++ public int villagerActivationRange = 32;
++ public int wakeUpInactiveAnimals = 4;
++ public int wakeUpInactiveAnimalsEvery = 60*20;
++ public int wakeUpInactiveAnimalsFor = 5*20;
++ public int wakeUpInactiveMonsters = 8;
++ public int wakeUpInactiveMonstersEvery = 20*20;
++ public int wakeUpInactiveMonstersFor = 5*20;
++ public int wakeUpInactiveVillagers = 4;
++ public int wakeUpInactiveVillagersEvery = 30*20;
++ public int wakeUpInactiveVillagersFor = 5*20;
++ public int wakeUpInactiveFlying = 8;
++ public int wakeUpInactiveFlyingEvery = 10*20;
++ public int wakeUpInactiveFlyingFor = 5*20;
++ public int villagersWorkImmunityAfter = 5*20;
++ public int villagersWorkImmunityFor = 20;
++ public boolean villagersActiveForPanic = true;
++ // Paper end
+ public boolean tickInactiveVillagers = true;
+ public boolean ignoreSpectatorActivation = false;
+ private void activationRange()
+ {
++ boolean hasAnimalsConfig = config.getInt("entity-activation-range.animals", this.animalActivationRange) != this.animalActivationRange; // Paper
+ this.animalActivationRange = this.getInt( "entity-activation-range.animals", this.animalActivationRange );
+ this.monsterActivationRange = this.getInt( "entity-activation-range.monsters", this.monsterActivationRange );
+ this.raiderActivationRange = this.getInt( "entity-activation-range.raiders", this.raiderActivationRange );
+ this.miscActivationRange = this.getInt( "entity-activation-range.misc", this.miscActivationRange );
++ // Paper start
++ this.waterActivationRange = this.getInt( "entity-activation-range.water", this.waterActivationRange );
++ this.villagerActivationRange = this.getInt( "entity-activation-range.villagers", hasAnimalsConfig ? this.animalActivationRange : this.villagerActivationRange );
++ this.flyingMonsterActivationRange = this.getInt( "entity-activation-range.flying-monsters", this.flyingMonsterActivationRange );
++
++ this.wakeUpInactiveAnimals = this.getInt("entity-activation-range.wake-up-inactive.animals-max-per-tick", this.wakeUpInactiveAnimals);
++ this.wakeUpInactiveAnimalsEvery = this.getInt("entity-activation-range.wake-up-inactive.animals-every", this.wakeUpInactiveAnimalsEvery);
++ this.wakeUpInactiveAnimalsFor = this.getInt("entity-activation-range.wake-up-inactive.animals-for", this.wakeUpInactiveAnimalsFor);
++
++ this.wakeUpInactiveMonsters = this.getInt("entity-activation-range.wake-up-inactive.monsters-max-per-tick", this.wakeUpInactiveMonsters);
++ this.wakeUpInactiveMonstersEvery = this.getInt("entity-activation-range.wake-up-inactive.monsters-every", this.wakeUpInactiveMonstersEvery);
++ this.wakeUpInactiveMonstersFor = this.getInt("entity-activation-range.wake-up-inactive.monsters-for", this.wakeUpInactiveMonstersFor);
++
++ this.wakeUpInactiveVillagers = this.getInt("entity-activation-range.wake-up-inactive.villagers-max-per-tick", this.wakeUpInactiveVillagers);
++ this.wakeUpInactiveVillagersEvery = this.getInt("entity-activation-range.wake-up-inactive.villagers-every", this.wakeUpInactiveVillagersEvery);
++ this.wakeUpInactiveVillagersFor = this.getInt("entity-activation-range.wake-up-inactive.villagers-for", this.wakeUpInactiveVillagersFor);
++
++ this.wakeUpInactiveFlying = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-max-per-tick", this.wakeUpInactiveFlying);
++ this.wakeUpInactiveFlyingEvery = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-every", this.wakeUpInactiveFlyingEvery);
++ this.wakeUpInactiveFlyingFor = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-for", this.wakeUpInactiveFlyingFor);
++
++ this.villagersWorkImmunityAfter = this.getInt( "entity-activation-range.villagers-work-immunity-after", this.villagersWorkImmunityAfter );
++ this.villagersWorkImmunityFor = this.getInt( "entity-activation-range.villagers-work-immunity-for", this.villagersWorkImmunityFor );
++ this.villagersActiveForPanic = this.getBoolean( "entity-activation-range.villagers-active-for-panic", this.villagersActiveForPanic );
++ // Paper end
+ this.tickInactiveVillagers = this.getBoolean( "entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers );
+ this.ignoreSpectatorActivation = this.getBoolean( "entity-activation-range.ignore-spectators", this.ignoreSpectatorActivation );
+ this.log( "Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers + " / Isa " + this.ignoreSpectatorActivation );