package pneumaticCraft.common.ai; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidHandler; import pneumaticCraft.common.semiblock.IProvidingInventoryListener; import pneumaticCraft.common.semiblock.ISpecificProvider; import pneumaticCraft.common.semiblock.ISpecificRequester; import pneumaticCraft.common.semiblock.SemiBlockLogistics; import pneumaticCraft.common.semiblock.SemiBlockLogistics.FluidStackWrapper; import pneumaticCraft.common.util.IOHelper; public class LogisticsManager{ private final List<SemiBlockLogistics>[] logistics = new List[4]; public LogisticsManager(){ for(int i = 0; i < logistics.length; i++) { logistics[i] = new ArrayList<SemiBlockLogistics>(); } } public void clearLogistics(){ for(List<SemiBlockLogistics> list : logistics) { list.clear(); } } public void addLogisticFrame(SemiBlockLogistics frame){ logistics[frame.getPriority()].add(frame); } public PriorityQueue<LogisticsTask> getTasks(Object holdingStack){ ItemStack item = holdingStack instanceof ItemStack ? (ItemStack)holdingStack : null; FluidStack fluid = holdingStack instanceof FluidStack ? (FluidStack)holdingStack : null; PriorityQueue<LogisticsTask> tasks = new PriorityQueue<LogisticsTask>(); for(int priority = logistics.length - 1; priority >= 0; priority--) { for(SemiBlockLogistics requester : logistics[priority]) { for(int i = 0; i < priority; i++) { for(SemiBlockLogistics provider : logistics[i]) { if(provider.shouldProvideTo(priority)) { if(item != null) { int requestedAmount = getRequestedAmount(requester, item); if(requestedAmount > 0) { ItemStack stack = item.copy(); stack.stackSize = requestedAmount; tasks.add(new LogisticsTask(provider, requester, stack)); return tasks; } } else if(fluid != null) { int requestedAmount = getRequestedAmount(requester, fluid); if(requestedAmount > 0) { fluid = fluid.copy(); fluid.amount = requestedAmount; tasks.add(new LogisticsTask(provider, requester, new FluidStackWrapper(fluid))); return tasks; } } else { tryProvide(provider, requester, tasks); } } } } } } return tasks; } //curAI = new DroneAILiquidImport(drone, new FakeWidgetLogistics(provider.getPos(), providingStack)); // transportingFluid = new FluidStackWrapper(providingStack); private void tryProvide(SemiBlockLogistics provider, SemiBlockLogistics requester, PriorityQueue<LogisticsTask> tasks){ IInventory providingInventory = IOHelper.getInventoryForTE(provider.getTileEntity()); if(providingInventory != null) { if(requester instanceof IProvidingInventoryListener) ((IProvidingInventoryListener)requester).notify(provider.getTileEntity()); for(int i = 0; i < providingInventory.getSizeInventory(); i++) { ItemStack providingStack = providingInventory.getStackInSlot(i); if(providingStack != null && (!(provider instanceof ISpecificProvider) || ((ISpecificProvider)provider).canProvide(providingStack)) && IOHelper.canExtractItemFromInventory(providingInventory, providingStack, i, 0)) { int requestedAmount = getRequestedAmount(requester, providingStack); if(requestedAmount > 0) { ItemStack stack = providingStack.copy(); stack.stackSize = requestedAmount; tasks.add(new LogisticsTask(provider, requester, stack)); } } } } if(provider.getTileEntity() instanceof IFluidHandler) { IFluidHandler providingTank = (IFluidHandler)provider.getTileEntity(); for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { FluidStack providingStack = providingTank.drain(d, 16000, false); if(providingStack != null && (!(provider instanceof ISpecificProvider) || ((ISpecificProvider)provider).canProvide(providingStack)) && providingTank.canDrain(d, providingStack.getFluid())) { int requestedAmount = getRequestedAmount(requester, providingStack); if(requestedAmount > 0) { FluidStack stack = providingStack.copy(); stack.amount = requestedAmount; tasks.add(new LogisticsTask(provider, requester, new FluidStackWrapper(stack))); } } } } } public static int getRequestedAmount(SemiBlockLogistics requester, ItemStack providingStack){ TileEntity te = requester.getTileEntity(); if(!(te instanceof IInventory)) return 0; int requestedAmount = requester instanceof ISpecificRequester ? ((ISpecificRequester)requester).amountRequested(providingStack) : providingStack.stackSize; if(requestedAmount == 0) return 0; providingStack = providingStack.copy(); providingStack.stackSize = requestedAmount; ItemStack remainder = providingStack.copy(); remainder.stackSize += requester.getIncomingItems(providingStack); for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { remainder = IOHelper.insert(te, remainder, d, true); if(remainder == null) break; } if(remainder != null) providingStack.stackSize -= remainder.stackSize; if(providingStack.stackSize <= 0) return 0; return providingStack.stackSize; } public static int getRequestedAmount(SemiBlockLogistics requester, FluidStack providingStack){ int requestedAmount = requester instanceof ISpecificRequester ? ((ISpecificRequester)requester).amountRequested(providingStack) : providingStack.amount; if(requestedAmount == 0) return 0; providingStack = providingStack.copy(); providingStack.amount = requestedAmount; FluidStack remainder = providingStack.copy(); remainder.amount += requester.getIncomingFluid(remainder.getFluid()); TileEntity te = requester.getTileEntity(); if(te instanceof IFluidHandler) { IFluidHandler fluidHandler = (IFluidHandler)te; for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { int fluidFilled = fluidHandler.fill(d, remainder, false); if(fluidFilled > 0) { remainder.amount -= fluidFilled; break; } } } providingStack.amount -= remainder.amount; if(providingStack.amount <= 0) return 0; return providingStack.amount; } public static class LogisticsTask implements Comparable<LogisticsTask>{ public final SemiBlockLogistics provider, requester; public final ItemStack transportingItem; public final FluidStackWrapper transportingFluid; public LogisticsTask(SemiBlockLogistics provider, SemiBlockLogistics requester, ItemStack transportingItem){ this.provider = provider; this.requester = requester; this.transportingItem = transportingItem; transportingFluid = null; } public LogisticsTask(SemiBlockLogistics provider, SemiBlockLogistics requester, FluidStackWrapper transportingFluid){ this.provider = provider; this.requester = requester; this.transportingFluid = transportingFluid; transportingItem = null; } public void informRequester(){ if(transportingItem != null) { requester.informIncomingStack(transportingItem); } else { requester.informIncomingStack(transportingFluid); } } public boolean isStillValid(Object stack){ if(transportingItem != null && stack instanceof ItemStack) { int requestedAmount = getRequestedAmount(requester, (ItemStack)stack); return requestedAmount == ((ItemStack)stack).stackSize; } else if(transportingFluid != null && stack instanceof FluidStack) { int requestedAmount = getRequestedAmount(requester, (FluidStack)stack); return requestedAmount == ((FluidStack)stack).amount; } else { return false; } } @Override public int compareTo(LogisticsTask task){ int value = transportingItem != null ? transportingItem.stackSize * 100 : transportingFluid.stack.amount; int otherValue = task.transportingItem != null ? task.transportingItem.stackSize * 100 : task.transportingFluid.stack.amount; return otherValue - value; } } }