All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spigotmc.ActivationRange Maven / Gradle / Ivy

package org.spigotmc;

import net.minecraft.server.*;
import org.bukkit.craftbukkit.SpigotTimings;

import java.util.List;

public class ActivationRange {

  static AxisAlignedBB maxBB = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
  static AxisAlignedBB miscBB = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
  static AxisAlignedBB animalBB = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
  static AxisAlignedBB monsterBB = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);

  /**
   * Initializes an entities type on construction to specify what group this
   * entity is in for activation ranges.
   *
   * @param entity
   * @return group id
   */
  public static byte initializeEntityActivationType(Entity entity) {
    if (entity instanceof EntityMonster || entity instanceof EntitySlime) {
      return 1; // Monster
    } else if (entity instanceof EntityCreature || entity instanceof EntityAmbient) {
      return 2; // Animal
    } else {
      return 3; // Misc
    }
  }

  /**
   * These entities are excluded from Activation range checks.
   *
   * @param entity
   * @param world
   * @return boolean If it should always tick.
   */
  public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) {
    return (entity.activationType == 3 && config.miscActivationRange == 0)
      || (entity.activationType == 2 && config.animalActivationRange == 0)
      || (entity.activationType == 1 && config.monsterActivationRange == 0)
      || entity instanceof EntityHuman
      || entity instanceof EntityProjectile
      || entity instanceof EntityEnderDragon
      || entity instanceof EntityComplexPart
      || entity instanceof EntityWither
      || entity instanceof EntityFireball
      || entity instanceof EntityWeather
      || entity instanceof EntityTNTPrimed
      || entity instanceof EntityEnderCrystal
      || entity instanceof EntityFireworks;
  }

  /**
   * Find what entities are in range of the players in the world and set
   * active if in range.
   *
   * @param world
   */
  public static void activateEntities(World world) {
    SpigotTimings.entityActivationCheckTimer.startTiming();
    final int miscActivationRange = world.spigotConfig.miscActivationRange;
    final int animalActivationRange = world.spigotConfig.animalActivationRange;
    final int monsterActivationRange = world.spigotConfig.monsterActivationRange;

    int maxRange = Math.max(monsterActivationRange, animalActivationRange);
    maxRange = Math.max(maxRange, miscActivationRange);
    maxRange = Math.min((world.spigotConfig.viewDistance << 4) - 8, maxRange);

    for (Entity player : (List) (List) world.players) {

      player.activatedTick = MinecraftServer.currentTick;
      maxBB = player.getBoundingBox().grow(maxRange, 256, maxRange);
      miscBB = player.getBoundingBox().grow(miscActivationRange, 256, miscActivationRange);
      animalBB = player.getBoundingBox().grow(animalActivationRange, 256, animalActivationRange);
      monsterBB = player.getBoundingBox().grow(monsterActivationRange, 256, monsterActivationRange);

      int i = MathHelper.floor(maxBB.a / 16.0D);
      int j = MathHelper.floor(maxBB.d / 16.0D);
      int k = MathHelper.floor(maxBB.c / 16.0D);
      int l = MathHelper.floor(maxBB.f / 16.0D);

      for (int i1 = i; i1 <= j; ++i1) {
        for (int j1 = k; j1 <= l; ++j1) {
          if (world.getWorld().isChunkLoaded(i1, j1)) {
            activateChunkEntities(world.getChunkAt(i1, j1));
          }
        }
      }
    }
    SpigotTimings.entityActivationCheckTimer.stopTiming();
  }

  /**
   * Checks for the activation state of all entities in this chunk.
   *
   * @param chunk
   */
  private static void activateChunkEntities(Chunk chunk) {
    for (List slice : chunk.entitySlices) {
      for (Entity entity : slice) {
        if (MinecraftServer.currentTick > entity.activatedTick) {
          if (entity.defaultActivationState) {
            entity.activatedTick = MinecraftServer.currentTick;
            continue;
          }
          switch (entity.activationType) {
            case 1:
              if (monsterBB.b(entity.getBoundingBox())) {
                entity.activatedTick = MinecraftServer.currentTick;
              }
              break;
            case 2:
              if (animalBB.b(entity.getBoundingBox())) {
                entity.activatedTick = MinecraftServer.currentTick;
              }
              break;
            case 3:
            default:
              if (miscBB.b(entity.getBoundingBox())) {
                entity.activatedTick = MinecraftServer.currentTick;
              }
          }
        }
      }
    }
  }

  /**
   * If an entity is not in range, do some more checks to see if we should
   * give it a shot.
   *
   * @param entity
   * @return
   */
  public static boolean checkEntityImmunities(Entity entity) {
    // quick checks.
    if (entity.inWater || entity.fireTicks > 0) {
      return true;
    }
    if (!(entity instanceof EntityArrow)) {
      if (!entity.onGround || entity.passenger != null
        || entity.vehicle != null) {
        return true;
      }
    } else if (!((EntityArrow) entity).inGround) {
      return true;
    }
    // special cases.
    if (entity instanceof EntityLiving) {
      EntityLiving living = (EntityLiving) entity;
      if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTicks > 0 || living.effects.size() > 0) {
        return true;
      }
      if (entity instanceof EntityCreature && ((EntityCreature) entity).getGoalTarget() != null) {
        return true;
      }
      if (entity instanceof EntityVillager && ((EntityVillager) entity).cm() /* Getter for first boolean */) {
        return true;
      }
      if (entity instanceof EntityAnimal) {
        EntityAnimal animal = (EntityAnimal) entity;
        if (animal.isBaby() || animal.isInLove()) {
          return true;
        }
        if (entity instanceof EntitySheep && ((EntitySheep) entity).isSheared()) {
          return true;
        }
      }
      // isExplosive
      return entity instanceof EntityCreeper && ((EntityCreeper) entity).cn();
    }
    return false;
  }

  /**
   * Checks if the entity is active for this tick.
   *
   * @param entity
   * @return
   */
  public static boolean checkIfActive(Entity entity) {
    SpigotTimings.checkIfActiveTimer.startTiming();
    // Never safe to skip fireworks or entities not yet added to chunk
    if (!entity.isAddedToChunk() || entity instanceof EntityFireworks) {
      SpigotTimings.checkIfActiveTimer.stopTiming();
      return true;
    }

    boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;

    // Should this entity tick?
    if (!isActive) {
      if ((MinecraftServer.currentTick - entity.activatedTick - 1) % 20 == 0) {
        // Check immunities every 20 ticks.
        if (checkEntityImmunities(entity)) {
          // Triggered some sort of immunity, give 20 full ticks before we check again.
          entity.activatedTick = MinecraftServer.currentTick + 20;
        }
        isActive = true;
      }
      // Add a little performance juice to active entities. Skip 1/4 if not immune.
    } else if (!entity.defaultActivationState && entity.ticksLived % 4 == 0 && !checkEntityImmunities(entity)) {
      isActive = false;
    }
    int x = MathHelper.floor(entity.locX);
    int z = MathHelper.floor(entity.locZ);
    // Make sure not on edge of unloaded chunk
    Chunk chunk = entity.world.getChunkIfLoaded(x >> 4, z >> 4);
    if (isActive && !(chunk != null && chunk.areNeighborsLoaded(1))) {
      isActive = false;
    }
    SpigotTimings.checkIfActiveTimer.stopTiming();
    return isActive;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy