diff --git a/src/main/java/mezz/jei/gui/CraftingGridHelper.java b/src/main/java/mezz/jei/gui/CraftingGridHelper.java index ec4a3451d..a3a6324b7 100644 --- a/src/main/java/mezz/jei/gui/CraftingGridHelper.java +++ b/src/main/java/mezz/jei/gui/CraftingGridHelper.java @@ -76,12 +76,12 @@ private int getCraftingIndex(int i, int width, int height) { if (height == 3) { index = (i * 3) + 1; } else if (height == 2) { - index = (i * 3) + 4; + index = (i * 3) + 1; } else { index = 4; } } else if (height == 1) { - index = i + 6; + index = i + 3; } else if (width == 2) { index = i; if (i > 1) { diff --git a/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java b/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java index af24f459a..f164c3e56 100644 --- a/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java +++ b/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java @@ -37,11 +37,12 @@ import mezz.jei.plugins.vanilla.ingredients.ItemStackHelper; import mezz.jei.plugins.vanilla.ingredients.ItemStackListFactory; import mezz.jei.plugins.vanilla.ingredients.ItemStackRenderer; -import mezz.jei.util.Log; +import mezz.jei.transfer.PlayerRecipeTransferHandler; import mezz.jei.util.StackHelper; import net.minecraft.client.gui.inventory.GuiBrewingStand; import net.minecraft.client.gui.inventory.GuiCrafting; import net.minecraft.client.gui.inventory.GuiFurnace; +import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerBrewingStand; @@ -117,12 +118,14 @@ public void register(IModRegistry registry) { ); registry.addRecipeClickArea(GuiCrafting.class, 88, 32, 28, 23, VanillaRecipeCategoryUid.CRAFTING); + registry.addRecipeClickArea(GuiInventory.class, 135, 29, 16, 13, VanillaRecipeCategoryUid.CRAFTING); registry.addRecipeClickArea(GuiBrewingStand.class, 97, 16, 14, 30, VanillaRecipeCategoryUid.BREWING); registry.addRecipeClickArea(GuiFurnace.class, 78, 32, 28, 23, VanillaRecipeCategoryUid.SMELTING, VanillaRecipeCategoryUid.FUEL); IRecipeTransferRegistry recipeTransferRegistry = registry.getRecipeTransferRegistry(); recipeTransferRegistry.addRecipeTransferHandler(ContainerWorkbench.class, VanillaRecipeCategoryUid.CRAFTING, 1, 9, 10, 36); + recipeTransferRegistry.addRecipeTransferHandler(new PlayerRecipeTransferHandler(jeiHelpers.recipeTransferHandlerHelper()), VanillaRecipeCategoryUid.CRAFTING); recipeTransferRegistry.addRecipeTransferHandler(ContainerFurnace.class, VanillaRecipeCategoryUid.SMELTING, 0, 1, 3, 36); recipeTransferRegistry.addRecipeTransferHandler(ContainerFurnace.class, VanillaRecipeCategoryUid.FUEL, 1, 1, 3, 36); recipeTransferRegistry.addRecipeTransferHandler(ContainerBrewingStand.class, VanillaRecipeCategoryUid.BREWING, 0, 4, 5, 36); diff --git a/src/main/java/mezz/jei/transfer/BasicRecipeTransferInfo.java b/src/main/java/mezz/jei/transfer/BasicRecipeTransferInfo.java index d35c2eb93..7103d6a3e 100644 --- a/src/main/java/mezz/jei/transfer/BasicRecipeTransferInfo.java +++ b/src/main/java/mezz/jei/transfer/BasicRecipeTransferInfo.java @@ -7,15 +7,15 @@ import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; -public class BasicRecipeTransferInfo implements IRecipeTransferInfo { - private final Class containerClass; +public class BasicRecipeTransferInfo implements IRecipeTransferInfo { + private final Class containerClass; private final String recipeCategoryUid; private final int recipeSlotStart; private final int recipeSlotCount; private final int inventorySlotStart; private final int inventorySlotCount; - public BasicRecipeTransferInfo(Class containerClass, String recipeCategoryUid, int recipeSlotStart, int recipeSlotCount, int inventorySlotStart, int inventorySlotCount) { + public BasicRecipeTransferInfo(Class containerClass, String recipeCategoryUid, int recipeSlotStart, int recipeSlotCount, int inventorySlotStart, int inventorySlotCount) { this.containerClass = containerClass; this.recipeCategoryUid = recipeCategoryUid; this.recipeSlotStart = recipeSlotStart; @@ -25,7 +25,7 @@ public BasicRecipeTransferInfo(Class containerClass, String } @Override - public Class getContainerClass() { + public Class getContainerClass() { return containerClass; } @@ -35,7 +35,7 @@ public String getRecipeCategoryUid() { } @Override - public List getRecipeSlots(Container container) { + public List getRecipeSlots(C container) { List slots = new ArrayList(); for (int i = recipeSlotStart; i < recipeSlotStart + recipeSlotCount; i++) { Slot slot = container.getSlot(i); @@ -45,7 +45,7 @@ public List getRecipeSlots(Container container) { } @Override - public List getInventorySlots(Container container) { + public List getInventorySlots(C container) { List slots = new ArrayList(); for (int i = inventorySlotStart; i < inventorySlotStart + inventorySlotCount; i++) { Slot slot = container.getSlot(i); diff --git a/src/main/java/mezz/jei/transfer/PlayerRecipeTransferHandler.java b/src/main/java/mezz/jei/transfer/PlayerRecipeTransferHandler.java new file mode 100644 index 000000000..0bbd0a85f --- /dev/null +++ b/src/main/java/mezz/jei/transfer/PlayerRecipeTransferHandler.java @@ -0,0 +1,171 @@ +package mezz.jei.transfer; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import mezz.jei.Internal; +import mezz.jei.JustEnoughItems; +import mezz.jei.api.gui.IGuiIngredient; +import mezz.jei.api.gui.IGuiItemStackGroup; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.VanillaRecipeCategoryUid; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; +import mezz.jei.api.recipe.transfer.IRecipeTransferInfo; +import mezz.jei.config.SessionData; +import mezz.jei.gui.Focus; +import mezz.jei.gui.ingredients.GuiItemStackGroup; +import mezz.jei.network.packets.PacketRecipeTransfer; +import mezz.jei.util.Log; +import mezz.jei.util.StackHelper; +import mezz.jei.util.Translator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ContainerPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class PlayerRecipeTransferHandler implements IRecipeTransferHandler { + private final StackHelper stackHelper; + private final IRecipeTransferHandlerHelper handlerHelper; + private final IRecipeTransferInfo transferHelper; + + public PlayerRecipeTransferHandler(IRecipeTransferHandlerHelper handlerHelper) { + this.stackHelper = Internal.getStackHelper(); + this.handlerHelper = handlerHelper; + this.transferHelper = new BasicRecipeTransferInfo(ContainerPlayer.class, VanillaRecipeCategoryUid.CRAFTING, 1, 4, 5, 36); + } + + @Override + public Class getContainerClass() { + return transferHelper.getContainerClass(); + } + + @Override + public String getRecipeCategoryUid() { + return transferHelper.getRecipeCategoryUid(); + } + + @Nullable + @Override + public IRecipeTransferError transferRecipe(ContainerPlayer container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + if (!SessionData.isJeiOnServer()) { + String tooltipMessage = Translator.translateToLocal("jei.tooltip.error.recipe.transfer.no.server"); + return handlerHelper.createUserErrorWithTooltip(tooltipMessage); + } + + Map inventorySlots = new HashMap(); + for (Slot slot : transferHelper.getInventorySlots(container)) { + inventorySlots.put(slot.slotNumber, slot); + } + + Map craftingSlots = new HashMap(); + for (Slot slot : transferHelper.getRecipeSlots(container)) { + craftingSlots.put(slot.slotNumber, slot); + } + + IGuiItemStackGroup itemStackGroup = recipeLayout.getItemStacks(); + int inputCount = 0; + { + // indexes that do not fit into the player crafting grid + Set badIndexes = ImmutableSet.of(2, 5, 6, 7, 8); + + int inputIndex = 0; + for (IGuiIngredient ingredient : itemStackGroup.getGuiIngredients().values()) { + if (ingredient.isInput()) { + if (!ingredient.getAllIngredients().isEmpty()) { + inputCount++; + if (badIndexes.contains(inputIndex)) { + String tooltipMessage = Translator.translateToLocal("jei.tooltip.error.recipe.transfer.too.large.player.inventory"); + return handlerHelper.createUserErrorWithTooltip(tooltipMessage); + } + } + inputIndex++; + } + } + } + + // compact the crafting grid into a 2x2 area + List> guiIngredients = new ArrayList>(); + for (IGuiIngredient guiIngredient : itemStackGroup.getGuiIngredients().values()) { + if (guiIngredient.isInput()) { + guiIngredients.add(guiIngredient); + } + } + IGuiItemStackGroup playerInvItemStackGroup = new GuiItemStackGroup(new Focus(null)); + int[] playerGridIndexes = {0, 1, 3, 4}; + for (int i = 0; i < 4; i++) { + IGuiIngredient ingredient = guiIngredients.get(playerGridIndexes[i]); + playerInvItemStackGroup.init(i, true, 0, 0); + playerInvItemStackGroup.set(i, ingredient.getAllIngredients()); + } + + Map availableItemStacks = new HashMap(); + int filledCraftSlotCount = 0; + int emptySlotCount = 0; + + for (Slot slot : craftingSlots.values()) { + final ItemStack stack = slot.getStack(); + if (stack != null) { + if (!slot.canTakeStack(player)) { + Log.error("Recipe Transfer helper {} does not work for container {}. Player can't move item out of Crafting Slot number {}", transferHelper.getClass(), container.getClass(), slot.slotNumber); + return handlerHelper.createInternalError(); + } + filledCraftSlotCount++; + availableItemStacks.put(slot.slotNumber, stack.copy()); + } + } + + for (Slot slot : inventorySlots.values()) { + final ItemStack stack = slot.getStack(); + if (stack != null) { + availableItemStacks.put(slot.slotNumber, stack.copy()); + } else { + emptySlotCount++; + } + } + + // check if we have enough inventory space to shuffle items around to their final locations + if (filledCraftSlotCount - inputCount > emptySlotCount) { + String message = Translator.translateToLocal("jei.tooltip.error.recipe.transfer.inventory.full"); + return handlerHelper.createUserErrorWithTooltip(message); + } + + StackHelper.MatchingItemsResult matchingItemsResult = stackHelper.getMatchingItems(availableItemStacks, playerInvItemStackGroup.getGuiIngredients()); + + if (matchingItemsResult.missingItems.size() > 0) { + String message = Translator.translateToLocal("jei.tooltip.error.recipe.transfer.missing"); + matchingItemsResult = stackHelper.getMatchingItems(availableItemStacks, itemStackGroup.getGuiIngredients()); + return handlerHelper.createUserErrorForSlots(message, matchingItemsResult.missingItems); + } + + List craftingSlotIndexes = new ArrayList(craftingSlots.keySet()); + Collections.sort(craftingSlotIndexes); + + List inventorySlotIndexes = new ArrayList(inventorySlots.keySet()); + Collections.sort(inventorySlotIndexes); + + // check that the slots exist and can be altered + for (Map.Entry entry : matchingItemsResult.matchingItems.entrySet()) { + int craftNumber = entry.getKey(); + int slotNumber = craftingSlotIndexes.get(craftNumber); + if (slotNumber < 0 || slotNumber >= container.inventorySlots.size()) { + Log.error("Recipes Transfer Helper {} references slot {} outside of the inventory's size {}", transferHelper.getClass(), slotNumber, container.inventorySlots.size()); + return handlerHelper.createInternalError(); + } + } + + if (doTransfer) { + PacketRecipeTransfer packet = new PacketRecipeTransfer(matchingItemsResult.matchingItems, craftingSlotIndexes, inventorySlotIndexes, maxTransfer); + JustEnoughItems.getProxy().sendPacketToServer(packet); + } + + return null; + } +} diff --git a/src/main/resources/assets/jei/lang/en_US.lang b/src/main/resources/assets/jei/lang/en_US.lang index 884d0fc04..8ae9535d2 100644 --- a/src/main/resources/assets/jei/lang/en_US.lang +++ b/src/main/resources/assets/jei/lang/en_US.lang @@ -16,6 +16,7 @@ jei.tooltip.error.recipe.transfer.missing=Missing Items jei.tooltip.error.recipe.transfer.inventory.full=Inventory is too full jei.tooltip.error.recipe.transfer.unknown=Unknown Error, see logs jei.tooltip.error.recipe.transfer.no.server=The server must have JEI installed +jei.tooltip.error.recipe.transfer.too.large.player.inventory=Recipe is not 2x2 jei.tooltip.error.crash=Tooltip error, see log # Error Messages