    001package net.minecraft.tileentity;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.ArrayList;
    006import java.util.Iterator;
    007import java.util.List;
    008import net.minecraft.block.Block;
    009import net.minecraft.entity.Entity;
    010import net.minecraft.nbt.NBTTagCompound;
    011import net.minecraft.util.AxisAlignedBB;
    012import net.minecraft.util.Facing;
    013
    014public class TileEntityPiston extends TileEntity
    015{
    016    private int storedBlockID;
    017    private int storedMetadata;
    018
    019    /** the side the front of the piston is on */
    020    private int storedOrientation;
    021
    022    /** if this piston is extending or not */
    023    private boolean extending;
    024    private boolean shouldHeadBeRendered;
    025    private float progress;
    026
    027    /** the progress in (de)extending */
    028    private float lastProgress;
    029    private List pushedObjects = new ArrayList();
    030
    031    public TileEntityPiston() {}
    032
    033    public TileEntityPiston(int par1, int par2, int par3, boolean par4, boolean par5)
    034    {
    035        this.storedBlockID = par1;
    036        this.storedMetadata = par2;
    037        this.storedOrientation = par3;
    038        this.extending = par4;
    039        this.shouldHeadBeRendered = par5;
    040    }
    041
    042    public int getStoredBlockID()
    043    {
    044        return this.storedBlockID;
    045    }
    046
    047    /**
    048     * Returns block data at the location of this entity (client-only).
    049     */
    050    public int getBlockMetadata()
    051    {
    052        return this.storedMetadata;
    053    }
    054
    055    /**
    056     * Returns true if a piston is extending
    057     */
    058    public boolean isExtending()
    059    {
    060        return this.extending;
    061    }
    062
    063    /**
    064     * Returns the orientation of the piston as an int
    065     */
    066    public int getPistonOrientation()
    067    {
    068        return this.storedOrientation;
    069    }
    070
    071    @SideOnly(Side.CLIENT)
    072    public boolean shouldRenderHead()
    073    {
    074        return this.shouldHeadBeRendered;
    075    }
    076
    077    /**
    078     * Get interpolated progress value (between lastProgress and progress) given the fractional time between ticks as an
    079     * argument.
    080     */
    081    public float getProgress(float par1)
    082    {
    083        if (par1 > 1.0F)
    084        {
    085            par1 = 1.0F;
    086        }
    087
    088        return this.lastProgress + (this.progress - this.lastProgress) * par1;
    089    }
    090
    091    private void updatePushedObjects(float par1, float par2)
    092    {
    093        if (this.extending)
    094        {
    095            par1 = 1.0F - par1;
    096        }
    097        else
    098        {
    099            --par1;
    100        }
    101
    102        AxisAlignedBB axisalignedbb = Block.pistonMoving.getAxisAlignedBB(this.worldObj, this.xCoord, this.yCoord, this.zCoord, this.storedBlockID, par1, this.storedOrientation);
    103
    104        if (axisalignedbb != null)
    105        {
    106            List list = this.worldObj.getEntitiesWithinAABBExcludingEntity((Entity)null, axisalignedbb);
    107
    108            if (!list.isEmpty())
    109            {
    110                this.pushedObjects.addAll(list);
    111                Iterator iterator = this.pushedObjects.iterator();
    112
    113                while (iterator.hasNext())
    114                {
    115                    Entity entity = (Entity)iterator.next();
    116                    entity.moveEntity((double)(par2 * (float)Facing.offsetsXForSide[this.storedOrientation]), (double)(par2 * (float)Facing.offsetsYForSide[this.storedOrientation]), (double)(par2 * (float)Facing.offsetsZForSide[this.storedOrientation]));
    117                }
    118
    119                this.pushedObjects.clear();
    120            }
    121        }
    122    }
    123
    124    @SideOnly(Side.CLIENT)
    125    public float getOffsetX(float par1)
    126    {
    127        return this.extending ? (this.getProgress(par1) - 1.0F) * (float)Facing.offsetsXForSide[this.storedOrientation] : (1.0F - this.getProgress(par1)) * (float)Facing.offsetsXForSide[this.storedOrientation];
    128    }
    129
    130    @SideOnly(Side.CLIENT)
    131    public float getOffsetY(float par1)
    132    {
    133        return this.extending ? (this.getProgress(par1) - 1.0F) * (float)Facing.offsetsYForSide[this.storedOrientation] : (1.0F - this.getProgress(par1)) * (float)Facing.offsetsYForSide[this.storedOrientation];
    134    }
    135
    136    @SideOnly(Side.CLIENT)
    137    public float getOffsetZ(float par1)
    138    {
    139        return this.extending ? (this.getProgress(par1) - 1.0F) * (float)Facing.offsetsZForSide[this.storedOrientation] : (1.0F - this.getProgress(par1)) * (float)Facing.offsetsZForSide[this.storedOrientation];
    140    }
    141
    142    /**
    143     * removes a pistons tile entity (and if the piston is moving, stops it)
    144     */
    145    public void clearPistonTileEntity()
    146    {
    147        if (this.lastProgress < 1.0F && this.worldObj != null)
    148        {
    149            this.lastProgress = this.progress = 1.0F;
    150            this.worldObj.removeBlockTileEntity(this.xCoord, this.yCoord, this.zCoord);
    151            this.invalidate();
    152
    153            if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord) == Block.pistonMoving.blockID)
    154            {
    155                this.worldObj.setBlockAndMetadataWithNotify(this.xCoord, this.yCoord, this.zCoord, this.storedBlockID, this.storedMetadata, 3);
    156                this.worldObj.notifyBlockOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.storedBlockID);
    157            }
    158        }
    159    }
    160
    161    /**
    162     * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    163     * ticks and creates a new spawn inside its implementation.
    164     */
    165    public void updateEntity()
    166    {
    167        this.lastProgress = this.progress;
    168
    169        if (this.lastProgress >= 1.0F)
    170        {
    171            this.updatePushedObjects(1.0F, 0.25F);
    172            this.worldObj.removeBlockTileEntity(this.xCoord, this.yCoord, this.zCoord);
    173            this.invalidate();
    174
    175            if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord) == Block.pistonMoving.blockID)
    176            {
    177                this.worldObj.setBlockAndMetadataWithNotify(this.xCoord, this.yCoord, this.zCoord, this.storedBlockID, this.storedMetadata, 3);
    178                this.worldObj.notifyBlockOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.storedBlockID);
    179            }
    180        }
    181        else
    182        {
    183            this.progress += 0.5F;
    184
    185            if (this.progress >= 1.0F)
    186            {
    187                this.progress = 1.0F;
    188            }
    189
    190            if (this.extending)
    191            {
    192                this.updatePushedObjects(this.progress, this.progress - this.lastProgress + 0.0625F);
    193            }
    194        }
    195    }
    196
    197    /**
    198     * Reads a tile entity from NBT.
    199     */
    200    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    201    {
    202        super.readFromNBT(par1NBTTagCompound);
    203        this.storedBlockID = par1NBTTagCompound.getInteger("blockId");
    204        this.storedMetadata = par1NBTTagCompound.getInteger("blockData");
    205        this.storedOrientation = par1NBTTagCompound.getInteger("facing");
    206        this.lastProgress = this.progress = par1NBTTagCompound.getFloat("progress");
    207        this.extending = par1NBTTagCompound.getBoolean("extending");
    208    }
    209
    210    /**
    211     * Writes a tile entity to NBT.
    212     */
    213    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    214    {
    215        super.writeToNBT(par1NBTTagCompound);
    216        par1NBTTagCompound.setInteger("blockId", this.storedBlockID);
    217        par1NBTTagCompound.setInteger("blockData", this.storedMetadata);
    218        par1NBTTagCompound.setInteger("facing", this.storedOrientation);
    219        par1NBTTagCompound.setFloat("progress", this.lastProgress);
    220        par1NBTTagCompound.setBoolean("extending", this.extending);
    221    }
    222}