package pneumaticCraft.common.ai; import java.util.HashSet; import java.util.Map; import java.util.PriorityQueue; import java.util.Set; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.world.ChunkPosition; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import pneumaticCraft.common.ai.LogisticsManager.LogisticsTask; import pneumaticCraft.common.progwidgets.ICountWidget; import pneumaticCraft.common.progwidgets.ILiquidFiltered; import pneumaticCraft.common.progwidgets.ISidedWidget; import pneumaticCraft.common.progwidgets.ProgWidgetAreaItemBase; import pneumaticCraft.common.semiblock.ISemiBlock; import pneumaticCraft.common.semiblock.SemiBlockLogistics; import pneumaticCraft.common.semiblock.SemiBlockManager; public class DroneAILogistics extends EntityAIBase{ private EntityAIBase curAI; private final IDroneBase drone; private final ProgWidgetAreaItemBase widget; private final LogisticsManager manager = new LogisticsManager(); private LogisticsTask curTask; public DroneAILogistics(IDroneBase drone, ProgWidgetAreaItemBase widget){ this.drone = drone; this.widget = widget; } @Override public boolean shouldExecute(){ manager.clearLogistics(); Set<ChunkPosition> area = widget.getCachedAreaSet(); if(area.size() == 0) return false; int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE; for(ChunkPosition pos : area) { minX = Math.min(minX, pos.chunkPosX); maxX = Math.max(maxX, pos.chunkPosX); minZ = Math.min(minZ, pos.chunkPosZ); maxZ = Math.max(maxZ, pos.chunkPosZ); } for(int x = minX; x < maxX + 16; x += 16) { for(int z = minZ; z < maxZ + 16; z += 16) { Chunk chunk = drone.getWorld().getChunkFromBlockCoords(x, z); Map<ChunkPosition, ISemiBlock> map = SemiBlockManager.getInstance(drone.getWorld()).getSemiBlocks().get(chunk); if(map != null) { for(Map.Entry<ChunkPosition, ISemiBlock> entry : map.entrySet()) { if(entry.getValue() instanceof SemiBlockLogistics && area.contains(entry.getKey())) { SemiBlockLogistics logisticsBlock = (SemiBlockLogistics)entry.getValue(); manager.addLogisticFrame(logisticsBlock); } } } } } curTask = null; return doLogistics(); } private boolean doLogistics(){ ItemStack item = drone.getInventory().getStackInSlot(0); FluidStack fluid = drone.getTank().getFluid(); PriorityQueue<LogisticsTask> tasks = manager.getTasks(item != null ? item : fluid); if(tasks.size() > 0) { curTask = tasks.poll(); return execute(curTask); } return false; } @Override public boolean continueExecuting(){ if(curTask == null) return false; if(!curAI.continueExecuting()) { if(curAI instanceof DroneEntityAIInventoryImport) { curTask.requester.clearIncomingStack(curTask.transportingItem); return clearAIAndProvideAgain(); } else if(curAI instanceof DroneAILiquidImport) { curTask.requester.clearIncomingStack(curTask.transportingFluid); return clearAIAndProvideAgain(); } else { curAI = null; return false; } } else { curTask.informRequester(); return true; } } private boolean clearAIAndProvideAgain(){ curAI = null; if(curTask.isStillValid(drone.getInventory().getStackInSlot(0) != null ? drone.getInventory().getStackInSlot(0) : drone.getTank().getFluid()) && execute(curTask)) { return true; } else { curTask = null; return doLogistics(); } } public boolean execute(LogisticsTask task){ if(drone.getInventory().getStackInSlot(0) != null) { if(!isPosPathfindable(task.requester.getPos())) return false; curAI = new DroneEntityAIInventoryExport(drone, new FakeWidgetLogistics(task.requester.getPos(), task.transportingItem)); } else if(drone.getTank().getFluidAmount() > 0) { if(!isPosPathfindable(task.requester.getPos())) return false; curAI = new DroneAILiquidExport(drone, new FakeWidgetLogistics(task.requester.getPos(), task.transportingFluid.stack)); } else if(task.transportingItem != null) { if(!isPosPathfindable(task.provider.getPos())) return false; curAI = new DroneEntityAIInventoryImport(drone, new FakeWidgetLogistics(task.provider.getPos(), task.transportingItem)); } else { if(!isPosPathfindable(task.provider.getPos())) return false; curAI = new DroneAILiquidImport(drone, new FakeWidgetLogistics(task.provider.getPos(), task.transportingFluid.stack)); } if(curAI.shouldExecute()) { task.informRequester(); return true; } else { return false; } } private boolean isPosPathfindable(ChunkPosition pos){ for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { if(drone.isBlockValidPathfindBlock(pos.chunkPosX + d.offsetX, pos.chunkPosY + d.offsetY, pos.chunkPosZ + d.offsetZ)) return true; } return false; } private static class FakeWidgetLogistics extends ProgWidgetAreaItemBase implements ISidedWidget, ICountWidget, ILiquidFiltered{ private ItemStack stack; private FluidStack fluid; private final Set<ChunkPosition> area; public FakeWidgetLogistics(ChunkPosition pos, ItemStack stack){ this.stack = stack; area = new HashSet<ChunkPosition>(); area.add(pos); } public FakeWidgetLogistics(ChunkPosition pos, FluidStack fluid){ this.fluid = fluid; area = new HashSet<ChunkPosition>(); area.add(pos); } @Override public String getWidgetString(){ return null; } @Override public int getCraftingColorIndex(){ return 0; } @Override public void getArea(Set<ChunkPosition> area){ area.addAll(this.area); } @Override public void setSides(boolean[] sides){} @Override public boolean[] getSides(){ return new boolean[]{true, true, true, true, true, true}; } @Override public boolean isItemValidForFilters(ItemStack item){ return item != null && item.isItemEqual(stack); } @Override protected ResourceLocation getTexture(){ return null; } @Override public boolean useCount(){ return true; } @Override public void setUseCount(boolean useCount){} @Override public int getCount(){ return stack != null ? stack.stackSize : fluid.amount; } @Override public void setCount(int count){} @Override public boolean isFluidValid(Fluid fluid){ return fluid == this.fluid.getFluid(); } } }