001 package net.minecraft.world; 002 003 import java.util.ArrayList; 004 import java.util.Collections; 005 import java.util.HashMap; 006 import java.util.Iterator; 007 import java.util.List; 008 import java.util.Random; 009 import net.minecraft.block.Block; 010 import net.minecraft.block.material.Material; 011 import net.minecraft.entity.EntityLiving; 012 import net.minecraft.entity.EnumCreatureType; 013 import net.minecraft.entity.monster.EntitySkeleton; 014 import net.minecraft.entity.monster.EntitySpider; 015 import net.minecraft.entity.monster.EntityZombie; 016 import net.minecraft.entity.player.EntityPlayer; 017 import net.minecraft.util.ChunkCoordinates; 018 import net.minecraft.util.MathHelper; 019 import net.minecraft.util.WeightedRandom; 020 import net.minecraft.world.biome.BiomeGenBase; 021 import net.minecraft.world.biome.SpawnListEntry; 022 import net.minecraft.world.chunk.Chunk; 023 024 import net.minecraftforge.common.MinecraftForge; 025 import net.minecraftforge.event.Event.Result; 026 import net.minecraftforge.event.ForgeEventFactory; 027 import net.minecraftforge.event.entity.living.LivingSpecialSpawnEvent; 028 029 public final class SpawnerAnimals 030 { 031 /** The 17x17 area around the player where mobs can spawn */ 032 private static HashMap eligibleChunksForSpawning = new HashMap(); 033 034 /** An array of entity classes that spawn at night. */ 035 protected static final Class[] nightSpawnEntities = new Class[] {EntitySpider.class, EntityZombie.class, EntitySkeleton.class}; 036 037 /** 038 * Given a chunk, find a random position in it. 039 */ 040 protected static ChunkPosition getRandomSpawningPointInChunk(World par0World, int par1, int par2) 041 { 042 Chunk var3 = par0World.getChunkFromChunkCoords(par1, par2); 043 int var4 = par1 * 16 + par0World.rand.nextInt(16); 044 int var5 = par2 * 16 + par0World.rand.nextInt(16); 045 int var6 = par0World.rand.nextInt(var3 == null ? par0World.getActualHeight() : var3.getTopFilledSegment() + 16 - 1); 046 return new ChunkPosition(var4, var6, var5); 047 } 048 049 /** 050 * adds all chunks within the spawn radius of the players to eligibleChunksForSpawning. pars: the world, 051 * hostileCreatures, passiveCreatures. returns number of eligible chunks. 052 */ 053 public static final int findChunksForSpawning(WorldServer par0WorldServer, boolean par1, boolean par2, boolean par3) 054 { 055 if (!par1 && !par2) 056 { 057 return 0; 058 } 059 else 060 { 061 eligibleChunksForSpawning.clear(); 062 int var4; 063 int var7; 064 065 for (var4 = 0; var4 < par0WorldServer.playerEntities.size(); ++var4) 066 { 067 EntityPlayer var5 = (EntityPlayer)par0WorldServer.playerEntities.get(var4); 068 int var6 = MathHelper.floor_double(var5.posX / 16.0D); 069 var7 = MathHelper.floor_double(var5.posZ / 16.0D); 070 byte var8 = 8; 071 072 for (int var9 = -var8; var9 <= var8; ++var9) 073 { 074 for (int var10 = -var8; var10 <= var8; ++var10) 075 { 076 boolean var11 = var9 == -var8 || var9 == var8 || var10 == -var8 || var10 == var8; 077 ChunkCoordIntPair var12 = new ChunkCoordIntPair(var9 + var6, var10 + var7); 078 079 if (!var11) 080 { 081 eligibleChunksForSpawning.put(var12, Boolean.valueOf(false)); 082 } 083 else if (!eligibleChunksForSpawning.containsKey(var12)) 084 { 085 eligibleChunksForSpawning.put(var12, Boolean.valueOf(true)); 086 } 087 } 088 } 089 } 090 091 var4 = 0; 092 ChunkCoordinates var32 = par0WorldServer.getSpawnPoint(); 093 EnumCreatureType[] var33 = EnumCreatureType.values(); 094 var7 = var33.length; 095 096 for (int var34 = 0; var34 < var7; ++var34) 097 { 098 EnumCreatureType var35 = var33[var34]; 099 100 if ((!var35.getPeacefulCreature() || par2) && (var35.getPeacefulCreature() || par1) && (!var35.getAnimal() || par3) && par0WorldServer.countEntities(var35.getCreatureClass()) <= var35.getMaxNumberOfCreature() * eligibleChunksForSpawning.size() / 256) 101 { 102 Iterator var37 = eligibleChunksForSpawning.keySet().iterator(); 103 ArrayList<ChunkCoordIntPair> tmp = new ArrayList(eligibleChunksForSpawning.keySet()); 104 Collections.shuffle(tmp); 105 var37 = tmp.iterator(); 106 label110: 107 108 while (var37.hasNext()) 109 { 110 ChunkCoordIntPair var36 = (ChunkCoordIntPair)var37.next(); 111 112 if (!((Boolean)eligibleChunksForSpawning.get(var36)).booleanValue()) 113 { 114 ChunkPosition var38 = getRandomSpawningPointInChunk(par0WorldServer, var36.chunkXPos, var36.chunkZPos); 115 int var13 = var38.x; 116 int var14 = var38.y; 117 int var15 = var38.z; 118 119 if (!par0WorldServer.isBlockNormalCube(var13, var14, var15) && par0WorldServer.getBlockMaterial(var13, var14, var15) == var35.getCreatureMaterial()) 120 { 121 int var16 = 0; 122 int var17 = 0; 123 124 while (var17 < 3) 125 { 126 int var18 = var13; 127 int var19 = var14; 128 int var20 = var15; 129 byte var21 = 6; 130 SpawnListEntry var22 = null; 131 int var23 = 0; 132 133 while (true) 134 { 135 if (var23 < 4) 136 { 137 label103: 138 { 139 var18 += par0WorldServer.rand.nextInt(var21) - par0WorldServer.rand.nextInt(var21); 140 var19 += par0WorldServer.rand.nextInt(1) - par0WorldServer.rand.nextInt(1); 141 var20 += par0WorldServer.rand.nextInt(var21) - par0WorldServer.rand.nextInt(var21); 142 143 if (canCreatureTypeSpawnAtLocation(var35, par0WorldServer, var18, var19, var20)) 144 { 145 float var24 = (float)var18 + 0.5F; 146 float var25 = (float)var19; 147 float var26 = (float)var20 + 0.5F; 148 149 if (par0WorldServer.getClosestPlayer((double)var24, (double)var25, (double)var26, 24.0D) == null) 150 { 151 float var27 = var24 - (float)var32.posX; 152 float var28 = var25 - (float)var32.posY; 153 float var29 = var26 - (float)var32.posZ; 154 float var30 = var27 * var27 + var28 * var28 + var29 * var29; 155 156 if (var30 >= 576.0F) 157 { 158 if (var22 == null) 159 { 160 var22 = par0WorldServer.spawnRandomCreature(var35, var18, var19, var20); 161 162 if (var22 == null) 163 { 164 break label103; 165 } 166 } 167 168 EntityLiving var39; 169 170 try 171 { 172 var39 = (EntityLiving)var22.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0WorldServer}); 173 } 174 catch (Exception var31) 175 { 176 var31.printStackTrace(); 177 return var4; 178 } 179 180 var39.setLocationAndAngles((double)var24, (double)var25, (double)var26, par0WorldServer.rand.nextFloat() * 360.0F, 0.0F); 181 182 Result canSpawn = ForgeEventFactory.canEntitySpawn(var39, par0WorldServer, var24, var25, var26); 183 if (canSpawn == Result.ALLOW || (canSpawn == Result.DEFAULT && var39.getCanSpawnHere())) 184 { 185 ++var16; 186 par0WorldServer.spawnEntityInWorld(var39); 187 creatureSpecificInit(var39, par0WorldServer, var24, var25, var26); 188 189 if (var16 >= var39.getMaxSpawnedInChunk()) 190 { 191 continue label110; 192 } 193 } 194 195 var4 += var16; 196 } 197 } 198 } 199 200 ++var23; 201 continue; 202 } 203 } 204 205 ++var17; 206 break; 207 } 208 } 209 } 210 } 211 } 212 } 213 } 214 215 return var4; 216 } 217 } 218 219 /** 220 * Returns whether or not the specified creature type can spawn at the specified location. 221 */ 222 public static boolean canCreatureTypeSpawnAtLocation(EnumCreatureType par0EnumCreatureType, World par1World, int par2, int par3, int par4) 223 { 224 if (par0EnumCreatureType.getCreatureMaterial() == Material.water) 225 { 226 return par1World.getBlockMaterial(par2, par3, par4).isLiquid() && par1World.getBlockMaterial(par2, par3 - 1, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4); 227 } 228 else if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) 229 { 230 return false; 231 } 232 else 233 { 234 int var5 = par1World.getBlockId(par2, par3 - 1, par4); 235 boolean spawnBlock = (Block.blocksList[var5] != null && Block.blocksList[var5].canCreatureSpawn(par0EnumCreatureType, par1World, par2, par3 - 1, par4)); 236 return spawnBlock && var5 != Block.bedrock.blockID && !par1World.isBlockNormalCube(par2, par3, par4) && !par1World.getBlockMaterial(par2, par3, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4); 237 } 238 } 239 240 /** 241 * determines if a skeleton spawns on a spider, and if a sheep is a different color 242 */ 243 private static void creatureSpecificInit(EntityLiving par0EntityLiving, World par1World, float par2, float par3, float par4) 244 { 245 if (ForgeEventFactory.doSpecialSpawn(par0EntityLiving, par1World, par2, par3, par4)) 246 { 247 return; 248 } 249 250 par0EntityLiving.initCreature(); 251 } 252 253 /** 254 * Called during chunk generation to spawn initial creatures. 255 */ 256 public static void performWorldGenSpawning(World par0World, BiomeGenBase par1BiomeGenBase, int par2, int par3, int par4, int par5, Random par6Random) 257 { 258 List var7 = par1BiomeGenBase.getSpawnableList(EnumCreatureType.creature); 259 260 if (!var7.isEmpty()) 261 { 262 while (par6Random.nextFloat() < par1BiomeGenBase.getSpawningChance()) 263 { 264 SpawnListEntry var8 = (SpawnListEntry)WeightedRandom.getRandomItem(par0World.rand, var7); 265 int var9 = var8.minGroupCount + par6Random.nextInt(1 + var8.maxGroupCount - var8.minGroupCount); 266 int var10 = par2 + par6Random.nextInt(par4); 267 int var11 = par3 + par6Random.nextInt(par5); 268 int var12 = var10; 269 int var13 = var11; 270 271 for (int var14 = 0; var14 < var9; ++var14) 272 { 273 boolean var15 = false; 274 275 for (int var16 = 0; !var15 && var16 < 4; ++var16) 276 { 277 int var17 = par0World.getTopSolidOrLiquidBlock(var10, var11); 278 279 if (canCreatureTypeSpawnAtLocation(EnumCreatureType.creature, par0World, var10, var17, var11)) 280 { 281 float var18 = (float)var10 + 0.5F; 282 float var19 = (float)var17; 283 float var20 = (float)var11 + 0.5F; 284 EntityLiving var21; 285 286 try 287 { 288 var21 = (EntityLiving)var8.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0World}); 289 } 290 catch (Exception var23) 291 { 292 var23.printStackTrace(); 293 continue; 294 } 295 296 var21.setLocationAndAngles((double)var18, (double)var19, (double)var20, par6Random.nextFloat() * 360.0F, 0.0F); 297 par0World.spawnEntityInWorld(var21); 298 creatureSpecificInit(var21, par0World, var18, var19, var20); 299 var15 = true; 300 } 301 302 var10 += par6Random.nextInt(5) - par6Random.nextInt(5); 303 304 for (var11 += par6Random.nextInt(5) - par6Random.nextInt(5); var10 < par2 || var10 >= par2 + par4 || var11 < par3 || var11 >= par3 + par4; var11 = var13 + par6Random.nextInt(5) - par6Random.nextInt(5)) 305 { 306 var10 = var12 + par6Random.nextInt(5) - par6Random.nextInt(5); 307 } 308 } 309 } 310 } 311 } 312 } 313 }