Package nallar.patched

Source Code of nallar.patched.PatchSpawnerAnimals

package nallar.patched;

import nallar.collections.LongList;
import nallar.collections.LongSet;
import nallar.tickthreading.Log;
import nallar.tickthreading.minecraft.TickThreading;
import nallar.tickthreading.patcher.Declare;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingData;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.profiler.Profiler;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.SpawnerAnimals;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.biome.SpawnListEntry;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.event.Event;
import net.minecraftforge.event.ForgeEventFactory;

import java.util.*;

public abstract class PatchSpawnerAnimals extends SpawnerAnimals {
  private static long hash(int x, int z) {
    return (((long) x) << 32) | (z & 0xffffffffL);
  }

  private static final int closeRange = 1;
  private static final int farRange = 5;
  private static final int spawnVariance = 6;
  private static final int clumping = 4;
  private static final int maxChunksPerPlayer = square(farRange * 2) - square(closeRange * 2);
  private static int surfaceChance;
  private static int gapChance;

  private static int square(int a) {
    return a * a;
  }

  // Spigot compatibility
  @SuppressWarnings("UnusedDeclaration")
  public static int getEntityCount(WorldServer server, Class oClass) {
    return server.countEntities(oClass);
  }

  private static int getPseudoRandomHeightValue(int wX, int wZ, WorldServer worldServer, boolean surface, int gapChance) {
    Chunk chunk = worldServer.getChunkIfExists(wX >> 4, wZ >> 4);
    if (chunk == null) {
      return -1;
    }
    int x = wX & 15;
    int z = wZ & 15;
    int height = chunk.getHeightValue(x, z);
    if (surface) {
      return height;
    }
    boolean inGap = false;
    int lastGap = 0;
    for (int y = 1; y < height; y++) {
      int blockId = chunk.getBlockID(x, y, z);
      if (blockId == 0) {
        if (!inGap) {
          inGap = true;
          if (gapChance++ % 3 == 0) {
            return y;
          }
          lastGap = y;
        }
      } else {
        inGap = false;
      }
    }
    return lastGap == 0 ? height : lastGap;
  }

  @Declare
  public static int spawnMobsQuickly(WorldServer worldServer, boolean peaceful, boolean hostile, boolean animal) {
    if (worldServer.tickCount % clumping != 0) {
      return 0;
    }
    final Profiler profiler = worldServer.theProfiler;
    profiler.startSection("creatureTypes");
    float loadFactor = 1 - (float) (MinecraftServer.getTickTime() / MinecraftServer.getTargetTickTime());
    if (loadFactor < 0.2f || loadFactor > 1f) {
      loadFactor = 0.2f;
    }
    float entityMultiplier = worldServer.playerEntities.size() * TickThreading.instance.mobSpawningMultiplier * loadFactor;
    if (entityMultiplier == 0) {
      profiler.endSection();
      return 0;
    }
    boolean dayTime = worldServer.isDaytime();
    float mobMultiplier = entityMultiplier * (dayTime ? 1 : 2);
    Map<EnumCreatureType, Integer> requiredSpawns = (Map<EnumCreatureType, Integer>) new EnumMap(EnumCreatureType.class);
    for (EnumCreatureType creatureType : EnumCreatureType.values()) {
      int count = (int) ((creatureType.getPeacefulCreature() ? entityMultiplier : mobMultiplier) * creatureType.getMaxNumberOfCreature());
      if (!(creatureType.getPeacefulCreature() && !peaceful || creatureType.getAnimal() && !animal || !creatureType.getPeacefulCreature() && !hostile) && count > worldServer.countEntities(creatureType.getCreatureClass())) {
        requiredSpawns.put(creatureType, count);
      }
    }
    profiler.endSection();

    if (requiredSpawns.isEmpty()) {
      return 0;
    }

    profiler.startSection("spawnableChunks");
    int attemptedSpawnedMobs = 0;
    LongSet closeChunks = new LongSet();
    Collection<EntityPlayer> entityPlayers = worldServer.playerEntities;
    LongList spawnableChunks = new LongList(entityPlayers.size() * maxChunksPerPlayer);
    for (EntityPlayer entityPlayer : entityPlayers) {
      int pX = entityPlayer.chunkCoordX;
      int pZ = entityPlayer.chunkCoordZ;
      int x = pX - closeRange;
      int maxX = pX + closeRange;
      int startZ = pZ - closeRange;
      int maxZ = pZ + closeRange;
      for (; x <= maxX; x++) {
        for (int z = startZ; z <= maxZ; z++) {
          closeChunks.add(hash(x, z));
        }
      }
    }
    for (EntityPlayer entityPlayer : entityPlayers) {
      int pX = entityPlayer.chunkCoordX;
      int pZ = entityPlayer.chunkCoordZ;
      int x = pX - farRange;
      int maxX = pX + farRange;
      int startZ = pZ - farRange;
      int maxZ = pZ + farRange;
      for (; x <= maxX; x++) {
        for (int z = startZ; z <= maxZ; z++) {
          long hash = hash(x, z);
          if (!closeChunks.contains(hash)) {
            spawnableChunks.add(hash);
          }
        }
      }
    }
    profiler.endStartSection("spawnMobs");

    int size = spawnableChunks.size;
    if (size < 1) {
      return 0;
    }

    SpawnLoop:
    for (Map.Entry<EnumCreatureType, Integer> entry : requiredSpawns.entrySet()) {
      EnumCreatureType creatureType = entry.getKey();
      long hash = spawnableChunks.get(worldServer.rand.nextInt(size));
      int x = (int) (hash >> 32);
      int z = (int) hash;
      int sX = x * 16 + worldServer.rand.nextInt(16);
      int sZ = z * 16 + worldServer.rand.nextInt(16);
      boolean surface = creatureType.getPeacefulCreature() || (dayTime ? surfaceChance++ % 5 == 0 : surfaceChance++ % 5 != 0);
      int gap = gapChance++;
      int sY;
      if (creatureType == EnumCreatureType.waterCreature) {
        String biomeName = worldServer.getBiomeGenForCoords(sX, sZ).biomeName;
        if (!"Ocean".equals(biomeName) && !"River".equals(biomeName)) {
          continue;
        }
        sY = getPseudoRandomHeightValue(sX, sZ, worldServer, true, gap) - 2;
      } else {
        sY = getPseudoRandomHeightValue(sX, sZ, worldServer, surface, gap);
      }
      if (sY < 0) {
        continue;
      }
      if (worldServer.getBlockMaterial(sX, sY, sZ) == creatureType.getCreatureMaterial()) {
        EntityLivingData unusedEntityLivingData = null;
        for (int i = 0; i < ((clumping * 3) / 2); i++) {
          int ssX = sX + (worldServer.rand.nextInt(spawnVariance) - spawnVariance / 2);
          int ssZ = sZ + (worldServer.rand.nextInt(spawnVariance) - spawnVariance / 2);
          int ssY;

          if (creatureType == EnumCreatureType.waterCreature) {
            ssY = sY;
          } else if (creatureType == EnumCreatureType.ambient) {
            ssY = worldServer.rand.nextInt(63) + 1;
          } else {
            ssY = getPseudoRandomHeightValue(ssX, ssZ, worldServer, surface, gap);
            if (ssY == -1 ||
                !worldServer.getBlockMaterial(ssX, ssY - 1, ssZ).isOpaque() ||
                !Block.blocksList[worldServer.getBlockId(ssX, ssY - 1, ssZ)].canCreatureSpawn(creatureType, worldServer, ssX, ssY - 1, ssZ)) {
              continue;
            }
          }

          if (creatureType == EnumCreatureType.waterCreature || (!worldServer.getBlockMaterial(ssX, ssY - 1, ssZ).isLiquid())) {
            SpawnListEntry creatureClass = worldServer.spawnRandomCreature(creatureType, ssX, ssY, ssZ);
            if (creatureClass == null) {
              break;
            }

            EntityLiving spawnedEntity;
            try {
              spawnedEntity = (EntityLiving) creatureClass.entityClass.getConstructor(World.class).newInstance(worldServer);
              spawnedEntity.setLocationAndAngles((double) ssX, (double) ssY, (double) ssZ, worldServer.rand.nextFloat() * 360.0F, 0.0F);

              Event.Result canSpawn = ForgeEventFactory.canEntitySpawn(spawnedEntity, worldServer, ssX, ssY, ssZ);
              if (canSpawn == Event.Result.ALLOW || (canSpawn == Event.Result.DEFAULT && spawnedEntity.getCanSpawnHere())) {
                worldServer.spawnEntityInWorld(spawnedEntity);
                if (!ForgeEventFactory.doSpecialSpawn(spawnedEntity, worldServer, ssX, ssY, ssZ)) {
                  unusedEntityLivingData = spawnedEntity.onSpawnWithEgg(unusedEntityLivingData);
                }
              }
              attemptedSpawnedMobs++;
            } catch (Exception e) {
              Log.warning("Failed to spawn entity " + creatureClass, e);
              break SpawnLoop;
            }
          }
        }
      }
      if (attemptedSpawnedMobs >= 24) {
        break;
      }
    }
    profiler.endSection();
    return attemptedSpawnedMobs;
  }
}
TOP

Related Classes of nallar.patched.PatchSpawnerAnimals

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.