package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.AdvancedAABB; import blusunrize.immersiveengineering.api.fluid.IFluidPipe; import blusunrize.immersiveengineering.client.models.IOBJModelCallback; import blusunrize.immersiveengineering.common.IEContent; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.*; import blusunrize.immersiveengineering.common.blocks.TileEntityIEBase; import blusunrize.immersiveengineering.common.blocks.wooden.BlockTypes_WoodenDecoration; import blusunrize.immersiveengineering.common.util.Utils; import blusunrize.immersiveengineering.common.util.chickenbones.Matrix4; import com.google.common.base.Function; import com.google.common.collect.Lists; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; 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.world.World; import net.minecraftforge.client.model.obj.OBJModel.OBJState; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.model.TRSRTransformation; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.FluidTankProperties; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidTankProperties; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import static java.util.Collections.newSetFromMap; public class TileEntityFluidPipe extends TileEntityIEBase implements IFluidPipe, IAdvancedHasObjProperty, IOBJModelCallback<IBlockState>, IColouredTile, IPlayerInteraction, IHammerInteraction, IAdvancedSelectionBounds, IAdvancedCollisionBounds, IAdditionalDrops { static ConcurrentHashMap<BlockPos, Set<DirectionalFluidOutput>> indirectConnections = new ConcurrentHashMap<BlockPos, Set<DirectionalFluidOutput>>(); public static ArrayList<Function<ItemStack, Boolean>> validPipeCovers = new ArrayList(); public static ArrayList<Function<ItemStack, Boolean>> climbablePipeCovers = new ArrayList(); static{ final ArrayList<ItemStack> scaffolds = Lists.newArrayList( new ItemStack(IEContent.blockWoodenDecoration, 1, BlockTypes_WoodenDecoration.SCAFFOLDING.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.STEEL_SCAFFOLDING_0.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.STEEL_SCAFFOLDING_1.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.STEEL_SCAFFOLDING_2.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.ALUMINUM_SCAFFOLDING_0.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.ALUMINUM_SCAFFOLDING_1.getMeta()), new ItemStack(IEContent.blockMetalDecoration1, 1, BlockTypes_MetalDecoration1.ALUMINUM_SCAFFOLDING_2.getMeta())); TileEntityFluidPipe.validPipeCovers.add(new Function<ItemStack, Boolean>() { @Nullable @Override public Boolean apply(@Nullable ItemStack input) { if(input == null) return Boolean.FALSE; for(ItemStack stack : scaffolds) if(OreDictionary.itemMatches(stack, input, false)) return Boolean.TRUE; return Boolean.FALSE; } }); TileEntityFluidPipe.climbablePipeCovers.add(new Function<ItemStack, Boolean>() { @Nullable @Override public Boolean apply(@Nullable ItemStack input) { if(input == null) return Boolean.FALSE; for(ItemStack stack : scaffolds) if(OreDictionary.itemMatches(stack, input, false)) return Boolean.TRUE; return Boolean.FALSE; } }); } public int[] sideConfig = new int[] {0,0,0,0,0,0}; public ItemStack pipeCover = null; public static Set<DirectionalFluidOutput> getConnectedFluidHandlers(BlockPos node, World world) { if(indirectConnections.containsKey(node)) return indirectConnections.get(node); ArrayList<BlockPos> openList = new ArrayList(); ArrayList<BlockPos> closedList = new ArrayList(); Set<DirectionalFluidOutput> fluidHandlers = Collections.newSetFromMap(new ConcurrentHashMap<DirectionalFluidOutput, Boolean>()); openList.add(node); while(!openList.isEmpty() && closedList.size()<1024) { BlockPos next = openList.get(0); if(world.isBlockLoaded(next)) { TileEntity pipeTile = world.getTileEntity(next); if(!closedList.contains(next) && (pipeTile instanceof IFluidPipe)) { if(pipeTile instanceof TileEntityFluidPipe) closedList.add(next); IFluidTankProperties[] tankInfo; for(int i=0; i<6; i++) { // boolean b = (te instanceof TileEntityFluidPipe)? (((TileEntityFluidPipe) te).sideConfig[i]==0): (((TileEntityFluidPump) te).sideConfig[i]==1); EnumFacing fd = EnumFacing.getFront(i); if(((IFluidPipe)pipeTile).hasOutputConnection(fd)) { BlockPos nextPos = next.offset(fd); if(world.isBlockLoaded(nextPos)) { TileEntity adjacentTile = world.getTileEntity(nextPos); if(adjacentTile!=null) if(adjacentTile instanceof TileEntityFluidPipe) openList.add(nextPos); else if(adjacentTile.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, fd.getOpposite())) { IFluidHandler handler = adjacentTile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, fd.getOpposite()); tankInfo = handler.getTankProperties(); if(tankInfo != null && tankInfo.length > 0) fluidHandlers.add(new DirectionalFluidOutput(handler, adjacentTile, fd)); } } } } } } openList.remove(0); } if(FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) { if(!indirectConnections.containsKey(node)) { indirectConnections.put(node, newSetFromMap(new ConcurrentHashMap<DirectionalFluidOutput, Boolean>())); indirectConnections.get(node).addAll(fluidHandlers); } } return fluidHandlers; } @Override public void invalidate() { super.invalidate(); if (!worldObj.isRemote) indirectConnections.clear(); } @Override public void onEntityCollision(World world, Entity entity) { if(!(entity instanceof EntityLivingBase) || ((EntityLivingBase)entity).isOnLadder() || pipeCover==null) return; else { boolean climb = false; for(Function<ItemStack,Boolean> f : climbablePipeCovers) if(f!=null && f.apply(pipeCover)==Boolean.TRUE) { climb = true; break; } if(!climb) return; float f5 = 0.15F; if(entity.motionX<-f5) entity.motionX=-f5; if(entity.motionX>f5) entity.motionX=f5; if(entity.motionZ<-f5) entity.motionZ=-f5; if(entity.motionZ>f5) entity.motionZ=f5; entity.fallDistance=0f; if(entity.motionY<-.15) entity.motionY = -0.15D; if(entity.motionY<0 && entity instanceof EntityPlayer && entity.isSneaking()) { entity.motionY=.05; return; } if(entity.isCollidedHorizontally) entity.motionY=.2; } } @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { sideConfig = nbt.getIntArray("sideConfig"); if(sideConfig==null || sideConfig.length!=6) sideConfig = new int[]{0,0,0,0,0,0}; pipeCover = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("pipeCover")); } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { nbt.setIntArray("sideConfig", sideConfig); if(pipeCover != null) nbt.setTag("pipeCover", (pipeCover.writeToNBT(new NBTTagCompound()))); } boolean canOutputPressurized(TileEntity output, boolean consumePower) { if(output instanceof IFluidPipe) return ((IFluidPipe)output).canOutputPressurized(consumePower); return false; } PipeFluidHandler[] sidedHandlers = {new PipeFluidHandler(this, EnumFacing.DOWN),new PipeFluidHandler(this, EnumFacing.UP),new PipeFluidHandler(this, EnumFacing.NORTH),new PipeFluidHandler(this, EnumFacing.SOUTH),new PipeFluidHandler(this, EnumFacing.WEST),new PipeFluidHandler(this, EnumFacing.EAST)}; @Override public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && facing!=null&&sideConfig[facing.ordinal()]==0) return true; return super.hasCapability(capability, facing); } @Override public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && facing!=null&&sideConfig[facing.ordinal()]==0) return (T)sidedHandlers[facing.ordinal()]; return super.getCapability(capability, facing); } @Override @SideOnly(Side.CLIENT) public TextureAtlasSprite getTextureReplacement(IBlockState object, String material) { return null; } @Override @SideOnly(Side.CLIENT) public boolean shouldRenderGroup(IBlockState object, String group) { return true; } @Override @SideOnly(Side.CLIENT) public Matrix4 handlePerspective(IBlockState Object, TransformType cameraTransformType, Matrix4 perspective) { return perspective; } @Override @SideOnly(Side.CLIENT) public List<BakedQuad> modifyQuads(IBlockState object, List<BakedQuad> quads) { if(pipeCover != null) { Block b = Block.getBlockFromItem(pipeCover.getItem()); IBlockState state = b != null ? b.getStateFromMeta(pipeCover.getMetadata()) : Blocks.STONE.getDefaultState(); IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getModelForState(state); if(model != null) { for(EnumFacing facing : EnumFacing.VALUES) quads.addAll(model.getQuads(state, facing, 0)); quads.addAll(model.getQuads(state, null, 0)); } } return quads; } @Override @SideOnly(Side.CLIENT) public String getCacheKey(IBlockState object) { return getRenderCacheKey(); } @Override @SideOnly(Side.CLIENT) public com.google.common.base.Optional<TRSRTransformation> applyTransformations(IBlockState object, String group, com.google.common.base.Optional<TRSRTransformation> transform) { return transform; } @Override public Collection<ItemStack> getExtraDrops(EntityPlayer player, IBlockState state) { if(pipeCover!=null) return Lists.newArrayList(pipeCover); return null; } static class PipeFluidHandler implements IFluidHandler { TileEntityFluidPipe pipe; EnumFacing facing; public PipeFluidHandler(TileEntityFluidPipe pipe, EnumFacing facing) { this.pipe = pipe; this.facing = facing; } @Override public IFluidTankProperties[] getTankProperties() { return new IFluidTankProperties[]{new FluidTankProperties(null, 1000, true, false)}; } @Override public int fill(FluidStack resource, boolean doFill) { // if(resource==null || from==null || sideConfig[from.ordinal()]!=0 || worldObj.isRemote) // return 0; if(resource == null) return 0; int canAccept = resource.amount; if(canAccept <= 0) return 0; ArrayList<DirectionalFluidOutput> outputList = new ArrayList(getConnectedFluidHandlers(pipe.getPos(), pipe.worldObj)); BlockPos ccFrom2 = new BlockPos(pipe.getPos().offset(facing)); if(outputList.size() < 1) //NO OUTPUTS! return 0; BlockPos ccFrom = new BlockPos(pipe.getPos().offset(facing)); int sum = 0; HashMap<DirectionalFluidOutput, Integer> sorting = new HashMap<DirectionalFluidOutput, Integer>(); for(DirectionalFluidOutput output : outputList) { BlockPos cc = Utils.toCC(output.containingTile); if(!cc.equals(ccFrom) && pipe.worldObj.isBlockLoaded(cc) && !pipe.equals(output.containingTile)) //&& output.output.canFill(output.direction.getOpposite(), resource.getFluid())) { int limit = (resource.tag != null && resource.tag.hasKey("pressurized")) || pipe.canOutputPressurized(output.containingTile, false) ? 1000 : 50; int tileSpecificAcceptedFluid = Math.min(limit, canAccept); int temp = output.output.fill(Utils.copyFluidStackWithAmount(resource, tileSpecificAcceptedFluid, true), false); if(temp > 0) { sorting.put(output, temp); sum += temp; } } } if(sum > 0) { int f = 0; for(DirectionalFluidOutput output : sorting.keySet()) { int limit = (resource.tag != null && resource.tag.hasKey("pressurized")) || pipe.canOutputPressurized(output.containingTile, false) ? 1000 : 50; int tileSpecificAcceptedFluid = Math.min(limit, canAccept); float prio = sorting.get(output) / (float) sum; int amount = (int) (tileSpecificAcceptedFluid * prio); int r = output.output.fill(Utils.copyFluidStackWithAmount(resource, amount, true), doFill); if(r > 50) pipe.canOutputPressurized(output.containingTile, true); f += r; canAccept -= r; if(canAccept <= 0) break; } return f; } return 0; } @Nullable @Override public FluidStack drain(FluidStack resource, boolean doDrain) { return null; } @Nullable @Override public FluidStack drain(int maxDrain, boolean doDrain) { return null; } } public static class DirectionalFluidOutput { IFluidHandler output; EnumFacing direction; TileEntity containingTile; public DirectionalFluidOutput(IFluidHandler output, TileEntity containingTile, EnumFacing direction) { this.output = output; this.direction = direction; this.containingTile = containingTile; } } public byte getConnectionByte() { byte connections = 0; IFluidTankProperties[] tankInfo; for(int i=5; i>=0; i--) { // TileEntity con = worldObj.getTileEntity(xCoord+(i==4?-1: i==5?1: 0),yCoord+(i==0?-1: i==1?1: 0),zCoord+(i==2?-1: i==3?1: 0)); EnumFacing dir = EnumFacing.getFront(i); TileEntity con = worldObj.getTileEntity(getPos().offset(dir)); connections <<= 1; if(sideConfig[i]==0 && con!=null && con.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite())) { IFluidHandler handler = con.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite()); tankInfo = handler.getTankProperties(); if(tankInfo!=null && tankInfo.length>0) connections |= 1; } } return connections; } public byte getAvailableConnectionByte() { byte connections = 0; IFluidTankProperties[] tankInfo; for(int i=5; i>=0; i--) { // TileEntity con = worldObj.getTileEntity(xCoord+(i==4?-1: i==5?1: 0),yCoord+(i==0?-1: i==1?1: 0),zCoord+(i==2?-1: i==3?1: 0)); EnumFacing dir = EnumFacing.getFront(i); TileEntity con = worldObj.getTileEntity(getPos().offset(dir)); connections <<= 1; if(con!=null && con.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite())) { IFluidHandler handler = con.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite()); tankInfo = handler.getTankProperties(); if(tankInfo!=null && tankInfo.length>0) connections |= 1; } } return connections; } public int getConnectionStyle(int connection) { if(sideConfig[connection]==-1) return 0; byte thisConnections = getConnectionByte(); if((thisConnections&(1<<connection))==0) return 0; if(thisConnections!=3&&thisConnections!=12&&thisConnections!=48) return 1; // TileEntity con = worldObj.getTileEntity(xCoord+(connection==4?-1: connection==5?1: 0),yCoord+(connection==0?-1: connection==1?1: 0),zCoord+(connection==2?-1: connection==3?1: 0)); TileEntity con = worldObj.getTileEntity(getPos().offset(EnumFacing.getFront(connection))); if(con instanceof TileEntityFluidPipe) { byte tileConnections = ((TileEntityFluidPipe)con).getConnectionByte(); if(thisConnections==tileConnections) return 0; } return 1; } public void toggleSide(int side) { sideConfig[side]++; if(sideConfig[side]>0) sideConfig[side] = -1; markDirty(); EnumFacing fd = EnumFacing.getFront(side); TileEntity connected = worldObj.getTileEntity(getPos().offset(fd)); if(connected instanceof TileEntityFluidPipe) { ((TileEntityFluidPipe)connected).sideConfig[fd.getOpposite().ordinal()] = sideConfig[side]; connected.markDirty(); worldObj.addBlockEvent(getPos().offset(fd), getBlockType(), 0,0); } worldObj.addBlockEvent(getPos(), getBlockType(), 0,0); } @Override public boolean receiveClientEvent(int id, int arg) { if(id==0) { this.markContainingBlockForUpdate(null); return true; } return false; } @Override public float[] getBlockBounds() { return null; } @Override public List<AxisAlignedBB> getAdvancedColisionBounds() { List<AxisAlignedBB> list = Lists.newArrayList(); if(pipeCover != null) { list.add(new AxisAlignedBB(0, 0, 0, 1, 1, 1).expandXyz(-.03125f).offset(getPos())); return list; } byte connections = getConnectionByte(); if(/*connections==16||connections==32||*/connections==48) { list.add(new AxisAlignedBB(0, .25f, .25f, 1, .75f, .75f).offset(getPos())); if((connections&16) == 0) list.add(new AxisAlignedBB(0, .125f, .125f, .125f, .875f, .875f).offset(getPos())); if((connections&32) == 0) list.add(new AxisAlignedBB(.875f, .125f, .125f, 1, .875f, .875f).offset(getPos())); } else if(/*connections==4||connections==8||*/connections==12) { list.add(new AxisAlignedBB(.25f, .25f, 0, .75f, .75f, 1).offset(getPos())); if((connections&4) == 0) list.add(new AxisAlignedBB(.125f, .125f, 0, .875f, .875f, .125f).offset(getPos())); if((connections&8) == 0) list.add(new AxisAlignedBB(.125f, .125f, .875f, .875f, .875f, 1).offset(getPos())); } else if(/*connections==1||connections==2||*/connections==3) { list.add(new AxisAlignedBB(.25f, 0, .25f, .75f, 1, .75f).offset(getPos())); if((connections&1) == 0) list.add(new AxisAlignedBB(.125f, 0, .125f, .875f, .125f, .875f).offset(getPos())); if((connections&2) == 0) list.add(new AxisAlignedBB(.125f, .875f, .125f, .875f, 1, .875f).offset(getPos())); } else { list.add(new AxisAlignedBB(.25f, .25f, .25f, .75f, .75f, .75f).offset(getPos())); for(int i=0; i<6; i++) { if((connections & 0x1)==1) list.add(new AxisAlignedBB(i == 4 ? 0 : i == 5 ? .875f : .125f, i == 0 ? 0 : i == 1 ? .875f : .125f, i == 2 ? 0 : i == 3 ? .875f : .125f, i == 4 ? .125f : i == 5 ? 1 : .875f, i == 0 ? .125f : i == 1 ? 1 : .875f, i == 2 ? .125f : i == 3 ? 1 : .875f).offset(getPos())); connections >>= 1; } } return list; } @Override public List<AxisAlignedBB> getAdvancedSelectionBounds() { List<AxisAlignedBB> list = Lists.newArrayList(); byte connections = getAvailableConnectionByte(); byte availableConnections = getConnectionByte(); double[] baseAABB = pipeCover != null ? new double[]{.002, .998, .002, .998, .002, .998} : new double[]{.25, .75, .25, .75, .25, .75}; for(int i=0; i<6; i++) { double depth = getConnectionStyle(i)==0?.25:.125; double size = getConnectionStyle(i)==0?.25:.125; // if(pipeCover!=null) // size = 0; if((connections & 0x1)==1) list.add(new AdvancedAABB(new AxisAlignedBB(i == 4 ? 0 : i == 5 ? 1 - depth : size, i == 0 ? 0 : i == 1 ? 1 - depth : size, i == 2 ? 0 : i == 3 ? 1 - depth : size, i == 4 ? depth : i == 5 ? 1 : 1 - size, i == 0 ? depth : i == 1 ? 1 : 1 - size, i == 2 ? depth : i == 3 ? 1 : 1 - size).offset(getPos()), EnumFacing.getFront(i))); if((availableConnections & 0x1)==1) baseAABB[i] += i%2==1?.125: -.125; baseAABB[i] = Math.min(Math.max(baseAABB[i], 0), 1); availableConnections = (byte)(availableConnections>>1); connections = (byte)(connections>>1); } list.add(new AdvancedAABB(new AxisAlignedBB(baseAABB[4], baseAABB[0], baseAABB[2], baseAABB[5], baseAABB[1], baseAABB[3]).offset(getPos()), null)); return list; } @Override public boolean isOverrideBox(AxisAlignedBB box, EntityPlayer player, RayTraceResult mop, ArrayList<AxisAlignedBB> list) { if(box instanceof AdvancedAABB) { if(box.expand(.002,.002,.002).isVecInside(mop.hitVec)) { AxisAlignedBB changedBox = ((AdvancedAABB)box).fd!=null?box.expand(((AdvancedAABB)box).fd.getFrontOffsetX()!=0?0:.03125, ((AdvancedAABB)box).fd.getFrontOffsetY()!=0?0:.03125, ((AdvancedAABB)box).fd.getFrontOffsetZ()!=0?0:.03125): box; list.add(changedBox); return true; } } return false; } public static HashMap<String, OBJState> cachedOBJStates = new HashMap<String, OBJState>(); static String[] CONNECTIONS = new String[]{ "con_yMin", "con_yMax", "con_zMin", "con_zMax", "con_xMin", "con_xMax" }; String getRenderCacheKey() { byte connections = getConnectionByte(); String key = ""; for(int i=0; i<6; i++) { if((connections&(1<<i))!=0) key += getConnectionStyle(i)==1?"2":"1"; else key += "0"; } if(pipeCover != null) key += "scaf:" + pipeCover.getItem().getRegistryName(); return key; } @Override public OBJState getOBJState() { byte connections = getConnectionByte(); String key = getRenderCacheKey(); if(!cachedOBJStates.containsKey(key)) { ArrayList<String> parts = new ArrayList(); Matrix4 rotationMatrix = new Matrix4(TRSRTransformation.identity().getMatrix());//new Matrix4(); // if(pipeCover!=null) // parts.add("cover"); int totalConnections = Integer.bitCount(connections); boolean straightY = (connections&3)==3; boolean straightZ = (connections&12)==12; boolean straightX = (connections&48)==48; switch(totalConnections) { case 0://stub parts.add("center"); break; case 1://stopper parts.add("stopper"); //default: y- if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); else if((connections&4)!=0)//z- rotationMatrix.rotate(Math.PI/2, 1,0,0); else if((connections&8)!=0)//z+ rotationMatrix.rotate(-Math.PI/2, 1,0,0); else if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); parts.add("con_yMin"); break; case 2://straight or curve if(straightY) { parts.add("pipe_y"); if(getConnectionStyle(0)==1) parts.add("con_yMin"); if(getConnectionStyle(1)==1) parts.add("con_yMax"); } else if(straightZ) { parts.add("pipe_z"); if(getConnectionStyle(2)==1) parts.add("con_zMin"); if(getConnectionStyle(3)==1) parts.add("con_zMax"); } else if(straightX) { parts.add("pipe_x"); if(getConnectionStyle(4)==1) parts.add("con_xMin"); if(getConnectionStyle(5)==1) parts.add("con_xMax"); } else { parts.add("curve"); parts.add("con_yMin"); parts.add("con_zMin"); byte connectTo = (byte)(connections&60); if((connections&3)!=0)//curve to top or bottom { if(connectTo==16)//x- rotationMatrix.rotate(Math.PI/2, 0,1,0); else if(connectTo==32)//x+ rotationMatrix.rotate(-Math.PI/2, 0,1,0); else if(connectTo==8)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//flip to top rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to z- } else//curve to horizontal { rotationMatrix.rotate(-Math.PI/2, 0,0,1); if(connectTo==40)//z+ to x+ rotationMatrix.rotate(Math.PI, 1,0,0); else if(connectTo==24)//z+ to x- rotationMatrix.rotate(-Math.PI/2, 1,0,0); else if(connectTo==36)//z- to x+ rotationMatrix.rotate(Math.PI/2, 1,0,0); //default: z- to x- } } break; case 3://tcross or tcurve if(straightX||straightZ||straightY)//has straight connect { parts.add("tcross"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_zMax"); if(straightX) { rotationMatrix.rotate(Math.PI/2, 0,1,0); if((connections&4)!=0)//z- rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&8)!=0)//z+ rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to y- } else if(straightY) { rotationMatrix.rotate(Math.PI/2, 1,0,0); if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to z- } else //default:z straight { if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to y- } } else //tcurve { parts.add("tcurve"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_xMax"); //default y-, z-, x+ if((connections&8)!=0)//z+ { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); else rotationMatrix.rotate(-Math.PI/2, 0,1,0); } else//z- { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI/2, 0,1,0); } if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } break; case 4://cross or complex tcross boolean cross = (straightX&&straightZ)||(straightX&&straightY)||(straightZ&&straightY); if(cross) { parts.add("cross"); parts.add("con_yMin"); parts.add("con_yMax"); parts.add("con_zMin"); parts.add("con_zMax"); if(!straightY)//x and z rotationMatrix.rotate(Math.PI/2, 0,0,1); else if(straightX)//x and y rotationMatrix.rotate(Math.PI/2, 0,1,0); } else { parts.add("tcross2"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_zMax"); parts.add("con_xMax"); if(straightZ) { //default y- z+- x+ if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } else if(straightY) { rotationMatrix.rotate(Math.PI / 2, 1, 0, 0); //default y+- z- x+ if((connections&8)!=0)//z+ { rotationMatrix.rotate(Math.PI/2, 0,0,1); if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI/2, 0,0,1); } else if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); } else { rotationMatrix.rotate(Math.PI/2, 0,1,0); //default y- z- x+- if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } } break; case 5://complete tcross parts.add("tcross3"); parts.add("con_yMin"); parts.add("con_yMax"); parts.add("con_zMin"); parts.add("con_zMax"); parts.add("con_xMax"); //default y+- z+- x+ if(straightZ) { if(straightY) { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); } else if(straightX) rotationMatrix.rotate(((connections&2)!=0)?(Math.PI/2):(-Math.PI/2), 0,0,1); } else if(straightX) { rotationMatrix.rotate(Math.PI/2, 0,1,0); if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); } break; case 6://Full Crossing parts.add("con_yMin"); parts.add("con_yMax"); parts.add("con_zMin"); parts.add("con_zMax"); parts.add("con_xMin"); parts.add("con_xMax"); break; } // connetionParts // for(int i=0; i<6; i++) // if(((TileEntityFluidPipe)tile).getConnectionStyle(i)==1) // connectionCaps.add(CONNECTIONS[i]); Matrix4 tempMatr = new Matrix4(); tempMatr.m03 = tempMatr.m13 = tempMatr.m23 = .5f; rotationMatrix.leftMultiply(tempMatr); tempMatr.invert(); rotationMatrix = rotationMatrix.multiply(tempMatr); cachedOBJStates.put(key, new OBJState(parts, true, new TRSRTransformation(rotationMatrix.toMatrix4f()))); } return cachedOBJStates.get(key); } // @Override // public HashMap<String, String> getTextureReplacements() // { // if(pipeCover!=null) // { // HashMap<String,String> map = new HashMap<String,String>(); //// map.put("cover","minecraft:blocks/stone"); // Block b = Block.getBlockFromItem(pipeCover.getItem()); // IBlockState state = b!=null?b.getStateFromMeta(pipeCover.getMetadata()): Blocks.STONE.getDefaultState(); // IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getModelForState(state); // if(model!=null && model.getParticleTexture()!=null) // map.put("cover", model.getParticleTexture().getIconName()); // // return map; // } // return null; // } public static OBJState getStateFromKey(String key) { if(!cachedOBJStates.containsKey(key)) { ArrayList<String> parts = new ArrayList(); Matrix4 rotationMatrix = new Matrix4(TRSRTransformation.identity().getMatrix());//new Matrix4(); byte connections = (byte)Integer.parseInt(key.replace("2","1"), 2); int totalConnections = Integer.bitCount(connections); boolean straightY = (connections&3)==3; boolean straightZ = (connections&12)==12; boolean straightX = (connections&48)==48; switch(totalConnections) { case 0://stub parts.add("center"); break; case 1://stopper parts.add("stopper"); //default: y- if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); else if((connections&4)!=0)//z- rotationMatrix.rotate(Math.PI/2, 1,0,0); else if((connections&8)!=0)//z+ rotationMatrix.rotate(-Math.PI/2, 1,0,0); else if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); parts.add("con_yMin"); break; case 2://straight or curve if(straightY) { parts.add("pipe_y"); if(key.charAt(5)=='2') parts.add("con_yMin"); if(key.charAt(4)==1) parts.add("con_yMax"); } else if(straightZ) { parts.add("pipe_z"); if(key.charAt(3)=='2') parts.add("con_zMin"); if(key.charAt(2)=='2') parts.add("con_zMax"); } else if(straightX) { parts.add("pipe_x"); if(key.charAt(1)=='2') parts.add("con_xMin"); if(key.charAt(0)=='2') parts.add("con_xMax"); } else { parts.add("curve"); parts.add("con_yMin"); parts.add("con_zMin"); byte connectTo = (byte)(connections&60); if((connections&3)!=0)//curve to top or bottom { if(connectTo==16)//x- rotationMatrix.rotate(Math.PI/2, 0,1,0); else if(connectTo==32)//x+ rotationMatrix.rotate(-Math.PI/2, 0,1,0); else if(connectTo==8)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//flip to top rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to z- } else//curve to horizontal { rotationMatrix.rotate(-Math.PI/2, 0,0,1); if(connectTo==40)//z+ to x+ rotationMatrix.rotate(Math.PI, 1,0,0); else if(connectTo==24)//z+ to x- rotationMatrix.rotate(-Math.PI/2, 1,0,0); else if(connectTo==36)//z- to x+ rotationMatrix.rotate(Math.PI/2, 1,0,0); //default: z- to x- } } break; case 3://tcross or tcurve if(straightX||straightZ||straightY)//has straight connect { parts.add("tcross"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_zMax"); if(straightX) { rotationMatrix.rotate(Math.PI/2, 0,1,0); if((connections&4)!=0)//z- rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&8)!=0)//z+ rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to y- } else if(straightY) { rotationMatrix.rotate(Math.PI/2, 1,0,0); if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to z- } else //default:z straight { if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); else if((connections&32)!=0)//x+ rotationMatrix.rotate(Math.PI/2, 0,0,1); else if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI, 0,0,1); //default: Curve to y- } } else //tcurve { parts.add("tcurve"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_xMax"); //default y-, z-, x+ if((connections&8)!=0)//z+ { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); else rotationMatrix.rotate(-Math.PI/2, 0,1,0); } else//z- { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI/2, 0,1,0); } if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } break; case 4://cross or complex tcross boolean cross = (straightX&&straightZ)||(straightX&&straightY)||(straightZ&&straightY); if(cross) { parts.add("cross"); parts.add("con_yMin"); parts.add("con_yMax"); parts.add("con_zMin"); parts.add("con_zMax"); if(!straightY)//x and z rotationMatrix.rotate(Math.PI/2, 0,0,1); else if(straightX)//x and y rotationMatrix.rotate(Math.PI/2, 0,1,0); } else { parts.add("tcross2"); parts.add("con_yMin"); parts.add("con_zMin"); parts.add("con_zMax"); parts.add("con_xMax"); if(straightZ) { //default y- z+- x+ if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } else if(straightY) { //default y+- z- x+ if((connections&8)!=0)//z+ { rotationMatrix.rotate(Math.PI/2, 0,0,1); if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI/2, 0,0,1); } else if((connections&16)!=0)//x- rotationMatrix.rotate(-Math.PI/2, 0,0,1); } else { rotationMatrix.rotate(Math.PI/2, 0,1,0); //default y- z- x+- if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); if((connections&2)!=0)//y+ rotationMatrix.rotate(Math.PI/2, 0,0,1); } } break; case 5://complete tcross parts.add("tcross3"); parts.add("con_yMin"); parts.add("con_yMax"); parts.add("con_zMin"); parts.add("con_zMax"); parts.add("con_xMax"); //default y+- z+- x+ if(straightZ) { if(straightY) { if((connections&16)!=0)//x- rotationMatrix.rotate(Math.PI, 0,1,0); } else if(straightX) rotationMatrix.rotate(((connections&2)!=0)?(Math.PI/2):(-Math.PI/2), 0,0,1); } else if(straightX) { rotationMatrix.rotate(Math.PI/2, 0,1,0); if((connections&8)!=0)//z+ rotationMatrix.rotate(Math.PI, 0,1,0); } break; case 6://Full Crossing break; } // connetionParts // for(int i=0; i<6; i++) // if(((TileEntityFluidPipe)tile).getConnectionStyle(i)==1) // connectionCaps.add(CONNECTIONS[i]); Matrix4 tempMatr = new Matrix4(); tempMatr.m03 = tempMatr.m13 = tempMatr.m23 = .5f; rotationMatrix.leftMultiply(tempMatr); tempMatr.invert(); rotationMatrix = rotationMatrix.multiply(tempMatr); cachedOBJStates.put(key, new OBJState(parts, true, new TRSRTransformation(rotationMatrix.toMatrix4f()))); } return cachedOBJStates.get(key); } @Override public int getRenderColour(int tintIndex) { return 0xffffff; } @Override public boolean interact(EnumFacing side, EntityPlayer player, EnumHand hand, ItemStack heldItem, float hitX, float hitY, float hitZ) { if(heldItem == null && player.isSneaking() && pipeCover != null) { if(!worldObj.isRemote && worldObj.getGameRules().getBoolean("doTileDrops")) { EntityItem entityitem = player.dropItem(pipeCover.copy(), false); if(entityitem != null) entityitem.setNoPickupDelay(); } pipeCover = null; this.markContainingBlockForUpdate(null); worldObj.addBlockEvent(getPos(), getBlockType(), 255, 0); return true; } else if(heldItem != null && !player.isSneaking()) for(Function<ItemStack, Boolean> func : validPipeCovers) if(func.apply(heldItem) == Boolean.TRUE) { if(!OreDictionary.itemMatches(pipeCover, heldItem, true)) { if(!worldObj.isRemote && pipeCover != null && worldObj.getGameRules().getBoolean("doTileDrops")) { EntityItem entityitem = player.dropItem(pipeCover.copy(), false); if(entityitem != null) entityitem.setNoPickupDelay(); } pipeCover = Utils.copyStackWithAmount(heldItem, 1); if((--heldItem.stackSize) <= 0) heldItem = null; this.markContainingBlockForUpdate(null); worldObj.addBlockEvent(getPos(), getBlockType(), 255, 0); return true; } } return false; } @Override public boolean hammerUseSide(EnumFacing side, EntityPlayer player, float hitX, float hitY, float hitZ) { if(worldObj.isRemote) return true; EnumFacing fd = side; List<AxisAlignedBB> boxes = this.getAdvancedSelectionBounds(); for(AxisAlignedBB box : boxes) if(box instanceof AdvancedAABB) { if(box.expand(.002,.002,.002).isVecInside(new Vec3d(getPos().getX()+hitX, getPos().getY()+hitY, getPos().getZ()+hitZ))) if(box instanceof AdvancedAABB && ((AdvancedAABB)box).fd != null) fd = ((AdvancedAABB)box).fd; } if(fd!=null) { toggleSide(fd.ordinal()); this.markContainingBlockForUpdate(null); TileEntityFluidPipe.indirectConnections.clear(); return true; } return false; } @Override public boolean canOutputPressurized(boolean consumePower) { return false; } @Override public boolean hasOutputConnection(EnumFacing side) { return side != null && sideConfig[side.ordinal()] == 0; } }