Skip to content

Commit

Permalink
Close #259 Support recipe tranfer to player 2x2 inventory
Browse files Browse the repository at this point in the history
  • Loading branch information
mezz committed Oct 26, 2016
1 parent e238a19 commit 6eb539f
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/main/java/mezz/jei/gui/CraftingGridHelper.java
Expand Up @@ -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) {
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/mezz/jei/transfer/BasicRecipeTransferInfo.java
Expand Up @@ -7,15 +7,15 @@
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;

public class BasicRecipeTransferInfo implements IRecipeTransferInfo {
private final Class<? extends Container> containerClass;
public class BasicRecipeTransferInfo<C extends Container> implements IRecipeTransferInfo<C> {
private final Class<C> containerClass;
private final String recipeCategoryUid;
private final int recipeSlotStart;
private final int recipeSlotCount;
private final int inventorySlotStart;
private final int inventorySlotCount;

public BasicRecipeTransferInfo(Class<? extends Container> containerClass, String recipeCategoryUid, int recipeSlotStart, int recipeSlotCount, int inventorySlotStart, int inventorySlotCount) {
public BasicRecipeTransferInfo(Class<C> containerClass, String recipeCategoryUid, int recipeSlotStart, int recipeSlotCount, int inventorySlotStart, int inventorySlotCount) {
this.containerClass = containerClass;
this.recipeCategoryUid = recipeCategoryUid;
this.recipeSlotStart = recipeSlotStart;
Expand All @@ -25,7 +25,7 @@ public BasicRecipeTransferInfo(Class<? extends Container> containerClass, String
}

@Override
public Class<? extends Container> getContainerClass() {
public Class<C> getContainerClass() {
return containerClass;
}

Expand All @@ -35,7 +35,7 @@ public String getRecipeCategoryUid() {
}

@Override
public List<Slot> getRecipeSlots(Container container) {
public List<Slot> getRecipeSlots(C container) {
List<Slot> slots = new ArrayList<Slot>();
for (int i = recipeSlotStart; i < recipeSlotStart + recipeSlotCount; i++) {
Slot slot = container.getSlot(i);
Expand All @@ -45,7 +45,7 @@ public List<Slot> getRecipeSlots(Container container) {
}

@Override
public List<Slot> getInventorySlots(Container container) {
public List<Slot> getInventorySlots(C container) {
List<Slot> slots = new ArrayList<Slot>();
for (int i = inventorySlotStart; i < inventorySlotStart + inventorySlotCount; i++) {
Slot slot = container.getSlot(i);
Expand Down
171 changes: 171 additions & 0 deletions 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<ContainerPlayer> {
private final StackHelper stackHelper;
private final IRecipeTransferHandlerHelper handlerHelper;
private final IRecipeTransferInfo<ContainerPlayer> transferHelper;

public PlayerRecipeTransferHandler(IRecipeTransferHandlerHelper handlerHelper) {
this.stackHelper = Internal.getStackHelper();
this.handlerHelper = handlerHelper;
this.transferHelper = new BasicRecipeTransferInfo<ContainerPlayer>(ContainerPlayer.class, VanillaRecipeCategoryUid.CRAFTING, 1, 4, 5, 36);
}

@Override
public Class<ContainerPlayer> 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<Integer, Slot> inventorySlots = new HashMap<Integer, Slot>();
for (Slot slot : transferHelper.getInventorySlots(container)) {
inventorySlots.put(slot.slotNumber, slot);
}

Map<Integer, Slot> craftingSlots = new HashMap<Integer, Slot>();
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<Integer> badIndexes = ImmutableSet.of(2, 5, 6, 7, 8);

int inputIndex = 0;
for (IGuiIngredient<ItemStack> 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<IGuiIngredient<ItemStack>> guiIngredients = new ArrayList<IGuiIngredient<ItemStack>>();
for (IGuiIngredient<ItemStack> guiIngredient : itemStackGroup.getGuiIngredients().values()) {
if (guiIngredient.isInput()) {
guiIngredients.add(guiIngredient);
}
}
IGuiItemStackGroup playerInvItemStackGroup = new GuiItemStackGroup(new Focus<ItemStack>(null));
int[] playerGridIndexes = {0, 1, 3, 4};
for (int i = 0; i < 4; i++) {
IGuiIngredient<ItemStack> ingredient = guiIngredients.get(playerGridIndexes[i]);
playerInvItemStackGroup.init(i, true, 0, 0);
playerInvItemStackGroup.set(i, ingredient.getAllIngredients());
}

Map<Integer, ItemStack> availableItemStacks = new HashMap<Integer, ItemStack>();
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<Integer> craftingSlotIndexes = new ArrayList<Integer>(craftingSlots.keySet());
Collections.sort(craftingSlotIndexes);

List<Integer> inventorySlotIndexes = new ArrayList<Integer>(inventorySlots.keySet());
Collections.sort(inventorySlotIndexes);

// check that the slots exist and can be altered
for (Map.Entry<Integer, Integer> 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;
}
}
1 change: 1 addition & 0 deletions src/main/resources/assets/jei/lang/en_US.lang
Expand Up @@ -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
Expand Down

0 comments on commit 6eb539f

Please sign in to comment.