blusunrize.immersiveengineering.common.blocks.metal.TileEntityAssembler.java Source code

Java tutorial

Introduction

Here is the source code for blusunrize.immersiveengineering.common.blocks.metal.TileEntityAssembler.java

Source

/*
 * BluSunrize
 * Copyright (c) 2017
 *
 * This code is licensed under "Blu's License of Common Sense"
 * Details can be found in the license file in the root folder of this project
 */

package blusunrize.immersiveengineering.common.blocks.metal;

import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.api.crafting.IMultiblockRecipe;
import blusunrize.immersiveengineering.api.crafting.IngredientStack;
import blusunrize.immersiveengineering.api.tool.AssemblerHandler;
import blusunrize.immersiveengineering.api.tool.ConveyorHandler.IConveyorAttachable;
import blusunrize.immersiveengineering.common.Config.IEConfig;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IGuiTile;
import blusunrize.immersiveengineering.common.blocks.multiblocks.MultiblockAssembler;
import blusunrize.immersiveengineering.common.util.Utils;
import blusunrize.immersiveengineering.common.util.inventory.IEInventoryHandler;
import com.google.common.base.Optional;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.oredict.OreDictionary;

import java.util.ArrayList;
import java.util.Iterator;

public class TileEntityAssembler extends TileEntityMultiblockMetal<TileEntityAssembler, IMultiblockRecipe>
        implements IGuiTile, IConveyorAttachable// IAdvancedSelectionBounds,IAdvancedCollisionBounds
{
    public boolean[] computerOn = new boolean[3];

    public TileEntityAssembler() {
        super(MultiblockAssembler.instance, new int[] { 3, 3, 3 }, 32000, true);
    }

    public FluidTank[] tanks = { new FluidTank(8000), new FluidTank(8000), new FluidTank(8000) };
    public NonNullList<ItemStack> inventory = NonNullList.withSize(18 + 3, ItemStack.EMPTY);
    public CrafterPatternInventory[] patterns = { new CrafterPatternInventory(this),
            new CrafterPatternInventory(this), new CrafterPatternInventory(this) };
    public boolean recursiveIngredients = false;

    @Override
    public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) {
        super.readCustomNBT(nbt, descPacket);
        tanks[0].readFromNBT(nbt.getCompoundTag("tank0"));
        tanks[1].readFromNBT(nbt.getCompoundTag("tank1"));
        tanks[2].readFromNBT(nbt.getCompoundTag("tank2"));
        recursiveIngredients = nbt.getBoolean("recursiveIngredients");
        if (!descPacket) {
            inventory = Utils.readInventory(nbt.getTagList("inventory", 10), 18 + 3);
            for (int iPattern = 0; iPattern < patterns.length; iPattern++) {
                NBTTagList patternList = nbt.getTagList("pattern" + iPattern, 10);
                patterns[iPattern] = new CrafterPatternInventory(this);
                patterns[iPattern].readFromNBT(patternList);
            }
        }
    }

    @Override
    public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) {
        super.writeCustomNBT(nbt, descPacket);
        nbt.setTag("tank0", tanks[0].writeToNBT(new NBTTagCompound()));
        nbt.setTag("tank1", tanks[1].writeToNBT(new NBTTagCompound()));
        nbt.setTag("tank2", tanks[2].writeToNBT(new NBTTagCompound()));
        nbt.setBoolean("recursiveIngredients", recursiveIngredients);
        if (!descPacket) {
            nbt.setTag("inventory", Utils.writeInventory(inventory));
            for (int iPattern = 0; iPattern < patterns.length; iPattern++) {
                NBTTagList patternList = new NBTTagList();
                patterns[iPattern].writeToNBT(patternList);
                nbt.setTag("pattern" + iPattern, patternList);
            }
        }
    }

    @Override
    public void receiveMessageFromClient(NBTTagCompound message) {
        if (message.hasKey("buttonID")) {
            int id = message.getInteger("buttonID");
            if (id >= 0 && id < patterns.length) {
                CrafterPatternInventory pattern = patterns[id];
                for (int i = 0; i < pattern.inv.size(); i++)
                    pattern.inv.set(i, ItemStack.EMPTY);
            } else if (id == 3) {
                recursiveIngredients = !recursiveIngredients;
            }
        } else if (message.hasKey("patternSync")) {
            int r = message.getInteger("recipe");
            NBTTagList list = message.getTagList("patternSync", 10);
            CrafterPatternInventory pattern = patterns[r];
            for (int i = 0; i < list.tagCount(); i++) {
                NBTTagCompound itemTag = list.getCompoundTagAt(i);
                pattern.inv.set(itemTag.getInteger("slot"), new ItemStack(itemTag));
            }
        }
    }

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

        if (isDummy() || isRSDisabled() || world.isRemote
                || world.getTotalWorldTime() % 16 != ((getPos().getX() ^ getPos().getZ()) & 15))
            return;
        boolean update = false;
        NonNullList<ItemStack>[] outputBuffer = new NonNullList[patterns.length];
        for (int p = 0; p < patterns.length; p++) {
            CrafterPatternInventory pattern = patterns[p];
            if ((controllingComputers != 0) && !computerOn[p])
                return;
            if (!pattern.inv.get(9).isEmpty() && canOutput(pattern.inv.get(9), p)) {
                ItemStack output = pattern.inv.get(9).copy();
                ArrayList<ItemStack> queryList = new ArrayList<>();//List of all available inputs in the inventory
                for (NonNullList<ItemStack> bufferedStacks : outputBuffer)
                    if (bufferedStacks != null)
                        for (ItemStack stack : bufferedStacks)
                            if (!stack.isEmpty())
                                queryList.add(stack.copy());
                for (ItemStack stack : this.inventory)
                    if (!stack.isEmpty())
                        queryList.add(stack.copy());
                int consumed = IEConfig.Machines.assembler_consumption;
                if (this.energyStorage.extractEnergy(consumed, true) == consumed
                        && this.hasIngredients(pattern, queryList)) {
                    this.energyStorage.extractEnergy(consumed, false);
                    NonNullList<ItemStack> outputList = NonNullList.create();//List of all outputs for the current recipe. This includes discarded containers
                    outputList.add(output);
                    AssemblerHandler.IRecipeAdapter adapter = AssemblerHandler.findAdapter(pattern.recipe);
                    AssemblerHandler.RecipeQuery[] queries = adapter.getQueriedInputs(pattern.recipe, pattern.inv);
                    NonNullList<ItemStack> gridItems = NonNullList.withSize(9, ItemStack.EMPTY);
                    for (int i = 0; i < queries.length; i++)
                        if (queries[i] != null) {
                            AssemblerHandler.RecipeQuery recipeQuery = queries[i];
                            Optional<ItemStack> taken = Optional.absent();
                            for (int j = 0; j < outputBuffer.length; j++)
                                if (outputBuffer[j] != null) {
                                    taken = consumeItem(recipeQuery.query, recipeQuery.querySize, outputBuffer[j],
                                            outputList);
                                    if (taken.isPresent())
                                        break;
                                }
                            if (!taken.isPresent())
                                taken = this.consumeItem(recipeQuery.query, recipeQuery.querySize, inventory,
                                        outputList);
                            gridItems.set(i, taken.or(ItemStack.EMPTY));
                        }
                    NonNullList<ItemStack> remainingItems = pattern.recipe.getRemainingItems(
                            Utils.InventoryCraftingFalse.createFilledCraftingInventory(3, 3, gridItems));
                    for (ItemStack rem : remainingItems)
                        if (!rem.isEmpty())
                            outputList.add(rem);
                    outputBuffer[p] = outputList;
                    update = true;
                }
            }
        }
        BlockPos outputPos = getPos().offset(facing, 2);
        TileEntity inventoryTile = Utils.getExistingTileEntity(world, outputPos);
        for (int buffer = 0; buffer < outputBuffer.length; buffer++)
            if (outputBuffer[buffer] != null && outputBuffer[buffer].size() > 0)
                for (int iOutput = 0; iOutput < outputBuffer[buffer].size(); iOutput++) {
                    ItemStack output = outputBuffer[buffer].get(iOutput);
                    if (!output.isEmpty() && output.getCount() > 0) {
                        if (!isRecipeIngredient(output, buffer) && inventoryTile != null) {
                            output = Utils.insertStackIntoInventory(inventoryTile, output, facing.getOpposite());
                            if (output.isEmpty() || output.getCount() <= 0)
                                continue;
                        }
                        int free = -1;
                        if (iOutput == 0)//Main recipe output
                        {
                            if (this.inventory.get(18 + buffer).isEmpty() && free < 0)
                                free = 18 + buffer;
                            else if (!this.inventory.get(18 + buffer).isEmpty()
                                    && OreDictionary.itemMatches(output, this.inventory.get(18 + buffer), true)
                                    && this.inventory.get(18 + buffer).getCount()
                                            + output.getCount() <= this.inventory.get(18 + buffer)
                                                    .getMaxStackSize()) {
                                this.inventory.get(18 + buffer).grow(output.getCount());
                                free = -1;
                                continue;
                            }
                        } else
                            for (int i = 0; i < this.inventory.size(); i++) {
                                if (this.inventory.get(i).isEmpty() && free < 0)
                                    free = i;
                                else if (!this.inventory.get(i).isEmpty()
                                        && OreDictionary.itemMatches(output, this.inventory.get(i), true)
                                        && this.inventory.get(i).getCount() + output.getCount() <= this.inventory
                                                .get(i).getMaxStackSize()) {
                                    this.inventory.get(i).grow(output.getCount());
                                    free = -1;
                                    break;
                                }
                            }
                        if (free >= 0)
                            this.inventory.set(free, output.copy());
                    }
                }
        for (int i = 0; i < 3; i++)
            if (!isRecipeIngredient(this.inventory.get(18 + i), i) && inventoryTile != null)
                this.inventory.set(18 + i, Utils.insertStackIntoInventory(inventoryTile, this.inventory.get(18 + i),
                        facing.getOpposite()));

        if (update) {
            this.markDirty();
            this.markContainingBlockForUpdate(null);
        }
    }

    public Optional<ItemStack> consumeItem(Object query, int querySize, NonNullList<ItemStack> inventory,
            NonNullList<ItemStack> containerItems) {
        FluidStack fs = query instanceof FluidStack ? (FluidStack) query
                : (query instanceof IngredientStack && ((IngredientStack) query).fluid != null)
                        ? ((IngredientStack) query).fluid
                        : null;
        if (fs != null)
            for (FluidTank tank : tanks)
                if (tank.getFluid() != null && tank.getFluid().containsFluid(fs)) {
                    tank.drain(fs.amount, true);
                    markDirty();
                    this.markContainingBlockForUpdate(null);
                    return Optional.of(ItemStack.EMPTY);
                }
        Optional<ItemStack> ret = Optional.absent();
        for (int i = 0; i < inventory.size(); i++)
            if (!inventory.get(i).isEmpty() && Utils.stackMatchesObject(inventory.get(i), query, true)) {
                int taken = Math.min(querySize, inventory.get(i).getCount());
                boolean doTake = true;
                if (doTake) {
                    ret = Optional.of(inventory.get(i).splitStack(taken));
                    if (inventory.get(i).getCount() <= 0)
                        inventory.set(i, ItemStack.EMPTY);
                }
                querySize -= taken;
                if (querySize <= 0)
                    break;
            }
        if (querySize <= 0)
            return ret;
        return Optional.absent();
    }

    public boolean hasIngredients(CrafterPatternInventory pattern, ArrayList<ItemStack> queryList) {
        boolean match = true;

        AssemblerHandler.IRecipeAdapter adapter = AssemblerHandler.findAdapter(pattern.recipe);
        if (adapter == null)
            //We don't know how to handle the recipe
            return false;
        AssemblerHandler.RecipeQuery[] queries = adapter.getQueriedInputs(pattern.recipe, pattern.inv);
        for (AssemblerHandler.RecipeQuery recipeQuery : queries)
            if (recipeQuery != null && recipeQuery.query != null) {
                FluidStack fs = recipeQuery.query instanceof FluidStack ? (FluidStack) recipeQuery.query
                        : (recipeQuery.query instanceof IngredientStack
                                && ((IngredientStack) recipeQuery.query).fluid != null)
                                        ? ((IngredientStack) recipeQuery.query).fluid
                                        : null;
                if (fs != null) {
                    boolean hasFluid = false;
                    for (FluidTank tank : tanks)
                        if (tank.getFluid() != null && tank.getFluid().containsFluid(fs)) {
                            hasFluid = true;
                            break;
                        }
                    if (hasFluid)
                        continue;
                }
                int querySize = recipeQuery.querySize;
                Iterator<ItemStack> it = queryList.iterator();
                while (it.hasNext()) {
                    ItemStack next = it.next();
                    if (!next.isEmpty() && Utils.stackMatchesObject(next, recipeQuery.query, true)) {
                        int taken = Math.min(querySize, next.getCount());
                        next.shrink(taken);
                        if (next.getCount() <= 0)
                            it.remove();
                        querySize -= taken;
                        if (querySize <= 0)
                            break;
                    }
                }
                if (querySize > 0) {
                    match = false;
                    break;
                }
            }
        return match;
    }

    public boolean canOutput(ItemStack output, int iPattern) {
        if (this.inventory.get(18 + iPattern).isEmpty())
            return true;
        else
            return OreDictionary.itemMatches(output, this.inventory.get(18 + iPattern), true)
                    && Utils.compareItemNBT(output, this.inventory.get(18 + iPattern))
                    && this.inventory.get(18 + iPattern).getCount() + output.getCount() <= this.inventory
                            .get(18 + iPattern).getMaxStackSize();
    }

    public boolean isRecipeIngredient(ItemStack stack, int slot) {
        if (stack.isEmpty())
            return false;
        if (slot - 1 < patterns.length || recursiveIngredients)
            for (int p = recursiveIngredients ? 0 : slot; p < patterns.length; p++) {
                CrafterPatternInventory pattern = patterns[p];
                for (int i = 0; i < 9; i++)
                    if (!pattern.inv.get(i).isEmpty()) {
                        if (OreDictionary.itemMatches(pattern.inv.get(i), stack, false))
                            return true;
                        else if (pattern.inv.get(i).getItem() == stack.getItem()
                                && !pattern.inv.get(i).getHasSubtypes()
                                && pattern.inv.get(i).isItemStackDamageable())
                            return true;
                    }
            }
        return false;
    }

    @Override
    public float[] getBlockBounds() {
        if (pos < 9 || pos == 10 || pos == 13 || pos == 16 || pos == 22)
            return new float[] { 0, 0, 0, 1, 1, 1 };
        float xMin = 0;
        float yMin = 0;
        float zMin = 0;
        float xMax = 1;
        float yMax = 1;
        float zMax = 1;
        if ((pos % 9 < 3 && facing == EnumFacing.SOUTH) || (pos % 9 >= 6 && facing == EnumFacing.NORTH))
            zMin = .25f;
        else if ((pos % 9 < 3 && facing == EnumFacing.NORTH) || (pos % 9 >= 6 && facing == EnumFacing.SOUTH))
            zMax = .75f;
        else if ((pos % 9 < 3 && facing == EnumFacing.EAST) || (pos % 9 >= 6 && facing == EnumFacing.WEST))
            xMin = .25f;
        else if ((pos % 9 < 3 && facing == EnumFacing.WEST) || (pos % 9 >= 6 && facing == EnumFacing.EAST))
            xMax = .75f;
        if ((pos % 3 == 0 && facing == EnumFacing.EAST) || (pos % 3 == 2 && facing == EnumFacing.WEST))
            zMin = .1875f;
        else if ((pos % 3 == 0 && facing == EnumFacing.WEST) || (pos % 3 == 2 && facing == EnumFacing.EAST))
            zMax = .8125f;
        else if ((pos % 3 == 0 && facing == EnumFacing.NORTH) || (pos % 3 == 2 && facing == EnumFacing.SOUTH))
            xMin = .1875f;
        else if ((pos % 3 == 0 && facing == EnumFacing.SOUTH) || (pos % 3 == 2 && facing == EnumFacing.NORTH))
            xMax = .8125f;
        return new float[] { xMin, yMin, zMin, xMax, yMax, zMax };
    }

    @Override
    public int[] getEnergyPos() {
        return new int[] { 22 };
    }

    @Override
    public int[] getRedstonePos() {
        return new int[] { 3, 5 };
    }

    @Override
    public void replaceStructureBlock(BlockPos pos, IBlockState state, ItemStack stack, int h, int l, int w) {
        super.replaceStructureBlock(pos, state, stack, h, l, w);
        if (h == 1 && w == 1 && l != 1) {
            TileEntity tile = world.getTileEntity(pos);
            if (tile instanceof TileEntityConveyorBelt)
                ((TileEntityConveyorBelt) tile).setFacing(this.facing);
        }
    }

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

    @Override
    public boolean additionalCanProcessCheck(MultiblockProcess<IMultiblockRecipe> process) {
        return false;
    }

    @Override
    public void doProcessOutput(ItemStack output) {
        BlockPos pos = getPos().offset(facing, -1);
        TileEntity inventoryTile = this.world.getTileEntity(pos);
        if (inventoryTile != null)
            output = Utils.insertStackIntoInventory(inventoryTile, output, facing.getOpposite());
        if (!output.isEmpty())
            Utils.dropStackAtPos(world, pos, output, facing);
    }

    @Override
    public void doProcessFluidOutput(FluidStack output) {
    }

    @Override
    public void onProcessFinish(MultiblockProcess<IMultiblockRecipe> process) {
    }

    @Override
    public int getMaxProcessPerTick() {
        return 0;
    }

    @Override
    public int getProcessQueueMaxLength() {
        return 0;
    }

    @Override
    public float getMinProcessDistance(MultiblockProcess<IMultiblockRecipe> process) {
        return 0;
    }

    @Override
    public NonNullList<ItemStack> getInventory() {
        return this.inventory;
    }

    @Override
    public boolean isStackValid(int slot, ItemStack stack) {
        return true;
    }

    @Override
    public int getSlotLimit(int slot) {
        return 64;
    }

    @Override
    public int[] getOutputSlots() {
        return new int[0];
    }

    @Override
    public int[] getOutputTanks() {
        return new int[0];
    }

    @Override
    public IFluidTank[] getInternalTanks() {
        return this.tanks;
    }

    @Override
    public void doGraphicalUpdates(int slot) {
        this.markDirty();
        this.markContainingBlockForUpdate(null);
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
        if ((pos == 10 || pos == 16) && capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
            return ((pos == 10 && facing == this.facing.getOpposite()) || (pos == 16 && facing == this.facing))
                    && master() != null;
        return super.hasCapability(capability, facing);
    }

    IItemHandler insertionHandler = new IEInventoryHandler(18, this, 0, true, false);
    IItemHandler extractionHandler = new IEInventoryHandler(3, this, 18, false, true);

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        if ((pos == 10 || pos == 16) && capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            TileEntityAssembler master = master();
            if (master == null)
                return null;
            if (pos == 10 && facing == this.facing.getOpposite())
                return (T) master.insertionHandler;
            if (pos == 16 && facing == this.facing)
                return (T) master.extractionHandler;
            return null;
        }
        return super.getCapability(capability, facing);
    }

    @Override
    public IMultiblockRecipe findRecipeForInsertion(ItemStack inserting) {
        return null;
    }

    @Override
    protected IMultiblockRecipe readRecipeFromNBT(NBTTagCompound tag) {
        return null;
    }

    @Override
    public boolean canOpenGui() {
        return formed;
    }

    @Override
    public int getGuiID() {
        return Lib.GUIID_Assembler;
    }

    @Override
    public TileEntity getGuiMaster() {
        return master();
    }

    @Override
    protected IFluidTank[] getAccessibleFluidTanks(EnumFacing side) {
        TileEntityAssembler master = master();
        if (master != null && pos == 1 && (side == null || side == facing.getOpposite()))
            return master.tanks;
        return new FluidTank[0];
    }

    @Override
    protected boolean canFillTankFrom(int iTank, EnumFacing side, FluidStack resource) {
        return true;
    }

    @Override
    protected boolean canDrainTankFrom(int iTank, EnumFacing side) {
        return true;
    }

    @Override
    public EnumFacing[] sigOutputDirections() {
        if (pos == 16)
            return new EnumFacing[] { this.facing };
        return new EnumFacing[0];
    }

    public static class CrafterPatternInventory implements IInventory {
        public NonNullList<ItemStack> inv = NonNullList.withSize(10, ItemStack.EMPTY);
        public IRecipe recipe;
        final TileEntityAssembler tile;

        public CrafterPatternInventory(TileEntityAssembler tile) {
            this.tile = tile;
        }

        @Override
        public int getSizeInventory() {
            return 10;
        }

        @Override
        public boolean isEmpty() {
            for (ItemStack stack : inv) {
                if (!stack.isEmpty())
                    return false;
            }
            return true;
        }

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

        @Override
        public ItemStack decrStackSize(int slot, int amount) {
            ItemStack stack = getStackInSlot(slot);
            if (slot < 9 && !stack.isEmpty())
                if (stack.getCount() <= amount)
                    setInventorySlotContents(slot, ItemStack.EMPTY);
                else {
                    stack = stack.splitStack(amount);
                    if (stack.getCount() == 0)
                        setInventorySlotContents(slot, ItemStack.EMPTY);
                }
            return stack;
        }

        @Override
        public ItemStack removeStackFromSlot(int slot) {
            ItemStack stack = getStackInSlot(slot);
            if (!stack.isEmpty())
                setInventorySlotContents(slot, ItemStack.EMPTY);
            return stack;
        }

        @Override
        public void setInventorySlotContents(int slot, ItemStack stack) {
            if (slot < 9) {
                inv.set(slot, stack);
                if (!stack.isEmpty() && stack.getCount() > getInventoryStackLimit())
                    stack.setCount(getInventoryStackLimit());
            }
            recalculateOutput();
        }

        @Override
        public void clear() {
            for (int i = 0; i < this.inv.size(); i++)
                this.inv.set(i, ItemStack.EMPTY);
        }

        public void recalculateOutput() {
            InventoryCrafting invC = Utils.InventoryCraftingFalse.createFilledCraftingInventory(3, 3, inv);
            this.recipe = Utils.findRecipe(invC, tile.getWorld());
            this.inv.set(9, recipe != null ? recipe.getCraftingResult(invC) : ItemStack.EMPTY);
        }

        public ArrayList<ItemStack> getTotalPossibleOutputs() {
            ArrayList<ItemStack> outputList = new ArrayList<ItemStack>();
            outputList.add(inv.get(9).copy());
            for (int i = 0; i < 9; i++) {
                FluidStack fs = FluidUtil.getFluidContained(inv.get(i));
                if (fs != null) {
                    boolean hasFluid = false;
                    for (FluidTank tank : tile.tanks)
                        if (tank.getFluid() != null && tank.getFluid().containsFluid(fs)) {
                            hasFluid = true;
                            break;
                        }
                    if (hasFluid)
                        continue;
                }
                //            ItemStack container = inv[i].getItem().getContainerItem(inv[i]);
                //            if(container!=null && inv[i].getItem().doesContainerItemLeaveCraftingGrid(inv[i]))
                //               outputList.add(container.copy());
            }
            InventoryCrafting invC = Utils.InventoryCraftingFalse.createFilledCraftingInventory(3, 3, inv);
            for (ItemStack ss : this.recipe.getRemainingItems(invC))
                if (!ss.isEmpty())
                    outputList.add(ss);
            return outputList;
        }

        @Override
        public String getName() {
            return "IECrafterPattern";
        }

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

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

        @Override
        public boolean isUsableByPlayer(EntityPlayer player) {
            return true;
        }

        @Override
        public void openInventory(EntityPlayer player) {
        }

        @Override
        public void closeInventory(EntityPlayer player) {
        }

        @Override
        public boolean isItemValidForSlot(int slot, ItemStack stack) {
            return true;
        }

        @Override
        public void markDirty() {
            this.tile.markDirty();
        }

        public void writeToNBT(NBTTagList list) {
            for (int i = 0; i < this.inv.size(); i++)
                if (!this.inv.get(i).isEmpty()) {
                    NBTTagCompound itemTag = new NBTTagCompound();
                    itemTag.setByte("Slot", (byte) i);
                    this.inv.get(i).writeToNBT(itemTag);
                    list.appendTag(itemTag);
                }
        }

        public void readFromNBT(NBTTagList list) {
            for (int i = 0; i < list.tagCount(); i++) {
                NBTTagCompound itemTag = list.getCompoundTagAt(i);
                int slot = itemTag.getByte("Slot") & 255;
                if (slot >= 0 && slot < getSizeInventory())
                    this.inv.set(slot, new ItemStack(itemTag));
            }
            recalculateOutput();
        }

        @Override
        public ITextComponent getDisplayName() {
            return new TextComponentString(this.getName());
        }

        @Override
        public int getField(int id) {
            return 0;
        }

        @Override
        public void setField(int id, int value) {
        }

        @Override
        public int getFieldCount() {
            return 0;
        }
    }
}