001 package net.minecraft.tileentity;
002
003 import cpw.mods.fml.common.FMLLog;
004 import cpw.mods.fml.relauncher.Side;
005 import cpw.mods.fml.relauncher.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 }