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.setBlock(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.setBlock(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}