* Fixes #4253: Just transfer the recipe id instead of every ingredient. * If possible handle any IRecipe for processing mode * Improvements and support for AE2 facades. * Switched to using JEI's displayed stacks (which means we can remove the shapeless variant). Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
This commit is contained in:
@@ -18,101 +18,128 @@
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.ShapedRecipe;
|
||||
import net.minecraft.item.crafting.ShapelessRecipe;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.ingredient.IGuiIngredient;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper;
|
||||
|
||||
import appeng.container.slot.CraftingMatrixSlot;
|
||||
import appeng.container.slot.FakeCraftingMatrixSlot;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.JEIRecipePacket;
|
||||
import appeng.util.Platform;
|
||||
import appeng.helpers.IContainerCraftingPacket;
|
||||
|
||||
class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandler<T> {
|
||||
abstract class RecipeTransferHandler<T extends Container & IContainerCraftingPacket>
|
||||
implements IRecipeTransferHandler<T> {
|
||||
|
||||
private final Class<T> containerClass;
|
||||
protected final IRecipeTransferHandlerHelper helper;
|
||||
|
||||
RecipeTransferHandler(Class<T> containerClass) {
|
||||
RecipeTransferHandler(Class<T> containerClass, IRecipeTransferHandlerHelper helper) {
|
||||
this.containerClass = containerClass;
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getContainerClass() {
|
||||
public final Class<T> getContainerClass() {
|
||||
return this.containerClass;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IRecipeTransferError transferRecipe(T container, IRecipeLayout recipeLayout, PlayerEntity player,
|
||||
boolean maxTransfer, boolean doTransfer) {
|
||||
if (!doTransfer) {
|
||||
return null;
|
||||
public final IRecipeTransferError transferRecipe(T container, Object recipe, IRecipeLayout recipeLayout,
|
||||
PlayerEntity player, boolean maxTransfer, boolean doTransfer) {
|
||||
if (!(recipe instanceof IRecipe)) {
|
||||
return this.helper.createInternalError();
|
||||
}
|
||||
final IRecipe<?> irecipe = (IRecipe<?>) recipe;
|
||||
final ResourceLocation recipeId = irecipe.getId();
|
||||
|
||||
if (recipeId == null) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.missing_id"));
|
||||
}
|
||||
|
||||
Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredients = recipeLayout.getItemStacks()
|
||||
.getGuiIngredients();
|
||||
|
||||
final CompoundNBT recipe = new CompoundNBT();
|
||||
|
||||
int slotIndex = 0;
|
||||
for (Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> ingredientEntry : ingredients.entrySet()) {
|
||||
IGuiIngredient<ItemStack> ingredient = ingredientEntry.getValue();
|
||||
if (!ingredient.isInput()) {
|
||||
continue;
|
||||
// Check that the recipe can actually be looked up via the manager, i.e. our
|
||||
// facade recipes
|
||||
// have an ID, but are never registered with the recipe manager.
|
||||
boolean canSendReference = true;
|
||||
if (!player.getEntityWorld().getRecipeManager().getRecipe(recipeId).isPresent()) {
|
||||
// Validate that the recipe is a shapeless or shapedrecipe, since we can
|
||||
// serialize those
|
||||
if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.missing_id"));
|
||||
}
|
||||
canSendReference = false;
|
||||
}
|
||||
|
||||
for (final Slot slot : container.inventorySlots) {
|
||||
if (slot instanceof CraftingMatrixSlot || slot instanceof FakeCraftingMatrixSlot) {
|
||||
if (slot.getSlotIndex() == slotIndex) {
|
||||
final ListNBT tags = new ListNBT();
|
||||
final List<ItemStack> list = new ArrayList<>();
|
||||
final ItemStack displayed = ingredient.getDisplayedIngredient();
|
||||
if (!irecipe.canFit(3, 3)) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.recipe_too_large"));
|
||||
}
|
||||
|
||||
// prefer currently displayed item
|
||||
if (displayed != null && !displayed.isEmpty()) {
|
||||
list.add(displayed);
|
||||
final IRecipeTransferError error = doTransferRecipe(container, irecipe, recipeLayout, player, maxTransfer);
|
||||
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (doTransfer) {
|
||||
if (canSendReference) {
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(recipeId, isCrafting()));
|
||||
} else {
|
||||
// To avoid earlier problems of too large packets being sent that crashed the
|
||||
// client,
|
||||
// as a fallback when the recipe ID could not be resolved, we'll just send the
|
||||
// displayed
|
||||
// items.
|
||||
NonNullList<Ingredient> flatIngredients = NonNullList.withSize(9, Ingredient.EMPTY);
|
||||
ItemStack output = ItemStack.EMPTY;
|
||||
|
||||
// Determine the first JEI slot that has an actual input, we'll use this to
|
||||
// offset the
|
||||
// crafting grid target slot
|
||||
int firstInputSlot = recipeLayout.getItemStacks().getGuiIngredients().entrySet().stream()
|
||||
.filter(e -> e.getValue().isInput()).mapToInt(Map.Entry::getKey).min().orElse(0);
|
||||
|
||||
// Now map the actual ingredients into the output/input
|
||||
for (Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> entry : recipeLayout.getItemStacks()
|
||||
.getGuiIngredients().entrySet()) {
|
||||
IGuiIngredient<ItemStack> item = entry.getValue();
|
||||
if (item.getDisplayedIngredient() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int inputIndex = entry.getKey() - firstInputSlot;
|
||||
if (item.isInput() && inputIndex < flatIngredients.size()) {
|
||||
ItemStack displayedIngredient = item.getDisplayedIngredient();
|
||||
if (displayedIngredient != null) {
|
||||
flatIngredients.set(inputIndex, Ingredient.fromStacks(displayedIngredient));
|
||||
}
|
||||
|
||||
// prefer pure crystals.
|
||||
for (ItemStack stack : ingredient.getAllIngredients()) {
|
||||
if (Platform.isRecipePrioritized(stack)) {
|
||||
list.add(0, stack);
|
||||
} else {
|
||||
list.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
for (final ItemStack is : list) {
|
||||
final CompoundNBT tag = new CompoundNBT();
|
||||
is.write(tag);
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
recipe.put("#" + slot.getSlotIndex(), tags);
|
||||
break;
|
||||
} else if (!item.isInput() && output.isEmpty()) {
|
||||
output = item.getDisplayedIngredient();
|
||||
}
|
||||
}
|
||||
|
||||
ShapedRecipe fallbackRecipe = new ShapedRecipe(recipeId, "", 3, 3, flatIngredients, output);
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(fallbackRecipe, isCrafting()));
|
||||
}
|
||||
|
||||
slotIndex++;
|
||||
}
|
||||
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(recipe));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract IRecipeTransferError doTransferRecipe(T container, IRecipe<?> recipe, IRecipeLayout recipeLayout,
|
||||
PlayerEntity player, boolean maxTransfer);
|
||||
|
||||
protected abstract boolean isCrafting();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user