package net.minecraft.world; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EnumCreatureType; import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.monster.EntitySpider; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.MathHelper; import net.minecraft.util.WeightedRandom; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.biome.SpawnListEntry; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.Event.Result; import net.minecraftforge.event.ForgeEventFactory; public final class SpawnerAnimals { /** The 17x17 area around the player where mobs can spawn */ private static HashMap eligibleChunksForSpawning = new HashMap(); /** An array of entity classes that spawn at night. */ protected static final Class[] nightSpawnEntities = new Class[] {EntitySpider.class, EntityZombie.class, EntitySkeleton.class}; /** * Given a chunk, find a random position in it. */ protected static ChunkPosition getRandomSpawningPointInChunk(World par0World, int par1, int par2) { Chunk chunk = par0World.getChunkFromChunkCoords(par1, par2); int k = par1 * 16 + par0World.rand.nextInt(16); int l = par2 * 16 + par0World.rand.nextInt(16); int i1 = par0World.rand.nextInt(chunk == null ? par0World.getActualHeight() : chunk.getTopFilledSegment() + 16 - 1); return new ChunkPosition(k, i1, l); } /** * adds all chunks within the spawn radius of the players to eligibleChunksForSpawning. pars: the world, * hostileCreatures, passiveCreatures. returns number of eligible chunks. */ public static final int findChunksForSpawning(WorldServer par0WorldServer, boolean par1, boolean par2, boolean par3) { if (!par1 && !par2) { return 0; } else { eligibleChunksForSpawning.clear(); int i; int j; for (i = 0; i < par0WorldServer.playerEntities.size(); ++i) { EntityPlayer entityplayer = (EntityPlayer)par0WorldServer.playerEntities.get(i); int k = MathHelper.floor_double(entityplayer.posX / 16.0D); j = MathHelper.floor_double(entityplayer.posZ / 16.0D); byte b0 = 8; for (int l = -b0; l <= b0; ++l) { for (int i1 = -b0; i1 <= b0; ++i1) { boolean flag3 = l == -b0 || l == b0 || i1 == -b0 || i1 == b0; ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(l + k, i1 + j); if (!flag3) { eligibleChunksForSpawning.put(chunkcoordintpair, Boolean.valueOf(false)); } else if (!eligibleChunksForSpawning.containsKey(chunkcoordintpair)) { eligibleChunksForSpawning.put(chunkcoordintpair, Boolean.valueOf(true)); } } } } i = 0; ChunkCoordinates chunkcoordinates = par0WorldServer.getSpawnPoint(); EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values(); j = aenumcreaturetype.length; for (int j1 = 0; j1 < j; ++j1) { EnumCreatureType enumcreaturetype = aenumcreaturetype[j1]; if ((!enumcreaturetype.getPeacefulCreature() || par2) && (enumcreaturetype.getPeacefulCreature() || par1) && (!enumcreaturetype.getAnimal() || par3) && par0WorldServer.countEntities(enumcreaturetype, true) <= enumcreaturetype.getMaxNumberOfCreature() * eligibleChunksForSpawning.size() / 256) { Iterator iterator = eligibleChunksForSpawning.keySet().iterator(); ArrayList<ChunkCoordIntPair> tmp = new ArrayList(eligibleChunksForSpawning.keySet()); Collections.shuffle(tmp); iterator = tmp.iterator(); label110: while (iterator.hasNext()) { ChunkCoordIntPair chunkcoordintpair1 = (ChunkCoordIntPair)iterator.next(); if (!((Boolean)eligibleChunksForSpawning.get(chunkcoordintpair1)).booleanValue()) { ChunkPosition chunkposition = getRandomSpawningPointInChunk(par0WorldServer, chunkcoordintpair1.chunkXPos, chunkcoordintpair1.chunkZPos); int k1 = chunkposition.x; int l1 = chunkposition.y; int i2 = chunkposition.z; if (!par0WorldServer.isBlockNormalCube(k1, l1, i2) && par0WorldServer.getBlockMaterial(k1, l1, i2) == enumcreaturetype.getCreatureMaterial()) { int j2 = 0; int k2 = 0; while (k2 < 3) { int l2 = k1; int i3 = l1; int j3 = i2; byte b1 = 6; SpawnListEntry spawnlistentry = null; int k3 = 0; while (true) { if (k3 < 4) { label103: { l2 += par0WorldServer.rand.nextInt(b1) - par0WorldServer.rand.nextInt(b1); i3 += par0WorldServer.rand.nextInt(1) - par0WorldServer.rand.nextInt(1); j3 += par0WorldServer.rand.nextInt(b1) - par0WorldServer.rand.nextInt(b1); if (canCreatureTypeSpawnAtLocation(enumcreaturetype, par0WorldServer, l2, i3, j3)) { float f = (float)l2 + 0.5F; float f1 = (float)i3; float f2 = (float)j3 + 0.5F; if (par0WorldServer.getClosestPlayer((double)f, (double)f1, (double)f2, 24.0D) == null) { float f3 = f - (float)chunkcoordinates.posX; float f4 = f1 - (float)chunkcoordinates.posY; float f5 = f2 - (float)chunkcoordinates.posZ; float f6 = f3 * f3 + f4 * f4 + f5 * f5; if (f6 >= 576.0F) { if (spawnlistentry == null) { spawnlistentry = par0WorldServer.spawnRandomCreature(enumcreaturetype, l2, i3, j3); if (spawnlistentry == null) { break label103; } } EntityLiving entityliving; try { entityliving = (EntityLiving)spawnlistentry.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0WorldServer}); } catch (Exception exception) { exception.printStackTrace(); return i; } entityliving.setLocationAndAngles((double)f, (double)f1, (double)f2, par0WorldServer.rand.nextFloat() * 360.0F, 0.0F); Result canSpawn = ForgeEventFactory.canEntitySpawn(entityliving, par0WorldServer, f, f1, f2); if (canSpawn == Result.ALLOW || (canSpawn == Result.DEFAULT && entityliving.getCanSpawnHere())) { ++j2; par0WorldServer.spawnEntityInWorld(entityliving); creatureSpecificInit(entityliving, par0WorldServer, f, f1, f2); if (j2 >= ForgeEventFactory.getMaxSpawnPackSize(entityliving)) { continue label110; } } i += j2; } } } ++k3; continue; } } ++k2; break; } } } } } } } return i; } } /** * Returns whether or not the specified creature type can spawn at the specified location. */ public static boolean canCreatureTypeSpawnAtLocation(EnumCreatureType par0EnumCreatureType, World par1World, int par2, int par3, int par4) { if (par0EnumCreatureType.getCreatureMaterial() == Material.water) { return par1World.getBlockMaterial(par2, par3, par4).isLiquid() && par1World.getBlockMaterial(par2, par3 - 1, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4); } else if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) { return false; } else { int l = par1World.getBlockId(par2, par3 - 1, par4); boolean spawnBlock = (Block.blocksList[l] != null && Block.blocksList[l].canCreatureSpawn(par0EnumCreatureType, par1World, par2, par3 - 1, par4)); return spawnBlock && l != Block.bedrock.blockID && !par1World.isBlockNormalCube(par2, par3, par4) && !par1World.getBlockMaterial(par2, par3, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4); } } /** * determines if a skeleton spawns on a spider, and if a sheep is a different color */ private static void creatureSpecificInit(EntityLiving par0EntityLiving, World par1World, float par2, float par3, float par4) { if (ForgeEventFactory.doSpecialSpawn(par0EntityLiving, par1World, par2, par3, par4)) { return; } par0EntityLiving.initCreature(); } /** * Called during chunk generation to spawn initial creatures. */ public static void performWorldGenSpawning(World par0World, BiomeGenBase par1BiomeGenBase, int par2, int par3, int par4, int par5, Random par6Random) { List list = par1BiomeGenBase.getSpawnableList(EnumCreatureType.creature); if (!list.isEmpty()) { while (par6Random.nextFloat() < par1BiomeGenBase.getSpawningChance()) { SpawnListEntry spawnlistentry = (SpawnListEntry)WeightedRandom.getRandomItem(par0World.rand, list); int i1 = spawnlistentry.minGroupCount + par6Random.nextInt(1 + spawnlistentry.maxGroupCount - spawnlistentry.minGroupCount); int j1 = par2 + par6Random.nextInt(par4); int k1 = par3 + par6Random.nextInt(par5); int l1 = j1; int i2 = k1; for (int j2 = 0; j2 < i1; ++j2) { boolean flag = false; for (int k2 = 0; !flag && k2 < 4; ++k2) { int l2 = par0World.getTopSolidOrLiquidBlock(j1, k1); if (canCreatureTypeSpawnAtLocation(EnumCreatureType.creature, par0World, j1, l2, k1)) { float f = (float)j1 + 0.5F; float f1 = (float)l2; float f2 = (float)k1 + 0.5F; EntityLiving entityliving; try { entityliving = (EntityLiving)spawnlistentry.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0World}); } catch (Exception exception) { exception.printStackTrace(); continue; } entityliving.setLocationAndAngles((double)f, (double)f1, (double)f2, par6Random.nextFloat() * 360.0F, 0.0F); par0World.spawnEntityInWorld(entityliving); creatureSpecificInit(entityliving, par0World, f, f1, f2); flag = true; } j1 += par6Random.nextInt(5) - par6Random.nextInt(5); for (k1 += par6Random.nextInt(5) - par6Random.nextInt(5); j1 < par2 || j1 >= par2 + par4 || k1 < par3 || k1 >= par3 + par4; k1 = i2 + par6Random.nextInt(5) - par6Random.nextInt(5)) { j1 = l1 + par6Random.nextInt(5) - par6Random.nextInt(5); } } } } } } }