508 lines
13 KiB
Java
508 lines
13 KiB
Java
package buildcraft.silicon;
|
|
|
|
import java.util.EnumMap;
|
|
import java.util.Map;
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
import gnu.trove.map.hash.TObjectIntHashMap;
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.init.Items;
|
|
import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.inventory.ISidedInventory;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
|
|
import buildcraft.BuildCraftCore;
|
|
import buildcraft.BuildCraftSilicon;
|
|
import buildcraft.api.core.BCLog;
|
|
import buildcraft.api.core.IInvSlot;
|
|
import buildcraft.core.lib.block.TileBuildCraft;
|
|
import buildcraft.core.lib.inventory.InventoryIterator;
|
|
import buildcraft.core.lib.inventory.SimpleInventory;
|
|
import buildcraft.core.lib.inventory.StackHelper;
|
|
import buildcraft.core.lib.utils.NBTUtils;
|
|
|
|
public class TilePackager extends TileBuildCraft implements ISidedInventory {
|
|
private class Requirement {
|
|
public final IInventory location;
|
|
public final int slot;
|
|
|
|
public Requirement(IInventory location, int slot) {
|
|
this.location = location;
|
|
this.slot = slot;
|
|
}
|
|
|
|
public boolean isValid() {
|
|
return location.getSizeInventory() > slot && (!(location instanceof TileEntity) || !((TileEntity) location).isInvalid());
|
|
}
|
|
|
|
public ItemStack getStack() {
|
|
return location.getStackInSlot(slot);
|
|
}
|
|
|
|
public ItemStack decrStackSize(int amount) {
|
|
return location.decrStackSize(slot, amount);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
if (other == null || !(other instanceof Requirement)) {
|
|
return false;
|
|
}
|
|
|
|
Requirement r = (Requirement) other;
|
|
|
|
return r.location.equals(this.location) && r.slot == this.slot;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return location.hashCode() + (slot * 17);
|
|
}
|
|
}
|
|
|
|
// Slot 10 is currently missing. Left in for backwards compat.
|
|
private static final int[] SLOTS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11};
|
|
|
|
public SimpleInventory inventoryPublic = new SimpleInventory(12, "Packager", 64);
|
|
public SimpleInventory inventoryPattern = new SimpleInventory(9, "Packager", 64);
|
|
|
|
private Requirement[] requirements = new Requirement[9];
|
|
private int patternsSet;
|
|
private int updateTime = BuildCraftCore.random.nextInt(5);
|
|
|
|
public boolean isPatternSlotSet(int p) {
|
|
return (patternsSet & (1 << p)) != 0;
|
|
}
|
|
|
|
public void setPatternSlot(int p, boolean v) {
|
|
if (v) {
|
|
patternsSet |= 1 << p;
|
|
} else {
|
|
patternsSet &= ~(1 << p);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void updateEntity() {
|
|
if (worldObj.isRemote) {
|
|
return;
|
|
}
|
|
|
|
if ((updateTime++) % 5 == 0 && patternsSet > 0) {
|
|
attemptCrafting(inventoryPublic.getStackInSlot(9));
|
|
}
|
|
}
|
|
|
|
private boolean validMissing(Requirement r, int missingCount) {
|
|
ItemStack inputStack = r.getStack();
|
|
if (inputStack != null && inputStack.stackSize >= missingCount) {
|
|
// Check if same type used elsewhere
|
|
for (int j = 0; j < 9; j++) {
|
|
ItemStack comparedStack = inventoryPattern.getStackInSlot(j);
|
|
if (isPatternSlotSet(j) && comparedStack != null && StackHelper.isMatchingItem(inputStack, comparedStack, true, false)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
private boolean attemptCrafting(ItemStack input) {
|
|
// STEP 0: Make sure the conditions are correct.
|
|
if (inventoryPublic.getStackInSlot(11) != null) {
|
|
return false;
|
|
}
|
|
|
|
if (input == null || input.stackSize == 0 || !(input.getItem() == Items.paper || input.getItem() instanceof ItemPackage)) {
|
|
return false;
|
|
}
|
|
|
|
if (input.getItem() instanceof ItemPackage) {
|
|
NBTTagCompound inputTag = NBTUtils.getItemData(input);
|
|
|
|
for (int i = 0; i < 9; i++) {
|
|
if (isPatternSlotSet(i) && inputTag.hasKey("item" + i)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
TObjectIntHashMap<Requirement> reqCounts = new TObjectIntHashMap<Requirement>(9);
|
|
int missingCount = 0;
|
|
|
|
int filteredReqsToFulfill = 0;
|
|
|
|
// STEP 1: Verify all requirements and nullify ones which don't match.
|
|
// Also, add them to a Multimap so we can know which ones get used how often.
|
|
for (int i = 0; i < 9; i++) {
|
|
if (isPatternSlotSet(i)) {
|
|
ItemStack inputStack = inventoryPattern.getStackInSlot(i);
|
|
if (inputStack != null) {
|
|
filteredReqsToFulfill++;
|
|
} else {
|
|
missingCount++;
|
|
requirements[i] = null;
|
|
continue;
|
|
}
|
|
|
|
Requirement r = requirements[i];
|
|
if (r == null) {
|
|
continue;
|
|
}
|
|
if (!r.isValid()) {
|
|
requirements[i] = null;
|
|
continue;
|
|
}
|
|
if (r.getStack() == null) {
|
|
requirements[i] = null;
|
|
continue;
|
|
}
|
|
if (inputStack != null) {
|
|
if (!StackHelper.isMatchingItem(inputStack, r.getStack(), true, false)) {
|
|
requirements[i] = null;
|
|
continue;
|
|
}
|
|
}
|
|
reqCounts.adjustOrPutValue(requirements[i], 1, 1);
|
|
filteredReqsToFulfill--;
|
|
} else {
|
|
requirements[i] = null;
|
|
}
|
|
}
|
|
|
|
// STEP 2: Verify that the counts are correct.
|
|
for (Requirement r : reqCounts.keys(new Requirement[reqCounts.size()])) {
|
|
if (r.getStack().stackSize < reqCounts.get(r)) {
|
|
int allowedAmount = 0;
|
|
for (int i = 0; i < 9; i++) {
|
|
if (requirements[i] != null && requirements[i].equals(r)) {
|
|
allowedAmount--;
|
|
if (allowedAmount < 0) {
|
|
requirements[i] = null;
|
|
filteredReqsToFulfill++;
|
|
}
|
|
}
|
|
}
|
|
reqCounts.remove(r);
|
|
}
|
|
}
|
|
|
|
// STEP 3: Look for all filtered slots. We also use adjacent inventories for this.
|
|
// STEP 3a: Local
|
|
if (filteredReqsToFulfill > 0) {
|
|
for (int i = 0; i < 9; i++) {
|
|
if (filteredReqsToFulfill == 0) {
|
|
break;
|
|
}
|
|
if (isPatternSlotSet(i) && requirements[i] == null) {
|
|
ItemStack inputStack = inventoryPattern.getStackInSlot(i);
|
|
if (inputStack != null) {
|
|
for (int j = 0; j < 9; j++) {
|
|
ItemStack comparedStack = inventoryPublic.getStackInSlot(j);
|
|
if (comparedStack == null) {
|
|
continue;
|
|
}
|
|
Requirement r = new Requirement(this, j);
|
|
if (comparedStack.stackSize <= reqCounts.get(r)) {
|
|
continue;
|
|
}
|
|
|
|
if (StackHelper.isMatchingItem(inputStack, comparedStack, true, false)) {
|
|
requirements[i] = r;
|
|
filteredReqsToFulfill--;
|
|
reqCounts.adjustOrPutValue(r, 1, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// STEP 3b: Remote
|
|
Map<ForgeDirection, IInventory> invs = new EnumMap<ForgeDirection, IInventory>(ForgeDirection.class);
|
|
if (filteredReqsToFulfill > 0 || missingCount > 0) {
|
|
for (int i = 2; i < 6; i++) {
|
|
TileEntity neighbor = getTile(ForgeDirection.getOrientation(i));
|
|
if (neighbor instanceof IInventory) {
|
|
invs.put(ForgeDirection.getOrientation(i), (IInventory) neighbor);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (filteredReqsToFulfill > 0) {
|
|
for (ForgeDirection dir : invs.keySet()) {
|
|
if (filteredReqsToFulfill == 0) {
|
|
break;
|
|
}
|
|
IInventory inv = invs.get(dir);
|
|
Iterable<IInvSlot> iterator = InventoryIterator.getIterable(inv, dir.getOpposite());
|
|
for (IInvSlot slot : iterator) {
|
|
if (filteredReqsToFulfill == 0) {
|
|
break;
|
|
}
|
|
ItemStack comparedStack = slot.getStackInSlot();
|
|
if (comparedStack == null || !slot.canTakeStackFromSlot(comparedStack)) {
|
|
continue;
|
|
}
|
|
Requirement r = new Requirement(inv, slot.getIndex());
|
|
if (comparedStack.stackSize <= reqCounts.get(r)) {
|
|
continue;
|
|
}
|
|
|
|
for (int j = 0; j < 9; j++) {
|
|
ItemStack inputStack = inventoryPattern.getStackInSlot(j);
|
|
if (isPatternSlotSet(j) && requirements[j] == null && inputStack != null) {
|
|
if (StackHelper.isMatchingItem(inputStack, comparedStack, true, false)) {
|
|
filteredReqsToFulfill--;
|
|
requirements[j] = r;
|
|
reqCounts.adjustOrPutValue(r, 1, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (filteredReqsToFulfill > 0) {
|
|
return false;
|
|
}
|
|
|
|
// STEP 4: Find a matching missing.
|
|
boolean foundMissing = false;
|
|
|
|
if (missingCount > 0) {
|
|
for (int i = 0; i < 9; i++) {
|
|
Requirement r = new Requirement(this, i);
|
|
if (reqCounts.contains(r)) {
|
|
continue;
|
|
}
|
|
if (validMissing(r, missingCount)) {
|
|
foundMissing = true;
|
|
for (int j = 0; j < 9; j++) {
|
|
if (requirements[j] == null && isPatternSlotSet(j) && inventoryPattern.getStackInSlot(j) == null) {
|
|
requirements[j] = r;
|
|
}
|
|
}
|
|
reqCounts.adjustOrPutValue(r, missingCount, missingCount);
|
|
missingCount = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (missingCount > 0) {
|
|
for (ForgeDirection dir : invs.keySet()) {
|
|
if (foundMissing) {
|
|
break;
|
|
}
|
|
IInventory inv = invs.get(dir);
|
|
Iterable<IInvSlot> iterator = InventoryIterator.getIterable(inv, dir.getOpposite());
|
|
for (IInvSlot slot : iterator) {
|
|
if (foundMissing) {
|
|
break;
|
|
}
|
|
Requirement r = new Requirement(inv, slot.getIndex());
|
|
if (reqCounts.contains(r)) {
|
|
continue;
|
|
}
|
|
if (validMissing(r, missingCount)) {
|
|
foundMissing = true;
|
|
for (int j = 0; j < 9; j++) {
|
|
if (requirements[j] == null && isPatternSlotSet(j) && inventoryPattern.getStackInSlot(j) == null) {
|
|
requirements[j] = r;
|
|
}
|
|
}
|
|
reqCounts.adjustOrPutValue(r, missingCount, missingCount);
|
|
missingCount = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (missingCount > 0) {
|
|
return false;
|
|
}
|
|
|
|
// STEP 5: Craft and output.
|
|
ItemStack pkg;
|
|
if (input.getItem() instanceof ItemPackage) {
|
|
pkg = input.copy();
|
|
} else {
|
|
pkg = new ItemStack(BuildCraftSilicon.packageItem);
|
|
}
|
|
NBTTagCompound pkgTag = NBTUtils.getItemData(pkg);
|
|
|
|
boolean broken = false;
|
|
|
|
for (int i = 0; i < 9; i++) {
|
|
if (isPatternSlotSet(i)) {
|
|
if (requirements[i] == null) {
|
|
BCLog.logger.error("(Recipe Packager) At " + xCoord + ", " + yCoord + ", " + zCoord + " requirement " + i + " was null! THIS SHOULD NOT HAPPEN!");
|
|
broken = true;
|
|
continue;
|
|
}
|
|
ItemStack usedStack = requirements[i].decrStackSize(1);
|
|
if (usedStack == null) {
|
|
BCLog.logger.error("(Recipe Packager) At " + xCoord + ", " + yCoord + ", " + zCoord + " stack at slot " + i + " was too small! THIS SHOULD NOT HAPPEN!");
|
|
broken = true;
|
|
continue;
|
|
}
|
|
NBTTagCompound itemTag = new NBTTagCompound();
|
|
usedStack.writeToNBT(itemTag);
|
|
pkgTag.setTag("item" + i, itemTag);
|
|
}
|
|
}
|
|
|
|
if (broken) {
|
|
return false;
|
|
}
|
|
|
|
ItemPackage.update(pkg);
|
|
|
|
decrStackSize(9, 1);
|
|
setInventorySlotContents(11, pkg);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void readData(ByteBuf stream) {
|
|
super.readData(stream);
|
|
patternsSet = stream.readUnsignedShort();
|
|
}
|
|
|
|
@Override
|
|
public void writeData(ByteBuf stream) {
|
|
super.writeData(stream);
|
|
stream.writeShort(patternsSet);
|
|
}
|
|
|
|
@Override
|
|
public void readFromNBT(NBTTagCompound cpd) {
|
|
super.readFromNBT(cpd);
|
|
inventoryPublic.readFromNBT(cpd, "items");
|
|
inventoryPattern.readFromNBT(cpd, "pattern");
|
|
patternsSet = cpd.getShort("patternSet");
|
|
}
|
|
|
|
@Override
|
|
public void writeToNBT(NBTTagCompound cpd) {
|
|
super.writeToNBT(cpd);
|
|
inventoryPublic.writeToNBT(cpd, "items");
|
|
inventoryPattern.writeToNBT(cpd, "pattern");
|
|
cpd.setShort("patternSet", (short) patternsSet);
|
|
}
|
|
|
|
@Override
|
|
public int getSizeInventory() {
|
|
return inventoryPublic.getSizeInventory();
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getStackInSlot(int slot) {
|
|
return inventoryPublic.getStackInSlot(slot);
|
|
}
|
|
|
|
@Override
|
|
public ItemStack decrStackSize(int slot, int amount) {
|
|
return inventoryPublic.decrStackSize(slot, amount);
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getStackInSlotOnClosing(int slot) {
|
|
return inventoryPublic.getStackInSlotOnClosing(slot);
|
|
}
|
|
|
|
@Override
|
|
public void setInventorySlotContents(int slot, ItemStack stack) {
|
|
inventoryPublic.setInventorySlotContents(slot, stack);
|
|
}
|
|
|
|
@Override
|
|
public String getInventoryName() {
|
|
return "Packager";
|
|
}
|
|
|
|
@Override
|
|
public boolean hasCustomInventoryName() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getInventoryStackLimit() {
|
|
return 64;
|
|
}
|
|
|
|
@Override
|
|
public boolean isUseableByPlayer(EntityPlayer player) {
|
|
return inventoryPublic.isUseableByPlayer(player);
|
|
}
|
|
|
|
@Override
|
|
public void openInventory() {
|
|
inventoryPublic.openInventory();
|
|
}
|
|
|
|
@Override
|
|
public void closeInventory() {
|
|
inventoryPublic.closeInventory();
|
|
}
|
|
|
|
@Override
|
|
public boolean isItemValidForSlot(int slot, ItemStack stack) {
|
|
if (slot == 9) {
|
|
return stack == null || stack.getItem() == Items.paper || stack.getItem() instanceof ItemPackage;
|
|
}
|
|
return inventoryPublic.isItemValidForSlot(slot, stack);
|
|
}
|
|
|
|
@Override
|
|
public int[] getAccessibleSlotsFromSide(int side) {
|
|
return SLOTS;
|
|
}
|
|
|
|
@Override
|
|
public boolean canInsertItem(int slot, ItemStack stack, int side) {
|
|
if (side >= 2) {
|
|
if (slot >= 9) {
|
|
return false;
|
|
}
|
|
ItemStack slotStack = inventoryPublic.getStackInSlot(slot);
|
|
if (StackHelper.canStacksMerge(stack, slotStack)) {
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0; i < 9; i++) {
|
|
if (isPatternSlotSet(i)) {
|
|
ItemStack inputStack = inventoryPattern.getStackInSlot(i);
|
|
if (inputStack == null) {
|
|
return true;
|
|
}
|
|
if (StackHelper.isMatchingItem(inputStack, stack, true, false)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
} else {
|
|
return slot == 9;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean canExtractItem(int slot, ItemStack stack, int side) {
|
|
return slot == 11;
|
|
}
|
|
}
|