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