@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;
}