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 }