aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0994-Entity-Activation-Range-2.0.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0994-Entity-Activation-Range-2.0.patch')
-rw-r--r--patches/server/0994-Entity-Activation-Range-2.0.patch813
1 files changed, 813 insertions, 0 deletions
diff --git a/patches/server/0994-Entity-Activation-Range-2.0.patch b/patches/server/0994-Entity-Activation-Range-2.0.patch
new file mode 100644
index 0000000000..8ce6ec4ca8
--- /dev/null
+++ b/patches/server/0994-Entity-Activation-Range-2.0.patch
@@ -0,0 +1,813 @@
+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
+
+== AT ==
+public net.minecraft.world.entity.Entity isInsidePortal
+
+diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
+index dec865affbaaa71d09806143d13a854100b98f23..eadbf175c69b6bb2d0df723afac96a517ebf0d83 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;
+@@ -1192,17 +1191,17 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
+ ++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();
+@@ -1213,9 +1212,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
+ return BuiltInRegistries.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()) {
+@@ -1223,13 +1226,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
+
+ 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();
+@@ -1238,8 +1246,17 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
+ return BuiltInRegistries.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();
+
+@@ -1249,6 +1266,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
+ 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 0d4e1a90dbdca72df5776b1294e87c85434e53ac..6043e9fafb6dca4134e0615f04c7a5cdd6bf1c2e 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -418,6 +418,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ // Spigot end
+ protected int numCollisions = 0; // Paper - Cap entity collisions
+ public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals
++ public long activatedImmunityTick = Integer.MIN_VALUE; // Paper - EAR
++ public boolean isTemporarilyActive; // Paper - EAR
+ public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
+ // Paper start - Entity origin API
+ @javax.annotation.Nullable
+@@ -1058,6 +1060,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ } 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;
+@@ -1070,6 +1074,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ this.stuckSpeedMultiplier = Vec3.ZERO;
+ this.setDeltaMovement(Vec3.ZERO);
+ }
++ // Paper start - ignore movement changes while inactive.
++ if (isTemporarilyActive && !(this instanceof ItemEntity) && 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 58ff5b4df2124901df757315e42b2490a7da7415..763abeea3f14f15c27d600e0bdae44b387687bb4 100644
+--- a/src/main/java/net/minecraft/world/entity/Mob.java
++++ b/src/main/java/net/minecraft/world/entity/Mob.java
+@@ -232,6 +232,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ 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() {
+ Entity entity = this.getControlledVehicle();
+
+diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
+index 812aecb88641c09fb5030d145620b95aff19c9cb..ec9e76c548393235dcc6658c29e72e07e5d3510b 100644
+--- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java
++++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
+@@ -22,6 +22,8 @@ public abstract class PathfinderMob extends Mob {
+ super(type, world);
+ }
+
++ public BlockPos movingTarget; 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 89b8a304fe9fae4b57640afbab04b6764ce9aab8..074ef807258139f818e30494126585262c2f33c0 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
+@@ -26,6 +26,7 @@ public class GoalSelector {
+ private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
+ private final Supplier<ProfilerFiller> profiler;
+ private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
++ private int curRate;
+
+ public GoalSelector(Supplier<ProfilerFiller> profiler) {
+ this.profiler = profiler;
+@@ -40,6 +41,20 @@ public class GoalSelector {
+ this.availableGoals.removeIf(goal -> predicate.test(goal.getGoal()));
+ }
+
++ // Paper start
++ public boolean inactiveTick() {
++ this.curRate++;
++ return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct
++ }
++ public boolean hasTasks() {
++ for (WrappedGoal task : this.availableGoals) {
++ if (task.isRunning()) {
++ return true;
++ }
++ }
++ return false;
++ }
++ // Paper end
+ public void removeGoal(Goal goal) {
+ for (WrappedGoal wrappedGoal : this.availableGoals) {
+ if (wrappedGoal.getGoal() == goal && wrappedGoal.isRunning()) {
+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 6d8ea05e5e86e9f6359b560043bb55a10784e952..aee0147649d458b87d92496eda0c1723ebe570d2 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
+@@ -23,6 +23,14 @@ 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();
++ this.blockPos = BlockPos.ZERO;
++ this.mob.movingTarget = null;
++ }
++ // Paper end
+
+ public MoveToBlockGoal(PathfinderMob mob, double speed, int range, int maxYDifference) {
+ this.mob = mob;
+@@ -115,6 +123,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;
++ this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : 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 393588661c41b490ee6bce2f687962f7ddeff7d4..7e1871401ec5e3e9a85232053490259f132aec0a 100644
+--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
++++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
+@@ -228,17 +228,34 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ @Override
+ public void inactiveTick() {
+ // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
+- if (this.level().spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) {
+- this.customServerAiStep();
++ // Paper start
++ if (this.getUnhappyCounter() > 0) {
++ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
+ }
++ if (this.isEffectiveAi()) {
++ if (this.level().spigotConfig.tickInactiveVillagers) {
++ this.customServerAiStep();
++ } else {
++ this.customServerAiStep(true);
++ }
++ }
++ maybeDecayGossip();
++ // Paper end
++
+ super.inactiveTick();
+ }
+ // Spigot End
+
+ @Override
++ @Deprecated // Paper
+ protected void customServerAiStep() {
++ // Paper start
++ this.customServerAiStep(false);
++ }
++ protected void customServerAiStep(final boolean inactive) {
++ // Paper end
+ 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;
+@@ -262,7 +279,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()) {
+@@ -273,6 +290,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 0b7f52021441d633c37543e8ae485e81c292b747..d7f8464bf3eed0e42a5fc7f14a5b243d171f8b5e 100644
+--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
++++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
+@@ -52,6 +52,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
+ if (bl != this.isEnabled()) {
+ this.setEnabled(bl);
+ }
++ this.immunize(); // Paper
+ }
+
+ public boolean isEnabled() {
+@@ -92,11 +93,13 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
+
+ public boolean suckInItems() {
+ if (HopperBlockEntity.suckInItems(this.level(), this)) {
++ this.immunize(); // Paper
+ return true;
+ } else {
+ for (ItemEntity itemEntity : this.level()
+ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) {
+ if (HopperBlockEntity.addItem(this, itemEntity)) {
++ this.immunize(); // Paper
+ return true;
+ }
+ }
+@@ -126,4 +129,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 574175449af5b767f28e95ff8708ed37fedf4c7d..ce9350ed3c5c5fbbd9b2ade9ae2880e03305c787 100644
+--- a/src/main/java/net/minecraft/world/level/Level.java
++++ b/src/main/java/net/minecraft/world/level/Level.java
+@@ -157,6 +157,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
+ public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates
+ 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 - add paper world config
+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 d7b963571c900f0f68005d6954bcd9ef1d9e0b7c..b35f476e26a020cf75e53a5eb488717d996a6935 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
+@@ -148,6 +148,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 9fb9fa62c32445ac3c3883a6433759c86dcfc428..bf2d18f74b0f0da7c3c30310c74224a1c0853564 100644
+--- a/src/main/java/org/spigotmc/ActivationRange.java
++++ b/src/main/java/org/spigotmc/ActivationRange.java
+@@ -1,33 +1,43 @@
+ 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
+ {
+@@ -44,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 );
+
+@@ -56,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 )
+@@ -80,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
+@@ -118,10 +172,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() )
+@@ -132,13 +201,30 @@ 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
+
+- world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity);
++ // Paper start
++ java.util.List<Entity> entities = world.getEntities((Entity)null, ActivationRange.maxBB, null);
++ boolean tickMarkers = world.paperConfig().entities.markers.tick; // Paper - Configurable marker ticking
++ for (Entity entity : entities) {
++ // Paper start - Configurable marker ticking
++ if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) {
++ continue;
++ }
++ // Paper end - Configurable marker ticking
++ ActivationRange.activateEntity(entity);
++ }
++ // Paper end
+ }
+ MinecraftTimings.entityActivationCheckTimer.stopTiming();
+ }
+@@ -171,60 +257,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.getRemainingFireTicks() > 0) {
++ return 2;
++ }
++ if (entity.activatedImmunityTick >= MinecraftServer.currentTick) {
++ return 1;
++ }
++ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
++ // Paper end
+ // quick checks.
+- if ( entity.wasTouchingWater || entity.getRemainingFireTicks() > 0 )
++ if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper
+ {
+- return true;
++ return 100; // Paper
++ }
++ // Paper start
++ if ( !entity.onGround() || entity.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D )
++ {
++ return 100;
+ }
++ // Paper end
+ if ( !( entity instanceof AbstractArrow ) )
+ {
+- if ( !entity.onGround() || !entity.passengers.isEmpty() || entity.isPassenger() )
++ if ( (!entity.onGround() && !(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 || living.isFreezing()) // 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 && ( (Villager) entity ).canBreed() )
++ 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 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
+ }
+
+ /**
+@@ -239,8 +383,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.portalProcess != null && !entity.portalProcess.hasExpired()) || entity.portalCooldown > 0) {
++ return true;
++ }
++ // immunize leashed entities
++ if (entity instanceof Mob && ((Mob)entity).getLeashHolder() 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 )
+@@ -248,15 +403,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()) % 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()) % 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 2b263246135c85aa225120519e9702a628773935..2c408fa4abcbe1171c58aee8799c8cf7867d0f0a 100644
+--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+@@ -211,14 +211,60 @@ public class SpigotWorldConfig
+ public int monsterActivationRange = 32;
+ public int raiderActivationRange = 64;
+ 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 );