    001    package net.minecraft.tileentity;
    002
    003    import cpw.mods.fml.relauncher.Side;
    004    import cpw.mods.fml.relauncher.SideOnly;
    005    import java.util.ArrayList;
    006    import java.util.Iterator;
    007    import java.util.List;
    008    import net.minecraft.entity.Entity;
    009    import net.minecraft.entity.EntityList;
    010    import net.minecraft.entity.EntityLiving;
    011    import net.minecraft.nbt.NBTBase;
    012    import net.minecraft.nbt.NBTTagCompound;
    013    import net.minecraft.nbt.NBTTagList;
    014    import net.minecraft.network.packet.Packet;
    015    import net.minecraft.network.packet.Packet132TileEntityData;
    016    import net.minecraft.util.AxisAlignedBB;
    017    import net.minecraft.util.WeightedRandom;
    018    import net.minecraft.world.World;
    019
    020    public class TileEntityMobSpawner extends TileEntity
    021    {
    022        /** The stored delay before a new spawn. */
    023        public int delay = -1;
    024
    025        /**
    026         * The string ID of the mobs being spawned from this spawner. Defaults to pig, apparently.
    027         */
    028        private String mobID = "Pig";
    029        private List field_92016_e = null;
    030
    031        /** The extra NBT data to add to spawned entities */
    032        private TileEntityMobSpawnerSpawnData spawnerTags = null;
    033        public double yaw;
    034        public double yaw2 = 0.0D;
    035        private int minSpawnDelay = 200;
    036        private int maxSpawnDelay = 800;
    037        private int spawnCount = 4;
    038        private Entity field_92017_j;
    039        private int field_82350_j = 6;
    040        private int field_82349_r = 16;
    041        private int field_82348_s = 4;
    042
    043        public TileEntityMobSpawner()
    044        {
    045            this.delay = 20;
    046        }
    047
    048        public String func_92015_a()
    049        {
    050            return this.spawnerTags == null ? this.mobID : this.spawnerTags.field_92033_c;
    051        }
    052
    053        public void setMobID(String par1Str)
    054        {
    055            this.mobID = par1Str;
    056        }
    057
    058        /**
    059         * Returns true if there is a player in range (using World.getClosestPlayer)
    060         */
    061        public boolean anyPlayerInRange()
    062        {
    063            return this.worldObj.getClosestPlayer((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D, (double)this.field_82349_r) != null;
    064        }
    065
    066        /**
    067         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    068         * ticks and creates a new spawn inside its implementation.
    069         */
    070        public void updateEntity()
    071        {
    072            if (this.anyPlayerInRange())
    073            {
    074                double var5;
    075
    076                if (this.worldObj.isRemote)
    077                {
    078                    double var1 = (double)((float)this.xCoord + this.worldObj.rand.nextFloat());
    079                    double var3 = (double)((float)this.yCoord + this.worldObj.rand.nextFloat());
    080                    var5 = (double)((float)this.zCoord + this.worldObj.rand.nextFloat());
    081                    this.worldObj.spawnParticle("smoke", var1, var3, var5, 0.0D, 0.0D, 0.0D);
    082                    this.worldObj.spawnParticle("flame", var1, var3, var5, 0.0D, 0.0D, 0.0D);
    083
    084                    if (this.delay > 0)
    085                    {
    086                        --this.delay;
    087                    }
    088
    089                    this.yaw2 = this.yaw;
    090                    this.yaw = (this.yaw + (double)(1000.0F / ((float)this.delay + 200.0F))) % 360.0D;
    091                }
    092                else
    093                {
    094                    if (this.delay == -1)
    095                    {
    096                        this.updateDelay();
    097                    }
    098
    099                    if (this.delay > 0)
    100                    {
    101                        --this.delay;
    102                        return;
    103                    }
    104
    105                    boolean var12 = false;
    106
    107                    for (int var2 = 0; var2 < this.spawnCount; ++var2)
    108                    {
    109                        Entity var13 = EntityList.createEntityByName(this.func_92015_a(), this.worldObj);
    110
    111                        if (var13 == null)
    112                        {
    113                            return;
    114                        }
    115
    116                        int var4 = this.worldObj.getEntitiesWithinAABB(var13.getClass(), AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)this.xCoord, (double)this.yCoord, (double)this.zCoord, (double)(this.xCoord + 1), (double)(this.yCoord + 1), (double)(this.zCoord + 1)).expand((double)(this.field_82348_s * 2), 4.0D, (double)(this.field_82348_s * 2))).size();
    117
    118                        if (var4 >= this.field_82350_j)
    119                        {
    120                            this.updateDelay();
    121                            return;
    122                        }
    123
    124                        if (var13 != null)
    125                        {
    126                            var5 = (double)this.xCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * (double)this.field_82348_s;
    127                            double var7 = (double)(this.yCoord + this.worldObj.rand.nextInt(3) - 1);
    128                            double var9 = (double)this.zCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * (double)this.field_82348_s;
    129                            EntityLiving var11 = var13 instanceof EntityLiving ? (EntityLiving)var13 : null;
    130                            var13.setLocationAndAngles(var5, var7, var9, this.worldObj.rand.nextFloat() * 360.0F, 0.0F);
    131
    132                            if (var11 == null || var11.getCanSpawnHere())
    133                            {
    134                                this.writeNBTTagsTo(var13);
    135                                this.worldObj.spawnEntityInWorld(var13);
    136                                this.worldObj.playAuxSFX(2004, this.xCoord, this.yCoord, this.zCoord, 0);
    137
    138                                if (var11 != null)
    139                                {
    140                                    var11.spawnExplosionParticle();
    141                                }
    142
    143                                var12 = true;
    144                            }
    145                        }
    146                    }
    147
    148                    if (var12)
    149                    {
    150                        this.updateDelay();
    151                    }
    152                }
    153
    154                super.updateEntity();
    155            }
    156        }
    157
    158        public void writeNBTTagsTo(Entity par1Entity)
    159        {
    160            if (this.spawnerTags != null)
    161            {
    162                NBTTagCompound var2 = new NBTTagCompound();
    163                par1Entity.addEntityID(var2);
    164                Iterator var3 = this.spawnerTags.field_92032_b.getTags().iterator();
    165
    166                while (var3.hasNext())
    167                {
    168                    NBTBase var4 = (NBTBase)var3.next();
    169                    var2.setTag(var4.getName(), var4.copy());
    170                }
    171
    172                par1Entity.readFromNBT(var2);
    173            }
    174            else if (par1Entity instanceof EntityLiving && par1Entity.worldObj != null)
    175            {
    176                ((EntityLiving)par1Entity).initCreature();
    177            }
    178        }
    179
    180        /**
    181         * Sets the delay before a new spawn (base delay of 200 + random number up to 600).
    182         */
    183        private void updateDelay()
    184        {
    185            if (this.maxSpawnDelay <= this.minSpawnDelay)
    186            {
    187                this.delay = this.minSpawnDelay;
    188            }
    189            else
    190            {
    191                this.delay = this.minSpawnDelay + this.worldObj.rand.nextInt(this.maxSpawnDelay - this.minSpawnDelay);
    192            }
    193
    194            if (this.field_92016_e != null && this.field_92016_e.size() > 0)
    195            {
    196                this.spawnerTags = (TileEntityMobSpawnerSpawnData)WeightedRandom.getRandomItem(this.worldObj.rand, this.field_92016_e);
    197                this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord);
    198            }
    199
    200            this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, 0);
    201        }
    202
    203        /**
    204         * Reads a tile entity from NBT.
    205         */
    206        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    207        {
    208            super.readFromNBT(par1NBTTagCompound);
    209            this.mobID = par1NBTTagCompound.getString("EntityId");
    210            this.delay = par1NBTTagCompound.getShort("Delay");
    211
    212            if (par1NBTTagCompound.hasKey("SpawnPotentials"))
    213            {
    214                this.field_92016_e = new ArrayList();
    215                NBTTagList var2 = par1NBTTagCompound.getTagList("SpawnPotentials");
    216
    217                for (int var3 = 0; var3 < var2.tagCount(); ++var3)
    218                {
    219                    this.field_92016_e.add(new TileEntityMobSpawnerSpawnData(this, (NBTTagCompound)var2.tagAt(var3)));
    220                }
    221            }
    222            else
    223            {
    224                this.field_92016_e = null;
    225            }
    226
    227            if (par1NBTTagCompound.hasKey("SpawnData"))
    228            {
    229                this.spawnerTags = new TileEntityMobSpawnerSpawnData(this, par1NBTTagCompound.getCompoundTag("SpawnData"), this.mobID);
    230            }
    231            else
    232            {
    233                this.spawnerTags = null;
    234            }
    235
    236            if (par1NBTTagCompound.hasKey("MinSpawnDelay"))
    237            {
    238                this.minSpawnDelay = par1NBTTagCompound.getShort("MinSpawnDelay");
    239                this.maxSpawnDelay = par1NBTTagCompound.getShort("MaxSpawnDelay");
    240                this.spawnCount = par1NBTTagCompound.getShort("SpawnCount");
    241            }
    242
    243            if (par1NBTTagCompound.hasKey("MaxNearbyEntities"))
    244            {
    245                this.field_82350_j = par1NBTTagCompound.getShort("MaxNearbyEntities");
    246                this.field_82349_r = par1NBTTagCompound.getShort("RequiredPlayerRange");
    247            }
    248
    249            if (par1NBTTagCompound.hasKey("SpawnRange"))
    250            {
    251                this.field_82348_s = par1NBTTagCompound.getShort("SpawnRange");
    252            }
    253
    254            if (this.worldObj != null && this.worldObj.isRemote)
    255            {
    256                this.field_92017_j = null;
    257            }
    258        }
    259
    260        /**
    261         * Writes a tile entity to NBT.
    262         */
    263        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    264        {
    265            super.writeToNBT(par1NBTTagCompound);
    266            par1NBTTagCompound.setString("EntityId", this.func_92015_a());
    267            par1NBTTagCompound.setShort("Delay", (short)this.delay);
    268            par1NBTTagCompound.setShort("MinSpawnDelay", (short)this.minSpawnDelay);
    269            par1NBTTagCompound.setShort("MaxSpawnDelay", (short)this.maxSpawnDelay);
    270            par1NBTTagCompound.setShort("SpawnCount", (short)this.spawnCount);
    271            par1NBTTagCompound.setShort("MaxNearbyEntities", (short)this.field_82350_j);
    272            par1NBTTagCompound.setShort("RequiredPlayerRange", (short)this.field_82349_r);
    273            par1NBTTagCompound.setShort("SpawnRange", (short)this.field_82348_s);
    274
    275            if (this.spawnerTags != null)
    276            {
    277                par1NBTTagCompound.setCompoundTag("SpawnData", (NBTTagCompound)this.spawnerTags.field_92032_b.copy());
    278            }
    279
    280            if (this.spawnerTags != null || this.field_92016_e != null && this.field_92016_e.size() > 0)
    281            {
    282                NBTTagList var2 = new NBTTagList();
    283
    284                if (this.field_92016_e != null && this.field_92016_e.size() > 0)
    285                {
    286                    Iterator var3 = this.field_92016_e.iterator();
    287
    288                    while (var3.hasNext())
    289                    {
    290                        TileEntityMobSpawnerSpawnData var4 = (TileEntityMobSpawnerSpawnData)var3.next();
    291                        var2.appendTag(var4.func_92030_a());
    292                    }
    293                }
    294                else
    295                {
    296                    var2.appendTag(this.spawnerTags.func_92030_a());
    297                }
    298
    299                par1NBTTagCompound.setTag("SpawnPotentials", var2);
    300            }
    301        }
    302
    303        @SideOnly(Side.CLIENT)
    304
    305        /**
    306         * will create the entity from the internalID the first time it is accessed
    307         */
    308        public Entity getMobEntity()
    309        {
    310            if (this.field_92017_j == null)
    311            {
    312                Entity var1 = EntityList.createEntityByName(this.func_92015_a(), (World)null);
    313                this.writeNBTTagsTo(var1);
    314                this.field_92017_j = var1;
    315            }
    316
    317            return this.field_92017_j;
    318        }
    319
    320        /**
    321         * Overriden in a sign to provide the text.
    322         */
    323        public Packet getDescriptionPacket()
    324        {
    325            NBTTagCompound var1 = new NBTTagCompound();
    326            this.writeToNBT(var1);
    327            var1.removeTag("SpawnPotentials");
    328            return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, var1);
    329        }
    330
    331        /**
    332         * Called when a client event is received with the event number and argument, see World.sendClientEvent
    333         */
    334        public void receiveClientEvent(int par1, int par2)
    335        {
    336            if (par1 == 1 && this.worldObj.isRemote)
    337            {
    338                this.delay = this.minSpawnDelay;
    339            }
    340        }
    341    }