package mekanism.common.tile;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import mekanism.api.Coord4D;
import mekanism.api.Range4D;
import mekanism.common.ITileComponent;
import mekanism.common.ITileNetwork;
import mekanism.common.Mekanism;
import mekanism.common.network.PacketDataRequest.DataRequestMessage;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.util.MekanismUtils;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import cpw.mods.fml.common.Optional.Interface;
import cpw.mods.fml.common.Optional.Method;
import io.netty.buffer.ByteBuf;
import ic2.api.tile.IWrenchable;
@Interface(iface = "ic2.api.tile.IWrenchable", modid = "IC2API")
public abstract class TileEntityBasicBlock extends TileEntity implements IWrenchable, ITileNetwork
{
/** The direction this block is facing. */
public int facing;
public int clientFacing;
public HashSet<EntityPlayer> openedThisTick = new HashSet<EntityPlayer>();
/** The players currently using this block. */
public HashSet<EntityPlayer> playersUsing = new HashSet<EntityPlayer>();
/** A timer used to send packets to clients. */
public int ticker;
public boolean redstone = false;
public boolean doAutoSync = true;
public List<ITileComponent> components = new ArrayList<ITileComponent>();
@Override
public void updateEntity()
{
for(ITileComponent component : components)
{
component.tick();
}
onUpdate();
if(!worldObj.isRemote)
{
openedThisTick.clear();
if(doAutoSync && playersUsing.size() > 0)
{
for(EntityPlayer player : playersUsing)
{
Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), (EntityPlayerMP)player);
}
}
}
ticker++;
}
public void open(EntityPlayer player)
{
playersUsing.add(player);
}
public void close(EntityPlayer player)
{
playersUsing.remove(player);
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
facing = dataStream.readInt();
redstone = dataStream.readBoolean();
if(clientFacing != facing)
{
MekanismUtils.updateBlock(worldObj, xCoord, yCoord, zCoord);
worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord));
clientFacing = facing;
}
for(ITileComponent component : components)
{
component.read(dataStream);
}
}
@Override
public ArrayList getNetworkedData(ArrayList data)
{
data.add(facing);
data.add(redstone);
for(ITileComponent component : components)
{
component.write(data);
}
return data;
}
@Override
public void validate()
{
super.validate();
if(worldObj.isRemote)
{
Mekanism.packetHandler.sendToServer(new DataRequestMessage(Coord4D.get(this)));
}
}
/**
* Update call for machines. Use instead of updateEntity -- it's called every tick.
*/
public abstract void onUpdate();
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
facing = nbtTags.getInteger("facing");
redstone = nbtTags.getBoolean("redstone");
for(ITileComponent component : components)
{
component.read(nbtTags);
}
}
@Override
public void writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
nbtTags.setInteger("facing", facing);
nbtTags.setBoolean("redstone", redstone);
for(ITileComponent component : components)
{
component.write(nbtTags);
}
}
@Override
@Method(modid = "IC2API")
public boolean wrenchCanSetFacing(EntityPlayer entityPlayer, int side)
{
return true;
}
@Override
@Method(modid = "IC2API")
public short getFacing()
{
return (short)facing;
}
@Override
public void setFacing(short direction)
{
if(canSetFacing(direction))
{
facing = direction;
}
if(!(facing == clientFacing || worldObj.isRemote))
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord));
clientFacing = facing;
}
}
/**
* Whether or not this block's orientation can be changed to a specific direction. True by default.
* @param facing - facing to check
* @return if the block's orientation can be changed
*/
public boolean canSetFacing(int facing)
{
return true;
}
@Override
@Method(modid = "IC2API")
public boolean wrenchCanRemove(EntityPlayer entityPlayer)
{
return true;
}
@Override
@Method(modid = "IC2API")
public float getWrenchDropRate()
{
return 1.0F;
}
@Override
@Method(modid = "IC2API")
public ItemStack getWrenchDrop(EntityPlayer entityPlayer)
{
return getBlockType().getPickBlock(null, worldObj, xCoord, yCoord, zCoord);
}
public boolean isPowered()
{
return redstone;
}
public void onNeighborChange(Block block)
{
if(!worldObj.isRemote)
{
boolean power = worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord);
if(redstone != power)
{
redstone = power;
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
}
}
}
}