Posted April 27, 20196 yr I'm using quite a few custom recipe types, and after updating from Forge 107 to 191, none of them seem to be working. The way I'm registering them hasn't changed. I took a quick look through the Forge commits since then (and follow Forge development pretty closely anyway) and I didn't see anything that seemed related. Has something changed? Note: I added logging, and the recipes get loaded and deserialized fine, but the matches method is never called when I try to craft things. IRecipe/Serializer: package lordmonoxide.gradient.recipes; import com.google.gson.JsonObject; import lordmonoxide.gradient.progress.Age; import lordmonoxide.gradient.utils.AgeUtils; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemTool; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.RecipeSerializers; import net.minecraft.item.crafting.ShapelessRecipe; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JsonUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.crafting.RecipeType; import net.minecraftforge.event.ForgeEventFactory; import java.util.Random; public class AgeGatedShapelessToolRecipe implements IRecipe { private static final Random rand = new Random(); private final ShapelessRecipe recipe; public final Age age; public AgeGatedShapelessToolRecipe(final ShapelessRecipe recipe, final Age age) { this.recipe = recipe; this.age = age; } @Override public boolean matches(final IInventory inv, final World world) { return AgeUtils.playerMeetsAgeRequirement((InventoryCrafting)inv, this.age) && this.recipe.matches(inv, world); } @Override public ItemStack getCraftingResult(final IInventory inv) { return this.recipe.getCraftingResult(inv); } @Override public boolean canFit(final int width, final int height) { return this.recipe.canFit(width, height); } @Override public ItemStack getRecipeOutput() { return this.recipe.getRecipeOutput(); } @Override public NonNullList<ItemStack> getRemainingItems(final IInventory inv) { final NonNullList<ItemStack> remaining = IRecipe.super.getRemainingItems(inv); for(int i = 0; i < remaining.size(); ++i) { final ItemStack stack = inv.getStackInSlot(i); if(stack.getItem() instanceof ItemTool) { stack.attemptDamageItem(1, rand, null); if(stack.isDamageable() && stack.getDamage() > stack.getMaxDamage()) { ForgeEventFactory.onPlayerDestroyItem(ForgeHooks.getCraftingPlayer(), stack, null); remaining.set(i, ItemStack.EMPTY); } else { remaining.set(i, stack.copy()); } } } return remaining; } @Override public NonNullList<Ingredient> getIngredients() { return this.recipe.getIngredients(); } @Override public boolean isDynamic() { return this.recipe.isDynamic(); } @Override public String getGroup() { return this.recipe.getGroup(); } @Override public ResourceLocation getId() { return this.recipe.getId(); } @Override public IRecipeSerializer<?> getSerializer() { return GradientRecipeSerializers.SHAPELESS; } @Override public RecipeType<? extends IRecipe> getType() { return GradientRecipeTypes.SHAPELESS; } public static final class Serializer implements IRecipeSerializer<AgeGatedShapelessToolRecipe> { @Override public AgeGatedShapelessToolRecipe read(final ResourceLocation recipeId, final JsonObject json) { final ShapelessRecipe recipe = RecipeSerializers.CRAFTING_SHAPELESS.read(recipeId, json); final Age age = Age.get(JsonUtils.getInt(json, "age", 1)); return new AgeGatedShapelessToolRecipe(recipe, age); } @Override public AgeGatedShapelessToolRecipe read(final ResourceLocation recipeId, final PacketBuffer buffer) { final ShapelessRecipe recipe = RecipeSerializers.CRAFTING_SHAPELESS.read(recipeId, buffer); final Age age = Age.get(buffer.readVarInt()); return new AgeGatedShapelessToolRecipe(recipe, age); } @Override public void write(final PacketBuffer buffer, final AgeGatedShapelessToolRecipe recipe) { RecipeSerializers.CRAFTING_SHAPELESS.write(buffer, recipe.recipe); buffer.writeVarInt(recipe.age.value()); } @Override public ResourceLocation getName() { return GradientRecipeTypes.SHAPELESS.getId(); } } } Type registration: package lordmonoxide.gradient.recipes; import lordmonoxide.gradient.GradientMod; import net.minecraftforge.common.crafting.RecipeType; public final class GradientRecipeTypes { private GradientRecipeTypes() { } public static final RecipeType<AgeGatedShapedToolRecipe> SHAPED = RecipeType.get(GradientMod.resource("shaped"), AgeGatedShapedToolRecipe.class); public static final RecipeType<AgeGatedShapelessToolRecipe> SHAPELESS = RecipeType.get(GradientMod.resource("shapeless"), AgeGatedShapelessToolRecipe.class); public static final RecipeType<DryingRecipe> DRYING = RecipeType.get(GradientMod.resource("drying"), DryingRecipe.class); public static final RecipeType<FirePitRecipe> FIREPIT = RecipeType.get(GradientMod.resource("firepit"), FirePitRecipe.class); public static final RecipeType<FuelRecipe> FUEL = RecipeType.get(GradientMod.resource("fuel"), FuelRecipe.class); public static final RecipeType<GrindingRecipe> GRINDING = RecipeType.get(GradientMod.resource("grinding"), GrindingRecipe.class); public static final RecipeType<HardeningRecipe> HARDENING = RecipeType.get(GradientMod.resource("hardening"), HardeningRecipe.class); public static final RecipeType<MixingRecipe> MIXING = RecipeType.get(GradientMod.resource("mixing"), MixingRecipe.class); } Serializer registration package lordmonoxide.gradient.recipes; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.RecipeSerializers; public final class GradientRecipeSerializers { private GradientRecipeSerializers() { } public static final IRecipeSerializer<AgeGatedShapedToolRecipe> SHAPED = RecipeSerializers.register(new AgeGatedShapedToolRecipe.Serializer()); public static final IRecipeSerializer<AgeGatedShapelessToolRecipe> SHAPELESS = RecipeSerializers.register(new AgeGatedShapelessToolRecipe.Serializer()); public static final IRecipeSerializer<DryingRecipe> DRYING = RecipeSerializers.register(new DryingRecipe.Serializer()); public static final IRecipeSerializer<FirePitRecipe> FIREPIT = RecipeSerializers.register(new FirePitRecipe.Serializer()); public static final IRecipeSerializer<FuelRecipe> FUEL = RecipeSerializers.register(new FuelRecipe.Serializer()); public static final IRecipeSerializer<GrindingRecipe> GRINDING = RecipeSerializers.register(new GrindingRecipe.Serializer()); public static final IRecipeSerializer<HardeningRecipe> HARDENING = RecipeSerializers.register(new HardeningRecipe.Serializer()); public static final IRecipeSerializer<MixingRecipe> MIXING = RecipeSerializers.register(new MixingRecipe.Serializer()); } Recipe example: { "type": "gradient:shapeless", "age": 1, "result": { "item": "gradient:twine" }, "ingredients": [{ "item": "gradient:fibre" }, { "item": "gradient:fibre" }, { "item": "gradient:fibre" }, { "item": "gradient:fibre" }] }
April 27, 20196 yr Author Container.slotChangedCraftingGrid has been updated to use Forge's overloaded RecipeManager.getRecipe, which accepts a RecipeType, and it is restricted to VanillaRecipeTypes.CRAFTING. This seems to mean that the only way to craft non-vanilla shaped/shapeless recipes in the inventory crafting grid or the crafting table is to replace those containers with custom ones which override slotChangedCraftingGrid. Fortunately for me, I'm already wrapping that container for other reasons, but this definitely doesn't seem ideal... Edit: I've implemented it in the way I described above, and it works, but it's not a good solution. Edited April 27, 20196 yr by Corey
April 27, 20196 yr Quote Container.slotChangedCraftingGrid has been updated to use Forge's overloaded RecipeManager.getRecipe, which accepts a RecipeType, and it is restricted to VanillaRecipeTypes.CRAFTING. This seems to mean that the only way to craft non-vanilla shaped/shapeless recipes in the inventory crafting grid or the crafting table is to replace those containers with custom ones which override slotChangedCraftingGrid. This is should not be the case, and most definitly is not the intention. You're using RecipeType incorrectly. It is meant to be a 'machine' type system. Which is why we have 'CRAFTING' and 'SMELTING' and not 'SHAPELESS'. Note that RecipeType is not the type in the json. That is your serializer. I do Forge for free, however the servers to run it arn't free, so anything is appreciated. Consider supporting the team on Patreon
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.