package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.ApiUtils; import blusunrize.immersiveengineering.api.IEEnums.SideConfig; import blusunrize.immersiveengineering.api.energy.immersiveflux.FluxStorage; import blusunrize.immersiveengineering.api.energy.wires.IImmersiveConnectable; import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler; import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler.AbstractConnection; 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.IBlockBounds; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IDirectionalTile; import blusunrize.immersiveengineering.common.util.EnergyHelper; import blusunrize.immersiveengineering.common.util.EnergyHelper.IEForgeEnergyWrapper; import blusunrize.immersiveengineering.common.util.EnergyHelper.IIEInternalFluxHandler; import blusunrize.immersiveengineering.common.util.Utils; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import javax.annotation.Nullable; import java.util.HashMap; import java.util.HashSet; import java.util.Set; //@Optional.Interface(iface = "ic2.api.energy.tile.IEnergySink", modid = "IC2") public class TileEntityConnectorLV extends TileEntityImmersiveConnectable implements ITickable, IDirectionalTile, IIEInternalFluxHandler, IBlockBounds//, ic2.api.energy.tile.IEnergySink { boolean inICNet=false; public EnumFacing facing = EnumFacing.DOWN; private long lastTransfer = -1; public int currentTickAccepted=0; public static int[] connectorInputValues = {}; private FluxStorage energyStorage = new FluxStorage(getMaxInput(),getMaxInput(),0); boolean firstTick = true; @Override public void update() { if(!worldObj.isRemote) { // if(Lib.IC2 && !this.inICNet) // { // IC2Helper.loadIC2Tile(this); // this.inICNet = true; // } if(energyStorage.getEnergyStored()>0) { int temp = this.transferEnergy(energyStorage.getEnergyStored(), true, 0); if(temp>0) { energyStorage.modifyEnergyStored(-this.transferEnergy(temp, false, 0)); markDirty(); } } currentTickAccepted = 0; } else if (firstTick) { Set<Connection> conns = ImmersiveNetHandler.INSTANCE.getConnections(worldObj, pos); if (conns!=null) for (Connection conn:conns) if (pos.compareTo(conn.end)<0&&worldObj.isBlockLoaded(conn.end)) this.markContainingBlockForUpdate(null); firstTick = false; } } // @Override // public void invalidate() // { // super.invalidate(); // unload(); // } // void unload() // { // if(Lib.IC2 && this.inICNet) // { // IC2Helper.unloadIC2Tile(this); // this.inICNet = false; // } // } // @Override // public void onChunkUnload() // { // unload(); // } @Override public EnumFacing getFacing() { return this.facing; } @Override public void setFacing(EnumFacing facing) { this.facing = facing; } @Override public int getFacingLimitation() { return 0; } @Override public boolean mirrorFacingOnPlacement(EntityLivingBase placer) { return true; } @Override public boolean canHammerRotate(EnumFacing side, float hitX, float hitY, float hitZ, EntityLivingBase entity) { return false; } @Override public boolean canRotate(EnumFacing axis) { return false; } @Override protected boolean canTakeLV() { return true; } @Override public boolean isEnergyOutput() { if(isRelay()) return false; TileEntity tile = worldObj.getTileEntity(getPos().offset(facing)); return EnergyHelper.isFluxReceiver(tile, facing.getOpposite()); } @Override public int outputEnergy(int amount, boolean simulate, int energyType) { if(isRelay()) return 0; int acceptanceLeft = getMaxOutput()-currentTickAccepted; if(acceptanceLeft<=0) return 0; int toAccept = Math.min(acceptanceLeft, amount); TileEntity capacitor = worldObj.getTileEntity(getPos().offset(facing)); int ret = EnergyHelper.insertFlux(capacitor, facing.getOpposite(), toAccept, simulate); // if(capacitor instanceof IFluxReceiver && ((IFluxReceiver)capacitor).canConnectEnergy(facing.getOpposite())) // { // ret = ((IFluxReceiver)capacitor).receiveEnergy(facing.getOpposite(), toAccept, simulate); // } // else if(capacitor instanceof IEnergyReceiver && ((IEnergyReceiver)capacitor).canConnectEnergy(facing.getOpposite())) // { // ret = ((IEnergyReceiver)capacitor).receiveEnergy(facing.getOpposite(), toAccept, simulate); // } // else if(Lib.IC2 && IC2Helper.isAcceptingEnergySink(capacitor, this, fd.getOpposite())) // { // double left = IC2Helper.injectEnergy(capacitor, fd.getOpposite(), ModCompatability.convertRFtoEU(toAccept, getIC2Tier()), canTakeHV()?(256*256): canTakeMV()?(128*128) : (32*32), simulate); // ret = amount-ModCompatability.convertEUtoRF(left); // } // else if(Lib.GREG && GregTechHelper.gregtech_isValidEnergyOutput(capacitor)) // { // long translAmount = (long)ModCompatability.convertRFtoEU(toAccept, getIC2Tier()); // long accepted = GregTechHelper.gregtech_outputGTPower(capacitor, (byte)fd.getOpposite().ordinal(), translAmount, 1L, simulate); // int reConv = ModCompatability.convertEUtoRF(accepted); // ret = reConv; // } if(!simulate) currentTickAccepted+=ret; return ret; } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.writeCustomNBT(nbt, descPacket); nbt.setInteger("facing", facing.ordinal()); nbt.setLong("lastTransfer", lastTransfer); energyStorage.writeToNBT(nbt); } @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.readCustomNBT(nbt, descPacket); facing = EnumFacing.getFront(nbt.getInteger("facing")); lastTransfer = nbt.getLong("lastTransfer"); energyStorage.readFromNBT(nbt); } @Override public Vec3d getRaytraceOffset(IImmersiveConnectable link) { EnumFacing side = facing.getOpposite(); return new Vec3d(.5+side.getFrontOffsetX()*.0625, .5+side.getFrontOffsetY()*.0625, .5+side.getFrontOffsetZ()*.0625); } @Override public Vec3d getConnectionOffset(Connection con) { EnumFacing side = facing.getOpposite(); double conRadius = con.cableType.getRenderDiameter()/2; return new Vec3d(.5-conRadius*side.getFrontOffsetX(), .5-conRadius*side.getFrontOffsetY(), .5-conRadius*side.getFrontOffsetZ()); } @SideOnly(Side.CLIENT) private AxisAlignedBB renderAABB; @SideOnly(Side.CLIENT) @Override public AxisAlignedBB getRenderBoundingBox() { // if(renderAABB==null) // { // if(Config.getBoolean("increasedRenderboxes")) // { int inc = getRenderRadiusIncrease(); return new AxisAlignedBB(this.pos.getX()-inc,this.pos.getY()-inc,this.pos.getZ()-inc, this.pos.getX()+inc+1,this.pos.getY()+inc+1,this.pos.getZ()+inc+1); // renderAABB = new AxisAlignedBB(this.pos.getX()-inc,this.pos.getY()-inc,this.pos.getZ()-inc, this.pos.getX()+inc+1,this.pos.getY()+inc+1,this.pos.getZ()+inc+1); // } // else // renderAABB = super.getRenderBoundingBox(); // } // return renderAABB; } int getRenderRadiusIncrease() { return WireType.COPPER.getMaxLength(); } IEForgeEnergyWrapper energyWrapper; @Override public IEForgeEnergyWrapper getCapabilityWrapper(EnumFacing facing) { if(facing!=this.facing || isRelay()) return null; if(energyWrapper==null || energyWrapper.side!=this.facing) energyWrapper = new IEForgeEnergyWrapper(this, this.facing); return energyWrapper; } @Override public FluxStorage getFluxStorage() { return energyStorage; } @Override public SideConfig getEnergySideConfig(EnumFacing facing) { return (!isRelay()&&facing==this.facing)?SideConfig.INPUT:SideConfig.NONE; } @Override public boolean canConnectEnergy(EnumFacing from) { if(isRelay()) return false; return from==facing; } @Override public int receiveEnergy(EnumFacing from, int energy, boolean simulate) { if(worldObj.isRemote || isRelay()) return 0; if(worldObj.getTotalWorldTime()==lastTransfer) return 0; int accepted = Math.min(Math.min(getMaxOutput(),getMaxInput()), energy); accepted = Math.min(getMaxOutput()-energyStorage.getEnergyStored(), accepted); if(accepted<=0) return 0; if(!simulate) { energyStorage.modifyEnergyStored(accepted); lastTransfer = worldObj.getTotalWorldTime(); markDirty(); } return accepted; } @Override public int getEnergyStored(EnumFacing from) { if(isRelay()) return 0; return energyStorage.getEnergyStored(); } @Override public int getMaxEnergyStored(EnumFacing from) { if(isRelay()) return 0; return getMaxInput(); } @Override public int extractEnergy(EnumFacing from, int energy, boolean simulate) { return 0; } public int transferEnergy(int energy, boolean simulate, final int energyType) { int received = 0; if(!worldObj.isRemote) { Set<AbstractConnection> outputs = ImmersiveNetHandler.INSTANCE.getIndirectEnergyConnections(Utils.toCC(this), worldObj); int powerLeft = Math.min(Math.min(getMaxOutput(),getMaxInput()), energy); final int powerForSort = powerLeft; if(outputs.size()<1) return 0; int sum = 0; HashMap<AbstractConnection,Integer> powerSorting = new HashMap<AbstractConnection,Integer>(); for(AbstractConnection con : outputs) { IImmersiveConnectable end = ApiUtils.toIIC(con.end, worldObj); if(con.cableType!=null && end!=null) { int atmOut = Math.min(powerForSort,con.cableType.getTransferRate()); int tempR = end.outputEnergy(atmOut, true, energyType); if(tempR>0) { powerSorting.put(con, tempR); sum += tempR; } } } if(sum>0) for(AbstractConnection con : powerSorting.keySet()) { IImmersiveConnectable end = ApiUtils.toIIC(con.end, worldObj); if(con.cableType!=null && end!=null) { float prio = powerSorting.get(con)/(float)sum; int output = (int)(powerForSort*prio); int tempR = end.outputEnergy(Math.min(output, con.cableType.getTransferRate()), true, energyType); int r = tempR; int maxInput = getMaxInput(); tempR -= (int) Math.max(0, Math.floor(tempR*con.getPreciseLossRate(tempR,maxInput))); end.outputEnergy(tempR, simulate, energyType); HashSet<IImmersiveConnectable> passedConnectors = new HashSet<IImmersiveConnectable>(); float intermediaryLoss = 0; for(Connection sub : con.subConnections) { float length = sub.length/(float)sub.cableType.getMaxLength(); float baseLoss = (float)sub.cableType.getLossRatio(); float mod = (((maxInput-tempR)/(float)maxInput)/.25f)*.1f; intermediaryLoss = MathHelper.clamp_float(intermediaryLoss+length*(baseLoss+baseLoss*mod), 0,1); int transferredPerCon = ImmersiveNetHandler.INSTANCE.getTransferedRates(worldObj.provider.getDimension()).containsKey(sub)?ImmersiveNetHandler.INSTANCE.getTransferedRates(worldObj.provider.getDimension()).get(sub):0; transferredPerCon += r; if(!simulate) { ImmersiveNetHandler.INSTANCE.getTransferedRates(worldObj.provider.getDimension()).put(sub,transferredPerCon); IImmersiveConnectable subStart = ApiUtils.toIIC(sub.start,worldObj); IImmersiveConnectable subEnd = ApiUtils.toIIC(sub.end,worldObj); if(subStart!=null && passedConnectors.add(subStart)) subStart.onEnergyPassthrough((int)(r-r*intermediaryLoss)); if(subEnd!=null && passedConnectors.add(subEnd)) subEnd.onEnergyPassthrough((int)(r-r*intermediaryLoss)); } } received += r; powerLeft -= r; if(powerLeft<=0) break; } } } return received; } public int getMaxInput() { return connectorInputValues[0]; } public int getMaxOutput() { return connectorInputValues[0]; } @Override public float[] getBlockBounds() { float length = this instanceof TileEntityRelayHV?.875f: this instanceof TileEntityConnectorHV?.75f: this instanceof TileEntityConnectorMV?.5625f: .5f; float wMin = this instanceof TileEntityConnectorStructural?.25f:.3125f; float wMax = this instanceof TileEntityConnectorStructural?.75f:.6875f; switch(facing.getOpposite() ) { case UP: return new float[]{wMin,0,wMin, wMax,length,wMax}; case DOWN: return new float[]{wMin,1-length,wMin, wMax,1,wMax}; case SOUTH: return new float[]{wMin,wMin,0, wMax,wMax,length}; case NORTH: return new float[]{wMin,wMin,1-length, wMax,wMax,1}; case EAST: return new float[]{0,wMin,wMin, length,wMax,wMax}; case WEST: return new float[]{1-length,wMin,wMin, 1,wMax,wMax}; } return new float[]{0,0,0,1,1,1}; } // @Optional.Method(modid = "IC2") // public boolean acceptsEnergyFrom(TileEntity emitter, ForgeDirection direction) // { // return Lib.IC2 && canConnectEnergy(direction); // } // @Optional.Method(modid = "IC2") // public double getDemandedEnergy() // { // return ModCompatability.convertRFtoEU(getMaxInput(), getIC2Tier()); // } // @Optional.Method(modid = "IC2") // public int getSinkTier() // { // return getIC2Tier(); // } // int getIC2Tier() // { // return this.canTakeHV()?3: this.canTakeMV()?2: 1; // } // @Optional.Method(modid = "IC2") // public double injectEnergy(ForgeDirection directionFrom, double amount, double voltage) // { // int rf = ModCompatability.convertEUtoRF(amount); // if(rf>this.getMaxInput())//More Input than allowed results in blocking // return amount; // int rSimul = transferEnergy(rf, true, 1); // if(rSimul==0)//This will prevent full power void but allow partial transfer // return amount; // int r = transferEnergy(rf, false, 1); // double eu = ModCompatability.convertRFtoEU(r, getIC2Tier()); // return amount-eu; // } }