diff --git a/api/buildcraft/api/crops/CropManager.java b/api/buildcraft/api/crops/CropManager.java new file mode 100644 index 00000000..ae5e5e48 --- /dev/null +++ b/api/buildcraft/api/crops/CropManager.java @@ -0,0 +1,57 @@ +package buildcraft.api.crops; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class CropManager { + + private static List handlers = new ArrayList(); + + public static void registerHandler(ICropHandler cropHandler) { + handlers.add(cropHandler); + } + + public static boolean isSeed(ItemStack stack) { + for (ICropHandler cropHandler : handlers) { + if (cropHandler.isSeed(stack)) { + return true; + } + } + return false; + } + + public static boolean canSustainPlant(World world, ItemStack seed, int x, int y, int z) { + for (ICropHandler cropHandler : handlers) { + if (cropHandler.isSeed(seed) && cropHandler.canSustainPlant(world, seed, x, y, z)) + return true; + } + return false; + } + + public static boolean isMature(IBlockAccess blockAccess, Block block, int meta, int x, int y, + int z) { + for (ICropHandler cropHandler : handlers) { + if (cropHandler.isMature(blockAccess, block, meta, x, y, z)) { + return true; + } + } + return false; + } + + public static boolean harvestCrop(World world, int x, int y, int z, List drops) { + for (ICropHandler cropHandler : handlers) { + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + if (cropHandler.isMature(world, block, meta, x, y, z)) { + return cropHandler.harvestCrop(world, x, y, z, drops); + } + } + return false; + } + +} diff --git a/api/buildcraft/api/crops/ICropHandler.java b/api/buildcraft/api/crops/ICropHandler.java new file mode 100644 index 00000000..7bf67030 --- /dev/null +++ b/api/buildcraft/api/crops/ICropHandler.java @@ -0,0 +1,59 @@ +package buildcraft.api.crops; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public interface ICropHandler { + + /** + * Check if an item is a seed. + * + * @param stack + * @return true if the item can be planted. + */ + boolean isSeed(ItemStack stack); + + /** + * Check if the item can be planted. You can assume canSustainPlant() will + * only be called if isSeed() returned true. + * + * @param world + * @param seed + * @param x + * @param y + * @param z + * @return true if the item can be planted at (x, y, z). + */ + boolean canSustainPlant(World world, ItemStack seed, int x, int y, int z); + + /** + * Check if a crop is mature and can be harvested. + * + * @param blockAccess + * @param block + * @param meta + * @param x + * @param y + * @param z + * @return true if the block at (x, y, z) is mature and can be harvested. + */ + boolean isMature(IBlockAccess blockAccess, Block block, int meta, int x, int y, int z); + + /** + * Harvest the crop. You can assume harvestCrop() will only be called if + * isMature() returned true. + * + * @param world + * @param x + * @param y + * @param z + * @param drops a list to return the harvest's drops. + * @return true if the block was successfully harvested. + */ + boolean harvestCrop(World world, int x, int y, int z, List drops); + +} diff --git a/common/buildcraft/BuildCraftCore.java b/common/buildcraft/BuildCraftCore.java index 78e0b7ee..58fd4e33 100644 --- a/common/buildcraft/BuildCraftCore.java +++ b/common/buildcraft/BuildCraftCore.java @@ -15,6 +15,7 @@ import java.nio.IntBuffer; import java.util.UUID; import com.mojang.authlib.GameProfile; + import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; @@ -29,6 +30,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.stats.Achievement; import net.minecraft.util.IIcon; + import cpw.mods.fml.client.event.ConfigChangedEvent; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Mod; @@ -42,6 +44,7 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; + import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.common.IPlantable; @@ -56,6 +59,7 @@ import buildcraft.api.core.BuildCraftAPI; import buildcraft.api.core.EnumColor; import buildcraft.api.core.IIconProvider; import buildcraft.api.core.IWorldProperty; +import buildcraft.api.crops.CropManager; import buildcraft.api.recipes.BuildcraftRecipeRegistry; import buildcraft.api.statements.IActionExternal; import buildcraft.api.statements.IActionInternal; @@ -93,6 +97,8 @@ import buildcraft.core.command.SubCommandChangelog; import buildcraft.core.command.SubCommandVersion; import buildcraft.core.config.BuildCraftConfiguration; import buildcraft.core.config.ConfigManager; +import buildcraft.core.crops.CropHandlerPlantable; +import buildcraft.core.crops.CropHandlerReeds; import buildcraft.core.lib.commands.RootCommand; import buildcraft.core.lib.engines.ItemEngine; import buildcraft.core.lib.engines.TileEngineBase; @@ -427,6 +433,9 @@ public class BuildCraftCore extends BuildCraftMod { FMLCommonHandler.instance().bus().register(new TickHandlerCore()); + CropManager.registerHandler(new CropHandlerPlantable()); + CropManager.registerHandler(new CropHandlerReeds()); + BuildCraftAPI.registerWorldProperty("soft", new WorldPropertyIsSoft()); BuildCraftAPI.registerWorldProperty("wood", new WorldPropertyIsWood()); BuildCraftAPI.registerWorldProperty("leaves", new WorldPropertyIsLeaf()); diff --git a/common/buildcraft/BuildCraftRobotics.java b/common/buildcraft/BuildCraftRobotics.java index 99a07689..48861fbc 100644 --- a/common/buildcraft/BuildCraftRobotics.java +++ b/common/buildcraft/BuildCraftRobotics.java @@ -84,6 +84,7 @@ import buildcraft.robotics.ai.AIRobotGotoStationToLoad; import buildcraft.robotics.ai.AIRobotGotoStationToLoadFluids; import buildcraft.robotics.ai.AIRobotGotoStationToUnload; import buildcraft.robotics.ai.AIRobotGotoStationToUnloadFluids; +import buildcraft.robotics.ai.AIRobotHarvest; import buildcraft.robotics.ai.AIRobotLoad; import buildcraft.robotics.ai.AIRobotLoadFluids; import buildcraft.robotics.ai.AIRobotMain; @@ -309,6 +310,7 @@ public class BuildCraftRobotics extends BuildCraftMod { RobotManager.registerAIRobot(AIRobotGotoStationToLoadFluids.class, "aiRobotGotoStationToLoadFluids", "buildcraft.core.robots.AIRobotGotoStationToLoadFluids"); RobotManager.registerAIRobot(AIRobotGotoStationToUnload.class, "aiRobotGotoStationToUnload", "buildcraft.core.robots.AIRobotGotoStationToUnload"); RobotManager.registerAIRobot(AIRobotGotoStationToUnloadFluids.class, "aiRobotGotoStationToUnloadFluids", "buildcraft.core.robots.AIRobotGotoStationToUnloadFluids"); + RobotManager.registerAIRobot(AIRobotHarvest.class, "aiRobotHarvest"); RobotManager.registerAIRobot(AIRobotLoad.class, "aiRobotLoad", "buildcraft.core.robots.AIRobotLoad"); RobotManager.registerAIRobot(AIRobotLoadFluids.class, "aiRobotLoadFluids", "buildcraft.core.robots.AIRobotLoadFluids"); RobotManager.registerAIRobot(AIRobotPumpBlock.class, "aiRobotPumpBlock", "buildcraft.core.robots.AIRobotPumpBlock"); diff --git a/common/buildcraft/core/crops/CropHandlerPlantable.java b/common/buildcraft/core/crops/CropHandlerPlantable.java new file mode 100644 index 00000000..befcf1c6 --- /dev/null +++ b/common/buildcraft/core/crops/CropHandlerPlantable.java @@ -0,0 +1,93 @@ +package buildcraft.core.crops; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockCrops; +import net.minecraft.block.BlockDoublePlant; +import net.minecraft.block.BlockFlower; +import net.minecraft.block.BlockMelon; +import net.minecraft.block.BlockMushroom; +import net.minecraft.block.BlockTallGrass; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.crops.ICropHandler; +import buildcraft.core.lib.utils.BlockUtils; + +public class CropHandlerPlantable implements ICropHandler { + + @Override + public boolean isSeed(ItemStack stack) { + if (stack.getItem() instanceof IPlantable) { + return true; + } + + if (stack.getItem() instanceof ItemBlock) { + Block block = ((ItemBlock) stack.getItem()).field_150939_a; + if (block instanceof IPlantable && block != Blocks.reeds) { + return true; + } + } + + return false; + } + + @Override + public boolean canSustainPlant(World world, ItemStack seed, int x, int y, int z) { + if (seed.getItem() instanceof IPlantable) { + return world.getBlock(x, y, z).canSustainPlant(world, x, y, z, ForgeDirection.UP, + (IPlantable) seed.getItem()) + && world.isAirBlock(x, y + 1, z); + } else { + Block block = world.getBlock(x, y, z); + IPlantable plantable = (IPlantable) ((ItemBlock) seed.getItem()).field_150939_a; + return block.canSustainPlant(world, x, y, z, ForgeDirection.UP, plantable) + && block != ((ItemBlock) seed.getItem()).field_150939_a + && world.isAirBlock(x, y + 1, z); + } + } + + @Override + public boolean isMature(IBlockAccess blockAccess, Block block, int meta, int x, int y, int z) { + if (block == null) { + return false; + } else if (block instanceof BlockFlower + || block instanceof BlockTallGrass + || block instanceof BlockMelon + || block instanceof BlockMushroom + || block instanceof BlockDoublePlant + || block == Blocks.pumpkin) { + return true; + } else if (block instanceof BlockCrops) { + return meta == 7; + } else if (block instanceof IPlantable) { + if (y > 0 && blockAccess.getBlock(x, y - 1, z) == block) { + return true; + } + } + return false; + } + + @Override + public boolean harvestCrop(World world, int x, int y, int z, List drops) { + if (!world.isRemote) { + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + if (BlockUtils.breakBlock((WorldServer) world, x, y, z, drops)) { + world.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(block) + + (meta << 12)); + return true; + } + } + return false; + } + +} diff --git a/common/buildcraft/core/crops/CropHandlerReeds.java b/common/buildcraft/core/crops/CropHandlerReeds.java new file mode 100644 index 00000000..d93e7a7f --- /dev/null +++ b/common/buildcraft/core/crops/CropHandlerReeds.java @@ -0,0 +1,59 @@ +package buildcraft.core.crops; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.crops.ICropHandler; +import buildcraft.core.lib.utils.BlockUtils; + +public class CropHandlerReeds implements ICropHandler { + + @Override + public boolean isSeed(ItemStack stack) { + return stack.getItem() == Items.reeds; + } + + @Override + public boolean canSustainPlant(World world, ItemStack seed, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + return block.canSustainPlant(world, x, y, z, ForgeDirection.UP, (IPlantable) Blocks.reeds) + && block != Blocks.reeds && world.isAirBlock(x, y + 1, z); + } + + @Override + public boolean isMature(IBlockAccess blockAccess, Block block, int meta, int x, int y, int z) { + if (block == null) { + return false; + } else if (block == Blocks.reeds) { + if (y > 0 && blockAccess.getBlock(x, y - 1, z) == block) { + return true; + } + } + return false; + } + + @Override + public boolean harvestCrop(World world, int x, int y, int z, List drops) { + if (!world.isRemote) { + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + if (BlockUtils.breakBlock((WorldServer) world, x, y, z, drops)) { + world.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(block) + + (meta << 12)); + return true; + } + } + return false; + } + +} diff --git a/common/buildcraft/core/lib/utils/BlockUtils.java b/common/buildcraft/core/lib/utils/BlockUtils.java index c65dd1ac..8f043a5a 100644 --- a/common/buildcraft/core/lib/utils/BlockUtils.java +++ b/common/buildcraft/core/lib/utils/BlockUtils.java @@ -76,6 +76,18 @@ public final class BlockUtils { } public static boolean breakBlock(WorldServer world, int x, int y, int z, int forcedLifespan) { + List items = new ArrayList(); + + if (breakBlock(world, x, y, z, items)) { + for (ItemStack item : items) { + dropItem(world, x, y, z, forcedLifespan, item); + } + return true; + } + return false; + } + + public static boolean breakBlock(WorldServer world, int x, int y, int z, List drops) { BreakEvent breakEvent = new BreakEvent(x, y, z, world, world.getBlock(x, y, z), world.getBlockMetadata(x, y, z), CoreProxy.proxy.getBuildCraftPlayer(world).get()); MinecraftForge.EVENT_BUS.post(breakEvent); @@ -84,14 +96,10 @@ public final class BlockUtils { return false; } - if (!world.isAirBlock(x, y, z) && !world.isRemote && world.getGameRules().getGameRuleBooleanValue("doTileDrops")) { - List items = getItemStackFromBlock(world, x, y, z); - - for (ItemStack item : items) { - dropItem(world, x, y, z, forcedLifespan, item); - } + if (!world.isAirBlock(x, y, z) && !world.isRemote + && world.getGameRules().getGameRuleBooleanValue("doTileDrops")) { + drops.addAll(getItemStackFromBlock(world, x, y, z)); } - world.setBlockToAir(x, y, z); return true; diff --git a/common/buildcraft/core/properties/WorldPropertyIsHarvestable.java b/common/buildcraft/core/properties/WorldPropertyIsHarvestable.java index 349475d3..7620f60f 100755 --- a/common/buildcraft/core/properties/WorldPropertyIsHarvestable.java +++ b/common/buildcraft/core/properties/WorldPropertyIsHarvestable.java @@ -9,36 +9,14 @@ package buildcraft.core.properties; import net.minecraft.block.Block; -import net.minecraft.block.BlockCactus; -import net.minecraft.block.BlockCrops; -import net.minecraft.block.BlockDoublePlant; -import net.minecraft.block.BlockFlower; -import net.minecraft.block.BlockMelon; -import net.minecraft.block.BlockMushroom; -import net.minecraft.block.BlockReed; -import net.minecraft.block.BlockTallGrass; import net.minecraft.world.IBlockAccess; +import buildcraft.api.crops.CropManager; + public class WorldPropertyIsHarvestable extends WorldProperty { @Override public boolean get(IBlockAccess blockAccess, Block block, int meta, int x, int y, int z) { - if (block == null) { - return false; - } else if (block instanceof BlockFlower - || block instanceof BlockTallGrass - || block instanceof BlockMelon - || block instanceof BlockMushroom - || block instanceof BlockDoublePlant) { - return true; - } else if (block instanceof BlockCactus || block instanceof BlockReed) { - if (y > 0 && blockAccess.getBlock(x, y - 1, z) == block) { - return true; - } - } else if (block instanceof BlockCrops) { - return meta == 7; - } - - return false; + return CropManager.isMature(blockAccess, block, meta, x, y, z); } } diff --git a/common/buildcraft/robotics/ai/AIRobotHarvest.java b/common/buildcraft/robotics/ai/AIRobotHarvest.java new file mode 100644 index 00000000..cab72561 --- /dev/null +++ b/common/buildcraft/robotics/ai/AIRobotHarvest.java @@ -0,0 +1,81 @@ +package buildcraft.robotics.ai; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.MathHelper; +import net.minecraft.world.WorldServer; + +import buildcraft.api.core.BlockIndex; +import buildcraft.api.core.BuildCraftAPI; +import buildcraft.api.crops.CropManager; +import buildcraft.api.robots.AIRobot; +import buildcraft.api.robots.EntityRobotBase; +import buildcraft.core.lib.utils.BlockUtils; + +public class AIRobotHarvest extends AIRobot { + + private BlockIndex blockFound; + private int delay = 0; + + public AIRobotHarvest(EntityRobotBase iRobot) { + super(iRobot); + } + + public AIRobotHarvest(EntityRobotBase iRobot, BlockIndex iBlockFound) { + super(iRobot); + blockFound = iBlockFound; + } + + @Override + public void update() { + if (blockFound == null) { + setSuccess(false); + terminate(); + return; + } + + if (delay++ > 20) { + if (!BuildCraftAPI.getWorldProperty("harvestable").get(robot.worldObj, blockFound.x, + blockFound.y, blockFound.z)) { + setSuccess(false); + terminate(); + return; + } + List drops = new ArrayList(); + if (!CropManager.harvestCrop(robot.worldObj, blockFound.x, blockFound.y, blockFound.z, + drops)) { + setSuccess(false); + terminate(); + return; + } + for (ItemStack stack : drops) { + BlockUtils.dropItem((WorldServer) robot.worldObj, + MathHelper.floor_double(robot.posX), MathHelper.floor_double(robot.posY), + MathHelper.floor_double(robot.posZ), 6000, stack); + } + } + } + + @Override + public void writeSelfToNBT(NBTTagCompound nbt) { + super.writeSelfToNBT(nbt); + + if (blockFound != null) { + NBTTagCompound sub = new NBTTagCompound(); + blockFound.writeTo(sub); + nbt.setTag("blockFound", sub); + } + } + + @Override + public void loadSelfFromNBT(NBTTagCompound nbt) { + super.loadSelfFromNBT(nbt); + + if (nbt.hasKey("blockFound")) { + blockFound = new BlockIndex(nbt.getCompoundTag("blockFound")); + } + } +} diff --git a/common/buildcraft/robotics/boards/BoardRobotGenericBreakBlock.java b/common/buildcraft/robotics/boards/BoardRobotGenericBreakBlock.java index 30c3f20c..13441aa1 100644 --- a/common/buildcraft/robotics/boards/BoardRobotGenericBreakBlock.java +++ b/common/buildcraft/robotics/boards/BoardRobotGenericBreakBlock.java @@ -8,36 +8,15 @@ */ package buildcraft.robotics.boards; -import java.util.ArrayList; - -import net.minecraft.block.Block; -import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.World; -import buildcraft.api.boards.RedstoneBoardRobot; -import buildcraft.api.core.BlockIndex; import buildcraft.api.robots.AIRobot; import buildcraft.api.robots.EntityRobotBase; -import buildcraft.api.robots.ResourceIdBlock; -import buildcraft.api.statements.IStatementParameter; -import buildcraft.api.statements.StatementParameterItemStack; -import buildcraft.api.statements.StatementSlot; import buildcraft.core.lib.inventory.filters.IStackFilter; -import buildcraft.core.lib.utils.IBlockFilter; import buildcraft.robotics.ai.AIRobotBreak; import buildcraft.robotics.ai.AIRobotFetchAndEquipItemStack; -import buildcraft.robotics.ai.AIRobotGotoSleep; -import buildcraft.robotics.ai.AIRobotSearchAndGotoBlock; -import buildcraft.robotics.statements.ActionRobotFilter; -public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot { - - protected BlockIndex blockFound; - - private ArrayList blockFilter = new ArrayList(); - private ArrayList metaFilter = new ArrayList(); +public abstract class BoardRobotGenericBreakBlock extends BoardRobotGenericSearchBlock { public BoardRobotGenericBreakBlock(EntityRobotBase iRobot) { super(iRobot); @@ -45,13 +24,6 @@ public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot { public abstract boolean isExpectedTool(ItemStack stack); - /** - * This function has to be derived in a thread safe manner, as it may be - * called from parallel jobs. In particular, world should not be directly - * used, only through WorldProperty class and subclasses. - */ - public abstract boolean isExpectedBlock(World world, int x, int y, int z); - @Override public final void update() { if (!isExpectedTool(null) && robot.getHeldItem() == null) { @@ -61,112 +33,18 @@ public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot { return isExpectedTool(stack); } })); + } else if (blockFound() != null) { + startDelegateAI(new AIRobotBreak(robot, blockFound())); } else { - updateFilter(); - - startDelegateAI(new AIRobotSearchAndGotoBlock(robot, false, new IBlockFilter() { - @Override - public boolean matches(World world, int x, int y, int z) { - if (isExpectedBlock(world, x, y, z) && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z))) { - return matchesGateFilter(world, x, y, z); - } else { - return false; - } - } - })); + super.update(); } } @Override public void delegateAIEnded(AIRobot ai) { - if (ai instanceof AIRobotSearchAndGotoBlock) { - if (ai.success()) { - blockFound = ((AIRobotSearchAndGotoBlock) ai).getBlockFound(); - startDelegateAI(getBlockBreakAI()); - } else { - startDelegateAI(new AIRobotGotoSleep(robot)); - } - } else if (ai.getClass().isInstance(getBlockBreakAI())) { - // TODO: if !ai.success() -> can't break block, blacklist it - releaseBlockFound(); - } - } - - protected AIRobot getBlockBreakAI() { - return new AIRobotBreak(robot, blockFound); - } - - private void releaseBlockFound() { - if (blockFound != null) { - robot.getRegistry().release(new ResourceIdBlock(blockFound)); - blockFound = null; - } - } - - @Override - public void end() { - releaseBlockFound(); - } - - public final void updateFilter() { - blockFilter.clear(); - metaFilter.clear(); - - for (StatementSlot slot : robot.getLinkedStation().getActiveActions()) { - if (slot.statement instanceof ActionRobotFilter) { - for (IStatementParameter p : slot.parameters) { - if (p != null && p instanceof StatementParameterItemStack) { - StatementParameterItemStack param = (StatementParameterItemStack) p; - ItemStack stack = param.getItemStack(); - - if (stack != null && stack.getItem() instanceof ItemBlock) { - blockFilter.add(((ItemBlock) stack.getItem()).field_150939_a); - metaFilter.add(stack.getItemDamage()); - } - } - } - } - } - } - - private boolean matchesGateFilter(World world, int x, int y, int z) { - if (blockFilter.size() == 0) { - return true; - } - - Block block; - int meta; - synchronized (world) { - block = world.getBlock(x, y, z); - meta = world.getBlockMetadata(x, y, z); - } - - for (int i = 0; i < blockFilter.size(); ++i) { - if (blockFilter.get(i) == block && metaFilter.get(i) == meta) { - return true; - } - } - - return false; - } - - @Override - public void writeSelfToNBT(NBTTagCompound nbt) { - super.writeSelfToNBT(nbt); - - if (blockFound != null) { - NBTTagCompound sub = new NBTTagCompound(); - blockFound.writeTo(sub); - nbt.setTag("indexStored", sub); - } - } - - @Override - public void loadSelfFromNBT(NBTTagCompound nbt) { - super.loadSelfFromNBT(nbt); - - if (nbt.hasKey("indexStored")) { - blockFound = new BlockIndex (nbt.getCompoundTag("indexStored")); + if (ai instanceof AIRobotBreak) { + releaseBlockFound(ai.success()); } + super.delegateAIEnded(ai); } } diff --git a/common/buildcraft/robotics/boards/BoardRobotGenericSearchBlock.java b/common/buildcraft/robotics/boards/BoardRobotGenericSearchBlock.java new file mode 100644 index 00000000..437e7b84 --- /dev/null +++ b/common/buildcraft/robotics/boards/BoardRobotGenericSearchBlock.java @@ -0,0 +1,148 @@ +package buildcraft.robotics.boards; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import buildcraft.api.boards.RedstoneBoardRobot; +import buildcraft.api.core.BlockIndex; +import buildcraft.api.robots.AIRobot; +import buildcraft.api.robots.EntityRobotBase; +import buildcraft.api.robots.ResourceIdBlock; +import buildcraft.api.statements.IStatementParameter; +import buildcraft.api.statements.StatementParameterItemStack; +import buildcraft.api.statements.StatementSlot; +import buildcraft.core.lib.utils.IBlockFilter; +import buildcraft.robotics.ai.AIRobotGotoSleep; +import buildcraft.robotics.ai.AIRobotSearchAndGotoBlock; +import buildcraft.robotics.statements.ActionRobotFilter; + +public abstract class BoardRobotGenericSearchBlock extends RedstoneBoardRobot { + + private BlockIndex blockFound; + private ArrayList blockFilter = new ArrayList(); + private ArrayList metaFilter = new ArrayList(); + + public BoardRobotGenericSearchBlock(EntityRobotBase iRobot) { + super(iRobot); + } + + /** + * This function has to be derived in a thread safe manner, as it may be + * called from parallel jobs. In particular, world should not be directly + * used, only through WorldProperty class and subclasses. + */ + public abstract boolean isExpectedBlock(World world, int x, int y, int z); + + @Override + public void update() { + updateFilter(); + + startDelegateAI(new AIRobotSearchAndGotoBlock(robot, false, new IBlockFilter() { + @Override + public boolean matches(World world, int x, int y, int z) { + if (isExpectedBlock(world, x, y, z) + && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z))) { + return matchesGateFilter(world, x, y, z); + } else { + return false; + } + } + })); + } + + @Override + public void delegateAIEnded(AIRobot ai) { + if (ai instanceof AIRobotSearchAndGotoBlock) { + if (ai.success()) { + blockFound = ((AIRobotSearchAndGotoBlock) ai).getBlockFound(); + } else { + startDelegateAI(new AIRobotGotoSleep(robot)); + } + } + } + + @Override + public void end() { + releaseBlockFound(true); + } + + protected BlockIndex blockFound() { + return blockFound; + } + + protected void releaseBlockFound(boolean success) { + if (blockFound != null) { + // TODO: if !ai.success() -> can't break block, blacklist it + robot.getRegistry().release(new ResourceIdBlock(blockFound)); + blockFound = null; + } + } + + public final void updateFilter() { + blockFilter.clear(); + metaFilter.clear(); + + for (StatementSlot slot : robot.getLinkedStation().getActiveActions()) { + if (slot.statement instanceof ActionRobotFilter) { + for (IStatementParameter p : slot.parameters) { + if (p != null && p instanceof StatementParameterItemStack) { + StatementParameterItemStack param = (StatementParameterItemStack) p; + ItemStack stack = param.getItemStack(); + + if (stack != null && stack.getItem() instanceof ItemBlock) { + blockFilter.add(((ItemBlock) stack.getItem()).field_150939_a); + metaFilter.add(stack.getItemDamage()); + } + } + } + } + } + } + + protected boolean matchesGateFilter(World world, int x, int y, int z) { + if (blockFilter.size() == 0) { + return true; + } + + Block block; + int meta; + synchronized (world) { + block = world.getBlock(x, y, z); + meta = world.getBlockMetadata(x, y, z); + } + + for (int i = 0; i < blockFilter.size(); ++i) { + if (blockFilter.get(i) == block && metaFilter.get(i) == meta) { + return true; + } + } + + return false; + } + + @Override + public void writeSelfToNBT(NBTTagCompound nbt) { + super.writeSelfToNBT(nbt); + + if (blockFound != null) { + NBTTagCompound sub = new NBTTagCompound(); + blockFound.writeTo(sub); + nbt.setTag("indexStored", sub); + } + } + + @Override + public void loadSelfFromNBT(NBTTagCompound nbt) { + super.loadSelfFromNBT(nbt); + + if (nbt.hasKey("indexStored")) { + blockFound = new BlockIndex(nbt.getCompoundTag("indexStored")); + } + } + +} \ No newline at end of file diff --git a/common/buildcraft/robotics/boards/BoardRobotHarvester.java b/common/buildcraft/robotics/boards/BoardRobotHarvester.java index 32d16ec8..8d8e647e 100755 --- a/common/buildcraft/robotics/boards/BoardRobotHarvester.java +++ b/common/buildcraft/robotics/boards/BoardRobotHarvester.java @@ -8,15 +8,16 @@ */ package buildcraft.robotics.boards; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import buildcraft.api.boards.RedstoneBoardRobotNBT; import buildcraft.api.core.BuildCraftAPI; +import buildcraft.api.robots.AIRobot; import buildcraft.api.robots.EntityRobotBase; +import buildcraft.robotics.ai.AIRobotHarvest; -public class BoardRobotHarvester extends BoardRobotGenericBreakBlock { +public class BoardRobotHarvester extends BoardRobotGenericSearchBlock { public BoardRobotHarvester(EntityRobotBase iRobot) { super(iRobot); @@ -31,13 +32,25 @@ public class BoardRobotHarvester extends BoardRobotGenericBreakBlock { return BCBoardNBT.REGISTRY.get("harvester"); } - @Override - public boolean isExpectedTool(ItemStack stack) { - return true; - } - @Override public boolean isExpectedBlock(World world, int x, int y, int z) { return BuildCraftAPI.getWorldProperty("harvestable").get(world, x, y, z); } + + @Override + public void update() { + if (blockFound() != null) { + startDelegateAI(new AIRobotHarvest(robot, blockFound())); + } else { + super.update(); + } + } + + @Override + public void delegateAIEnded(AIRobot ai) { + if (ai instanceof AIRobotHarvest) { + releaseBlockFound(ai.success()); + } + super.delegateAIEnded(ai); + } } diff --git a/common/buildcraft/robotics/boards/BoardRobotPlanter.java b/common/buildcraft/robotics/boards/BoardRobotPlanter.java index b95d3eff..fe6734f0 100644 --- a/common/buildcraft/robotics/boards/BoardRobotPlanter.java +++ b/common/buildcraft/robotics/boards/BoardRobotPlanter.java @@ -8,29 +8,18 @@ */ package buildcraft.robotics.boards; -import java.util.ArrayList; -import java.util.Collection; - -import net.minecraft.block.Block; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.ItemBlock; -import net.minecraft.item.ItemReed; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; -import net.minecraftforge.common.IPlantable; -import net.minecraftforge.common.util.ForgeDirection; import buildcraft.api.boards.RedstoneBoardRobot; import buildcraft.api.boards.RedstoneBoardRobotNBT; import buildcraft.api.core.BlockIndex; +import buildcraft.api.crops.CropManager; import buildcraft.api.robots.AIRobot; import buildcraft.api.robots.EntityRobotBase; import buildcraft.api.robots.ResourceIdBlock; -import buildcraft.core.lib.inventory.filters.ArrayStackFilter; -import buildcraft.core.lib.inventory.filters.ArrayStackOrListFilter; -import buildcraft.core.lib.inventory.filters.CompositeFilter; +import buildcraft.core.lib.inventory.filters.AggregateFilter; import buildcraft.core.lib.inventory.filters.IStackFilter; import buildcraft.core.lib.utils.IBlockFilter; import buildcraft.robotics.ai.AIRobotFetchAndEquipItemStack; @@ -41,8 +30,14 @@ import buildcraft.robotics.statements.ActionRobotFilter; public class BoardRobotPlanter extends RedstoneBoardRobot { - private IStackFilter stackFilter = new CompositeFilter(new PlantableFilter(), new ReedFilter()); private BlockIndex blockFound; + private IStackFilter filter = new IStackFilter() { + + @Override + public boolean matches(ItemStack stack) { + return CropManager.isSeed(stack); + } + }; public BoardRobotPlanter(EntityRobotBase iRobot) { super(iRobot); @@ -56,62 +51,17 @@ public class BoardRobotPlanter extends RedstoneBoardRobot { @Override public void update() { if (robot.getHeldItem() == null) { - Collection gateFilter = ActionRobotFilter.getGateFilterStacks(robot - .getLinkedStation()); - - if (gateFilter.size() != 0) { - ArrayList filteredFilter = new ArrayList(); - - for (ItemStack tentative : gateFilter) { - if (stackFilter.matches(tentative)) { - filteredFilter.add(tentative); - } - } - - if (filteredFilter.size() > 0) { - ArrayStackFilter arrayFilter = new ArrayStackOrListFilter( - filteredFilter.toArray(new ItemStack[filteredFilter.size()])); - - startDelegateAI(new AIRobotFetchAndEquipItemStack(robot, arrayFilter)); - } else { - startDelegateAI(new AIRobotGotoSleep(robot)); - } - } else { - startDelegateAI(new AIRobotFetchAndEquipItemStack(robot, stackFilter)); - } + startDelegateAI(new AIRobotFetchAndEquipItemStack(robot, new AggregateFilter(filter, + ActionRobotFilter.getGateFilter(robot.getLinkedStation())))); } else { final ItemStack itemStack = robot.getHeldItem(); - IBlockFilter blockFilter; - if (itemStack.getItem() instanceof ItemReed) { - blockFilter = new IBlockFilter() { - @Override - public boolean matches(World world, int x, int y, int z) { - return isPlantable((IPlantable) Blocks.reeds, Blocks.reeds, world, x, y, z) - && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z)) - && isAirAbove(world, x, y, z); - } - }; - } else if (itemStack.getItem() instanceof ItemBlock) { - final Block plantBlock = ((ItemBlock) itemStack.getItem()).field_150939_a; - blockFilter = new IBlockFilter() { - @Override - public boolean matches(World world, int x, int y, int z) { - return isPlantable((IPlantable) plantBlock, plantBlock, world, x, y, z) - && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z)) - && isAirAbove(world, x, y, z); - } - - }; - } else { - blockFilter = new IBlockFilter() { - @Override - public boolean matches(World world, int x, int y, int z) { - return isPlantable((IPlantable) itemStack.getItem(), null, world, x, y, z) - && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z)) - && isAirAbove(world, x, y, z); - } - }; - } + IBlockFilter blockFilter = new IBlockFilter() { + @Override + public boolean matches(World world, int x, int y, int z) { + return isPlantable(itemStack, world, x, y, z) + && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z)); + } + }; startDelegateAI(new AIRobotSearchAndGotoBlock(robot, true, blockFilter)); } } @@ -141,36 +91,9 @@ public class BoardRobotPlanter extends RedstoneBoardRobot { } } - private static class PlantableFilter implements IStackFilter { - @Override - public boolean matches(ItemStack stack) { - if (stack.getItem() instanceof IPlantable) { - return true; - } - if (stack.getItem() instanceof ItemBlock && ((ItemBlock) stack.getItem()).field_150939_a instanceof IPlantable) { - return true; - } - return false; - } - } - - private static class ReedFilter implements IStackFilter { - @Override - public boolean matches(ItemStack stack) { - return stack.getItem() == Items.reeds; - } - } - - private boolean isPlantable(IPlantable plant, Block block, World world, int x, int y, int z) { + private boolean isPlantable(ItemStack seed, World world, int x, int y, int z) { synchronized (world) { - return world.getBlock(x, y, z).canSustainPlant(world, x, y, z, ForgeDirection.UP, plant) - && (block == null || world.getBlock(x, y, z) != block); - } - } - - private boolean isAirAbove(World world, int x, int y, int z) { - synchronized (world) { - return world.isAirBlock(x, y + 1, z); + return CropManager.canSustainPlant(world, seed, x, y, z); } }