package com.arkcraft.module.crafting.common.inventory; import java.util.Iterator; import java.util.List; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.InventoryBasic; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.arkcraft.lib.LogHelper; import com.arkcraft.module.core.ARKCraft; import com.arkcraft.module.core.common.entity.data.ARKPlayer; import com.arkcraft.module.core.common.network.UpdatePlayerCrafting; import com.arkcraft.module.crafting.common.handlers.ARKCraftingManager; import com.arkcraft.module.crafting.common.handlers.IARKRecipe; /** * @author wildbill22 */ public class InventoryBlueprints extends InventoryBasic { ARKCraftingManager craftingManager; InventoryPlayerCrafting invCrafting; // IInventory invCrafting; public InventoryBlueprints(String title, boolean customName, int slotCount) { super(title, customName, slotCount); } public InventoryBlueprints(String title, boolean customName, int slotCount, ARKCraftingManager craftingManager, InventoryPlayerCrafting invCrafting, short craftTimeForItem) { super(title, customName, slotCount); this.craftingManager = craftingManager; setNumBlueprints(craftingManager.getNumRecipes()); fillInventoryWithRecipes(); this.invCrafting = invCrafting; CRAFT_TIME_FOR_ITEM = craftTimeForItem; } // We do not save the blueprint inventory to NBT, it is loaded from the Crafting Manager /** * Do not give this method the name canInteractWith because it clashes with Container */ public boolean isUseableByPlayer(EntityPlayer player) { return false; } public void openInventory(EntityPlayer player) { super.openInventory(player); } public void closeInventory(EntityPlayer player) { super.closeInventory(player); } //----------------- End of normal inventory function, rest for crafting ----------------- // Variables to sync from client to server private boolean craftOne = false; private short blueprintPressed = 0; // Button pressed private void sendUpdateToServer() { ARKCraft.modChannel.sendToServer(new UpdatePlayerCrafting(craftOne, blueprintPressed)); } public void setCraftOnePressed(boolean craftOnePressed, int i, boolean andUpdateServer) { // LogHelper.info("InventoryBlueprints: Set craftOne to " + craftOnePressed + " on " + FMLCommonHandler.instance().getEffectiveSide()); this.craftOne = craftOnePressed; blueprintPressed = (short) i; if (andUpdateServer) { sendUpdateToServer(); } } /** * The number of blueprints (number of recipes defined) */ private int numBlueprints; public int getNumBlueprints() { return numBlueprints; } public void setNumBlueprints(int num) { this.numBlueprints = num; } public boolean isCrafting() { return craftOne; } /** * Returns double between 0 and 1 representing % done */ public double fractionCraftingRemainingForItem() { if (craftingTime < 0) { return 0.0D; } double fraction = craftingTime / (double) CRAFT_TIME_FOR_ITEM; return MathHelper.clamp_double(fraction, 0.0, 1.0); } /** * The number of items that can be crafted */ private short numThatCanBeCrafted = 0; private final int craftTickRefreshRate = 5; private int canCraftTick = craftTickRefreshRate; // Warning: numThatCanBeCrafted is only set on client when this is called, but crafting logic takes this into account @SideOnly(Side.CLIENT) public int getNumToBeCrafted(int i) { if (canCraftTick >= 0) { canCraftTick--; } else { canCraftTick = craftTickRefreshRate; } if (canCraftTick == craftTickRefreshRate) { blueprintPressed = (short) i; canCraft(); } return numThatCanBeCrafted; } /** * The number of seconds required to craft an item */ private static short CRAFT_TIME_FOR_ITEM; /** * The number of seconds the current item has been crafting * Logic: * -1 when none are being crafted * 0 when the items is to be crafted * n seconds until it will be crafted */ private short craftingTime = -1; /** * Time to craft current item being crafted */ public int craftingTimeRemainingOnItem() { return (int) craftingTime; } private int tick = 20; // This method is called every tick to update the tile entity (called from PlayerTickEvent) // It runs both on the server and the client. public void update() { if (tick >= 0) { tick--; return; } else { tick = 20; } // LogHelper.info("InventoryBlueprints: Update called on " + FMLCommonHandler.instance().getEffectiveSide()); // If not crafting an item, return if (!craftOne) { return; } // Reset crafting time if it reaches -1 (is true after crafting one of multiple, or after pushing button in GUI) if (craftingTime < 0) { craftingTime = CRAFT_TIME_FOR_ITEM; // See if an item can be crafted if (!craftItem(false)) { craftOne = false; craftingTime = -1; return; } } else { craftingTime--; } // If craftingTime has reached -1, try and craft the item if (craftingTime < 0) { LogHelper.info("InventoryBlueprints: About to craft the item on " + FMLCommonHandler.instance().getEffectiveSide()); craftItem(); craftOne = false; } } /** * Check if the item is craftable and there is sufficient space in the output slots * * @return true if crafting the item is possible */ private boolean canCraft() { return craftItem(false); } /** * Craft an item, if possible */ private boolean craftItem() { return craftItem(true); } /** * checks that there are enough items to craft the item and that there is room for the result in the output slots * If desired, crafts the item * * @param doCraftItem - If true, craft the item. If false, check whether crafting is possible, but don't change the inventory * @return false if no item can be crafted, true otherwise */ private boolean craftItem(boolean doCraftItem) { Integer firstSuitableOutputSlot = null; ItemStack result = getStackInSlot(blueprintPressed); // No recipes? if (result == null) { return false; } // find the first suitable output slot, 1st check for identical item that has enough space for (int outputSlot = ARKPlayer.LAST_INVENTORY_SLOT; outputSlot > ARKPlayer.FIRST_INVENTORY_SLOT; outputSlot--) { ItemStack outputStack = invCrafting.getStackInSlot(outputSlot); if (outputStack != null && outputStack.getItem() == result.getItem() && (!result.getHasSubtypes() || outputStack.getMetadata() == result.getMetadata()) && ItemStack.areItemStackTagsEqual(outputStack, result)) { int combinedSize = invCrafting.getStackInSlot(outputSlot).stackSize + result.stackSize; if (combinedSize <= invCrafting.getInventoryStackLimit() && combinedSize <= invCrafting.getStackInSlot(outputSlot).getMaxStackSize()) { firstSuitableOutputSlot = outputSlot; break; } } } if (firstSuitableOutputSlot == null) { // 2nd look for empty slot if no partially filled slots are found for (int outputSlot = ARKPlayer.LAST_INVENTORY_SLOT; outputSlot > ARKPlayer.FIRST_INVENTORY_SLOT; outputSlot--) { ItemStack outputStack = invCrafting.getStackInSlot(outputSlot); if (outputStack == null) { firstSuitableOutputSlot = outputSlot; break; } } } if (firstSuitableOutputSlot == null) { LogHelper.info("InventoryBlueprints: No output slots available."); return false; } // finds if there is enough inventory to craft the result numThatCanBeCrafted = (short) craftingManager.hasMatchingRecipe(result, invCrafting, false); if (numThatCanBeCrafted <= 0) { LogHelper.info("InventoryBlueprints: Can't craft item from inventory."); return false; } else if (!doCraftItem) { return true; } // Craft an item (after testing that there is enough inventory above) int numCrafted = (short) craftingManager.hasMatchingRecipe(result, invCrafting, true); // This should never be true! if (numCrafted <= 0) { return false; } // alter output slot LogHelper.info("InventoryBlueprints: Copy craft result to slot: " + firstSuitableOutputSlot); if (invCrafting.getStackInSlot(firstSuitableOutputSlot) == null) { invCrafting.setInventorySlotContents(firstSuitableOutputSlot, result.copy()); // Use deep .copy() to avoid altering the recipe } else { invCrafting.getStackInSlot(firstSuitableOutputSlot).stackSize += result.stackSize; } invCrafting.markDirty(); return true; } @SuppressWarnings("rawtypes") public void fillInventoryWithRecipes() { List recipes = craftingManager.getRecipeList(); Iterator iterator = recipes.iterator(); IARKRecipe irecipe; int i = 0; while (iterator.hasNext() && i < getSizeInventory()) { irecipe = (IARKRecipe) iterator.next(); setInventorySlotContents(i, irecipe.getRecipeOutput()); i++; } } // ----- For the progress indicator in the GUI: ----- /** * x position in GUI of the button pressed */ private int xButtonPressed; public int getxButtonPressed() { return xButtonPressed; } public void setxButtonPressed(int xButtonPressed) { this.xButtonPressed = xButtonPressed;} /** * y position in GUI of the button pressed */ private int yButtonPressed; public int getyButtonPressed() { return yButtonPressed; } public void setyButtonPressed(int yButtonPressed) { this.yButtonPressed = yButtonPressed; } }