package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.ApiUtils; import blusunrize.immersiveengineering.api.IEProperties; import blusunrize.immersiveengineering.api.IEProperties.PropertyBoolInverted; import blusunrize.immersiveengineering.api.TargetingInfo; import blusunrize.immersiveengineering.api.energy.wires.IImmersiveConnectable; 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 com.google.common.collect.ImmutableSet; 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.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing.Axis; 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 java.util.ArrayList; import java.util.List; import java.util.Set; public class TileEntityTransformer extends TileEntityImmersiveConnectable implements IDirectionalTile, IMirrorAble, IHasDummyBlocks, IAdvancedSelectionBounds, IDualState { WireType secondCable; public EnumFacing facing=EnumFacing.NORTH; public int dummy=0; public boolean onPost=false; public static boolean _Immovable() { return true; } @Override protected boolean canTakeLV() { return true; } @Override protected boolean canTakeMV() { return true; } @Override public boolean canConnect() { return true; } // @Override // public boolean canUpdate() // { // return false; // } @Override public boolean isEnergyOutput() { return false; } @Override public int outputEnergy(int amount, boolean simulate, int energyType) { return 0; } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.writeCustomNBT(nbt, descPacket); nbt.setInteger("facing", facing.ordinal()); if(secondCable!=null) nbt.setString("secondCable", secondCable.getUniqueName()); nbt.setInteger("dummy", dummy); nbt.setBoolean("postAttached", onPost); } @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.readCustomNBT(nbt, descPacket); facing = EnumFacing.getFront(nbt.getInteger("facing")); if(nbt.hasKey("secondCable")) secondCable = ApiUtils.getWireTypeFromNBT(nbt, "secondCable"); else secondCable = null; dummy = nbt.getInteger("dummy"); onPost = nbt.getBoolean("postAttached"); } @Override public BlockPos getConnectionMaster(WireType cableType, TargetingInfo target) { return getPos().add(0,-dummy,0); } @Override public boolean canConnectCable(WireType cableType, TargetingInfo target) { if(cableType==WireType.STEEL&&!canTakeHV()) return false; if(dummy!=0) { TileEntity master = worldObj.getTileEntity(getPos().add(0, -dummy, 0)); return master instanceof TileEntityTransformer && ((TileEntityTransformer) master).canConnectCable(cableType, target); } int tc = getTargetedConnector(target); switch(tc) { case 0: return canAttach(cableType, limitType, secondCable); case 1: return canAttach(cableType, secondCable, limitType); } return false; } private boolean canAttach(WireType toAttach, WireType atConn, WireType other) { if (atConn!=null) return false; if (other==null) return true; WireType higher = this instanceof TileEntityTransformerHV?WireType.STEEL:WireType.ELECTRUM; return toAttach==higher||other==higher; } @Override public void connectCable(WireType cableType, TargetingInfo target, IImmersiveConnectable other) { if(dummy!=0) { TileEntity master = worldObj.getTileEntity(getPos().add(0,-dummy,0)); if(master instanceof TileEntityTransformer) ((TileEntityTransformer) master).connectCable(cableType, target, other); return; } switch(getTargetedConnector(target)) { case 0: if(this.limitType==null) this.limitType = cableType; break; case 1: if(secondCable==null) this.secondCable = cableType; break; } } @Override public WireType getCableLimiter(TargetingInfo target) { switch(getTargetedConnector(target)) { case 0: return limitType; case 1: return secondCable; } return null; } @Override public void removeCable(Connection connection) { WireType type = connection!=null?connection.cableType:null; if(type==null) { limitType=null; secondCable=null; } if(type==limitType) this.limitType = null; if(type==secondCable) this.secondCable = null; this.markContainingBlockForUpdate(null); } @Override public Vec3d getRaytraceOffset(IImmersiveConnectable link) { if(onPost) return new Vec3d(.5, 1.5, .5); return new Vec3d(.5, 2.75, .5); } @Override public Vec3d getConnectionOffset(Connection con) { boolean b = con.cableType==limitType; if(onPost) { if(b) return new Vec3d(.5+(facing==EnumFacing.EAST?.4375: facing==EnumFacing.WEST?-.4375: 0),1.4375,.5+(facing==EnumFacing.SOUTH?.4375: facing==EnumFacing.NORTH?-.4375: 0)); else return new Vec3d(.5+(facing==EnumFacing.EAST?-.0625: facing==EnumFacing.WEST?.0625: 0),.25,.5+(facing==EnumFacing.SOUTH?-.0625: facing==EnumFacing.NORTH?.0625: 0)); } else { double conRadius = con.cableType.getRenderDiameter()/2; double offset = getIsMirrored()^b?getLowerOffset():getHigherOffset(); if(facing==EnumFacing.NORTH) return new Vec3d(b?.8125:.1875, 2+offset-conRadius, .5); if(facing==EnumFacing.SOUTH) return new Vec3d(b?.1875:.8125, 2+offset-conRadius, .5); if(facing==EnumFacing.WEST) return new Vec3d(.5, 2+offset-conRadius, b?.1875:.8125); if(facing==EnumFacing.EAST) return new Vec3d(.5, 2+offset-conRadius, b?.8125:.1875); } return new Vec3d(.5,.5,.5); } public int getTargetedConnector(TargetingInfo target) { if(onPost) { if(target.hitY>=.5) return 0; else return 1; } else { if(facing==EnumFacing.NORTH) if(target.hitX<.5) return 1; else return 0; else if(facing==EnumFacing.SOUTH) if(target.hitX<.5) return 0; else return 1; else if(facing==EnumFacing.WEST) if(target.hitZ<.5) return 0; else return 1; else if(facing==EnumFacing.EAST) if(target.hitZ<.5) return 1; else return 0; } return -1; } public WireType getLimiter(int side) { if(side==0) return limitType; return secondCable; } @Override public PropertyBoolInverted getBoolProperty(Class<? extends IUsesBooleanProperty> inf) { return inf==IMirrorAble.class?IEProperties.BOOLEANS[0]:inf==IDualState.class?IEProperties.BOOLEANS[1]:null; } @Override public boolean getIsMirrored() { if (onPost) return false; if (dummy!=0) { TileEntity master = worldObj.getTileEntity(pos.down(dummy)); return master instanceof TileEntityTransformer && ((TileEntityTransformer) master).getIsMirrored(); } else { if (limitType==null&&secondCable==null) return true; WireType higher = this instanceof TileEntityTransformerHV ? WireType.STEEL : WireType.ELECTRUM; boolean b = (limitType != null && higher.equals(limitType)) || (secondCable != null && !higher.equals(secondCable)); return b; } } @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; } @Override public boolean isDummy() { return dummy!=0; } public boolean isOnPost() { return onPost; } @Override public void placeDummies(BlockPos pos, IBlockState state, EnumFacing side, float hitX, float hitY, float hitZ) { if (state.getValue(IEProperties.BOOLEANS[1])) { onPost = true; markDirty(); this.markContainingBlockForUpdate(null); } else for(int i=1; i<=2; i++) { worldObj.setBlockState(pos.add(0,i,0), state); ((TileEntityTransformer)worldObj.getTileEntity(pos.add(0,i,0))).dummy = i; ((TileEntityTransformer)worldObj.getTileEntity(pos.add(0,i,0))).facing = this.facing; } } @Override public void breakDummies(BlockPos pos, IBlockState state) { if (onPost) return; for(int i=0; i<=2; i++) worldObj.setBlockToAir(getPos().add(0,-dummy,0).add(0,i,0)); } @Override public float[] getBlockBounds() { if(dummy==2) return new float[]{facing.getAxis()==Axis.Z?0:.3125f, 0, facing.getAxis()==Axis.X?0:.3125f, facing.getAxis()==Axis.Z?1:.6875f,this instanceof TileEntityTransformerHV?.75f:.5625f,facing.getAxis()==Axis.X?1:.6875f}; if (onPost) return new float[]{facing.getAxis()==Axis.Z?.25F:facing==EnumFacing.WEST?-.375F:.6875F, 0, facing.getAxis()==Axis.X?.25F:facing==EnumFacing.NORTH?-.375F:.6875F, facing.getAxis()==Axis.Z?.75F:facing==EnumFacing.EAST?1.375F:.3125F, 1, facing.getAxis()==Axis.X?.75F:facing==EnumFacing.SOUTH?1.375F:.3125F}; return null; } boolean cachedMirrored = false; private List<AxisAlignedBB> advSelectionBoxes = null; @Override public List<AxisAlignedBB> getAdvancedSelectionBounds() { boolean mirrored = getIsMirrored(); if(dummy==2&&(advSelectionBoxes==null||cachedMirrored!=mirrored)) { double offsetA = mirrored?getHigherOffset():getLowerOffset(); double offsetB = mirrored?getLowerOffset():getHigherOffset(); if(facing==EnumFacing.NORTH) advSelectionBoxes = Lists.newArrayList(new AxisAlignedBB(0,0,.3125, .375, offsetB,.6875).offset(getPos().getX(),getPos().getY(),getPos().getZ()), new AxisAlignedBB(.625,0,.3125, 1, offsetA,.6875).offset(getPos().getX(),getPos().getY(),getPos().getZ())); if(facing==EnumFacing.SOUTH) advSelectionBoxes = Lists.newArrayList(new AxisAlignedBB(0,0,.3125, .375, offsetA,.6875).offset(getPos().getX(),getPos().getY(),getPos().getZ()), new AxisAlignedBB(.625,0,.3125, 1, offsetB,.6875).offset(getPos().getX(),getPos().getY(),getPos().getZ())); if(facing==EnumFacing.WEST) advSelectionBoxes = Lists.newArrayList(new AxisAlignedBB(.3125,0,0, .6875, offsetA,.375).offset(getPos().getX(),getPos().getY(),getPos().getZ()), new AxisAlignedBB(.3125,0,.625, .6875, offsetB,1).offset(getPos().getX(),getPos().getY(),getPos().getZ())); if(facing==EnumFacing.EAST) advSelectionBoxes = Lists.newArrayList(new AxisAlignedBB(.3125,0,0, .6875, offsetB,.375).offset(getPos().getX(),getPos().getY(),getPos().getZ()), new AxisAlignedBB(.3125,0,.625, .6875, offsetA,1).offset(getPos().getX(),getPos().getY(),getPos().getZ())); cachedMirrored = mirrored; } else if (dummy!=2) { advSelectionBoxes = null; } return advSelectionBoxes; } @Override public boolean isOverrideBox(AxisAlignedBB box, EntityPlayer player, RayTraceResult mop, ArrayList<AxisAlignedBB> list) { return box.expand(.002, .002, .002).isVecInside(mop.hitVec); } @Override public Set<BlockPos> getIgnored(IImmersiveConnectable other) { if (onPost) return super.getIgnored(other); return ImmutableSet.of(pos.up(), pos.up(2)); } @Override public boolean getIsSecondState() { return onPost; } protected float getLowerOffset() { return .5F; } protected float getHigherOffset() { return .5625F; } }