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"
}]
}