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        @SideOnly(Side.CLIENT)
054    
055        /**
056         * Returns the worldObj for this tileEntity.
057         */
058        public World getWorldObj()
059        {
060            return this.worldObj;
061        }
062    
063        /**
064         * Sets the worldObj for this tileEntity.
065         */
066        public void setWorldObj(World par1World)
067        {
068            this.worldObj = par1World;
069        }
070    
071        public boolean func_70309_m()
072        {
073            return this.worldObj != null;
074        }
075    
076        /**
077         * Reads a tile entity from NBT.
078         */
079        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
080        {
081            this.xCoord = par1NBTTagCompound.getInteger("x");
082            this.yCoord = par1NBTTagCompound.getInteger("y");
083            this.zCoord = par1NBTTagCompound.getInteger("z");
084        }
085    
086        /**
087         * Writes a tile entity to NBT.
088         */
089        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
090        {
091            String var2 = (String)classToNameMap.get(this.getClass());
092    
093            if (var2 == null)
094            {
095                throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
096            }
097            else
098            {
099                par1NBTTagCompound.setString("id", var2);
100                par1NBTTagCompound.setInteger("x", this.xCoord);
101                par1NBTTagCompound.setInteger("y", this.yCoord);
102                par1NBTTagCompound.setInteger("z", this.zCoord);
103            }
104        }
105    
106        /**
107         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
108         * ticks and creates a new spawn inside its implementation.
109         */
110        public void updateEntity() {}
111    
112        /**
113         * Creates a new entity and loads its data from the specified NBT.
114         */
115        public static TileEntity createAndLoadEntity(NBTTagCompound par0NBTTagCompound)
116        {
117            TileEntity var1 = null;
118    
119            try
120            {
121                Class var2 = (Class)nameToClassMap.get(par0NBTTagCompound.getString("id"));
122    
123                if (var2 != null)
124                {
125                    var1 = (TileEntity)var2.newInstance();
126                }
127            }
128            catch (Exception var3)
129            {
130                var3.printStackTrace();
131            }
132    
133            if (var1 != null)
134            {
135                var1.readFromNBT(par0NBTTagCompound);
136            }
137            else
138            {
139                System.out.println("Skipping TileEntity with id " + par0NBTTagCompound.getString("id"));
140            }
141    
142            return var1;
143        }
144    
145        /**
146         * Returns block data at the location of this entity (client-only).
147         */
148        public int getBlockMetadata()
149        {
150            if (this.blockMetadata == -1)
151            {
152                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
153            }
154    
155            return this.blockMetadata;
156        }
157    
158        /**
159         * Called when an the contents of an Inventory change, usually
160         */
161        public void onInventoryChanged()
162        {
163            if (this.worldObj != null)
164            {
165                this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
166                this.worldObj.updateTileEntityChunkAndDoNothing(this.xCoord, this.yCoord, this.zCoord, this);
167            }
168        }
169    
170        @SideOnly(Side.CLIENT)
171    
172        /**
173         * Returns the square of the distance between this entity and the passed in coordinates.
174         */
175        public double getDistanceFrom(double par1, double par3, double par5)
176        {
177            double var7 = (double)this.xCoord + 0.5D - par1;
178            double var9 = (double)this.yCoord + 0.5D - par3;
179            double var11 = (double)this.zCoord + 0.5D - par5;
180            return var7 * var7 + var9 * var9 + var11 * var11;
181        }
182    
183        @SideOnly(Side.CLIENT)
184        public double func_82115_m()
185        {
186            return 4096.0D;
187        }
188    
189        /**
190         * Gets the block type at the location of this entity (client-only).
191         */
192        public Block getBlockType()
193        {
194            if (this.blockType == null)
195            {
196                this.blockType = Block.blocksList[this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord)];
197            }
198    
199            return this.blockType;
200        }
201    
202        /**
203         * Overriden in a sign to provide the text.
204         */
205        public Packet getDescriptionPacket()
206        {
207            return null;
208        }
209    
210        /**
211         * returns true if tile entity is invalid, false otherwise
212         */
213        public boolean isInvalid()
214        {
215            return this.tileEntityInvalid;
216        }
217    
218        /**
219         * invalidates a tile entity
220         */
221        public void invalidate()
222        {
223            this.tileEntityInvalid = true;
224        }
225    
226        /**
227         * validates a tile entity
228         */
229        public void validate()
230        {
231            this.tileEntityInvalid = false;
232        }
233    
234        /**
235         * Called when a client event is received with the event number and argument, see World.sendClientEvent
236         */
237        public void receiveClientEvent(int par1, int par2) {}
238    
239        /**
240         * Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case
241         * of chests, the adjcacent chest check
242         */
243        public void updateContainingBlockInfo()
244        {
245            this.blockType = null;
246            this.blockMetadata = -1;
247        }
248    
249        static
250        {
251            addMapping(TileEntityFurnace.class, "Furnace");
252            addMapping(TileEntityChest.class, "Chest");
253            addMapping(TileEntityEnderChest.class, "EnderChest");
254            addMapping(TileEntityRecordPlayer.class, "RecordPlayer");
255            addMapping(TileEntityDispenser.class, "Trap");
256            addMapping(TileEntitySign.class, "Sign");
257            addMapping(TileEntityMobSpawner.class, "MobSpawner");
258            addMapping(TileEntityNote.class, "Music");
259            addMapping(TileEntityPiston.class, "Piston");
260            addMapping(TileEntityBrewingStand.class, "Cauldron");
261            addMapping(TileEntityEnchantmentTable.class, "EnchantTable");
262            addMapping(TileEntityEndPortal.class, "Airportal");
263            addMapping(TileEntityCommandBlock.class, "Control");
264            addMapping(TileEntityBeacon.class, "Beacon");
265            addMapping(TileEntitySkull.class, "Skull");
266        }
267    
268        /**
269         * Determines if this TileEntity requires update calls.
270         * @return True if you want updateEntity() to be called, false if not
271         */
272        public boolean canUpdate()
273        {
274            return true;
275        }
276    
277        /**
278         * Called when you receive a TileEntityData packet for the location this
279         * TileEntity is currently in. On the client, the NetworkManager will always
280         * be the remote server. On the server, it will be whomever is responsible for 
281         * sending the packet.
282         * 
283         * @param net The NetworkManager the packet originated from 
284         * @param pkt The data packet
285         */
286        public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt)
287        {
288        }
289    
290        /**
291         * Called when the chunk this TileEntity is on is Unloaded.
292         */
293        public void onChunkUnload()
294        {
295        }
296    }