buildcraft.builders.TileBuilder.java Source code

Java tutorial

Introduction

Here is the source code for buildcraft.builders.TileBuilder.java

Source

/**
 * Copyright (c) 2011-2015, 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.builders;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import io.netty.buffer.ByteBuf;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.WorldSettings.GameType;

import cpw.mods.fml.relauncher.Side;

import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;

import buildcraft.BuildCraftBuilders;
import buildcraft.BuildCraftCore;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.core.IInvSlot;
import buildcraft.api.core.Position;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.api.robots.IRequestProvider;
import buildcraft.api.robots.StackRequest;
import buildcraft.api.tiles.IControllable;
import buildcraft.api.tiles.IHasWork;
import buildcraft.core.Box;
import buildcraft.core.Box.Kind;
import buildcraft.core.LaserData;
import buildcraft.core.blueprints.Blueprint;
import buildcraft.core.blueprints.BlueprintBase;
import buildcraft.core.blueprints.BptBuilderBase;
import buildcraft.core.blueprints.BptBuilderBlueprint;
import buildcraft.core.blueprints.BptBuilderTemplate;
import buildcraft.core.blueprints.RecursiveBlueprintBuilder;
import buildcraft.core.builders.TileAbstractBuilder;
import buildcraft.core.fluids.Tank;
import buildcraft.core.fluids.TankManager;
import buildcraft.core.inventory.ITransactor;
import buildcraft.core.inventory.InvUtils;
import buildcraft.core.inventory.InventoryIterator;
import buildcraft.core.inventory.SimpleInventory;
import buildcraft.core.inventory.StackHelper;
import buildcraft.core.inventory.Transactor;
import buildcraft.core.network.BuildCraftPacket;
import buildcraft.core.network.CommandWriter;
import buildcraft.core.network.PacketCommand;
import buildcraft.core.utils.Utils;
import buildcraft.robots.ResourceIdRequest;
import buildcraft.robots.RobotRegistry;

public class TileBuilder extends TileAbstractBuilder
        implements IHasWork, IFluidHandler, IRequestProvider, IControllable {

    private static int POWER_ACTIVATION = 500;

    public Box box = new Box();
    public PathIterator currentPathIterator;
    public Tank[] fluidTanks = new Tank[] { new Tank("fluid1", FluidContainerRegistry.BUCKET_VOLUME * 8, this),
            new Tank("fluid2", FluidContainerRegistry.BUCKET_VOLUME * 8, this),
            new Tank("fluid3", FluidContainerRegistry.BUCKET_VOLUME * 8, this),
            new Tank("fluid4", FluidContainerRegistry.BUCKET_VOLUME * 8, this) };
    public TankManager<Tank> fluidTank = new TankManager<Tank>(fluidTanks);

    private SimpleInventory inv = new SimpleInventory(28, "Builder", 64);
    private BptBuilderBase currentBuilder;
    private RecursiveBlueprintBuilder recursiveBuilder;
    private LinkedList<BlockIndex> path;
    private ArrayList<ItemStack> requiredToBuild;
    private NBTTagCompound initNBT = null;
    private boolean done = true;
    private boolean isBuilding = false;

    private class PathIterator {

        public Iterator<BlockIndex> currentIterator;
        public double cx, cy, cz;
        public float ix, iy, iz;
        public BlockIndex to;
        public double lastDistance;
        AxisAlignedBB oldBoundingBox = null;
        ForgeDirection o = null;

        public PathIterator(BlockIndex from, Iterator<BlockIndex> it, ForgeDirection initialDir) {
            this.to = it.next();

            currentIterator = it;

            double dx = to.x - from.x;
            double dy = to.y - from.y;
            double dz = to.z - from.z;

            double size = Math.sqrt(dx * dx + dy * dy + dz * dz);

            cx = dx / size / 10;
            cy = dy / size / 10;
            cz = dz / size / 10;

            ix = from.x;
            iy = from.y;
            iz = from.z;

            lastDistance = (ix - to.x) * (ix - to.x) + (iy - to.y) * (iy - to.y) + (iz - to.z) * (iz - to.z);

            if (dx == 0 && dz == 0) {
                o = initialDir;
            } else if (Math.abs(dx) > Math.abs(dz)) {
                if (dx > 0) {
                    o = ForgeDirection.EAST;
                } else {
                    o = ForgeDirection.WEST;
                }
            } else {
                if (dz > 0) {
                    o = ForgeDirection.SOUTH;
                } else {
                    o = ForgeDirection.NORTH;
                }
            }
        }

        /**
         * Return false when reached the end of the iteration
         */
        public BptBuilderBase next() {
            while (true) {
                BptBuilderBase bpt;

                int newX = Math.round(ix);
                int newY = Math.round(iy);
                int newZ = Math.round(iz);

                bpt = instanciateBluePrintBuilder(newX, newY, newZ, o);

                if (bpt == null) {
                    return null;
                }

                AxisAlignedBB boundingBox = bpt.getBoundingBox();

                if (oldBoundingBox == null || !collision(oldBoundingBox, boundingBox)) {

                    oldBoundingBox = boundingBox;

                    if (bpt != null) {
                        return bpt;
                    }
                }

                ix += cx;
                iy += cy;
                iz += cz;

                double distance = (ix - to.x) * (ix - to.x) + (iy - to.y) * (iy - to.y) + (iz - to.z) * (iz - to.z);

                if (distance > lastDistance) {
                    return null;
                } else {
                    lastDistance = distance;
                }
            }
        }

        public PathIterator iterate() {
            if (currentIterator.hasNext()) {
                PathIterator next = new PathIterator(to, currentIterator, o);
                next.oldBoundingBox = oldBoundingBox;

                return next;
            } else {
                return null;
            }
        }

        public boolean collision(AxisAlignedBB left, AxisAlignedBB right) {
            if (left.maxX < right.minX || left.minX > right.maxX) {
                return false;
            }
            if (left.maxY < right.minY || left.minY > right.maxY) {
                return false;
            }
            if (left.maxZ < right.minZ || left.minZ > right.maxZ) {
                return false;
            }
            return true;
        }
    }

    public TileBuilder() {
        super();

        box.kind = Kind.STRIPES;
    }

    @Override
    public void initialize() {
        super.initialize();

        if (worldObj.isRemote) {
            return;
        }

        if (initNBT != null) {
            iterateBpt(true);

            if (initNBT.hasKey("iterator")) {
                BlockIndex expectedTo = new BlockIndex(initNBT.getCompoundTag("iterator"));

                while (!done && currentBuilder != null && currentPathIterator != null) {
                    BlockIndex bi = new BlockIndex((int) currentPathIterator.ix, (int) currentPathIterator.iy,
                            (int) currentPathIterator.iz);

                    if (bi.equals(expectedTo)) {
                        break;
                    }

                    iterateBpt(true);
                }
            }

            if (currentBuilder != null) {
                currentBuilder.loadBuildStateToNBT(initNBT.getCompoundTag("builderState"), this);
            }

            initNBT = null;
        }

        box.kind = Kind.STRIPES;

        for (int x = xCoord - 1; x <= xCoord + 1; ++x) {
            for (int y = yCoord - 1; y <= yCoord + 1; ++y) {
                for (int z = zCoord - 1; z <= zCoord + 1; ++z) {
                    TileEntity tile = worldObj.getTileEntity(x, y, z);

                    if (tile instanceof TilePathMarker) {
                        path = ((TilePathMarker) tile).getPath();

                        for (BlockIndex b : path) {
                            worldObj.setBlockToAir(b.x, b.y, b.z);

                            BuildCraftBuilders.pathMarkerBlock.dropBlockAsItem(worldObj, b.x, b.y, b.z, 0, 0);
                        }

                        break;
                    }
                }
            }
        }

        if (path != null && pathLasers.size() == 0) {
            createLasersForPath();

            sendNetworkUpdate();
        }

        iterateBpt(false);
    }

    public void createLasersForPath() {
        pathLasers = new LinkedList<LaserData>();
        BlockIndex previous = null;

        for (BlockIndex b : path) {
            if (previous != null) {
                LaserData laser = new LaserData(new Position(previous.x + 0.5, previous.y + 0.5, previous.z + 0.5),
                        new Position(b.x + 0.5, b.y + 0.5, b.z + 0.5));

                pathLasers.add(laser);
            }

            previous = b;
        }
    }

    public BlueprintBase instanciateBlueprint() {
        BlueprintBase bpt = null;

        try {
            bpt = ItemBlueprint.loadBlueprint(getStackInSlot(0));
        } catch (Throwable t) {
            setInventorySlotContents(0, null);
            t.printStackTrace();
            return null;
        }

        return bpt;
    }

    @Deprecated
    public BptBuilderBase instanciateBluePrintBuilder(int x, int y, int z, ForgeDirection o) {
        BlueprintBase bpt = instanciateBlueprint();
        if (bpt == null) {
            return null;
        }

        bpt = bpt.adjustToWorld(worldObj, x, y, z, o);

        if (bpt != null) {
            if (getStackInSlot(0).getItem() instanceof ItemBlueprintStandard) {
                return new BptBuilderBlueprint((Blueprint) bpt, worldObj, x, y, z);
            } else if (getStackInSlot(0).getItem() instanceof ItemBlueprintTemplate) {
                return new BptBuilderTemplate(bpt, worldObj, x, y, z);
            }
        }
        return null;
    }

    public void iterateBpt(boolean forceIterate) {
        if (getStackInSlot(0) == null || !(getStackInSlot(0).getItem() instanceof ItemBlueprint)) {
            if (box.isInitialized()) {
                if (currentBuilder != null) {
                    currentBuilder = null;
                }

                if (box.isInitialized()) {
                    box.reset();
                }

                if (currentPathIterator != null) {
                    currentPathIterator = null;
                }

                updateRequirements();

                sendNetworkUpdate();

                return;
            }
        }

        if (currentBuilder == null || (currentBuilder.isDone(this) || forceIterate)) {
            if (path != null && path.size() > 1) {
                if (currentPathIterator == null) {
                    Iterator<BlockIndex> it = path.iterator();
                    BlockIndex start = it.next();
                    currentPathIterator = new PathIterator(start, it,
                            ForgeDirection.values()[worldObj.getBlockMetadata(xCoord, yCoord, zCoord)]
                                    .getOpposite());
                }

                if (currentBuilder != null && currentBuilder.isDone(this)) {
                    currentBuilder.postProcessing(worldObj);
                }

                currentBuilder = currentPathIterator.next();

                if (currentBuilder != null) {
                    box.reset();
                    box.initialize(currentBuilder);
                    sendNetworkUpdate();
                }

                if (currentBuilder == null) {
                    currentPathIterator = currentPathIterator.iterate();
                }

                if (currentPathIterator == null) {
                    done = true;
                } else {
                    done = false;
                }

                updateRequirements();
            } else {
                if (currentBuilder != null && currentBuilder.isDone(this)) {
                    currentBuilder.postProcessing(worldObj);
                    currentBuilder = recursiveBuilder.nextBuilder();

                    updateRequirements();
                } else {
                    BlueprintBase bpt = instanciateBlueprint();

                    if (bpt != null) {
                        recursiveBuilder = new RecursiveBlueprintBuilder(bpt, worldObj, xCoord, yCoord, zCoord,
                                ForgeDirection.values()[worldObj.getBlockMetadata(xCoord, yCoord, zCoord)]
                                        .getOpposite());

                        currentBuilder = recursiveBuilder.nextBuilder();

                        updateRequirements();
                    }
                }

                if (currentBuilder == null) {
                    done = true;
                } else {
                    box.initialize(currentBuilder);
                    sendNetworkUpdate();
                    done = false;
                }
            }
        }

        if (done && getStackInSlot(0) != null) {
            boolean dropBlueprint = true;
            for (int i = 1; i < getSizeInventory(); ++i) {
                if (getStackInSlot(i) == null) {
                    setInventorySlotContents(i, getStackInSlot(0));
                    dropBlueprint = false;
                    break;
                }
            }
            if (dropBlueprint) {
                InvUtils.dropItems(getWorldObj(), getStackInSlot(0), xCoord, yCoord, zCoord);
            }

            setInventorySlotContents(0, null);
            box.reset();
        }
    }

    @Override
    public int getSizeInventory() {
        return inv.getSizeInventory();
    }

    @Override
    public ItemStack getStackInSlot(int i) {
        return inv.getStackInSlot(i);
    }

    @Override
    public ItemStack decrStackSize(int i, int j) {
        ItemStack result = inv.decrStackSize(i, j);

        if (!worldObj.isRemote) {
            if (i == 0) {
                BuildCraftCore.instance.sendToWorld(new PacketCommand(this, "clearItemRequirements", null),
                        worldObj);
                iterateBpt(false);
            }
        }

        return result;
    }

    @Override
    public void setInventorySlotContents(int i, ItemStack itemstack) {
        inv.setInventorySlotContents(i, itemstack);

        if (!worldObj.isRemote) {
            if (i == 0) {
                iterateBpt(false);
                done = false;
            }
        }
    }

    @Override
    public ItemStack getStackInSlotOnClosing(int slot) {
        return inv.getStackInSlotOnClosing(slot);
    }

    @Override
    public String getInventoryName() {
        return "Builder";
    }

    @Override
    public int getInventoryStackLimit() {
        return 64;
    }

    @Override
    public boolean isUseableByPlayer(EntityPlayer entityplayer) {
        return worldObj.getTileEntity(xCoord, yCoord, zCoord) == this;
    }

    @Override
    public void readFromNBT(NBTTagCompound nbttagcompound) {
        super.readFromNBT(nbttagcompound);

        inv.readFromNBT(nbttagcompound);

        if (nbttagcompound.hasKey("box")) {
            box.initialize(nbttagcompound.getCompoundTag("box"));
        }

        if (nbttagcompound.hasKey("path")) {
            path = new LinkedList<BlockIndex>();
            NBTTagList list = nbttagcompound.getTagList("path", Constants.NBT.TAG_COMPOUND);

            for (int i = 0; i < list.tagCount(); ++i) {
                path.add(new BlockIndex(list.getCompoundTagAt(i)));
            }
        }

        done = nbttagcompound.getBoolean("done");
        fluidTank.readFromNBT(nbttagcompound);

        // The rest of load has to be done upon initialize.
        initNBT = (NBTTagCompound) nbttagcompound.getCompoundTag("bptBuilder").copy();
    }

    @Override
    public void writeToNBT(NBTTagCompound nbttagcompound) {
        super.writeToNBT(nbttagcompound);

        inv.writeToNBT(nbttagcompound);

        if (box.isInitialized()) {
            NBTTagCompound boxStore = new NBTTagCompound();
            box.writeToNBT(boxStore);
            nbttagcompound.setTag("box", boxStore);
        }

        if (path != null) {
            NBTTagList list = new NBTTagList();

            for (BlockIndex i : path) {
                NBTTagCompound c = new NBTTagCompound();
                i.writeTo(c);
                list.appendTag(c);
            }

            nbttagcompound.setTag("path", list);
        }

        nbttagcompound.setBoolean("done", done);
        fluidTank.writeToNBT(nbttagcompound);

        NBTTagCompound bptNBT = new NBTTagCompound();

        if (currentBuilder != null) {
            NBTTagCompound builderCpt = new NBTTagCompound();
            currentBuilder.saveBuildStateToNBT(builderCpt, this);
            bptNBT.setTag("builderState", builderCpt);
        }

        if (currentPathIterator != null) {
            NBTTagCompound iteratorNBT = new NBTTagCompound();
            new BlockIndex((int) currentPathIterator.ix, (int) currentPathIterator.iy, (int) currentPathIterator.iz)
                    .writeTo(iteratorNBT);
            bptNBT.setTag("iterator", iteratorNBT);
        }

        nbttagcompound.setTag("bptBuilder", bptNBT);
    }

    @Override
    public void invalidate() {
        super.invalidate();
        destroy();
    }

    @Override
    public void openInventory() {
    }

    @Override
    public void closeInventory() {
    }

    @Override
    public void updateEntity() {
        super.updateEntity();

        if (worldObj.isRemote) {
            return;
        }

        if (currentBuilder != null) {
            currentBuilder.removeDoneBuilders(this);
        }

        if ((currentBuilder == null || currentBuilder.isDone(this)) && box.isInitialized()) {
            box.reset();

            sendNetworkUpdate();

            return;
        }

        iterateBpt(false);

        if (mode != Mode.Off) {
            if (getWorldObj().getWorldInfo().getGameType() == GameType.CREATIVE) {
                build();
            } else if (getBattery().getEnergyStored() > POWER_ACTIVATION) {
                build();
            }
        }

        if (!isBuilding && this.isBuildingBlueprint()) {
            updateRequirements();
        }
        isBuilding = this.isBuildingBlueprint();

        if (done) {
            return;
        } else if (getBattery().getEnergyStored() < 25) {
            return;
        }
    }

    @Override
    public boolean hasWork() {
        return !done;
    }

    public boolean isBuildingBlueprint() {
        return getStackInSlot(0) != null && getStackInSlot(0).getItem() instanceof ItemBlueprint;
    }

    public Collection<ItemStack> getNeededItems() {
        return requiredToBuild;
    }

    @Override
    public void receiveCommand(String command, Side side, Object sender, ByteBuf stream) {
        super.receiveCommand(command, side, sender, stream);
        if (side.isClient()) {
            if ("clearItemRequirements".equals(command)) {
                requiredToBuild = null;
            } else if ("setItemRequirements".equals(command)) {
                int size = stream.readUnsignedShort();
                requiredToBuild = new ArrayList<ItemStack>();
                for (int i = 0; i < size; i++) {
                    ItemStack stack = Utils.readStack(stream);
                    stack.stackSize = Math.min(999, stream.readUnsignedShort());
                    requiredToBuild.add(stack);
                }
            }
        } else if (side.isServer()) {
            EntityPlayer player = (EntityPlayer) sender;
            if ("eraseFluidTank".equals(command)) {
                int id = stream.readInt();
                if (id < 0 || id >= fluidTanks.length) {
                    return;
                }
                if (isUseableByPlayer(player) && player.getDistanceSq(xCoord, yCoord, zCoord) <= 64) {
                    fluidTanks[id].setFluid(null);
                    sendNetworkUpdate();
                }
            }
        }
    }

    private BuildCraftPacket getItemRequirementsPacket(final ArrayList<ItemStack> items) {
        if (items != null) {
            return new PacketCommand(this, "setItemRequirements", new CommandWriter() {
                public void write(ByteBuf data) {
                    data.writeShort(items.size());
                    if (items != null) {
                        for (ItemStack rb : items) {
                            Utils.writeStack(data, rb);
                            data.writeShort(rb.stackSize);
                        }
                    }
                }
            });
        } else {
            return new PacketCommand(this, "clearItemRequirements", null);
        }
    }

    @Override
    public boolean isBuildingMaterialSlot(int i) {
        return i != 0;
    }

    @Override
    public boolean hasCustomInventoryName() {
        return false;
    }

    @Override
    public boolean isItemValidForSlot(int slot, ItemStack stack) {
        if (slot == 0) {
            return stack.getItem() instanceof ItemBlueprint;
        } else {
            return true;
        }
    }

    @Override
    public Box getBox() {
        return box;
    }

    @Override
    public AxisAlignedBB getRenderBoundingBox() {
        Box renderBox = new Box(this).extendToEncompass(box);

        for (LaserData l : pathLasers) {
            renderBox = renderBox.extendToEncompass(l.head);
            renderBox = renderBox.extendToEncompass(l.tail);
        }

        return renderBox.expand(50).getBoundingBox();
    }

    public void build() {
        if (currentBuilder != null) {
            if (currentBuilder.buildNextSlot(worldObj, this, xCoord, yCoord, zCoord)) {
                updateRequirements();
            }
        }
    }

    public void updateRequirements() {
        ArrayList<ItemStack> reqCopy = null;
        if (currentBuilder instanceof BptBuilderBlueprint) {
            currentBuilder.initialize();
            reqCopy = ((BptBuilderBlueprint) currentBuilder).neededItems;
        }

        for (EntityPlayer p : guiWatchers) {
            BuildCraftCore.instance.sendToPlayer(p, getItemRequirementsPacket(reqCopy));
        }
    }

    public void updateRequirements(EntityPlayer caller) {
        ArrayList<ItemStack> reqCopy = null;
        if (currentBuilder instanceof BptBuilderBlueprint) {
            currentBuilder.initialize();
            reqCopy = ((BptBuilderBlueprint) currentBuilder).neededItems;
        }

        BuildCraftCore.instance.sendToPlayer(caller, getItemRequirementsPacket(reqCopy));
    }

    public BptBuilderBase getBlueprint() {
        if (currentBuilder != null) {
            return currentBuilder;
        } else {
            return null;
        }
    }

    @Override
    public boolean canDrain(ForgeDirection from, Fluid fluid) {
        return false;
    }

    @Override
    public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
        return null;
    }

    @Override
    public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
        return null;
    }

    public boolean drainBuild(FluidStack fluidStack, boolean realDrain) {
        for (Tank tank : fluidTanks) {
            if (tank.getFluidType() == fluidStack.getFluid()) {
                return tank.getFluidAmount() >= fluidStack.amount
                        && tank.drain(fluidStack.amount, realDrain).amount > 0;
            }
        }
        return false;
    }

    @Override
    public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
        Fluid fluid = resource.getFluid();
        Tank emptyTank = null;
        for (Tank tank : fluidTanks) {
            Fluid type = tank.getFluidType();
            if (type == fluid) {
                int used = tank.fill(resource, doFill);
                if (used > 0 && doFill) {
                    sendNetworkUpdate();
                }
                return used;
            } else if (emptyTank == null && tank.isEmpty()) {
                emptyTank = tank;
            }
        }
        if (emptyTank != null) {
            int used = emptyTank.fill(resource, doFill);
            if (used > 0 && doFill) {
                sendNetworkUpdate();
            }
            return used;
        }
        return 0;
    }

    @Override
    public boolean canFill(ForgeDirection from, Fluid fluid) {
        boolean emptyAvailable = false;
        for (Tank tank : fluidTanks) {
            Fluid type = tank.getFluidType();
            if (type == fluid) {
                return !tank.isFull();
            } else if (!emptyAvailable) {
                emptyAvailable = tank.isEmpty();
            }
        }
        return emptyAvailable;
    }

    @Override
    public FluidTankInfo[] getTankInfo(ForgeDirection from) {
        return fluidTank.getTankInfo(from);
    }

    @Override
    public int getNumberOfRequests() {
        if (currentBuilder == null) {
            return 0;
        } else if (!(currentBuilder instanceof BptBuilderBlueprint)) {
            return 0;
        } else {
            BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;

            return bpt.neededItems.size();
        }
    }

    @Override
    public StackRequest getAvailableRequest(int i) {
        if (currentBuilder == null) {
            return null;
        } else if (!(currentBuilder instanceof BptBuilderBlueprint)) {
            return null;
        } else {
            BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;

            if (bpt.neededItems.size() <= i) {
                return null;
            }

            ItemStack requirement = bpt.neededItems.get(i);

            int qty = quantityMissing(requirement);

            if (qty <= 0) {
                return null;
            }

            StackRequest request = new StackRequest();

            request.index = i;
            request.requester = this;
            request.stack = requirement;

            return request;
        }
    }

    @Override
    public boolean takeRequest(int i, EntityRobotBase robot) {
        if (currentBuilder == null) {
            return false;
        } else if (!(currentBuilder instanceof BptBuilderBlueprint)) {
            return false;
        } else {
            return RobotRegistry.getRegistry(worldObj).take(new ResourceIdRequest(this, i), robot);
        }
    }

    @Override
    public ItemStack provideItemsForRequest(int i, ItemStack stack) {
        if (currentBuilder == null) {
            return stack;
        } else if (!(currentBuilder instanceof BptBuilderBlueprint)) {
            return stack;
        } else {
            BptBuilderBlueprint bpt = (BptBuilderBlueprint) currentBuilder;

            if (bpt.neededItems.size() <= i) {
                return stack;
            }

            ItemStack requirement = bpt.neededItems.get(i);

            int qty = quantityMissing(requirement);

            if (qty <= 0) {
                return stack;
            }

            ItemStack toAdd = stack.copy();

            if (qty < toAdd.stackSize) {
                toAdd.stackSize = qty;
            }

            ITransactor t = Transactor.getTransactorFor(this);
            ItemStack added = t.add(toAdd, ForgeDirection.UNKNOWN, true);

            if (added.stackSize >= stack.stackSize) {
                return null;
            } else {
                stack.stackSize -= added.stackSize;
                return stack;
            }
        }
    }

    private int quantityMissing(ItemStack requirement) {
        int left = requirement.stackSize;

        for (IInvSlot slot : InventoryIterator.getIterable(this)) {
            if (slot.getStackInSlot() != null) {
                if (StackHelper.isMatchingItem(requirement, slot.getStackInSlot())) {
                    if (slot.getStackInSlot().stackSize >= left) {
                        return 0;
                    } else {
                        left -= slot.getStackInSlot().stackSize;
                    }
                }
            }
        }

        return left;
    }

    @Override
    public boolean acceptsControlMode(Mode mode) {
        return mode == Mode.Off || mode == Mode.On;
    }

    @Override
    public void writeData(ByteBuf stream) {
        super.writeData(stream);
        box.writeData(stream);
        fluidTank.writeData(stream);
    }

    @Override
    public void readData(ByteBuf stream) {
        super.readData(stream);
        box.readData(stream);
        fluidTank.readData(stream);
    }
}