    001package net.minecraft.world;
    002
    003import java.util.ArrayList;
    004import java.util.Collections;
    005import java.util.HashMap;
    006import java.util.Iterator;
    007import java.util.List;
    008import java.util.Random;
    009import net.minecraft.block.Block;
    010import net.minecraft.block.material.Material;
    011import net.minecraft.entity.EntityLiving;
    012import net.minecraft.entity.EnumCreatureType;
    013import net.minecraft.entity.monster.EntitySkeleton;
    014import net.minecraft.entity.monster.EntitySpider;
    015import net.minecraft.entity.monster.EntityZombie;
    016import net.minecraft.entity.player.EntityPlayer;
    017import net.minecraft.util.ChunkCoordinates;
    018import net.minecraft.util.MathHelper;
    019import net.minecraft.util.WeightedRandom;
    020import net.minecraft.world.biome.BiomeGenBase;
    021import net.minecraft.world.biome.SpawnListEntry;
    022import net.minecraft.world.chunk.Chunk;
    023
    024import net.minecraftforge.common.MinecraftForge;
    025import net.minecraftforge.event.Event.Result;
    026import net.minecraftforge.event.ForgeEventFactory;
    027import net.minecraftforge.event.entity.living.LivingSpecialSpawnEvent;
    028
    029public 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}