Posted January 3, 20205 yr I'm currently working on recipes for my custom paxel mod. Explanation with pictures: Spoiler Recipe book works if all ingredients are undamaged and unenchanted: Recipe book fails if any ingredient is damaged (or has any other NBT data): The recipe does, however, work with damaged items: I created a custom recipe class for the recipe. The recipe accepts an axe, pickaxe, shovel and two sticks and yields a paxel. My recipe also works if the tools are damaged: the result is a damaged paxel. My problem is that when clicking on the recipe in the recipe book, it doesn't accept damaged items (or even undamaged, enchanted ones) from my inventory. Code of the 1.14.4 project for reference: In this version of the code, I hadn't written a proper json serializer yet so my recipe constructor is hardcoded to create the recipe for the golden paxel. This is probably more readable anyway. Spoiler package com.theonlytrueente.entespaxel.item.crafting; import com.google.gson.JsonObject; import com.theonlytrueente.entespaxel.EntesPaxel; import com.theonlytrueente.entespaxel.lists.EnteItems; import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.crafting.ICraftingRecipe; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.network.PacketBuffer; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.crafting.IShapedRecipe; import net.minecraftforge.registries.ForgeRegistryEntry; import javax.annotation.Nullable; import java.util.LinkedList; import java.util.List; public class PaxelRecipe implements ICraftingRecipe, IShapedRecipe<CraftingInventory> { private final ResourceLocation id; private final Item pickaxe, shovel, axe; private final Item paxel; private final Item stick; public PaxelRecipe(ResourceLocation idIn) { id = idIn; pickaxe = Items.GOLDEN_PICKAXE; shovel = Items.GOLDEN_SHOVEL; axe = Items.GOLDEN_AXE; paxel = EnteItems.GOLDEN_PAXEL; stick = Items.STICK; } @Override public boolean matches(CraftingInventory inv, World worldIn) { for(int x=0; x<=inv.getWidth()-3; x++){ for(int y=0; y<=inv.getHeight()-3; y++){ if(checkMatch(inv, x, y) != -1) { return true; } } } return false; } //returns -1 if no match, otherwise returns the damage of the result. private int checkMatch(CraftingInventory craftingInventory, int widthOffset, int heightOffset) { //check top row first List<Item> toolIngredients= new LinkedList<>(); toolIngredients.add(pickaxe); toolIngredients.add(shovel); toolIngredients.add(axe); int totalDamage = 0; for(int x=0; x<3; x++){ ItemStack stack = craftingInventory.getStackInSlot(x+widthOffset + heightOffset * craftingInventory.getWidth()); if(toolIngredients.remove(stack.getItem())){ totalDamage += stack.getItem() != shovel ? stack.getDamage()*3 : stack.getDamage(); } else return -1; } if(totalDamage >= new ItemStack(paxel, 1).getMaxDamage()) return -1; //check sticks now for(int y=1; y<3; y++){ if(!Ingredient.EMPTY.test(craftingInventory.getStackInSlot(widthOffset + (heightOffset+y) * craftingInventory.getWidth())) || !(stick == (craftingInventory.getStackInSlot(1 + widthOffset + (heightOffset+y) * craftingInventory.getWidth())).getItem()) || !Ingredient.EMPTY.test(craftingInventory.getStackInSlot(2 + widthOffset + (heightOffset+y) * craftingInventory.getWidth()))) { return -1; } } return totalDamage; } @Override public ItemStack getCraftingResult(CraftingInventory inv) { for(int x=0; x<=inv.getWidth()-3; x++){ for(int y=0; y<=inv.getHeight()-3; y++){ int damage; if((damage = checkMatch(inv, x, y)) != -1) { ItemStack result = new ItemStack(paxel); result.setDamage(damage); return result; } } } return ItemStack.EMPTY; } @Override public boolean canFit(int width, int height) { return width >= 3 && height >= 3; } //for recipe book @Override public ItemStack getRecipeOutput() { return new ItemStack(paxel); } @Override public NonNullList<Ingredient> getIngredients() { return NonNullList.from(Ingredient.EMPTY, Ingredient.fromItems(pickaxe), Ingredient.fromItems(axe), Ingredient.fromItems(shovel), Ingredient.EMPTY, Ingredient.fromItems(stick), Ingredient.EMPTY, Ingredient.EMPTY, Ingredient.fromItems(stick), Ingredient.EMPTY); } @Override public ResourceLocation getId() { return id; } @Override public boolean isDynamic() { return false; } @Override public IRecipeSerializer<?> getSerializer() { return EntesPaxel.PAXEL; } @Override public int getRecipeWidth() { return 3; } @Override public int getRecipeHeight() { return 3; } public static class Serializer extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<PaxelRecipe> { public Serializer(){ } @Override public PaxelRecipe read(ResourceLocation recipeId, JsonObject json) { return new PaxelRecipe(recipeId); } @Nullable @Override public PaxelRecipe read(ResourceLocation recipeId, PacketBuffer buffer) { return new PaxelRecipe(recipeId); } @Override public void write(PacketBuffer buffer, PaxelRecipe recipe) { } } } The method responsible for matching a recipe from the recipe book to my inventory seems to be IRecipe#getIngredients. Since Ingredient#test only tests for the ItemStack's Item and not other data though, I'm very confused as to why item stack's nbt matters there. Edited January 3, 20205 yr by TheOnlyTrueEnte added version
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.