    001    package net.minecraft.tileentity;
    002
    003    import cpw.mods.fml.common.FMLLog;
    004    import cpw.mods.fml.common.Side;
    005    import cpw.mods.fml.common.asm.SideOnly;
    006    import java.util.HashMap;
    007    import java.util.Map;
    008    import java.util.logging.Level;
    009
    010    import net.minecraft.block.Block;
    011    import net.minecraft.block.TileEntityRecordPlayer;
    012    import net.minecraft.crash.CrashReportCategory;
    013    import net.minecraft.nbt.NBTTagCompound;
    014    import net.minecraft.network.INetworkManager;
    015    import net.minecraft.network.packet.Packet;
    016    import net.minecraft.network.packet.Packet132TileEntityData;
    017    import net.minecraft.world.World;
    018
    019    public class TileEntity
    020    {
    021        /**
    022         * A HashMap storing string names of classes mapping to the actual java.lang.Class type.
    023         */
    024        private static Map nameToClassMap = new HashMap();
    025
    026        /**
    027         * A HashMap storing the classes and mapping to the string names (reverse of nameToClassMap).
    028         */
    029        private static Map classToNameMap = new HashMap();
    030
    031        /** The reference to the world. */
    032        public World worldObj;
    033
    034        /** The x coordinate of the tile entity. */
    035        public int xCoord;
    036
    037        /** The y coordinate of the tile entity. */
    038        public int yCoord;
    039
    040        /** The z coordinate of the tile entity. */
    041        public int zCoord;
    042        protected boolean tileEntityInvalid;
    043        public int blockMetadata = -1;
    044
    045        /** the Block type that this TileEntity is contained within */
    046        public Block blockType;
    047
    048        /**
    049         * Adds a new two-way mapping between the class and its string name in both hashmaps.
    050         */
    051        public static void addMapping(Class par0Class, String par1Str)
    052        {
    053            if (nameToClassMap.containsKey(par1Str))
    054            {
    055                throw new IllegalArgumentException("Duplicate id: " + par1Str);
    056            }
    057            else
    058            {
    059                nameToClassMap.put(par1Str, par0Class);
    060                classToNameMap.put(par0Class, par1Str);
    061            }
    062        }
    063
    064        @SideOnly(Side.CLIENT)
    065
    066        /**
    067         * Returns the worldObj for this tileEntity.
    068         */
    069        public World getWorldObj()
    070        {
    071            return this.worldObj;
    072        }
    073
    074        /**
    075         * Sets the worldObj for this tileEntity.
    076         */
    077        public void setWorldObj(World par1World)
    078        {
    079            this.worldObj = par1World;
    080        }
    081
    082        public boolean func_70309_m()
    083        {
    084            return this.worldObj != null;
    085        }
    086
    087        /**
    088         * Reads a tile entity from NBT.
    089         */
    090        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    091        {
    092            this.xCoord = par1NBTTagCompound.getInteger("x");
    093            this.yCoord = par1NBTTagCompound.getInteger("y");
    094            this.zCoord = par1NBTTagCompound.getInteger("z");
    095        }
    096
    097        /**
    098         * Writes a tile entity to NBT.
    099         */
    100        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    101        {
    102            String var2 = (String)classToNameMap.get(this.getClass());
    103
    104            if (var2 == null)
    105            {
    106                throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
    107            }
    108            else
    109            {
    110                par1NBTTagCompound.setString("id", var2);
    111                par1NBTTagCompound.setInteger("x", this.xCoord);
    112                par1NBTTagCompound.setInteger("y", this.yCoord);
    113                par1NBTTagCompound.setInteger("z", this.zCoord);
    114            }
    115        }
    116
    117        /**
    118         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    119         * ticks and creates a new spawn inside its implementation.
    120         */
    121        public void updateEntity() {}
    122
    123        /**
    124         * Creates a new entity and loads its data from the specified NBT.
    125         */
    126        public static TileEntity createAndLoadEntity(NBTTagCompound par0NBTTagCompound)
    127        {
    128            TileEntity var1 = null;
    129
    130            Class var2 = null;
    131
    132            try
    133            {
    134                var2 = (Class)nameToClassMap.get(par0NBTTagCompound.getString("id"));
    135
    136                if (var2 != null)
    137                {
    138                    var1 = (TileEntity)var2.newInstance();
    139                }
    140            }
    141            catch (Exception var3)
    142            {
    143                var3.printStackTrace();
    144            }
    145
    146            if (var1 != null)
    147            {
    148                try
    149                {
    150                    var1.readFromNBT(par0NBTTagCompound);
    151                }
    152                catch (Exception e)
    153                {
    154                    FMLLog.log(Level.SEVERE, e,
    155                            "A TileEntity %s(%s) has thrown an exception during loading, its state cannot be restored. Report this to the mod author",
    156                            par0NBTTagCompound.getString("id"), var2.getName());
    157                    var1 = null;
    158                }
    159            }
    160            else
    161            {
    162                System.out.println("Skipping TileEntity with id " + par0NBTTagCompound.getString("id"));
    163            }
    164
    165            return var1;
    166        }
    167
    168        /**
    169         * Returns block data at the location of this entity (client-only).
    170         */
    171        public int getBlockMetadata()
    172        {
    173            if (this.blockMetadata == -1)
    174            {
    175                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
    176            }
    177
    178            return this.blockMetadata;
    179        }
    180
    181        /**
    182         * Called when an the contents of an Inventory change, usually
    183         */
    184        public void onInventoryChanged()
    185        {
    186            if (this.worldObj != null)
    187            {
    188                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
    189                this.worldObj.updateTileEntityChunkAndDoNothing(this.xCoord, this.yCoord, this.zCoord, this);
    190            }
    191        }
    192
    193        @SideOnly(Side.CLIENT)
    194
    195        /**
    196         * Returns the square of the distance between this entity and the passed in coordinates.
    197         */
    198        public double getDistanceFrom(double par1, double par3, double par5)
    199        {
    200            double var7 = (double)this.xCoord + 0.5D - par1;
    201            double var9 = (double)this.yCoord + 0.5D - par3;
    202            double var11 = (double)this.zCoord + 0.5D - par5;
    203            return var7 * var7 + var9 * var9 + var11 * var11;
    204        }
    205
    206        @SideOnly(Side.CLIENT)
    207        public double func_82115_m()
    208        {
    209            return 4096.0D;
    210        }
    211
    212        /**
    213         * Gets the block type at the location of this entity (client-only).
    214         */
    215        public Block getBlockType()
    216        {
    217            if (this.blockType == null)
    218            {
    219                this.blockType = Block.blocksList[this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord)];
    220            }
    221
    222            return this.blockType;
    223        }
    224
    225        /**
    226         * Overriden in a sign to provide the text.
    227         */
    228        public Packet getDescriptionPacket()
    229        {
    230            return null;
    231        }
    232
    233        /**
    234         * returns true if tile entity is invalid, false otherwise
    235         */
    236        public boolean isInvalid()
    237        {
    238            return this.tileEntityInvalid;
    239        }
    240
    241        /**
    242         * invalidates a tile entity
    243         */
    244        public void invalidate()
    245        {
    246            this.tileEntityInvalid = true;
    247        }
    248
    249        /**
    250         * validates a tile entity
    251         */
    252        public void validate()
    253        {
    254            this.tileEntityInvalid = false;
    255        }
    256
    257        /**
    258         * Called when a client event is received with the event number and argument, see World.sendClientEvent
    259         */
    260        public void receiveClientEvent(int par1, int par2) {}
    261
    262        /**
    263         * Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case
    264         * of chests, the adjcacent chest check
    265         */
    266        public void updateContainingBlockInfo()
    267        {
    268            this.blockType = null;
    269            this.blockMetadata = -1;
    270        }
    271
    272        public void func_85027_a(CrashReportCategory par1CrashReportCategory)
    273        {
    274            par1CrashReportCategory.addCrashSectionCallable("Name", new CallableTileEntityName(this));
    275            CrashReportCategory.func_85068_a(par1CrashReportCategory, this.xCoord, this.yCoord, this.zCoord, this.blockType != null ? this.blockType.blockID : 0, this.blockMetadata);
    276        }
    277
    278        static Map func_85028_t()
    279        {
    280            return classToNameMap;
    281        }
    282
    283        static
    284        {
    285            addMapping(TileEntityFurnace.class, "Furnace");
    286            addMapping(TileEntityChest.class, "Chest");
    287            addMapping(TileEntityEnderChest.class, "EnderChest");
    288            addMapping(TileEntityRecordPlayer.class, "RecordPlayer");
    289            addMapping(TileEntityDispenser.class, "Trap");
    290            addMapping(TileEntitySign.class, "Sign");
    291            addMapping(TileEntityMobSpawner.class, "MobSpawner");
    292            addMapping(TileEntityNote.class, "Music");
    293            addMapping(TileEntityPiston.class, "Piston");
    294            addMapping(TileEntityBrewingStand.class, "Cauldron");
    295            addMapping(TileEntityEnchantmentTable.class, "EnchantTable");
    296            addMapping(TileEntityEndPortal.class, "Airportal");
    297            addMapping(TileEntityCommandBlock.class, "Control");
    298            addMapping(TileEntityBeacon.class, "Beacon");
    299            addMapping(TileEntitySkull.class, "Skull");
    300        }
    301
    302        /**
    303         * Determines if this TileEntity requires update calls.
    304         * @return True if you want updateEntity() to be called, false if not
    305         */
    306        public boolean canUpdate()
    307        {
    308            return true;
    309        }
    310
    311        /**
    312         * Called when you receive a TileEntityData packet for the location this
    313         * TileEntity is currently in. On the client, the NetworkManager will always
    314         * be the remote server. On the server, it will be whomever is responsible for
    315         * sending the packet.
    316         *
    317         * @param net The NetworkManager the packet originated from
    318         * @param pkt The data packet
    319         */
    320        public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt)
    321        {
    322        }
    323
    324        /**
    325         * Called when the chunk this TileEntity is on is Unloaded.
    326         */
    327        public void onChunkUnload()
    328        {
    329        }
    330
    331        /**
    332         * Called from Chunk.setBlockIDWithMetadata, determines if this tile entity should be re-created when the ID, or Metadata changes.
    333         * Use with caution as this will leave straggler TileEntities, or create conflicts with other TileEntities if not used properly.
    334         *
    335         * @param oldID The old ID of the block
    336         * @param newID The new ID of the block (May be the same)
    337         * @param oldMeta The old metadata of the block
    338         * @param newMeta The new metadata of the block (May be the same)
    339         * @param world Current world
    340         * @param x X Postion
    341         * @param y Y Position
    342         * @param z Z Position
    343         * @return True to remove the old tile entity, false to keep it in tact {and create a new one if the new values specify to}
    344         */
    345        public boolean shouldRefresh(int oldID, int newID, int oldMeta, int newMeta, World world, int x, int y, int z)
    346        {
    347            return true;
    348        }
    349    }