package crazypants.enderio.machine.invpanel;
import java.awt.Point;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
import com.enderio.core.client.gui.widget.GhostBackgroundItemSlot;
import com.enderio.core.client.gui.widget.GhostSlot;
import com.enderio.core.common.util.ItemUtil;
import cpw.mods.fml.common.FMLCommonHandler;
import crazypants.enderio.EnderIO;
import crazypants.enderio.Log;
import crazypants.enderio.machine.gui.AbstractMachineContainer;
import crazypants.enderio.machine.invpanel.server.ChangeLog;
import crazypants.enderio.machine.invpanel.server.InventoryDatabaseServer;
import crazypants.enderio.machine.invpanel.server.ItemEntry;
import crazypants.enderio.network.PacketHandler;
public class InventoryPanelContainer extends AbstractMachineContainer<TileInventoryPanel> implements ChangeLog {
public static final int CRAFTING_GRID_X = 24+7;
public static final int CRAFTING_GRID_Y = 16;
public static final int RETURN_INV_X = 24+7;
public static final int RETURN_INV_Y = 82;
public static final int FILTER_SLOT_X = 24+233;
public static final int FILTER_SLOT_Y = 7;
private final HashSet<ItemEntry> changedItems;
private Slot slotFilter;
private int slotCraftResult;
private int firstSlotReturn;
private int endSlotReturn;
private int firstSlotCraftingGrid;
private int endSlotCraftingGrid;
private boolean updateReturnAreaSlots;
private boolean storedRecipeExists;
public InventoryPanelContainer(InventoryPlayer playerInv, TileInventoryPanel te) {
super(playerInv, te);
te.eventHandler = this;
if(te.getWorldObj().isRemote) {
changedItems = null;
} else {
changedItems = new HashSet<ItemEntry>();
}
}
@Override
protected void addMachineSlots(InventoryPlayer playerInv) {
slotCraftResult = inventorySlots.size();
addSlotToContainer(new SlotCrafting(playerInv.player, getInv(), getInv(), TileInventoryPanel.SLOT_CRAFTING_RESULT, CRAFTING_GRID_X + 59,
CRAFTING_GRID_Y + 18) {
@Override
public void onPickupFromSlot(EntityPlayer player, ItemStack p_82870_2_) {
FMLCommonHandler.instance().firePlayerCraftingEvent(player, p_82870_2_, getInv());
for (int i = TileInventoryPanel.SLOT_CRAFTING_START; i < TileInventoryPanel.SLOT_CRAFTING_RESULT; i++) {
ItemStack itemstack = getInv().getStackInSlot(i);
if(itemstack == null)
continue;
getInv().decrStackSize(i, 1);
if(!itemstack.getItem().hasContainerItem(itemstack))
continue;
ItemStack containerIS = itemstack.getItem().getContainerItem(itemstack);
if(containerIS != null && containerIS.isItemStackDamageable() && containerIS.getItemDamage() > containerIS.getMaxDamage()) {
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, containerIS));
} else {
if(itemstack.getItem().doesContainerItemLeaveCraftingGrid(itemstack)) {
if(ItemUtil.doInsertItem(getInv(), 10, 20, itemstack) > 0)
continue;
if(player.inventory.addItemStackToInventory(containerIS))
continue;
}
if(getInv().getStackInSlot(i) == null) {
getInv().setInventorySlotContents(i, containerIS);
} else {
player.dropPlayerItemWithRandomChoice(containerIS, false);
}
}
}
}
@Override
public ItemStack decrStackSize(int p_75209_1_) {
if (this.getHasStack()) {
// on a right click we are asked to craft half a result. Ignore that.
return super.decrStackSize(this.getStack().stackSize);
}
return super.decrStackSize(p_75209_1_);
}
});
firstSlotCraftingGrid = inventorySlots.size();
for (int y = 0, i = TileInventoryPanel.SLOT_CRAFTING_START; y < 3; y++) {
for (int x = 0; x < 3; x++, i++) {
addSlotToContainer(new Slot(getInv(), i, CRAFTING_GRID_X + x * 18, CRAFTING_GRID_Y + y * 18));
}
}
endSlotCraftingGrid = inventorySlots.size();
slotFilter = addSlotToContainer(new Slot(getInv(), TileInventoryPanel.SLOT_VIEW_FILTER, FILTER_SLOT_X, FILTER_SLOT_Y) {
@Override
public int getSlotStackLimit() {
return 1;
}
});
firstSlotReturn = inventorySlots.size();
for (int y = 0, i = TileInventoryPanel.SLOT_RETURN_START; y < 2; y++) {
for (int x = 0; x < 5; x++, i++) {
addSlotToContainer(new Slot(getInv(), i, RETURN_INV_X + x * 18, RETURN_INV_Y + y * 18));
}
}
endSlotReturn = inventorySlots.size();
}
public void createGhostSlots(List<GhostSlot> slots) {
slots.add(new GhostBackgroundItemSlot(EnderIO.itemBasicFilterUpgrade, FILTER_SLOT_X, FILTER_SLOT_Y));
}
@Override
public Point getPlayerInventoryOffset() {
return new Point(24+39, 130);
}
@Override
public void onContainerClosed(EntityPlayer player) {
super.onContainerClosed(player);
if(!getInv().getWorldObj().isRemote) {
((TileInventoryPanel) getInv()).eventHandler = null;
}
removeChangeLog();
}
public TileInventoryPanel getInventoryPanel() {
return (TileInventoryPanel) getInv();
}
public Slot getSlotFilter() {
return slotFilter;
}
@SuppressWarnings("unchecked")
public List<Slot> getCraftingGridSlots() {
return inventorySlots.subList(firstSlotCraftingGrid, endSlotCraftingGrid);
}
@SuppressWarnings("unchecked")
public List<Slot> getReturnAreaSlots() {
return inventorySlots.subList(firstSlotReturn, endSlotReturn);
}
@SuppressWarnings("unchecked")
public List<Slot> getPlayerInventorySlots() {
return inventorySlots.subList(startPlayerSlot, endPlayerSlot);
}
@SuppressWarnings("unchecked")
public List<Slot> getPlayerHotbarSlots() {
return inventorySlots.subList(startHotBarSlot, endHotBarSlot);
}
private void removeChangeLog() {
if(changedItems != null) {
InventoryDatabaseServer db = getInventoryPanel().getDatabaseServer();
if(db != null) {
db.removeChangeLog(this);
}
}
}
@Override
public void removeCraftingFromCrafters(ICrafting crafting) {
super.removeCraftingFromCrafters(crafting);
removeChangeLog();
}
@Override
public void addCraftingToCrafters(ICrafting crafting) {
if(changedItems != null) {
sendChangeLog();
}
super.addCraftingToCrafters(crafting);
if(changedItems != null) {
InventoryDatabaseServer db = getInventoryPanel().getDatabaseServer();
if(db != null) {
db.addChangeLog(this);
if(crafting instanceof EntityPlayerMP) {
try {
byte[] compressed = db.compressItemList();
PacketItemList pil = new PacketItemList(getInventoryPanel(), db.getGeneration(), compressed);
PacketHandler.sendTo(pil, (EntityPlayerMP) crafting);
} catch (IOException ex) {
Logger.getLogger(InventoryPanelContainer.class.getName()).log(Level.SEVERE, "Exception while compressing item list", ex);
}
}
}
}
}
@Override
public void onCraftMatrixChanged(IInventory inv) {
InventoryCrafting tmp = new InventoryCrafting(new Container() {
@Override
public boolean canInteractWith(EntityPlayer ep) {
return false;
}
}, 3, 3);
for (int i = 0; i < 9; i++) {
tmp.setInventorySlotContents(i, getInv().getStackInSlot(i));
}
getInv().setInventorySlotContents(9, CraftingManager.getInstance().findMatchingRecipe(tmp, getInv().getWorldObj()));
checkCraftingRecipes();
}
public void checkCraftingRecipes() {
storedRecipeExists = false;
int storedCraftingRecipes = getInventoryPanel().getStoredCraftingRecipes();
if(hasCraftingRecipe() && storedCraftingRecipes > 0) {
List<Slot> craftingGrid = getCraftingGridSlots();
for(int idx = 0; idx < storedCraftingRecipes; idx++) {
if(getInventoryPanel().getStoredCraftingRecipe(idx).isEqual(craftingGrid)) {
storedRecipeExists = true;
break;
}
}
}
}
@Override
public boolean func_94530_a(ItemStack par1, Slot slot) {
return !(slot instanceof SlotCrafting) && super.func_94530_a(par1, slot);
}
public boolean clearCraftingGrid() {
boolean cleared = true;
for (Slot slot : getCraftingGridSlots()) {
if(slot.getHasStack()) {
moveItemsToReturnArea(slot.slotNumber);
if(slot.getHasStack()) {
cleared = false;
}
}
}
return cleared;
}
public boolean hasCraftingRecipe() {
return getSlot(slotCraftResult).getHasStack();
}
public boolean hasNewCraftingRecipe() {
return hasCraftingRecipe() && !storedRecipeExists;
}
@Override
protected List<SlotRange> getTargetSlotsForTransfer(int slotIndex, Slot slot) {
if((slotIndex == slotCraftResult) || (slotIndex >= firstSlotReturn && slotIndex < endSlotReturn)) {
return Collections.singletonList(getPlayerInventorySlotRange(true));
}
if(slotIndex >= firstSlotCraftingGrid && slotIndex < endSlotCraftingGrid) {
ArrayList<SlotRange> res = new ArrayList<SlotRange>();
res.add(new SlotRange(firstSlotReturn, endSlotReturn, false));
res.add(getPlayerInventorySlotRange(false));
return res;
}
if(slotIndex >= startPlayerSlot) {
return Collections.singletonList(new SlotRange(firstSlotReturn, endSlotReturn, false));
}
return Collections.emptyList();
}
@Override
protected boolean mergeItemStack(ItemStack par1ItemStack, int fromIndex, int toIndex, boolean reversOrder) {
if(!super.mergeItemStack(par1ItemStack, fromIndex, toIndex, reversOrder)) {
return false;
}
if(fromIndex < endSlotReturn && toIndex > firstSlotReturn) {
updateReturnAreaSlots = true;
}
return true;
}
@Override
public void detectAndSendChanges() {
if(updateReturnAreaSlots) {
updateReturnAreaSlots = false;
sendReturnAreaSlots();
}
super.detectAndSendChanges();
}
@SuppressWarnings("unchecked")
private void sendReturnAreaSlots() {
for (int slotIdx = firstSlotReturn; slotIdx < endSlotReturn; slotIdx++) {
ItemStack stack = ((Slot) inventorySlots.get(slotIdx)).getStack();
if(stack != null) {
stack = stack.copy();
}
inventoryItemStacks.set(slotIdx, stack);
for (Object crafter : this.crafters) {
((ICrafting) crafter).sendSlotContents(this, slotIdx, stack);
}
}
}
@Override
public void entryChanged(ItemEntry entry) {
changedItems.add(entry);
}
@Override
public void databaseReset() {
changedItems.clear();
}
@Override
public void sendChangeLog() {
if(!changedItems.isEmpty() && !crafters.isEmpty()) {
InventoryDatabaseServer db = getInventoryPanel().getDatabaseServer();
if(db != null) {
try {
byte[] compressed = db.compressChangedItems(changedItems);
PacketItemList pil = new PacketItemList(getInventoryPanel(), db.getGeneration(), compressed);
for (Object crafting : crafters) {
if(crafting instanceof EntityPlayerMP) {
PacketHandler.sendTo(pil, (EntityPlayerMP) crafting);
}
}
} catch (IOException ex) {
Logger.getLogger(InventoryPanelContainer.class.getName()).log(Level.SEVERE, "Exception while compressing changed items", ex);
}
}
}
changedItems.clear();
}
public int getSlotIndex(IInventory inv, int index) {
for (int i = 0; i < inventorySlots.size(); i++) {
Slot slot = (Slot) inventorySlots.get(i);
if(slot.isSlotInInventory(inv, index)) {
return i;
}
}
return -1;
}
public void executeFetchItems(EntityPlayerMP player, int generation, int dbID, int targetSlot, int count) {
TileInventoryPanel te = getInventoryPanel();
InventoryDatabaseServer db = te.getDatabaseServer();
if(db == null || db.getGeneration() != generation || !db.isCurrent()) {
return;
}
ItemEntry entry = db.getExistingItem(dbID);
if(entry != null) {
ItemStack targetStack;
Slot slot;
int maxStackSize;
if(targetSlot < 0) {
slot = null;
targetStack = player.inventory.getItemStack();
maxStackSize = player.inventory.getInventoryStackLimit();
} else {
slot = getSlot(targetSlot);
targetStack = slot.getStack();
maxStackSize = slot.getSlotStackLimit();
}
ItemStack tmpStack = new ItemStack(entry.getItem(), 0, entry.meta);
Log.info("Loading item from ID " + entry.itemID + ". Result: " + Item.itemRegistry.getNameForObject(tmpStack.getItem()) + " side: " + FMLCommonHandler.instance().getEffectiveSide());
tmpStack.stackTagCompound = entry.nbt;
maxStackSize = Math.min(maxStackSize, tmpStack.getMaxStackSize());
if(targetStack != null && targetStack.stackSize > 0) {
if(!ItemUtil.areStackMergable(tmpStack, targetStack)) {
return;
}
} else {
targetStack = tmpStack.copy();
}
count = Math.min(count, maxStackSize - targetStack.stackSize);
if(count > 0) {
int extracted = db.extractItems(entry, count, te);
if(extracted > 0) {
targetStack.stackSize += extracted;
sendChangeLog();
if(slot != null) {
slot.putStack(targetStack);
} else {
player.inventory.setItemStack(targetStack);
player.updateHeldItem();
}
}
}
}
}
public boolean moveItemsToReturnArea(int fromSlot) {
return moveItems(fromSlot, firstSlotReturn, endSlotReturn, Short.MAX_VALUE);
}
public boolean moveItems(int fromSlot, int toSlotStart, int toSlotEnd, int amount) {
if(!executeMoveItems(fromSlot, toSlotStart, toSlotEnd, amount)) {
return false;
}
if(getInv().getWorldObj().isRemote) {
PacketHandler.INSTANCE.sendToServer(new PacketMoveItems(fromSlot, toSlotStart, toSlotEnd, amount));
}
return true;
}
public boolean executeMoveItems(int fromSlot, int toSlotStart, int toSlotEnd, int amount) {
if((fromSlot >= toSlotStart && fromSlot < toSlotEnd) || toSlotEnd <= toSlotStart || amount <= 0) {
return false;
}
Slot srcSlot = getSlot(fromSlot);
ItemStack src = srcSlot.getStack();
if(src != null) {
ItemStack toMove = src.copy();
toMove.stackSize = Math.min(src.stackSize, amount);
int remaining = src.stackSize - toMove.stackSize;
if(mergeItemStack(toMove, toSlotStart, toSlotEnd, false)) {
remaining += toMove.stackSize;
if(remaining == 0) {
srcSlot.putStack(null);
} else {
src.stackSize = remaining;
srcSlot.onSlotChanged();
}
return true;
}
}
return false;
}
}