progress in interaction of crafting robot and furnace, for #1973

This commit is contained in:
SpaceToad 2014-08-08 09:36:11 +02:00
parent 0b6ff77515
commit 0e78b4a308
9 changed files with 391 additions and 85 deletions

View file

@ -8,16 +8,11 @@
*/
package buildcraft.api.boards;
import java.util.HashSet;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
public abstract class RedstoneBoardRobot extends AIRobot implements IRedstoneBoard<EntityRobotBase> {
public static HashSet<BlockIndex> reservedBlocks = new HashSet<BlockIndex>();
public RedstoneBoardRobot(EntityRobotBase iRobot) {
super(iRobot);
}
@ -30,32 +25,4 @@ public abstract class RedstoneBoardRobot extends AIRobot implements IRedstoneBoa
}
// TODO: we should put the three calls below into one object making sure
// that blocks are released before being assigned again, and which has a
// finalize () method to free potential block upon garbage collection.
public static boolean isFreeBlock(BlockIndex index) {
synchronized (reservedBlocks) {
return !reservedBlocks.contains(index);
}
}
public static boolean reserveBlock(BlockIndex index) {
synchronized (reservedBlocks) {
if (!reservedBlocks.contains(index)) {
reservedBlocks.add(index);
return true;
} else {
return false;
}
}
}
public static void releaseBlock(BlockIndex index) {
synchronized (reservedBlocks) {
if (reservedBlocks.contains(index)) {
reservedBlocks.remove(index);
}
}
}
}

View file

@ -11,6 +11,7 @@ package buildcraft.api.core;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
/**
@ -23,7 +24,7 @@ public class BlockIndex implements Comparable<BlockIndex> {
public int z;
public BlockIndex() {
}
/**
@ -48,6 +49,10 @@ public class BlockIndex implements Comparable<BlockIndex> {
z = (int) Math.floor(entity.posZ);
}
public BlockIndex(TileEntity entity) {
this(entity.xCoord, entity.yCoord, entity.xCoord);
}
/**
* Provides a deterministic and complete ordering of block positions.
*/

View file

@ -8,9 +8,20 @@
*/
package buildcraft.api.robots;
import java.util.HashSet;
import net.minecraft.nbt.NBTTagCompound;
import buildcraft.api.core.BlockIndex;
public class AIRobot {
// TODO: we need a more generic resource handler here, for:
// - blocks taken by robots
// - stations reserved by robots
// - orders taken by robots
// and possibly others.
public static HashSet<BlockIndex> reservedBlocks = new HashSet<BlockIndex>();
public EntityRobotBase robot;
private AIRobot delegateAI;
@ -179,4 +190,32 @@ public class AIRobot {
return ai;
}
// TODO: we should put the three calls below into one object making sure
// that blocks are released before being assigned again, and which has a
// finalize () method to free potential block upon garbage collection.
public static boolean isFreeBlock(BlockIndex index) {
synchronized (reservedBlocks) {
return !reservedBlocks.contains(index);
}
}
public static boolean reserveBlock(BlockIndex index) {
synchronized (reservedBlocks) {
if (!reservedBlocks.contains(index)) {
reservedBlocks.add(index);
return true;
} else {
return false;
}
}
}
public static void releaseBlock(BlockIndex index) {
synchronized (reservedBlocks) {
if (reservedBlocks.contains(index)) {
reservedBlocks.remove(index);
}
}
}
}

View file

@ -10,21 +10,122 @@ package buildcraft.core.robots;
import java.util.ArrayList;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFurnace;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraftforge.common.util.ForgeDirection;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.core.IInvSlot;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.core.inventory.InventoryIterator;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.inventory.filters.ArrayStackFilter;
import buildcraft.core.inventory.filters.IStackFilter;
public class AIRobotCraftFurnace extends AIRobotCraftGeneric {
private static final int INPUT_SLOT = 0;
private static final int FUEL_SLOT = 1;
private static final int OUTPUT_SLOT = 2;
private ItemStack input;
private DockingStation stationFound;
private TileEntityFurnace furnace;
public AIRobotCraftFurnace(EntityRobotBase iRobot) {
super(iRobot);
}
public AIRobotCraftFurnace(EntityRobotBase iRobot, ItemStack iInput) {
super(iRobot);
input = iInput;
}
@Override
public void start() {
startDelegateAI(new AIRobotSearchStation(robot, new StationFurnaceFilter(), robot.getZoneToWork()));
}
@Override
public void update() {
if (furnace != null) {
if (furnace.getStackInSlot(FUEL_SLOT) == null && getItem(new FuelFilter()) == null) {
startDelegateAI(new AIRobotGotoStationAndLoad(robot, new FuelFilter(), robot.getZoneToWork()));
return;
}
if (getItem(new ArrayStackFilter(input)) == null) {
startDelegateAI(new AIRobotGotoStationAndLoad(robot, new ArrayStackFilter(input), robot.getZoneToWork()));
return;
}
if (robot.getDockingStation() != stationFound) {
startDelegateAI(new AIRobotGotoStation(robot, stationFound));
return;
}
// TODO: Does this need a timing thing?
if (furnace.getStackInSlot(FUEL_SLOT) == null) {
IInvSlot s = getItem(new FuelFilter());
furnace.setInventorySlotContents(FUEL_SLOT, s.decreaseStackInSlot(1));
}
if (furnace.getStackInSlot(INPUT_SLOT) == null) {
IInvSlot s = getItem(new ArrayStackFilter(input));
furnace.setInventorySlotContents(INPUT_SLOT, s.decreaseStackInSlot(1));
}
// TODO: Create a delegate AI, waiting until the thing is done
terminate();
}
}
@Override
public void delegateAIEnded(AIRobot ai) {
if (ai instanceof AIRobotSearchStation) {
if (!ai.success()) {
crafted = false;
terminate();
} else {
stationFound = ((AIRobotSearchStation) ai).targetStation;
furnace = getUsableFurnace(new BlockIndex(stationFound.x(), stationFound.y(), stationFound.z()));
if (furnace == null) {
terminate();
return;
}
BlockIndex index = new BlockIndex(furnace);
if (!reserveBlock(index)) {
terminate();
}
robot.reserveStation(stationFound);
}
} 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
@ -35,4 +136,66 @@ public class AIRobotCraftFurnace extends AIRobotCraftGeneric {
// How to operate assembly tables
private class StationFurnaceFilter implements IStationFilter {
@Override
public boolean matches(DockingStation station) {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (getUsableFurnace(new BlockIndex(station.x(), station.y(), station.z())) != null) {
return true;
}
}
return false;
}
}
private class FuelFilter implements IStackFilter {
@Override
public boolean matches(ItemStack stack) {
return TileEntityFurnace.getItemBurnTime(stack) > 0 && !StackHelper.isMatchingItem(stack, input);
}
}
private TileEntityFurnace getUsableFurnace(BlockIndex b) {
// reserve that furnace if found from the block reserve system
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
BlockIndex index = new BlockIndex (b.x + dir.offsetX, b.y
+ dir.offsetY, b.z
+ dir.offsetZ);
if (!isFreeBlock(index)) {
continue;
}
Block nearbyBlock = robot.worldObj.getBlock(index.x, index.y, index.z);
if (nearbyBlock instanceof BlockFurnace) {
TileEntityFurnace f = (TileEntityFurnace) robot.worldObj.getTileEntity(index.x, index.y, index.z);
if (f.getStackInSlot(INPUT_SLOT) != null
&& !StackHelper.isMatchingItem(input, f.getStackInSlot(INPUT_SLOT))) {
continue;
}
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;
}
}

View file

@ -0,0 +1,54 @@
/**
* 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.IZone;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.core.inventory.filters.IStackFilter;
public class AIRobotGotoStationAndLoad extends AIRobot {
private boolean found = false;
private IStackFilter filter;
private IZone zone;
public AIRobotGotoStationAndLoad(EntityRobotBase iRobot) {
super(iRobot);
}
public AIRobotGotoStationAndLoad(EntityRobotBase iRobot, IStackFilter iFilter, IZone iZone) {
super(iRobot);
filter = iFilter;
zone = iZone;
}
@Override
public void start() {
startDelegateAI(new AIRobotGotoStationToLoad(robot, filter, zone));
}
@Override
public void delegateAIEnded(AIRobot ai) {
if (ai instanceof AIRobotGotoStationToLoad) {
if (ai.success()) {
found = true;
startDelegateAI(new AIRobotLoad(robot, filter, 1));
} else {
terminate();
}
}
}
@Override
public boolean success() {
return found;
}
}

View file

@ -10,10 +10,7 @@ package buildcraft.core.robots;
import buildcraft.api.core.IZone;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.DockingStationRegistry;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.api.robots.IDockingStation;
import buildcraft.silicon.statements.ActionStationForbidRobot;
public class AIRobotSearchAndGotoStation extends AIRobot {
@ -34,54 +31,21 @@ public class AIRobotSearchAndGotoStation extends AIRobot {
@Override
public void start() {
if (robot.getDockingStation() != null
&& filter.matches((DockingStation) robot.getDockingStation())) {
targetStation = (DockingStation) robot.getDockingStation();
terminate();
return;
}
double potentialStationDistance = Float.MAX_VALUE;
DockingStation potentialStation = null;
for (IDockingStation d : DockingStationRegistry.getStations()) {
DockingStation station = (DockingStation) d;
if (station.reserved() != null) {
continue;
}
if (zone != null && !zone.contains(d.x(), d.y(), d.z())) {
continue;
}
if (filter.matches(station)) {
if (ActionStationForbidRobot.isForbidden(station, robot)) {
continue;
}
double dx = robot.posX - d.x();
double dy = robot.posY - d.y();
double dz = robot.posZ - d.z();
double distance = dx * dx + dy * dy + dz * dz;
if (potentialStation == null || distance < potentialStationDistance) {
potentialStation = station;
potentialStationDistance = distance;
}
}
}
if (potentialStation != null) {
targetStation = potentialStation;
startDelegateAI(new AIRobotGotoStation(robot, potentialStation));
} else {
terminate();
}
startDelegateAI(new AIRobotSearchStation(robot, filter, zone));
}
@Override
public void delegateAIEnded(AIRobot ai) {
terminate();
if (ai instanceof AIRobotSearchStation) {
if (ai.success()) {
targetStation = ((AIRobotSearchStation) ai).targetStation;
startDelegateAI(new AIRobotGotoStation(robot, targetStation));
}
}
}
@Override
public boolean success() {
return targetStation != null;
}
}

View file

@ -0,0 +1,91 @@
/**
* 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.IZone;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.DockingStationRegistry;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.api.robots.IDockingStation;
import buildcraft.silicon.statements.ActionStationForbidRobot;
public class AIRobotSearchStation extends AIRobot {
public DockingStation targetStation;
private IStationFilter filter;
private IZone zone;
public AIRobotSearchStation(EntityRobotBase iRobot) {
super(iRobot);
}
public AIRobotSearchStation(EntityRobotBase iRobot, IStationFilter iFilter, IZone iZone) {
super(iRobot);
filter = iFilter;
zone = iZone;
}
@Override
public void start() {
if (robot.getDockingStation() != null
&& filter.matches((DockingStation) robot.getDockingStation())) {
targetStation = (DockingStation) robot.getDockingStation();
terminate();
return;
}
double potentialStationDistance = Float.MAX_VALUE;
DockingStation potentialStation = null;
for (IDockingStation d : DockingStationRegistry.getStations()) {
DockingStation station = (DockingStation) d;
if (station.reserved() != null) {
continue;
}
if (zone != null && !zone.contains(d.x(), d.y(), d.z())) {
continue;
}
if (filter.matches(station)) {
if (ActionStationForbidRobot.isForbidden(station, robot)) {
continue;
}
double dx = robot.posX - d.x();
double dy = robot.posY - d.y();
double dz = robot.posZ - d.z();
double distance = dx * dx + dy * dy + dz * dz;
if (potentialStation == null || distance < potentialStationDistance) {
potentialStation = station;
potentialStationDistance = distance;
}
}
}
if (potentialStation != null) {
targetStation = potentialStation;
}
terminate();
}
@Override
public void delegateAIEnded(AIRobot ai) {
terminate();
}
@Override
public boolean success () {
return targetStation != null;
}
}

View file

@ -10,9 +10,11 @@ package buildcraft.core.robots.boards;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;
@ -28,6 +30,7 @@ import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.api.robots.IDockingStation;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.robots.AIRobotCraftFurnace;
import buildcraft.core.robots.AIRobotCraftGeneric;
import buildcraft.core.robots.AIRobotCraftWorkbench;
import buildcraft.core.robots.AIRobotGotoSleep;
@ -81,10 +84,13 @@ public class BoardRobotCrafter extends RedstoneBoardRobot {
return;
}
ItemStack furnaceInput = lookForFurnaceRecipe(order);
if (furnaceInput != null) {
startDelegateAI(new AIRobotCraftFurnace(robot, furnaceInput));
}
/*
* if (hasFurnaceRecipe(order)) { startDelegateAI(new
* AIRobotCraftFurnace(robot)); }
*
* recipe = lookForAssemblyTableRecipe(order);
*
* if (recipe != null) { startDelegateAI(new
@ -134,6 +140,20 @@ public class BoardRobotCrafter extends RedstoneBoardRobot {
return null;
}
private ItemStack lookForFurnaceRecipe(ItemStack order) {
for (Object o : FurnaceRecipes.smelting().getSmeltingList().entrySet()) {
Map.Entry e = (Map.Entry) o;
ItemStack input = (ItemStack) e.getKey();
ItemStack output = (ItemStack) e.getValue();
if (StackHelper.isMatchingItem(output, order)) {
return input;
}
}
return null;
}
private boolean isBlacklisted(ItemStack stack) {
for (ItemStack black : craftingBlacklist) {
if (StackHelper.isMatchingItem(stack, black)) {

View file

@ -69,6 +69,9 @@ public class PathFinding {
maxDistanceToEnd = iMaxDistanceToEnd;
}
// TODO: It's probably more efficient to start a search first, and then to
// compute the path, instead of computing all possible path from the get
// go.
public PathFinding(World iWorld, BlockIndex iStart, IBlockFilter iPathFound, float iMaxDistance, IZone iZone) {
world = iWorld;
start = iStart;