Jump to content

Recommended Posts

Posted

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

 

Posted (edited)

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 by Corey
Posted
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.

  • Like 1

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.