Skip to content

Cooking Recipe Predicates

spigbop edited this page Jun 16, 2026 · 1 revision

By default, there are available 11 cooking predicates:

  • hotc:always: will always pass.
  • hotc:any: if any predicate in array predicates passes this will pass.
  • hotc:contains: passes if the ingredient field exists, this field is the same as minecraft crafting ingredients.
  • hotc:contains_filler: passes if any of the items belong to the ingredient category category.
  • hotc:filler_at_least: passes if the combined value of the items for the ingredient category category is above or equal to value.
  • hotc:filler_at_most: passes if the combined value of the items for the ingredient category category is below or equal to value.
  • hotc:filler_exact: passes if the combined value of the items for the ingredient category category is equal to value.
  • hotc:filler_less_than: passes if the combined value of the items for the ingredient category category is below value.
  • hotc:filler_more_than: passes if the combined value of the items for the ingredient category category is above value.
  • hotc:never: will never pass.
  • hotc:not: will invert the result of predicate.

It is also possible to create new cooking recipe predicates using external mods. The predicate should be its own class extending from CookingPredicate:

package tld.myname.mymod.cooking.predicate;

// ...
import net.spigbop.hotc.cooking.predicate.CookingPredicate;
import com.mojang.serialization.codecs.RecordCodecBuilder;
// ...

public class MyCookingPredicate extends CookingPredicate {
    // the codec specifies which json keys should be accepted by this predicate,
    // here in this example it will take a cooking ingredient with the key 
    // "category"
    public static final MapCodec<MyCookingPredicate> CODEC = RecordCodecBuilder.mapCodec(
        i -> i
            .group(IngredientCategoryKey.CODEC
                .fieldOf("category")
                .forGetter(p -> p.category))
            .apply(i, ContainsFillerCookingPredicate::new));

    private final IngredientCategoryKey category;

    public ContainsFillerCookingPredicate(IngredientCategoryKey category) {
        this.category = category;
    }

    @Override
    public MapCodec<? extends CookingPredicate> codec() {
        return CODEC;
    }

    // should return true if the predicate succeeded and should pass to the next
    // predicate in line, false otherwise
    @Override
    public boolean test(Level level, ItemStack... items) {
        // in this example, let's check if every item in the cooker slots 
        // belongs to an ingredient category:
        for (ItemStack item : items) {
            if (!category.contains(item, level.registryAccess())) {
                return false;
            }
        }
        return true;
    }
}

And then register your predicate:

package tld.myname.mymod.cooking.predicate;

// ...
import tld.myname.mymod.cooking.predicate.MyCookingPredicate;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.spigbop.hotc.cooking.predicate.CookingPredicateTypes;
// ...

public class ModCookingPredicateTypes {
    public static final MapCodec<MyCookingPredicate> MY_PREDICATE =
        CookingPredicateTypes.register(
            ResourceLocation.fromNamespaceAndPath("mymod", "my_predicate"),
            MyCookingPredicate.CODEC
        );
}

Now, your predicate should be usable in cooking recipes:

{
  "priority": 0,
  "predicates": [
    {
      "type": "mymod:my_predicate",
      "category": "hotc:veggie"
    }
  ],
  "time": 1.0,
  "result": {
    "id": "mymod:myitem",
    "count": 1
  }
}

Clone this wiki locally