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 var3 = Block.pistonMoving.getAxisAlignedBB(this.worldObj, this.xCoord, this.yCoord, this.zCoord, this.storedBlockID, par1, this.storedOrientation);
103
104        if (var3 != null)
105        {
106            List var4 = this.worldObj.getEntitiesWithinAABBExcludingEntity((Entity)null, var3);
107
108            if (!var4.isEmpty())
109            {
110                this.pushedObjects.addAll(var4);
111                Iterator var5 = this.pushedObjects.iterator();
112
113                while (var5.hasNext())
114                {
115                    Entity var6 = (Entity)var5.next();
116                    var6.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);
156            }
157        }
158    }
159
160    /**
161     * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
162     * ticks and creates a new spawn inside its implementation.
163     */
164    public void updateEntity()
165    {
166        this.lastProgress = this.progress;
167
168        if (this.lastProgress >= 1.0F)
169        {
170            this.updatePushedObjects(1.0F, 0.25F);
171            this.worldObj.removeBlockTileEntity(this.xCoord, this.yCoord, this.zCoord);
172            this.invalidate();
173
174            if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord) == Block.pistonMoving.blockID)
175            {
176                this.worldObj.setBlockAndMetadataWithNotify(this.xCoord, this.yCoord, this.zCoord, this.storedBlockID, this.storedMetadata);
177            }
178        }
179        else
180        {
181            this.progress += 0.5F;
182
183            if (this.progress >= 1.0F)
184            {
185                this.progress = 1.0F;
186            }
187
188            if (this.extending)
189            {
190                this.updatePushedObjects(this.progress, this.progress - this.lastProgress + 0.0625F);
191            }
192        }
193    }
194
195    /**
196     * Reads a tile entity from NBT.
197     */
198    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
199    {
200        super.readFromNBT(par1NBTTagCompound);
201        this.storedBlockID = par1NBTTagCompound.getInteger("blockId");
202        this.storedMetadata = par1NBTTagCompound.getInteger("blockData");
203        this.storedOrientation = par1NBTTagCompound.getInteger("facing");
204        this.lastProgress = this.progress = par1NBTTagCompound.getFloat("progress");
205        this.extending = par1NBTTagCompound.getBoolean("extending");
206    }
207
208    /**
209     * Writes a tile entity to NBT.
210     */
211    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
212    {
213        super.writeToNBT(par1NBTTagCompound);
214        par1NBTTagCompound.setInteger("blockId", this.storedBlockID);
215        par1NBTTagCompound.setInteger("blockData", this.storedMetadata);
216        par1NBTTagCompound.setInteger("facing", this.storedOrientation);
217        par1NBTTagCompound.setFloat("progress", this.lastProgress);
218        par1NBTTagCompound.setBoolean("extending", this.extending);
219    }
220}