Recipe based question

My hacky rewrite results in the isValid() returning false always AFTER the recipe is initialized (Since the registration fails if it doesn’t return true), and yes, when forced false in that case, it will smelt copperore to copper nuggets, granite to copper nuggets, and not smelt andesite.

I’ll post the issue shortly

I think I got a fix pushing now…

Should the original approach --of using the recipe builder via sponge, specifying a lore+display name laden itemstack in the builder as the ingredient – resulted in a recipe specific for that lore/displayname containing item only, and not even require digging this deep into the custom-implimentation? Or would that still require doing this custom implimentation approach, when fixed?

builder using the predicate should work as well

you just commented as I was writing, as I just got to test this a moment ago (And the above custom implmentation mechanism DOES work now)

I tested the builder method now as 302 did fix the problem…

SmeltingRecipe sr = SmeltingRecipe.builder().ingredient(copperore).result(coppernuggets).experience(0.5).build();

but it does not work. “using predicate” – how would that work here?

I just noticed something rather interesting regarding the TEXT parts, which may be an issue or it may be the way things are supposed to be…

I normally use the .add(Keys.blah, value) format in my itemstack builders, but I just copied pie’s code for testing, which uses the .keyValue(Keys.blah, value) format. So I changed them all to add() to compare.

Itemstacks created with the .add() method result in unformatted text on the client, looking like all other items in inventory. Itemstacks created with the .keyValue() method result in italicized text on the client display. That might point towards the modified TEXT issue, and the client auto-rendering the children in italics on the system???

Its pretty clear in the javadocs…
If you use the ItemStackSnapshot version of it it will only use vanilla matching behaviour. (Matching ItemType and DamageValue)
For more specific matching use this one:
ResultStep ingredient(Predicate<ItemStackSnapshot> ingredientPredicate, ItemStackSnapshot exemplaryIngredient);

Might be worth renaming those methods?

I’ve been trying to wrap my head around this one a few times in the past few days, but I’ve reached a point where I have to beg for an example again… Im sure its due to my limited way in thinking about predicates in other places, where pieces of information on the argument are being tested , but being tested against things visible to them. How can a predicate here be used to compare parts of the ingredient to the exemplary ingredient, I don’t understand. It must not be, rather something else… I’m certain once I see it, it will be one of those “Ohhhhhhhhhhhhhhhhhhh, okay” moments that is retrospectively obvious and impossible to not see - actually, I’m counting on it to be that :slight_smile:

How would a predicate look for making the specific match of the granite type, display name, lore’d block of copperore producing the coppernuggets in the recipe in the missing spot of code below?

    //  Step 1: Define reference itemstacks        
    List<Text>       smeltable = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Smeltable"));        
    copperore = ItemStack.builder()
            .itemType(ItemTypes.STONE)
            .add(Keys.STONE_TYPE, StoneTypes.GRANITE)
            .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Ore"))
            .add(Keys.ITEM_LORE, smeltable)
            .build();
    List<Text>       special   = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Special Resource"));        
    coppernuggets = ItemStack.builder()
            .itemType(ItemTypes.DYE)
            .add(Keys.DYE_COLOR, DyeColors.BROWN)
            .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Nuggets"))
            .add(Keys.ITEM_LORE, special)
            .build();
    ItemStackSnapshot coress =  copperore.createSnapshot();
    ItemStackSnapshot cnugss =coppernuggets.createSnapshot();  
    SmeltingRecipe smeltrec = SmeltingRecipe.builder().ingredient(
   // Step 2:???           ingredientPredicate , 
            cnugss)
            .result(coppernuggets).build();
    
    Sponge.getRegistry().getSmeltingRecipeRegistry().register(smeltrec);
    // Step 3:Profit

When you give code examples, can you make sure they at least compile? it makes it a ton easier.

//  Step 1: Define reference itemstacks
    List<Text> smeltable = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Smeltable"));
    ItemStack copperore = ItemStack.builder()
            .itemType(ItemTypes.STONE)
            .add(Keys.STONE_TYPE, StoneTypes.GRANITE)
            .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Ore"))
            .add(Keys.ITEM_LORE, smeltable)
            .build();

    List<Text> special = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Special Resource"));

    ItemStack coppernuggets = ItemStack.builder()
            .itemType(ItemTypes.DYE)
            .add(Keys.DYE_COLOR, DyeColors.BROWN)
            .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Nuggets"))
            .add(Keys.ITEM_LORE, special)
            .build();

    ItemStackSnapshot coress =  copperore.createSnapshot();
    ItemStackSnapshot cnugss =coppernuggets.createSnapshot();

    SmeltingRecipe smeltrec = SmeltingRecipe.builder().ingredient(
            this.match(ingredient),
            copperore)
            .result(coppernuggets).build();

    Sponge.getRegistry().getSmeltingRecipeRegistry().register(smeltrec);
    // Step 3:Profit
}

public Predicate<ItemStackSnapshot> match(ItemStack myItemType){
    return ingredient -> {
        return     ingredient.itemType().equals(myItemType.itemType())
                && ingredient.get(Keys.ITEM_LORE).equals(myItemType.get(Keys.ITEM_LORE)
    }
}

Would work, if it wasn’t for the Data not being available when the ItemStack copperore is created. You could replace that with a lazy loaded itemstack, that’s only created once the Data system is ready until the bug is fixed and it should work.

Smelting recipes can be added in the GamePostInitializeEvent when Data IS available.

The code I gave should have compiled when the predicate was added, as the predicate based form of the ingredient system wants a predicate and exemplary SNAPSHOT for both arguments, hence coress instead of copperore, etc… ooh, yes, i see I put cnugss instead of coress , mistake there…

And yeah, this is an ah-ha, trying to picture an inline predicate and not realizing to use something with an argument to pass the second thing in. I can’t wait to try this out tonight when I get home from work.

Thanks ryantheleach.

It still could have been an inline predicate. I just made it a method since I’m assuming you are going to have a single idea of equality for all your custom items :slight_smile:

@ryantheleach

I haven’t had a chance to test this until recently, and in the recent version they’ve fixed the data manipulator availability for recipes in preinit - that works fantastic, tests are great there! – but while now trying to work on this copper ore via predicate testing, I have run into a bunch of snags :frowning:

To quote a wise man (wise-guy?)

When you give code examples, can you make sure they at least compile? it makes it a ton easier.

in the predicate function, ingredient.itemType() and myItemType.itemType() aren’t valid, the complier shows missing braces, and a couple missing semicolins.

Is this what you meant it to be ?? (I don’t know, because I still can’t test for other reasons)…

public Predicate<ItemStackSnapshot> match(ItemStack myItemType) {
    return ingredient -> {
        return ingredient.getType().equals(myItemType.getItem().getType())
                && ingredient.get(Keys.ITEM_LORE).equals(myItemType.get(Keys.ITEM_LORE));
    };
}

The other problem (and again, the exact reason I couldn’t comprehend how predicates worked in this ingredient arguments…) is that your ingredient doesn’t work.

  1. The exemplary needs to the the itemstacksnapshot

.ingredient(match(ingredient), copperore.createSnapshot())

  1. where the heck does the argument “ingredient” come from? The compiiler is stuck here, as that is an object that isn’t defined in the scope. Its an argument for the predicate function, but… it doesnt exist as anything to be able to use it there. This was my entire sticking point for the predicates, what exactly gets put into the system?? What are we supposed to be putting in to check against the exemplary this way?

I want to make sure that this thread will contain the final actual working code once we get there, for other people to reference in searching :slight_smile: but we’re still not there yet, and while I’ve managed to make sense of the concept of that predicate-function you wrote, it still comes down to ‘okay, that function will test a against b, but still, where is a coming from???’ as the bottom line, and the compiler is also asking the same question.

I was editing it on a PC that didn’t have SpongeAPI available, so was basing it off the docs / github / the code you had given me. I didn’t know what ingredient you expected for the Smelting Recipe, as the code you had given me didn’t have the predicate defined. shrug.

ingredient was a placeholder for the ingredient item stack that you would be replacing with the required ingredient, as I didn’t infer the recipe you were wanting at the time. On the assumption it was copperore, it would look like the following. But again, you are an experienced developer, you should be able to provide a compileable micro plugin to show errors when asked…

/**
 * Adds BedRock. Literally.
 */
@Plugin(id = "recipetest", name = "Recipe Test", description = "A plugin to test recipes")
public class RecipeTest {

    @Listener
    public void onInit(GameInitializationEvent event) {
        Ingredient s = Ingredient.of(STONE);
        Ingredient b = Ingredient.of(BED);
        ShapedCraftingRecipe recipe = CraftingRecipe.shapedBuilder().rows()
                .row(s, s, s)
                .row(s, b, s)
                .row(s, s, s)
                .result(ItemStack.of(BEDROCK, 1))
                .build("bedrock", this);
        Sponge.getRegistry().getCraftingRecipeRegistry().register(recipe);

        List<Text> special = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Special Resource"));

        List<Text> smeltable = Arrays.asList(Text.of(TextColors.LIGHT_PURPLE, "Smeltable"));
        ItemStack copperore = ItemStack.builder()
                .itemType(ItemTypes.STONE)
                .add(Keys.STONE_TYPE, StoneTypes.GRANITE)
                .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Ore"))
                .add(Keys.ITEM_LORE, smeltable)
                .build();
        
        ItemStack coppernuggets = ItemStack.builder()
                .itemType(ItemTypes.DYE)
                .add(Keys.DYE_COLOR, DyeColors.BROWN)
                .add(Keys.DISPLAY_NAME, Text.of(TextColors.GREEN, "Copper Nuggets"))
                .add(Keys.ITEM_LORE, special)
                .build();

        
        SmeltingRecipe.builder()
                .ingredient(
                    this.match(copperore),
                    copperore.createSnapshot()
                )
                .result(coppernuggets).build();
    }

    public Predicate<ItemStackSnapshot> match(ItemStack myItemType) {
        return ingredient -> {
            return ingredient.getType().equals(myItemType.getItem().getType())
                    && ingredient.get(Keys.ITEM_LORE).equals(myItemType.get(Keys.ITEM_LORE));
        };
    }

}

Okay, that makes sense, the exemplary ingredient as the predicate function argument. Should have been able to figure that out after a bit of sleep, and remembering all the error messages in startup recipe registering that will only allow a recipe to register if the isvalid aka the predicate results in true for the exemplary ingredient. Just have to register that recipe in the code you posted and its all good.

But then after a fair bit more playing around trying to seek out generalization things, ie, not having to know if an item has stonetype data or dye type data to compare… it turns out that its not required anymore: The recent fixes now mean that using an itemstack with various data associated with it (like the copperore here) when registering the recipe as an ingredient itemstack only — it works for that level of specificity. IE an andesite block with the exact same “copper ore” name and lore as the granite block “copper ore” does not smelt, but the granite block does - no predicate checks required.

Even stepping back further more intersting goofball testing: Making a straight-up recipe to smelt black dyed wool into an apple works on black wool, but not green or white wool , automatically – no need to predicate add for the color data, its automagic for the stack!

Hence now not only is needing to impliment ones own smeltrecipe class no longer a workaround required, but this predicate approach is not either :slight_smile:

Thank you @ryantheleach though for all the help , even with hiccups back and forth, the way you make the predicate function work there now makes sense to me and that was just an unseeable thing to my mind before, and while no longer required for me, will be a good reference for any such similar processes that may be put to use elsewhere in my future.

Thank you to @pie_flavor for the original workaround process to kick start me last week and let me go hog wild testing things, to @Faithcaio for weighing in here as well and making numerous updates to the server code as a result , and to @gabizou for following up to push the data manipulator support into the crafting recipes processes making 97% of this thread “irrelevant” by simplifying everything to the way that first comes to mind to try now that the bugs are shaken loose.