package net.minecraft.tileentity;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import net.minecraft.block.Block;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet132TileEntityData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;
public class TileEntity
{
/**
* A HashMap storing string names of classes mapping to the actual java.lang.Class type.
*/
private static Map nameToClassMap = new HashMap();
/**
* A HashMap storing the classes and mapping to the string names (reverse of nameToClassMap).
*/
private static Map classToNameMap = new HashMap();
/** The reference to the world. */
public World worldObj;
/** The x coordinate of the tile entity. */
public int xCoord;
/** The y coordinate of the tile entity. */
public int yCoord;
/** The z coordinate of the tile entity. */
public int zCoord;
protected boolean tileEntityInvalid;
public int blockMetadata = -1;
/** the Block type that this TileEntity is contained within */
public Block blockType;
/**
* Adds a new two-way mapping between the class and its string name in both hashmaps.
*/
public static void addMapping(Class par0Class, String par1Str)
{
if (nameToClassMap.containsKey(par1Str))
{
throw new IllegalArgumentException("Duplicate id: " + par1Str);
}
else
{
nameToClassMap.put(par1Str, par0Class);
classToNameMap.put(par0Class, par1Str);
}
}
/**
* Returns the worldObj for this tileEntity.
*/
public World getWorldObj()
{
return this.worldObj;
}
/**
* Sets the worldObj for this tileEntity.
*/
public void setWorldObj(World par1World)
{
this.worldObj = par1World;
}
public boolean func_70309_m()
{
return this.worldObj != null;
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
this.xCoord = par1NBTTagCompound.getInteger("x");
this.yCoord = par1NBTTagCompound.getInteger("y");
this.zCoord = par1NBTTagCompound.getInteger("z");
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
String s = (String)classToNameMap.get(this.getClass());
if (s == null)
{
throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
}
else
{
par1NBTTagCompound.setString("id", s);
par1NBTTagCompound.setInteger("x", this.xCoord);
par1NBTTagCompound.setInteger("y", this.yCoord);
par1NBTTagCompound.setInteger("z", this.zCoord);
}
}
/**
* Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
* ticks and creates a new spawn inside its implementation.
*/
public void updateEntity() {}
/**
* Creates a new entity and loads its data from the specified NBT.
*/
public static TileEntity createAndLoadEntity(NBTTagCompound par0NBTTagCompound)
{
TileEntity tileentity = null;
Class oclass = null;
try
{
oclass = (Class)nameToClassMap.get(par0NBTTagCompound.getString("id"));
if (oclass != null)
{
tileentity = (TileEntity)oclass.newInstance();
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
if (tileentity != null)
{
try
{
tileentity.readFromNBT(par0NBTTagCompound);
}
catch (Exception e)
{
FMLLog.log(Level.SEVERE, e,
"A TileEntity %s(%s) has thrown an exception during loading, its state cannot be restored. Report this to the mod author",
par0NBTTagCompound.getString("id"), oclass.getName());
tileentity = null;
}
}
else
{
MinecraftServer.getServer().getLogAgent().logWarning("Skipping TileEntity with id " + par0NBTTagCompound.getString("id"));
}
return tileentity;
}
/**
* Returns block data at the location of this entity (client-only).
*/
public int getBlockMetadata()
{
if (this.blockMetadata == -1)
{
this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
}
return this.blockMetadata;
}
/**
* Called when an the contents of an Inventory change, usually
*/
public void onInventoryChanged()
{
if (this.worldObj != null)
{
this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord);
this.worldObj.updateTileEntityChunkAndDoNothing(this.xCoord, this.yCoord, this.zCoord, this);
if (this.getBlockType() != null)
{
this.worldObj.func_96440_m(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID);
}
}
}
@SideOnly(Side.CLIENT)
/**
* Returns the square of the distance between this entity and the passed in coordinates.
*/
public double getDistanceFrom(double par1, double par3, double par5)
{
double d3 = (double)this.xCoord + 0.5D - par1;
double d4 = (double)this.yCoord + 0.5D - par3;
double d5 = (double)this.zCoord + 0.5D - par5;
return d3 * d3 + d4 * d4 + d5 * d5;
}
@SideOnly(Side.CLIENT)
public double getMaxRenderDistanceSquared()
{
return 4096.0D;
}
/**
* Gets the block type at the location of this entity (client-only).
*/
public Block getBlockType()
{
if (this.blockType == null)
{
this.blockType = Block.blocksList[this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord)];
}
return this.blockType;
}
/**
* Overriden in a sign to provide the text.
*/
public Packet getDescriptionPacket()
{
return null;
}
/**
* returns true if tile entity is invalid, false otherwise
*/
public boolean isInvalid()
{
return this.tileEntityInvalid;
}
/**
* invalidates a tile entity
*/
public void invalidate()
{
this.tileEntityInvalid = true;
}
/**
* validates a tile entity
*/
public void validate()
{
this.tileEntityInvalid = false;
}
/**
* Called when a client event is received with the event number and argument, see World.sendClientEvent
*/
public boolean receiveClientEvent(int par1, int par2)
{
return false;
}
/**
* Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case
* of chests, the adjcacent chest check
*/
public void updateContainingBlockInfo()
{
this.blockType = null;
this.blockMetadata = -1;
}
public void func_85027_a(CrashReportCategory par1CrashReportCategory)
{
par1CrashReportCategory.addCrashSectionCallable("Name", new CallableTileEntityName(this));
CrashReportCategory.func_85068_a(par1CrashReportCategory, this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, this.getBlockMetadata());
par1CrashReportCategory.addCrashSectionCallable("Actual block type", new CallableTileEntityID(this));
par1CrashReportCategory.addCrashSectionCallable("Actual block data value", new CallableTileEntityData(this));
}
static Map getClassToNameMap()
{
return classToNameMap;
}
static
{
addMapping(TileEntityFurnace.class, "Furnace");
addMapping(TileEntityChest.class, "Chest");
addMapping(TileEntityEnderChest.class, "EnderChest");
addMapping(TileEntityRecordPlayer.class, "RecordPlayer");
addMapping(TileEntityDispenser.class, "Trap");
addMapping(TileEntityDropper.class, "Dropper");
addMapping(TileEntitySign.class, "Sign");
addMapping(TileEntityMobSpawner.class, "MobSpawner");
addMapping(TileEntityNote.class, "Music");
addMapping(TileEntityPiston.class, "Piston");
addMapping(TileEntityBrewingStand.class, "Cauldron");
addMapping(TileEntityEnchantmentTable.class, "EnchantTable");
addMapping(TileEntityEndPortal.class, "Airportal");
addMapping(TileEntityCommandBlock.class, "Control");
addMapping(TileEntityBeacon.class, "Beacon");
addMapping(TileEntitySkull.class, "Skull");
addMapping(TileEntityDaylightDetector.class, "DLDetector");
addMapping(TileEntityHopper.class, "Hopper");
addMapping(TileEntityComparator.class, "Comparator");
}
// -- BEGIN FORGE PATCHES --
/**
* Determines if this TileEntity requires update calls.
* @return True if you want updateEntity() to be called, false if not
*/
public boolean canUpdate()
{
return true;
}
/**
* Called when you receive a TileEntityData packet for the location this
* TileEntity is currently in. On the client, the NetworkManager will always
* be the remote server. On the server, it will be whomever is responsible for
* sending the packet.
*
* @param net The NetworkManager the packet originated from
* @param pkt The data packet
*/
public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt)
{
}
/**
* Called when the chunk this TileEntity is on is Unloaded.
*/
public void onChunkUnload()
{
}
/**
* Called from Chunk.setBlockIDWithMetadata, determines if this tile entity should be re-created when the ID, or Metadata changes.
* Use with caution as this will leave straggler TileEntities, or create conflicts with other TileEntities if not used properly.
*
* @param oldID The old ID of the block
* @param newID The new ID of the block (May be the same)
* @param oldMeta The old metadata of the block
* @param newMeta The new metadata of the block (May be the same)
* @param world Current world
* @param x X Postion
* @param y Y Position
* @param z Z Position
* @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}
*/
public boolean shouldRefresh(int oldID, int newID, int oldMeta, int newMeta, World world, int x, int y, int z)
{
return true;
}
public boolean shouldRenderInPass(int pass)
{
return pass == 0;
}
/**
* Sometimes default render bounding box: infinite in scope. Used to control rendering on {@link TileEntitySpecialRenderer}.
*/
public static final AxisAlignedBB INFINITE_EXTENT_AABB = AxisAlignedBB.getBoundingBox(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
/**
* Return an {@link AxisAlignedBB} that controls the visible scope of a {@link TileEntitySpecialRenderer} associated with this {@link TileEntity}
* Defaults to the collision bounding box {@link Block#getCollisionBoundingBoxFromPool(World, int, int, int)} associated with the block
* at this location.
*
* @return an appropriately size {@link AxisAlignedBB} for the {@link TileEntity}
*/
@SideOnly(Side.CLIENT)
public AxisAlignedBB getRenderBoundingBox()
{
AxisAlignedBB bb = INFINITE_EXTENT_AABB;
Block type = getBlockType();
if (type == Block.enchantmentTable)
{
bb = AxisAlignedBB.getAABBPool().getAABB(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 1, zCoord + 1);
}
else if (type == Block.chest)
{
bb = AxisAlignedBB.getAABBPool().getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 2, zCoord + 2);
}
else if (type != null && type != Block.beacon)
{
AxisAlignedBB cbb = getBlockType().getCollisionBoundingBoxFromPool(worldObj, xCoord, yCoord, zCoord);
if (cbb != null)
{
bb = cbb;
}
}
return bb;
}
}