package pneumaticCraft.common.ai; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; import pneumaticCraft.api.item.IProgrammable; import pneumaticCraft.common.progwidgets.IProgWidget; import pneumaticCraft.common.progwidgets.ProgWidgetExternalProgram; import pneumaticCraft.common.tileentity.TileEntityProgrammer; import pneumaticCraft.common.util.IOHelper; public class DroneAIExternalProgram extends DroneAIBlockInteraction<ProgWidgetExternalProgram>{ private final DroneAIManager subAI, mainAI; private final Set<ChunkPosition> traversedPositions = new HashSet<ChunkPosition>(); private int curSlot; private NBTTagCompound curProgramTag; //Used to see if changes have been made to the program while running it. public DroneAIExternalProgram(IDroneBase drone, DroneAIManager mainAI, ProgWidgetExternalProgram widget){ super(drone, widget); this.mainAI = mainAI; subAI = new DroneAIManager(drone, new ArrayList<IProgWidget>()); } @Override public boolean shouldExecute(){ if(super.shouldExecute()) { traversedPositions.clear(); return true; } else { return false; } } @Override protected boolean moveToPositions(){ return false; } @Override protected boolean isValidPosition(ChunkPosition pos){ if(traversedPositions.add(pos)) { curSlot = 0; TileEntity te = drone.getWorld().getTileEntity(pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ); return te instanceof IInventory; } return false; } @Override protected boolean doBlockInteraction(ChunkPosition pos, double distToBlock){ IInventory inv = IOHelper.getInventoryForTE(drone.getWorld().getTileEntity(pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ)); if(inv == null) return false; if(curProgramTag != null) { if(curSlot < inv.getSizeInventory()) { ItemStack stack = inv.getStackInSlot(curSlot); if(stack != null && curProgramTag.equals(stack.getTagCompound())) { subAI.onUpdateTasks(); if(subAI.isIdling() || isRunningSameProgram(subAI.getCurrentAI())) { curProgramTag = null; curSlot++; } } else { curProgramTag = null; subAI.setWidgets(new ArrayList<IProgWidget>()); } } return true; } else { while(curSlot < inv.getSizeInventory()) { ItemStack stack = inv.getStackInSlot(curSlot); if(stack != null && stack.getItem() instanceof IProgrammable) { IProgrammable programmable = (IProgrammable)stack.getItem(); if(programmable.canProgram(stack) && programmable.usesPieces(stack)) { List<IProgWidget> widgets = TileEntityProgrammer.getProgWidgets(stack); boolean areWidgetsValid = true; for(IProgWidget widget : widgets) { if(!drone.isProgramApplicable(widget)) { areWidgetsValid = false; break; } } if(areWidgetsValid) { if(widget.shareVariables) mainAI.connectVariables(subAI); subAI.getDrone().getAIManager().setLabel("Main"); subAI.setWidgets(widgets); curProgramTag = stack.getTagCompound(); if(!subAI.isIdling()) { return true; } } } } curSlot++; } return false; } } //Prevent a memory leak, as a result of the same External program recursively calling itself. private boolean isRunningSameProgram(EntityAIBase ai){ return ai instanceof DroneAIExternalProgram && curProgramTag.equals(((DroneAIExternalProgram)ai).curProgramTag); } public DroneAIManager getRunningAI(){ return subAI; } }