001    package net.minecraft.src;
002    
003    import cpw.mods.fml.common.Side;
004    import cpw.mods.fml.common.asm.SideOnly;
005    import java.util.HashMap;
006    import java.util.Map;
007    
008    public class TileEntity
009    {
010        /**
011         * A HashMap storing string names of classes mapping to the actual java.lang.Class type.
012         */
013        private static Map nameToClassMap = new HashMap();
014    
015        /**
016         * A HashMap storing the classes and mapping to the string names (reverse of nameToClassMap).
017         */
018        private static Map classToNameMap = new HashMap();
019    
020        /** The reference to the world. */
021        public World worldObj;
022    
023        /** The x coordinate of the tile entity. */
024        public int xCoord;
025    
026        /** The y coordinate of the tile entity. */
027        public int yCoord;
028    
029        /** The z coordinate of the tile entity. */
030        public int zCoord;
031        protected boolean tileEntityInvalid;
032        public int blockMetadata = -1;
033    
034        /** the Block type that this TileEntity is contained within */
035        public Block blockType;
036    
037        /**
038         * Adds a new two-way mapping between the class and its string name in both hashmaps.
039         */
040        public static void addMapping(Class par0Class, String par1Str)
041        {
042            if (nameToClassMap.containsKey(par1Str))
043            {
044                throw new IllegalArgumentException("Duplicate id: " + par1Str);
045            }
046            else
047            {
048                nameToClassMap.put(par1Str, par0Class);
049                classToNameMap.put(par0Class, par1Str);
050            }
051        }
052    
053        public void func_70308_a(World par1World)
054        {
055            this.worldObj = par1World;
056        }
057    
058        @SideOnly(Side.CLIENT)
059        public World func_70314_l()
060        {
061            return this.worldObj;
062        }
063    
064        public boolean func_70309_m()
065        {
066            return this.worldObj != null;
067        }
068    
069        /**
070         * Reads a tile entity from NBT.
071         */
072        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
073        {
074            this.xCoord = par1NBTTagCompound.getInteger("x");
075            this.yCoord = par1NBTTagCompound.getInteger("y");
076            this.zCoord = par1NBTTagCompound.getInteger("z");
077        }
078    
079        /**
080         * Writes a tile entity to NBT.
081         */
082        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
083        {
084            String var2 = (String)classToNameMap.get(this.getClass());
085    
086            if (var2 == null)
087            {
088                throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
089            }
090            else
091            {
092                par1NBTTagCompound.setString("id", var2);
093                par1NBTTagCompound.setInteger("x", this.xCoord);
094                par1NBTTagCompound.setInteger("y", this.yCoord);
095                par1NBTTagCompound.setInteger("z", this.zCoord);
096            }
097        }
098    
099        /**
100         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
101         * ticks and creates a new spawn inside its implementation.
102         */
103        public void updateEntity() {}
104    
105        /**
106         * Creates a new entity and loads its data from the specified NBT.
107         */
108        public static TileEntity createAndLoadEntity(NBTTagCompound par0NBTTagCompound)
109        {
110            TileEntity var1 = null;
111    
112            try
113            {
114                Class var2 = (Class)nameToClassMap.get(par0NBTTagCompound.getString("id"));
115    
116                if (var2 != null)
117                {
118                    var1 = (TileEntity)var2.newInstance();
119                }
120            }
121            catch (Exception var3)
122            {
123                var3.printStackTrace();
124            }
125    
126            if (var1 != null)
127            {
128                var1.readFromNBT(par0NBTTagCompound);
129            }
130            else
131            {
132                System.out.println("Skipping TileEntity with id " + par0NBTTagCompound.getString("id"));
133            }
134    
135            return var1;
136        }
137    
138        /**
139         * Returns block data at the location of this entity (client-only).
140         */
141        public int getBlockMetadata()
142        {
143            if (this.blockMetadata == -1)
144            {
145                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
146            }
147    
148            return this.blockMetadata;
149        }
150    
151        /**
152         * Called when an the contents of an Inventory change, usually
153         */
154        public void onInventoryChanged()
155        {
156            if (this.worldObj != null)
157            {
158                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
159                this.worldObj.updateTileEntityChunkAndDoNothing(this.xCoord, this.yCoord, this.zCoord, this);
160            }
161        }
162    
163        @SideOnly(Side.CLIENT)
164    
165        /**
166         * Returns the square of the distance between this entity and the passed in coordinates.
167         */
168        public double getDistanceFrom(double par1, double par3, double par5)
169        {
170            double var7 = (double)this.xCoord + 0.5D - par1;
171            double var9 = (double)this.yCoord + 0.5D - par3;
172            double var11 = (double)this.zCoord + 0.5D - par5;
173            return var7 * var7 + var9 * var9 + var11 * var11;
174        }
175    
176        @SideOnly(Side.CLIENT)
177    
178        /**
179         * Gets the block type at the location of this entity (client-only).
180         */
181        public Block getBlockType()
182        {
183            if (this.blockType == null)
184            {
185                this.blockType = Block.blocksList[this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord)];
186            }
187    
188            return this.blockType;
189        }
190    
191        /**
192         * signs and mobSpawners use this to send text and meta-data
193         */
194        public Packet getAuxillaryInfoPacket()
195        {
196            return null;
197        }
198    
199        /**
200         * returns true if tile entity is invalid, false otherwise
201         */
202        public boolean isInvalid()
203        {
204            return this.tileEntityInvalid;
205        }
206    
207        /**
208         * invalidates a tile entity
209         */
210        public void invalidate()
211        {
212            this.tileEntityInvalid = true;
213        }
214    
215        /**
216         * validates a tile entity
217         */
218        public void validate()
219        {
220            this.tileEntityInvalid = false;
221        }
222    
223        /**
224         * Called when a client event is received with the event number and argument, see World.sendClientEvent
225         */
226        public void receiveClientEvent(int par1, int par2) {}
227    
228        /**
229         * Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case
230         * of chests, the adjcacent chest check
231         */
232        public void updateContainingBlockInfo()
233        {
234            this.blockType = null;
235            this.blockMetadata = -1;
236        }
237    
238        static
239        {
240            addMapping(TileEntityFurnace.class, "Furnace");
241            addMapping(TileEntityChest.class, "Chest");
242            addMapping(TileEntityEnderChest.class, "EnderChest");
243            addMapping(TileEntityRecordPlayer.class, "RecordPlayer");
244            addMapping(TileEntityDispenser.class, "Trap");
245            addMapping(TileEntitySign.class, "Sign");
246            addMapping(TileEntityMobSpawner.class, "MobSpawner");
247            addMapping(TileEntityNote.class, "Music");
248            addMapping(TileEntityPiston.class, "Piston");
249            addMapping(TileEntityBrewingStand.class, "Cauldron");
250            addMapping(TileEntityEnchantmentTable.class, "EnchantTable");
251            addMapping(TileEntityEndPortal.class, "Airportal");
252        }
253    
254        /**
255         * Determines if this TileEntity requires update calls.
256         * @return True if you want updateEntity() to be called, false if not
257         */
258        public boolean canUpdate()
259        {
260            return true;
261        }
262    
263        /**
264         * Called when you receive a TileEntityData packet for the location this
265         * TileEntity is currently in. On the client, the NetworkManager will always
266         * be the remote server. On the server, it will be whomever is responsible for 
267         * sending the packet.
268         * 
269         * @param net The NetworkManager the packet originated from 
270         * @param pkt The data packet
271         */
272        public void onDataPacket(NetworkManager net, Packet132TileEntityData pkt)
273        {
274        }
275    
276        /**
277         * Called when the chunk this TileEntity is on is Unloaded.
278         */
279        public void onChunkUnload()
280        {
281        }
282    
283        /**
284         *  @return The maximum distance between the player and the TileEntity at which the TileEntitySpecialRenderer will be called
285         */
286        public double getRenderDistance()
287        {
288            return 64;
289        }
290    }