package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.crafting.BottlingMachineRecipe; import blusunrize.immersiveengineering.api.crafting.IMultiblockRecipe; import blusunrize.immersiveengineering.api.tool.ConveyorHandler.IConveyorAttachable; import blusunrize.immersiveengineering.common.Config; import blusunrize.immersiveengineering.common.blocks.multiblocks.MultiblockBottlingMachine; import blusunrize.immersiveengineering.common.util.Utils; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.IFluidTank; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TileEntityBottlingMachine extends TileEntityMultiblockMetal<TileEntityBottlingMachine,IMultiblockRecipe> implements IConveyorAttachable// IAdvancedSelectionBounds,IAdvancedCollisionBounds { public TileEntityBottlingMachine() { super(MultiblockBottlingMachine.instance, new int[]{3,2,3}, 16000, true); } public FluidTank[] tanks = new FluidTank[]{new FluidTank(8000)}; public List<BottlingProcess> bottlingProcessQueue = new ArrayList<>(); @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.readCustomNBT(nbt, descPacket); NBTTagList processNBT = nbt.getTagList("bottlingQueue", 10); bottlingProcessQueue.clear(); for(int i=0; i<processNBT.tagCount(); i++) { NBTTagCompound tag = processNBT.getCompoundTagAt(i); BottlingProcess process = BottlingProcess.readFromNBT(tag); bottlingProcessQueue.add(process); } tanks[0].readFromNBT(nbt.getCompoundTag("tank")); } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { super.writeCustomNBT(nbt, descPacket); NBTTagList processNBT = new NBTTagList(); for(BottlingProcess process : this.bottlingProcessQueue) processNBT.appendTag(process.writeToNBT()); nbt.setTag("bottlingQueue", processNBT); nbt.setTag("tank",tanks[0].writeToNBT(new NBTTagCompound())); } @Override public void receiveMessageFromClient(NBTTagCompound message) { } @Override public void update() { super.update(); if(isDummy() || isRSDisabled() || worldObj.isRemote) return; tickedProcesses = 0; int max = getMaxProcessPerTick(); int i = 0; Iterator<BottlingProcess> processIterator = bottlingProcessQueue.iterator(); tickedProcesses = 0; while(processIterator.hasNext() && i++<max) { BottlingProcess process = processIterator.next(); if(process.processStep(this)) tickedProcesses++; if(process.processFinished) { ItemStack output = process.items[1]!=null?process.items[1]:process.items[0]; EnumFacing outDir = mirrored?facing.rotateYCCW():facing.rotateY(); BlockPos outPos = getBlockPosForPos(8).offset(outDir); TileEntity inventoryTile = this.worldObj.getTileEntity(outPos); if(inventoryTile!=null) output = Utils.insertStackIntoInventory(inventoryTile, output, outDir.getOpposite()); if(output!=null) Utils.dropStackAtPos(worldObj, outPos, output, outDir); processIterator.remove(); } } } @Override public float[] getBlockBounds() { if(pos==4) return new float[]{0,0,0,1,.5f,1}; if(pos<6 || pos==11) return new float[]{0,0,0,1,1,1}; if(pos>=6 && pos<=8) return new float[]{0,0,0,1,.125f,1}; if(pos==9) return new float[]{.0625f,0,.0625f,.9375f,1,.9375f}; if(pos==10) { EnumFacing f = mirrored?facing.rotateYCCW():facing.rotateY(); float xMin = f==EnumFacing.EAST?-.0625f:f==EnumFacing.WEST?.25f: facing==EnumFacing.WEST?.125f:facing==EnumFacing.EAST?.25f: 0; float zMin = facing==EnumFacing.NORTH?.125f:facing==EnumFacing.SOUTH?.25f: f==EnumFacing.SOUTH?-.0625f:f==EnumFacing.NORTH?.25f: 0; float xMax = f==EnumFacing.EAST?.75f:f==EnumFacing.WEST?1.0625f: facing==EnumFacing.WEST?.75f:facing==EnumFacing.EAST?.875f: 1; float zMax = facing==EnumFacing.NORTH?.75f:facing==EnumFacing.SOUTH?.875f: f==EnumFacing.SOUTH?.75f:f==EnumFacing.NORTH?1.0625f: 1; return new float[]{xMin,.0625f,zMin, xMax,.6875f,zMax}; } if(pos==13) { float xMin = facing==EnumFacing.WEST?0:.21875f; float zMin = facing==EnumFacing.NORTH?0:.21875f; float xMax = facing==EnumFacing.EAST?1:.78125f; float zMax = facing==EnumFacing.SOUTH?1:.78125f; return new float[]{xMin,-.4375f,zMin, xMax,.5625f,zMax}; } if(pos==16) { float xMin = facing==EnumFacing.WEST?.8125f:facing==EnumFacing.EAST?0:.125f; float zMin = facing==EnumFacing.NORTH?.8125f:facing==EnumFacing.SOUTH?0:.125f; float xMax = facing==EnumFacing.WEST?1:facing==EnumFacing.EAST?.1875f:.875f; float zMax = facing==EnumFacing.NORTH?1:facing==EnumFacing.SOUTH?.1875f:.875f; return new float[]{xMin,-1,zMin, xMax,.25f,zMax}; } return new float[]{0,0,0, 1,1,1}; } @Override public int[] getEnergyPos() { return new int[]{11}; } @Override public int[] getRedstonePos() { return new int[]{1}; } @Override public void replaceStructureBlock(BlockPos pos, IBlockState state, ItemStack stack, int h, int l, int w) { super.replaceStructureBlock(pos, state, stack, h, l, w); if(h==2&&l==1&&w==1) { TileEntity tile = worldObj.getTileEntity(pos); if(tile instanceof TileEntityFluidPump) ((TileEntityFluidPump)tile).dummy = true; } else if(h==1&&l==0) { TileEntity tile = worldObj.getTileEntity(pos); if(tile instanceof TileEntityConveyorBelt) ((TileEntityConveyorBelt)tile).setFacing(this.mirrored?this.facing.rotateYCCW():this.facing.rotateY()); } } @Override public void onEntityCollision(World world, Entity entity) { if(pos==6 && !world.isRemote && entity!=null && !entity.isDead && entity instanceof EntityItem) { TileEntityBottlingMachine master = master(); if(master==null) return; ItemStack stack = ((EntityItem)entity).getEntityItem(); if(stack==null) return; if(master.bottlingProcessQueue.size() < master.getProcessQueueMaxLength()) { float dist = 1; BottlingProcess p = null; if(master.bottlingProcessQueue.size() > 0) { p = master.bottlingProcessQueue.get(master.bottlingProcessQueue.size()-1); if(p!=null) dist = p.processTick/(float)p.maxProcessTick; } if(p!=null&&dist < master.getMinProcessDistance(null)) return; p = new BottlingProcess(Utils.copyStackWithAmount(stack, 1)); master.bottlingProcessQueue.add(p); master.markDirty(); master.markContainingBlockForUpdate(null); stack.stackSize -= 1; if(stack.stackSize <= 0) entity.setDead(); } } } @Override public boolean isInWorldProcessingMachine() { return true; } @Override public boolean additionalCanProcessCheck(MultiblockProcess<IMultiblockRecipe> process) { return true; } @Override public void doProcessOutput(ItemStack output) { EnumFacing outDir = mirrored?facing.rotateYCCW():facing.rotateY(); BlockPos pos = getPos().offset(outDir,2); TileEntity inventoryTile = this.worldObj.getTileEntity(pos); if(inventoryTile!=null) output = Utils.insertStackIntoInventory(inventoryTile, output, outDir.getOpposite()); if(output!=null) Utils.dropStackAtPos(worldObj, pos, output, outDir); } @Override public void doProcessFluidOutput(FluidStack output) { } @Override public void onProcessFinish(MultiblockProcess<IMultiblockRecipe> process) { } @Override public int getMaxProcessPerTick() { return 2; } @Override public int getProcessQueueMaxLength() { return 2; } @Override public float getMinProcessDistance(MultiblockProcess<IMultiblockRecipe> process) { return .5f; } @Override public ItemStack[] getInventory() { return null; } @Override public boolean isStackValid(int slot, ItemStack stack) { return true; } @Override public int getSlotLimit(int slot) { return 64; } @Override public int[] getOutputSlots() { return null; } @Override public int[] getOutputTanks() { return new int[0]; } @Override public IFluidTank[] getInternalTanks() { return tanks; } @Override public void doGraphicalUpdates(int slot) { this.markDirty(); this.markContainingBlockForUpdate(null); } @Override public IMultiblockRecipe findRecipeForInsertion(ItemStack inserting) { return null; } @Override protected IMultiblockRecipe readRecipeFromNBT(NBTTagCompound tag) { return null; } @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { TileEntityBottlingMachine master = master(); if(master == null) return false; return pos==6 && facing==(mirrored?this.facing.rotateY():this.facing.rotateYCCW()); } return super.hasCapability(capability, facing); } IItemHandler insertionHandler = new BottlingMachineInventoryHandler(this); @Override public <T> T getCapability(Capability<T> capability, EnumFacing facing) { if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { TileEntityBottlingMachine master = master(); if(master==null) return null; if(pos==6 && facing==(mirrored?this.facing.rotateY():this.facing.rotateYCCW())) return (T)master.insertionHandler; return null; } return super.getCapability(capability, facing); } @Override protected IFluidTank[] getAccessibleFluidTanks(EnumFacing side) { TileEntityBottlingMachine master = this.master(); if(master!=null) { if(pos==3 && (side==null||side.getAxis()!=Axis.Y)) return master.tanks; } return new FluidTank[0]; } @Override protected boolean canFillTankFrom(int iTank, EnumFacing side, FluidStack resource) { if(pos==3 && (side== null||side.getAxis()!=Axis.Y)) { TileEntityBottlingMachine master = this.master(); return !(master==null||master.tanks[iTank].getFluidAmount() >= master.tanks[iTank].getCapacity()); } return false; } @Override protected boolean canDrainTankFrom(int iTank, EnumFacing side) { return false; } @Override public EnumFacing[] sigOutputDirections() { if(pos==8) return new EnumFacing[]{mirrored?facing.rotateYCCW():facing.rotateY()}; return new EnumFacing[0]; } public static class BottlingProcess { public ItemStack[] items; public int processTick; public int maxProcessTick = (int)(120*Config.IEConfig.Machines.bottlingMachine_timeModifier); boolean processFinished = false; public BottlingProcess(ItemStack input) { this.items = new ItemStack[]{input,null}; } public boolean processStep(TileEntityBottlingMachine tile) { int energyExtracted = (int)(8*Config.IEConfig.Machines.bottlingMachine_energyModifier); if(tile.energyStorage.extractEnergy(energyExtracted, true)>=energyExtracted) { tile.energyStorage.extractEnergy(energyExtracted, false); if(++processTick==(int)(maxProcessTick*.4375)) { FluidStack fs = tile.tanks[0].getFluid(); if(fs!=null) { BottlingMachineRecipe recipe = BottlingMachineRecipe.findRecipe(items[0], fs); if(recipe!=null) { if (tile.tanks[0].drainInternal(recipe.fluidInput, false).amount==recipe.fluidInput.amount) { items[1] = recipe.getActualItemOutputs(tile).get(0); tile.tanks[0].drainInternal(recipe.fluidInput, true); } } else { ItemStack ret = Utils.fillFluidContainer(tile.tanks[0], items[0], null, null); if(ret!=null) items[1] = ret; } if(items[1]==null) items[1] = items[0]; } } if(processTick>=maxProcessTick) processFinished = true; return true; } return false; } public NBTTagCompound writeToNBT() { NBTTagCompound nbt = new NBTTagCompound(); if(items[0]!=null) nbt.setTag("input", items[0].writeToNBT(new NBTTagCompound())); if(items[1]!=null) nbt.setTag("output", items[1].writeToNBT(new NBTTagCompound())); nbt.setInteger("processTick", processTick); return nbt; } public static BottlingProcess readFromNBT(NBTTagCompound nbt) { ItemStack input = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("input")); BottlingProcess process = new BottlingProcess(input); if(nbt.hasKey("output")) process.items[1] = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("output")); process.processTick = nbt.getInteger("processTick"); return process; } } public static class BottlingMachineInventoryHandler implements IItemHandlerModifiable { TileEntityBottlingMachine multiblock; public BottlingMachineInventoryHandler(TileEntityBottlingMachine multiblock) { this.multiblock = multiblock; } @Override public int getSlots() { return 1; } @Override public ItemStack getStackInSlot(int slot) { return null; } @Override public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { if(multiblock.bottlingProcessQueue.size() < multiblock.getProcessQueueMaxLength()) { stack = stack.copy(); float dist = 1; BottlingProcess p = null; if(multiblock.bottlingProcessQueue.size()>0) { p = multiblock.bottlingProcessQueue.get(multiblock.bottlingProcessQueue.size()-1); if(p != null) dist = p.processTick/(float)p.maxProcessTick; } if(p!=null && dist<multiblock.getMinProcessDistance(null)) return stack; if(!simulate) { p = new BottlingProcess(Utils.copyStackWithAmount(stack, 1)); multiblock.bottlingProcessQueue.add(p); multiblock.markDirty(); multiblock.markContainingBlockForUpdate(null); } stack.stackSize-=1; if(stack.stackSize<=0) stack = null; } return stack; } @Override public ItemStack extractItem(int slot, int amount, boolean simulate) { return null; } @Override public void setStackInSlot(int slot, ItemStack stack) { } } }