Justenoughitems: Question & Suggestion about Recipe Hiding

Created on 22 Oct 2016  路  35Comments  路  Source: mezz/JustEnoughItems

I just recently did the JEI Plugin for IC2Classic... And it was easier & harder then i through.
Good work mate. Its way more modular now. And the caching of recipes is a good idea.
But 1 feature is sadly not really possible with JEI which i kinda wish that would be possible.
The option that you could hide Recipe Entries. Without forcing the player to reload resource locations when they unhide them. (Not via JEI more via the mod who adds them)
I made a semi hidden recipe at the moment where i just show the output and not the input but i am not really happy about that idea.
So a question? Is it possible to hide recipes without making them invalid?

question

All 35 comments

It is possible, just not very easy to find.
Take a look at IRecipeRegistry.addRecipe, it will let you do this.
Here's the javadoc for it:

/**
 * Add a new recipe while the game is running.
 * This is only for things like gated recipes becoming available, like the ones in Thaumcraft.
 * Use your IRecipeHandler.isValid to determine which recipes are hidden, and when a recipe becomes valid you can add it here.
 * (note that IRecipeHandler.isValid must be true when the recipe is added here for it to work)
 */

Let me know if you have more questions.

@mezz i have a live config which allows you to unhide recipes. they have to call: Reload Resources to make that effect anything if i use the IRecipeHandler.isValid function for that since you prefabricate everything. (Which is totally fine)
And i am trying to avoid that part exactly. If they change the config it should be applied instantly, no world/Resource Reload required.

There is no resource reload required if you set your recipe to valid and add it using the API above.

First: isValid does not exist. Its isValidRecipe.
Second: If isValid is called false it will not be added to the Seen RecipeList i checkt that in your code.
RecipeRegistry.addRecipe(T recipe, Class recipeClass)
And since that is only called when the plugins get added (aka worldload/ResourceReload) it means it forces then that the player has to do that after a config change on my side...

Please don't even try and then tell me it wont work.

Read the javadoc I posted above, it is specifically for this exact case.
If you implement it and it does not work, then please report here with a link to your code and what happened.

no i do not know your code better. Its just something i found after testing it out. I just searched through all your classes in the version i use for a function that is called isValid (JDGUI is the programm i used) and there is no reference of that kind of string: "*isValid" in your mod i am using.
Here is the reference: i am using JEI 1.10.2-3.12.8.323
and before you say again: I know your code better then you or call me a jerk i am telling you here what i am experiencing and i just ask you if you could add a way when the recipe list is build when the user asks for usage/recipe to an item that you can make a optional: "Do not show" override. Because that does not exist. I checkt that.

I'm telling you it exists, and showing you how to do it, and you are telling me it does not exist without trying it. That is frustrating.

The javadoc should say IRecipeHandler.isRecipeValid, I think it's not ambiguous that this is what's meant by IRecipeHandler.isValid.

its fustrating for both of us. Because first the function you referencing to is not existend.
Here is the code i have directly in front of my eyes:

package mezz.jei.api.recipe;

public abstract interface IRecipeHandler<T>
{
  public abstract Class<T> getRecipeClass();
  @Deprecated
  public abstract String getRecipeCategoryUid();
  public abstract String getRecipeCategoryUid(T paramT);
  public abstract IRecipeWrapper getRecipeWrapper(T paramT);
  public abstract boolean isRecipeValid(T paramT);
}

Do you see there a IsValid function?

isValid recipe is not used for that because its directly hookt into the Adding of recipes function:

  public void addRecipe(@Nullable Object recipe)
  {
    if (recipe == null) {
      Log.error("Null recipe", new Object[] { new NullPointerException() });
      return;
    }

    addRecipe(recipe, recipe.getClass());
  }

  private <T> void addRecipe(T recipe, Class<? extends T> recipeClass) {
    IRecipeHandler recipeHandler = getRecipeHandler(recipeClass);
    if (recipeHandler == null) {
      if (!this.unhandledRecipeClasses.contains(recipeClass)) {
        this.unhandledRecipeClasses.add(recipeClass);
        if (Config.isDebugModeEnabled()) {
          Log.debug("Can't handle recipe: {}", new Object[] { recipeClass });
        }
      }
      return;
    }
    String recipeCategoryUid;
    try
    {
      recipeCategoryUid = recipeHandler.getRecipeCategoryUid(recipe);
    }
    catch (AbstractMethodError ignored)
    {
      String recipeCategoryUid;
      recipeCategoryUid = recipeHandler.getRecipeCategoryUid();
    }

    IRecipeCategory recipeCategory = (IRecipeCategory)this.recipeCategoriesMap.get(recipeCategoryUid);
    if (recipeCategory == null) {
      Log.error("No recipe category registered for recipeCategoryUid: {}", new Object[] { recipeCategoryUid });
      return;
    }

    if (!recipeHandler.isRecipeValid(recipe)) {
      return;
    }
    try
    {
      addRecipeUnchecked(recipe, recipeCategory, recipeHandler);
    } catch (RuntimeException e) {
      String recipeInfo = ErrorUtil.getInfoFromBrokenRecipe(recipe, recipeHandler);

      String errorMessage = e.getMessage();
      if ("Found an itemStack with a null item. This is an error from another mod.".equals(errorMessage))
        Log.error("Found a broken recipe: {}\n", new Object[] { recipeInfo });
      else
        Log.error("Found a broken recipe: {}\n", new Object[] { recipeInfo, e });
    }
    catch (LinkageError e) {
      String recipeInfo = ErrorUtil.getInfoFromBrokenRecipe(recipe, recipeHandler);

      String errorMessage = e.getMessage();
      if ("Found an itemStack with a null item. This is an error from another mod.".equals(errorMessage))
        Log.error("Found a broken recipe: {}\n", new Object[] { recipeInfo });
      else
        Log.error("Found a broken recipe: {}\n", new Object[] { recipeInfo, e });
    }
  }

That is the only function where the isRecipeIsValid is called. Nowhere else. I checkt that. And this is also the function that is used with addingMod Recipes... Simply if the handler then do not say: "Recipe is Valid" then the recipe will be never listed unless they refresh all handlers with a world/ResourceReload...

Here I have updated the javadoc to show the correct method. Now please read it...

/**
 * Add a new recipe while the game is running.
 * This is only for things like gated recipes becoming available, like the ones in Thaumcraft.
 * Use your {@link IRecipeHandler#isRecipeValid(Object)} to determine which recipes are hidden, and when a recipe becomes valid you can add it here.
 * (note that {@link IRecipeHandler#isRecipeValid(Object)} must be true when the recipe is added here for it to work)
 */

(note that {@link IRecipeHandler#isRecipeValid(Object)} must be true when the recipe is added here for it to work)

This means that when your recipe is hidden isRecipeValid should return false.
When the recipe should be shown, isRecipeValid should return true, and then you add it to JEI again using IRecipeRegistry.addRecipe and it will accept it.

Not if you are using a ForgeIngame config that requires a world/resource reload. I just download recording software. If you want a video proof

I don't see what that has to do with anything.
JEI only reloads the ItemList when you do a resource reload, it does not reload everything.

Oh so you want that I read the recipes when my config will be changed... That would require to track these down. Also it would require when you disable those again I have to modify your recipe list again. And here is the question do you have a funtion to remove recipes?

Yeah I know but what I ask for is a thing from NEI When the player asked for recipes the handlers then got asked if they had recipes. Yes it was slower but it allow to hide recipes without always reloading neis stuff
So I ask for a function that asks the handler: is this wrapper valid?

And I mean every time a player asks for recipes for an item.

Yes, you must keep track of your recipes as they become valid.
No, there is no way to remove recipes without restarting JEI. You can restart it if you really need to but it'll be slow.

And that is my request: make a function into IRecipeHandler that asks: isRecipeAllowed(IRecipeWrapper).
Edit: Because i either have to put blank recipes into the game which nobody can see what they are in or what they result to or i have to force a world reload which i do not like... thats why i am asking for it
because forge config can enable & disable it ingame while you play...

Also sry for not putting what i am asking for not clear enough.

This is one of those things that helps 1 in 1000 mods but complicates JEI's code while also slowing everything down slightly. I don't think I will be adding direct support like that.

So blank recipes it will be.
Thanks (And i do not mean that in a bad mind i mean that honest) for spending your time to talk to me^^"
Have a nice day.

What I ended up doing for the Thaumcraft plugin was rendering a red X over the crafting arrow when it was not available, like when a villager will no longer trade with you. You might implement something like that where you show a message instead of the recipes.

That would be a great addition. Because uuMatter and some other stuff i would like to be hidden.

So that they have to discover stuff...

That is possible to implement, using the existing method.

Not with Crafting Recipes since your Category is controlling it.

You can make uu recipes a subclass of the vanilla crafting recipe, and add your own IRecipeHandler for that class.

I have more then UUMatter Recipes that are just basic Crafting recipes that should be hidden. If it were just UUMatter no problem... Also i would then be easy to tell which recipe is hidden and which not. thats not the idea behind hidden recipes

Just a question can i return a null as output in the Crafting Recipe Wrapper?

Can you format that as a valid JavaDoc? I don't know what you're referring to ;P

    @Override
    public void getIngredients(IIngredients ingridient)
    {
        List<List<ItemStack>> inputs = new ArrayList<List<ItemStack>>();
        List<ItemStack>[] array = new List[9];
        boolean hidden = (!recipe.hidden || !IC2.config.getFlag("SecretRecipeHiding"));
        if(!hidden)
        {
            for(IRecipeObject obj : recipe.getRecipeInput())
            {
                array[obj.getSlot()] = copyList(obj);
            }
        }
        int maxSlot = recipe.height * recipe.length;
        for(int i = 0;i<maxSlot;i++)
        {
            List<ItemStack> list = array[i];
            if(list == null)
            {
                list = Collections.EMPTY_LIST;
            }
            inputs.add(list);
        }
        ingridient.setInputLists(ItemStack.class, inputs);
        ingridient.setOutput(ItemStack.class, hidden ? null : recipe.getRecipeOutput().copy());
    }

Crash or no Crash?
setOutputLine

Unless the API says @Nullable you should probably not. I doubt it will crash but you should follow the specification or it may break later.

i just had a funny idea. I just exchange all items with a DisplayItem xD (That has a questionmark) xDDD Best solution ever xD

anyway thanks for the help.
And finally i will leave now.
Bye and have a nice time.

finally ;) (sry)

Was this page helpful?
0 / 5 - 0 ratings