added assembly table drivers to crafting robot, for #1973

This commit is contained in:
SpaceToad 2014-08-13 22:11:44 +02:00
parent 8c5b2563d3
commit f864f16f0a
18 changed files with 438 additions and 34 deletions

View file

@ -106,4 +106,10 @@ public class BlockIndex implements Comparable<BlockIndex> {
public int hashCode() {
return (x * 37 + y) * 37 + z;
}
public boolean nextTo(BlockIndex blockIndex) {
return (Math.abs(blockIndex.x - x) <= 1 && blockIndex.y == y && blockIndex.z == z)
|| (blockIndex.x == x && Math.abs(blockIndex.y - y) <= 1 && blockIndex.z == z)
|| (blockIndex.x == x && blockIndex.y == y && Math.abs(blockIndex.z - z) <= 1);
}
}

View file

@ -21,5 +21,5 @@ public class CraftingResult<T> {
public ArrayList<FluidStack> usedFluids = new ArrayList<FluidStack>();
public double energyCost = 0;
public long craftingTime = 0;
public IFlexibleRecipe<?> recipe;
public IFlexibleRecipe<T> recipe;
}

View file

@ -8,11 +8,15 @@
*/
package buildcraft.api.recipes;
import net.minecraft.item.ItemStack;
public interface IFlexibleRecipe<T> {
boolean canBeCrafted(IFlexibleCrafter crafter);
CraftingResult<T> craft(IFlexibleCrafter crafter, boolean preview);
CraftingResult<T> canCraft(ItemStack expectedOutput);
String getId();
}

View file

@ -8,6 +8,7 @@
*/
package buildcraft.api.robots;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
public class AIRobot {
@ -63,6 +64,14 @@ public class AIRobot {
return 0.1;
}
/**
* Tries to receive items in parameters, return items that are left after
* the operation.
*/
public ItemStack receiveItem(ItemStack stack) {
return stack;
}
public final void terminate() {
abortDelegateAI();
end();

View file

@ -20,6 +20,7 @@ import net.minecraftforge.fluids.FluidStack;
import buildcraft.api.recipes.CraftingResult;
import buildcraft.api.recipes.IFlexibleCrafter;
import buildcraft.api.recipes.IFlexibleRecipe;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.inventory.filters.ArrayStackFilter;
import buildcraft.core.inventory.filters.IStackFilter;
@ -209,4 +210,21 @@ public class FlexibleRecipe<T> implements IFlexibleRecipe<T> {
return amount;
}
@Override
public CraftingResult<T> canCraft(ItemStack expectedOutput) {
if (output instanceof ItemStack
&& StackHelper.isMatchingItem(expectedOutput, (ItemStack) output)) {
CraftingResult<T> result = new CraftingResult<T>();
result.recipe = this;
result.usedFluids = inputFluids;
result.usedItems = inputItems;
result.crafted = output;
return result;
} else {
return null;
}
}
}

View file

@ -0,0 +1,266 @@
/**
* Copyright (c) 2011-2014, SpaceToad and the BuildCraft Team
* http://www.mod-buildcraft.com
*
* BuildCraft is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package buildcraft.core.robots;
import java.util.ArrayList;
import net.minecraft.block.Block;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.ForgeDirection;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.core.IInvSlot;
import buildcraft.api.recipes.CraftingResult;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.core.inventory.ITransactor;
import buildcraft.core.inventory.InventoryCopy;
import buildcraft.core.inventory.InventoryIterator;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.inventory.Transactor;
import buildcraft.core.inventory.filters.ArrayStackFilter;
import buildcraft.core.inventory.filters.IStackFilter;
import buildcraft.silicon.BlockLaserTable;
import buildcraft.silicon.TileAssemblyTable;
public class AIRobotCraftAssemblyTable extends AIRobotCraftGeneric {
private CraftingResult<ItemStack> expectedResult;
private DockingStation stationFound;
private TileAssemblyTable table;
private boolean craftStarted = false;
private ArrayList<ArrayStackFilter> requirements;
private int waitedTime = 0;
public AIRobotCraftAssemblyTable(EntityRobotBase iRobot) {
super(iRobot);
}
public AIRobotCraftAssemblyTable(EntityRobotBase iRobot, CraftingResult craftingResult) {
super(iRobot);
expectedResult = craftingResult;
}
@Override
public void start() {
requirements = tryCraft();
startDelegateAI(new AIRobotSearchStation(robot, new StationAssemblyTableFilter(), robot.getZoneToWork()));
}
@Override
public void update() {
if (table != null) {
if (!craftStarted) {
if (requirements.size() != 0) {
startDelegateAI(new AIRobotGotoStationAndLoad(robot, new ReqStackFilter(), robot.getZoneToWork()));
return;
}
if (robot.getDockingStation() != stationFound) {
startDelegateAI(new AIRobotGotoStation(robot, stationFound));
return;
}
ITransactor trans = Transactor.getTransactorFor(table);
for (IInvSlot s : InventoryIterator.getIterable(robot)) {
if (s.getStackInSlot() != null) {
ItemStack added = trans.add(s.getStackInSlot(), ForgeDirection.UNKNOWN, true);
if (added.stackSize == 0) {
terminate();
} else if (added.stackSize == s.getStackInSlot().stackSize) {
s.setStackInSlot(null);
} else {
s.getStackInSlot().stackSize -= added.stackSize;
}
}
}
RobotRegistry.getRegistry(robot.worldObj).take(new ResourceIdAssemblyTable(table), robot);
table.planOutput(expectedResult.recipe);
// TODO: How to make sure this output is not crafted more than
// once??
craftStarted = true;
} else {
waitedTime++;
if (getItem(new ArrayStackFilter(expectedResult.crafted)) != null) {
crafted = true;
terminate();
} else if (waitedTime > 120 * 60) {
terminate();
}
}
}
}
@Override
public void delegateAIEnded(AIRobot ai) {
if (ai instanceof AIRobotSearchStation) {
if (!ai.success()) {
crafted = false;
terminate();
} else {
stationFound = ((AIRobotSearchStation) ai).targetStation;
table = getUsableAssemblyTable(new BlockIndex(stationFound.x(), stationFound.y(), stationFound.z()));
if (table == null) {
terminate();
return;
}
BlockIndex index = new BlockIndex(table);
if (!robot.getRegistry().take(new ResourceIdBlock(index), robot)) {
terminate();
}
if (!stationFound.take(robot)) {
terminate();
}
}
} else if (ai instanceof AIRobotGotoStationAndLoad) {
if (!ai.success()) {
terminate();
} else {
requirements = tryCraft();
}
}
}
@Override
public ItemStack receiveItem(ItemStack stack) {
if (StackHelper.isMatchingItem(stack, expectedResult.crafted)) {
ITransactor robotTransactor = Transactor.getTransactorFor(robot);
ItemStack added = robotTransactor.add(stack, ForgeDirection.UNKNOWN, true);
stack.stackSize -= added.stackSize;
return stack;
} else {
return stack;
}
}
protected ArrayList<ArrayStackFilter> tryCraft() {
Object[] items = expectedResult.usedItems.toArray();
ArrayList<ArrayStackFilter> result = new ArrayList<ArrayStackFilter>();
IInventory inv = new InventoryCopy(robot);
for (Object tmp : items) {
if (tmp == null) {
continue;
}
int qty = 0;
ArrayStackFilter filter;
if (tmp instanceof ItemStack) {
ItemStack stack = (ItemStack) tmp;
qty = stack.stackSize;
filter = new ArrayStackFilter(stack);
} else {
ArrayList<ItemStack> stacks = (ArrayList<ItemStack>) tmp;
qty = stacks.get(0).stackSize;
filter = new ArrayStackFilter(stacks.toArray(new ItemStack[stacks.size()]));
}
for (IInvSlot s : InventoryIterator.getIterable(inv)) {
if (filter.matches(s.getStackInSlot())) {
ItemStack removed = s.decreaseStackInSlot(qty);
qty = qty - removed.stackSize;
if (removed.stackSize == 0) {
break;
}
}
}
if (qty > 0) {
result.add(filter);
}
}
return result;
}
private class StationAssemblyTableFilter implements IStationFilter {
@Override
public boolean matches(DockingStation station) {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (getUsableAssemblyTable(new BlockIndex(station.x(), station.y(), station.z())) != null) {
return true;
}
}
return false;
}
}
private TileAssemblyTable getUsableAssemblyTable(BlockIndex b) {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
BlockIndex index = new BlockIndex (b.x + dir.offsetX, b.y
+ dir.offsetY, b.z
+ dir.offsetZ);
if (robot.getRegistry().isTaken(new ResourceIdBlock(index))) {
continue;
}
Block nearbyBlock = robot.worldObj.getBlock(index.x, index.y, index.z);
int nearbyMeta = robot.worldObj.getBlockMetadata(index.x, index.y, index.z);
if (nearbyBlock instanceof BlockLaserTable && nearbyMeta == 0) {
TileAssemblyTable f = (TileAssemblyTable) robot.worldObj.getTileEntity(index.x, index.y, index.z);
// TODO: check if assembly table has some empty slots
return f;
}
}
return null;
}
private IInvSlot getItem(IStackFilter filter) {
for (IInvSlot s : InventoryIterator.getIterable(robot)) {
if (s.getStackInSlot() != null && filter.matches(s.getStackInSlot())) {
return s;
}
}
return null;
}
private class ReqStackFilter implements IStackFilter {
@Override
public boolean matches(ItemStack stack) {
for (ArrayStackFilter s : requirements) {
if (s.matches(stack)) {
return true;
}
}
return false;
}
}
}

View file

@ -8,8 +8,6 @@
*/
package buildcraft.core.robots;
import java.util.ArrayList;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFurnace;
import net.minecraft.item.ItemStack;
@ -138,20 +136,15 @@ public class AIRobotCraftFurnace extends AIRobotCraftGeneric {
terminate();
}
stationFound.take(robot);
if (!stationFound.take(robot)) {
terminate();
}
}
} else if (ai instanceof AIRobotGotoStationAndLoad) {
}
}
@Override
protected ArrayList<ArrayStackFilter> tryCraft(boolean doRemove) {
// TODO Auto-generated method stub
return null;
}
// How to operate furnaces
// [1] identify a furnace
// [2] verify that proper item is in. If empty, and slot out empty or
@ -160,8 +153,6 @@ public class AIRobotCraftFurnace extends AIRobotCraftGeneric {
// [4] as soon as output contains expected item, get it and place it
// somewhere
// How to operate assembly tables
private class StationFurnaceFilter implements IStationFilter {
@Override

View file

@ -23,8 +23,6 @@ public abstract class AIRobotCraftGeneric extends AIRobot {
super(iRobot);
}
protected abstract ArrayList<ArrayStackFilter> tryCraft(boolean doRemove);
@Override
public void end() {
robot.releaseResources();

View file

@ -104,7 +104,6 @@ public class AIRobotCraftWorkbench extends AIRobotCraftGeneric {
}
}
@Override
protected ArrayList<ArrayStackFilter> tryCraft(boolean doRemove) {
Object[] items = new Object[0];

View file

@ -21,6 +21,7 @@ public class AIRobotGotoStation extends AIRobot {
private BlockIndex stationIndex;
private ForgeDirection stationSide;
private boolean docked = false;
public AIRobotGotoStation(EntityRobotBase iRobot) {
super(iRobot);
@ -67,11 +68,17 @@ public class AIRobotGotoStation extends AIRobot {
stationIndex.y + 0.5F + stationSide.offsetY * 0.5F,
stationIndex.z + 0.5F + stationSide.offsetZ * 0.5F));
} else {
docked = true;
robot.dock(station);
terminate();
}
}
@Override
public boolean success() {
return docked;
}
@Override
public void writeSelfToNBT(NBTTagCompound nbt) {
NBTTagCompound indexNBT = new NBTTagCompound();

View file

@ -16,6 +16,7 @@ public class AIRobotGotoStationAndUnload extends AIRobot {
private boolean found = false;
private IZone zone;
private DockingStation station;
public AIRobotGotoStationAndUnload(EntityRobotBase iRobot) {
super(iRobot);
@ -27,9 +28,19 @@ public class AIRobotGotoStationAndUnload extends AIRobot {
zone = iZone;
}
public AIRobotGotoStationAndUnload(EntityRobotBase iRobot, DockingStation iStation) {
super(iRobot);
station = iStation;
}
@Override
public void start() {
startDelegateAI(new AIRobotGotoStationToUnload(robot, zone));
if (station == null) {
startDelegateAI(new AIRobotGotoStationToUnload(robot, zone));
} else {
startDelegateAI(new AIRobotGotoStation(robot, station));
}
}
@Override
@ -41,6 +52,13 @@ public class AIRobotGotoStationAndUnload extends AIRobot {
} else {
terminate();
}
} else if (ai instanceof AIRobotGotoStation) {
if (ai.success()) {
found = true;
startDelegateAI(new AIRobotUnload(robot));
} else {
terminate();
}
}
}

View file

@ -22,6 +22,7 @@ import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
@ -849,4 +850,19 @@ public class EntityRobot extends EntityRobotBase implements
public void releaseResources() {
getRegistry().releaseResources(this);
}
/**
* Tries to receive items in parameters, return items that are left after
* the operation.
*/
public ItemStack receiveItem(TileEntity tile, ItemStack stack) {
if (currentDockingStation != null
&& currentDockingStation.index().nextTo(new BlockIndex(tile))
&& mainAI != null) {
return mainAI.getActiveAI().receiveItem(stack);
} else {
return stack;
}
}
}

View file

@ -0,0 +1,24 @@
/**
* Copyright (c) 2011-2014, SpaceToad and the BuildCraft Team
* http://www.mod-buildcraft.com
*
* BuildCraft is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package buildcraft.core.robots;
import buildcraft.api.core.BlockIndex;
import buildcraft.silicon.TileAssemblyTable;
public class ResourceIdAssemblyTable extends ResourceId {
public ResourceIdAssemblyTable() {
}
public ResourceIdAssemblyTable(TileAssemblyTable tile) {
index = new BlockIndex(tile);
}
}

View file

@ -77,10 +77,10 @@ public class RobotRegistry extends WorldSavedData {
}
public boolean isTaken(ResourceId resourceId) {
return robotTaking(resourceId) != EntityRobotBase.NULL_ROBOT_ID;
return robotIdTaking(resourceId) != EntityRobotBase.NULL_ROBOT_ID;
}
public long robotTaking(ResourceId resourceId) {
public long robotIdTaking(ResourceId resourceId) {
if (!resourcesTaken.containsKey(resourceId)) {
return EntityRobotBase.NULL_ROBOT_ID;
}
@ -97,6 +97,16 @@ public class RobotRegistry extends WorldSavedData {
}
}
public EntityRobot robotTaking(ResourceId resourceId) {
long robotId = robotIdTaking(resourceId);
if (robotId == EntityRobotBase.NULL_ROBOT_ID || !robotsLoaded.containsKey(robotId)) {
return null;
} else {
return robotsLoaded.get(robotId);
}
}
public boolean take(ResourceId resourceId, EntityRobotBase robot) {
markDirty();
@ -151,7 +161,8 @@ public class RobotRegistry extends WorldSavedData {
markDirty();
if (resourcesTakenByRobot.containsKey(robot.getRobotId())) {
HashSet<ResourceId> resourceSet = resourcesTakenByRobot.get(robot.getRobotId());
HashSet<ResourceId> resourceSet = (HashSet<ResourceId>) resourcesTakenByRobot.get(robot.getRobotId())
.clone();
ResourceId mainId = null;

View file

@ -26,10 +26,14 @@ import buildcraft.api.boards.RedstoneBoardRobot;
import buildcraft.api.boards.RedstoneBoardRobotNBT;
import buildcraft.api.gates.ActionParameterItemStack;
import buildcraft.api.gates.IActionParameter;
import buildcraft.api.recipes.CraftingResult;
import buildcraft.api.recipes.IFlexibleRecipe;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.api.robots.IDockingStation;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.recipes.AssemblyRecipeManager;
import buildcraft.core.robots.AIRobotCraftAssemblyTable;
import buildcraft.core.robots.AIRobotCraftFurnace;
import buildcraft.core.robots.AIRobotCraftGeneric;
import buildcraft.core.robots.AIRobotCraftWorkbench;
@ -69,6 +73,7 @@ public class BoardRobotCrafter extends RedstoneBoardRobot {
}
order = getCraftingOrder();
robot.releaseResources();
if (order == null) {
craftingBlacklist.clear();
@ -87,19 +92,15 @@ public class BoardRobotCrafter extends RedstoneBoardRobot {
if (furnaceInput != null) {
startDelegateAI(new AIRobotCraftFurnace(robot, furnaceInput));
return;
}
/*
* recipe = lookForAssemblyTableRecipe(order);
*
* if (recipe != null) { startDelegateAI(new
* AIRobotCraftAssemblyTable(robot)); }
*
* recipe = lookForIntegrationTableRecipe(order);
*
* if (recipe != null) { startDelegateAI(new
* AIRobotCraftIntegrationTable(robot)); }
*/
CraftingResult craftingResult = lookForAssemblyTableRecipe(order);
if (craftingResult != null) {
startDelegateAI(new AIRobotCraftAssemblyTable(robot, craftingResult));
return;
}
craftingBlacklist.add(order);
}
@ -153,6 +154,18 @@ public class BoardRobotCrafter extends RedstoneBoardRobot {
return null;
}
private CraftingResult<?> lookForAssemblyTableRecipe(ItemStack order) {
for (IFlexibleRecipe r : AssemblyRecipeManager.INSTANCE.getRecipes()) {
CraftingResult<?> result = r.canCraft(order);
if (result != null) {
return result;
}
}
return null;
}
private boolean isBlacklisted(ItemStack stack) {
for (ItemStack black : craftingBlacklist) {
if (StackHelper.isMatchingItem(stack, black)) {

View file

@ -35,6 +35,9 @@ import buildcraft.core.network.RPC;
import buildcraft.core.network.RPCHandler;
import buildcraft.core.network.RPCSide;
import buildcraft.core.recipes.AssemblyRecipeManager;
import buildcraft.core.robots.EntityRobot;
import buildcraft.core.robots.ResourceIdAssemblyTable;
import buildcraft.core.robots.RobotRegistry;
import buildcraft.core.triggers.ActionMachineControl;
import buildcraft.core.utils.StringUtils;
import buildcraft.core.utils.Utils;
@ -90,13 +93,24 @@ public class TileAssemblyTable extends TileLaserTableBase implements IMachine, I
if (currentRecipe.canBeCrafted(this)) {
ItemStack remaining = currentRecipe.craft(this, false).crafted.copy();
remaining.stackSize -= Utils.addToRandomInventoryAround(worldObj, xCoord, yCoord, zCoord, remaining);
if (remaining.stackSize > 0) {
EntityRobot robot = RobotRegistry.getRegistry(worldObj)
.robotTaking(new ResourceIdAssemblyTable(this));
if (robot != null) {
remaining = robot.receiveItem(this, remaining);
}
if (remaining != null && remaining.stackSize > 0) {
remaining.stackSize -= Utils
.addToRandomInventoryAround(worldObj, xCoord, yCoord, zCoord, remaining);
}
if (remaining != null && remaining.stackSize > 0) {
remaining.stackSize -= Utils.addToRandomPipeAround(worldObj, xCoord, yCoord, zCoord, ForgeDirection.UNKNOWN, remaining);
}
if (remaining.stackSize > 0) {
if (remaining != null && remaining.stackSize > 0) {
EntityItem entityitem = new EntityItem(worldObj, xCoord + 0.5, yCoord + 0.7, zCoord + 0.5,
remaining);

View file

@ -41,4 +41,9 @@ public class BoardRecipe extends FlexibleRecipe {
return null;
}
}
@Override
public CraftingResult canCraft(ItemStack expectedOutput) {
return null;
}
}

View file

@ -48,4 +48,9 @@ public abstract class IntegrationTableRecipe extends FlexibleRecipe<ItemStack> i
ItemStack inputB) {
return super.craft(crafter, preview);
}
@Override
public CraftingResult canCraft(ItemStack expectedOutput) {
return null;
}
}