From 0e78b4a308b6e352a5d08eb7468460d0fd3e2532 Mon Sep 17 00:00:00 2001 From: SpaceToad Date: Fri, 8 Aug 2014 09:36:11 +0200 Subject: [PATCH] progress in interaction of crafting robot and furnace, for #1973 --- .../api/boards/RedstoneBoardRobot.java | 33 ---- api/buildcraft/api/core/BlockIndex.java | 7 +- api/buildcraft/api/robots/AIRobot.java | 39 +++++ .../core/robots/AIRobotCraftFurnace.java | 163 ++++++++++++++++++ .../robots/AIRobotGotoStationAndLoad.java | 54 ++++++ .../robots/AIRobotSearchAndGotoStation.java | 60 ++----- .../core/robots/AIRobotSearchStation.java | 91 ++++++++++ .../core/robots/boards/BoardRobotCrafter.java | 26 ++- common/buildcraft/core/utils/PathFinding.java | 3 + 9 files changed, 391 insertions(+), 85 deletions(-) create mode 100755 common/buildcraft/core/robots/AIRobotGotoStationAndLoad.java create mode 100755 common/buildcraft/core/robots/AIRobotSearchStation.java diff --git a/api/buildcraft/api/boards/RedstoneBoardRobot.java b/api/buildcraft/api/boards/RedstoneBoardRobot.java index 68225161..f084cc71 100755 --- a/api/buildcraft/api/boards/RedstoneBoardRobot.java +++ b/api/buildcraft/api/boards/RedstoneBoardRobot.java @@ -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 { - public static HashSet reservedBlocks = new HashSet(); - 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); - } - } - } - } diff --git a/api/buildcraft/api/core/BlockIndex.java b/api/buildcraft/api/core/BlockIndex.java index 6024155d..91fb05b4 100644 --- a/api/buildcraft/api/core/BlockIndex.java +++ b/api/buildcraft/api/core/BlockIndex.java @@ -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 { public int z; public BlockIndex() { - + } /** @@ -48,6 +49,10 @@ public class BlockIndex implements Comparable { 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. */ diff --git a/api/buildcraft/api/robots/AIRobot.java b/api/buildcraft/api/robots/AIRobot.java index 1a45f639..e2101ac3 100755 --- a/api/buildcraft/api/robots/AIRobot.java +++ b/api/buildcraft/api/robots/AIRobot.java @@ -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 reservedBlocks = new HashSet(); + 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); + } + } + } } diff --git a/common/buildcraft/core/robots/AIRobotCraftFurnace.java b/common/buildcraft/core/robots/AIRobotCraftFurnace.java index f8bbacb2..2a767a0f 100755 --- a/common/buildcraft/core/robots/AIRobotCraftFurnace.java +++ b/common/buildcraft/core/robots/AIRobotCraftFurnace.java @@ -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 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; + } + } diff --git a/common/buildcraft/core/robots/AIRobotGotoStationAndLoad.java b/common/buildcraft/core/robots/AIRobotGotoStationAndLoad.java new file mode 100755 index 00000000..73147daa --- /dev/null +++ b/common/buildcraft/core/robots/AIRobotGotoStationAndLoad.java @@ -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; + } +} diff --git a/common/buildcraft/core/robots/AIRobotSearchAndGotoStation.java b/common/buildcraft/core/robots/AIRobotSearchAndGotoStation.java index 1afe472c..4611f5e8 100755 --- a/common/buildcraft/core/robots/AIRobotSearchAndGotoStation.java +++ b/common/buildcraft/core/robots/AIRobotSearchAndGotoStation.java @@ -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; } } diff --git a/common/buildcraft/core/robots/AIRobotSearchStation.java b/common/buildcraft/core/robots/AIRobotSearchStation.java new file mode 100755 index 00000000..86ba6de3 --- /dev/null +++ b/common/buildcraft/core/robots/AIRobotSearchStation.java @@ -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; + } +} diff --git a/common/buildcraft/core/robots/boards/BoardRobotCrafter.java b/common/buildcraft/core/robots/boards/BoardRobotCrafter.java index 5a855961..290f42a4 100755 --- a/common/buildcraft/core/robots/boards/BoardRobotCrafter.java +++ b/common/buildcraft/core/robots/boards/BoardRobotCrafter.java @@ -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)) { diff --git a/common/buildcraft/core/utils/PathFinding.java b/common/buildcraft/core/utils/PathFinding.java index 4b4de6b1..b274678a 100755 --- a/common/buildcraft/core/utils/PathFinding.java +++ b/common/buildcraft/core/utils/PathFinding.java @@ -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;