package blusunrize.immersiveengineering.common.blocks.metal;
import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.api.TargetingInfo;
import blusunrize.immersiveengineering.api.energy.wires.IImmersiveConnectable;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler.Connection;
import blusunrize.immersiveengineering.api.energy.wires.TileEntityImmersiveConnectable;
import blusunrize.immersiveengineering.api.energy.wires.WireType;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.*;
import blusunrize.immersiveengineering.common.util.ChatUtils;
import blusunrize.immersiveengineering.common.util.Utils;
import com.google.common.collect.Lists;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class TileEntityEnergyMeter extends TileEntityImmersiveConnectable implements ITickable, IDirectionalTile, IHasDummyBlocks, IAdvancedCollisionBounds,IAdvancedSelectionBounds, IPlayerInteraction, IComparatorOverride
{
public EnumFacing facing = EnumFacing.NORTH;
public int lastEnergyPassed = 0;
public ArrayList<Integer> lastPackets = new ArrayList<Integer>(25);
public boolean dummy=true;
private int compVal = -1;
@Override
protected boolean canTakeLV()
{
return true;
}
@Override
protected boolean canTakeMV()
{
return true;
}
@Override
protected boolean canTakeHV()
{
return true;
}
@Override
protected boolean isRelay()
{
return true;
}
@Override
public boolean interact(EnumFacing side, EntityPlayer player, EnumHand hand, ItemStack heldItem, float hitX, float hitY, float hitZ)
{
int transfer = getAveragePower();
int packets = lastPackets.size();
if(dummy)
{
TileEntity above = worldObj.getTileEntity(getPos().add(0,1,0));
if(above instanceof TileEntityEnergyMeter)
packets = ((TileEntityEnergyMeter)above).lastPackets.size();
}
String transferred = "0";
if(transfer>0)
transferred = Utils.formatDouble(transfer, "0.###");
ChatUtils.sendServerNoSpamMessages(player, new TextComponentTranslation(Lib.CHAT_INFO+"energyTransfered",packets,transferred));
return true;
}
@Override
public void update()
{
if (!worldObj.isRemote&&((worldObj.getTotalWorldTime()&31)==(pos.toLong()&31)||compVal<0))
updateComparatorValues();
if(dummy || worldObj.isRemote)
return;
//Yes, this might tick in between different connectors sending power, but since this is a block for statistical evaluation over a tick, that is irrelevant.
lastPackets.add(lastEnergyPassed);
if(lastPackets.size()>20)
lastPackets.remove(0);
lastEnergyPassed = 0;
}
@Override
public boolean canConnect()
{
return !dummy;
}
@Override
public void onEnergyPassthrough(int amount)
{
lastEnergyPassed += amount;
}
@Override
public boolean canConnectCable(WireType cableType, TargetingInfo target)
{
if(dummy)
{
TileEntity above = worldObj.getTileEntity(getPos().add(0,1,0));
if(above instanceof TileEntityEnergyMeter)
return ((TileEntityEnergyMeter)above).canConnectCable(cableType, target);
return false;
}
return super.canConnectCable(cableType, target);
}
@Override
public void connectCable(WireType cableType, TargetingInfo target, IImmersiveConnectable other)
{
if(dummy)
{
TileEntity above = worldObj.getTileEntity(getPos().add(0,1,0));
if(above instanceof TileEntityEnergyMeter)
((TileEntityEnergyMeter) above).connectCable(cableType, target, other);
}
else
super.connectCable(cableType, target, other);
}
@Override
public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.writeCustomNBT(nbt, descPacket);
nbt.setInteger("facing", facing.ordinal());
nbt.setBoolean("dummy", dummy);
}
@Override
public void readCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.readCustomNBT(nbt, descPacket);
facing = EnumFacing.values()[nbt.getInteger("facing")];
dummy = nbt.getBoolean("dummy");
}
@Override
public Vec3d getRaytraceOffset(IImmersiveConnectable link)
{
int xDif = ((TileEntity)link).getPos().getX()-getPos().getX();
int zDif = ((TileEntity)link).getPos().getZ()-getPos().getZ();
if(facing.getAxis()==Axis.X)
return new Vec3d(.5,.4375,zDif>0?.8125:.1875);
else
return new Vec3d(xDif>0?.8125:.1875,.4375,.5);
}
@Override
public Vec3d getConnectionOffset(Connection con)
{
int xDif = (con==null||con.start==null||con.end==null)?0: (con.start.equals(Utils.toCC(this))&&con.end!=null)? con.end.getX()-getPos().getX(): (con.end.equals(Utils.toCC(this))&& con.start!=null)?con.start.getX()-getPos().getX(): 0;
int zDif = (con==null||con.start==null||con.end==null)?0: (con.start.equals(Utils.toCC(this))&&con.end!=null)? con.end.getZ()-getPos().getZ(): (con.end.equals(Utils.toCC(this))&& con.start!=null)?con.start.getZ()-getPos().getZ(): 0;
if(facing.getAxis()==Axis.X)
return new Vec3d(.5,.4375,zDif>0?.8125:.1875);
else
return new Vec3d(xDif>0?.8125:.1875,.4375,.5);
}
@Override
public boolean isDummy()
{
return !dummy;
}
@Override
public void placeDummies(BlockPos pos, IBlockState state, EnumFacing side, float hitX, float hitY, float hitZ)
{
worldObj.setBlockState(pos.add(0,1,0), state);
((TileEntityEnergyMeter)worldObj.getTileEntity(pos.add(0,1,0))).dummy = false;
((TileEntityEnergyMeter)worldObj.getTileEntity(pos.add(0,1,0))).facing = this.facing;
}
@Override
public void breakDummies(BlockPos pos, IBlockState state)
{
for(int i=0; i<=1; i++)
if(worldObj.getTileEntity(getPos().add(0,!dummy?-1:0,0).add(0,i,0)) instanceof TileEntityEnergyMeter)
worldObj.setBlockToAir(getPos().add(0,!dummy?-1:0,0).add(0,i,0));
}
public int getAveragePower()
{
TileEntityEnergyMeter te = this;
if(te.dummy)
{
TileEntity tmp = worldObj.getTileEntity(getPos().add(0,1,0));
if(!(tmp instanceof TileEntityEnergyMeter))
return -1;
te = (TileEntityEnergyMeter) tmp;
}
if(te.lastPackets.size()==0)
return 0;
int sum = 0;
synchronized (te.lastPackets)
{
for(int transfer: te.lastPackets)
sum += transfer;
}
return sum/te.lastPackets.size();
}
@Override
public float[] getBlockBounds()
{
// return new float[]{0,0,0,1,1,1};
return null;
}
@Override
public List<AxisAlignedBB> getAdvancedSelectionBounds()
{
List<AxisAlignedBB> list = Lists.newArrayList(new AxisAlignedBB(.1875f,-.625f,.1875f, .8125f,.8125f,.8125f).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
if(dummy)
{
list.set(0, list.get(0).offset(0,1,0));
list.add(new AxisAlignedBB(0,0,0, 1,.375f,1).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
}
return list;
}
@Override
public boolean isOverrideBox(AxisAlignedBB box, EntityPlayer player, RayTraceResult mop, ArrayList<AxisAlignedBB> list)
{
return false;
}
@Override
public List<AxisAlignedBB> getAdvancedColisionBounds()
{
return getAdvancedSelectionBounds();
}
@Override
public EnumFacing getFacing()
{
return facing;
}
@Override
public void setFacing(EnumFacing facing)
{
this.facing = facing;
}
@Override
public int getFacingLimitation()
{
return 2;
}
@Override
public boolean mirrorFacingOnPlacement(EntityLivingBase placer)
{
return false;
}
@Override
public boolean canHammerRotate(EnumFacing side, float hitX, float hitY, float hitZ, EntityLivingBase entity)
{
return false;
}
@Override
public boolean canRotate(EnumFacing axis)
{
return false;
}
private void updateComparatorValues()
{
int oldVal = compVal;
int maxTrans = 0;
Set<Connection> conns = ImmersiveNetHandler.INSTANCE.getConnections(worldObj, dummy?pos.up():pos);
if (conns==null)
{
compVal = 0;
return;
}
for (Connection c:conns)
maxTrans+=c.cableType.getTransferRate();
maxTrans/=2;
double val = getAveragePower()/(double)maxTrans;
compVal = (int) Math.ceil(15*val);
if (oldVal!=compVal)
worldObj.updateComparatorOutputLevel(pos, getBlockType());
}
@Override
public int getComparatorInputOverride()
{
return compVal;
}
}