User Tools

Site Tools


drafts:resourceconditions

Thinking With Resource Conditions (DRAFT)

Introduction

Sometimes you want a recipe to only exist when a certain mod is loaded, or maybe have something happen when an empty tag actually has some items. This is where resource conditions come into play. Resource Conditions allow you to define things like these in a non-breaking way.

Usage in JSON

Resource Conditions are placed in a list, often at the top of the file for simplicity.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": ...
    },
    {
      ...
    }
  ],
  ...
}

Types of Conditions

There are 6 basic types, and 3 'modifier' types.

TrueResourceCondition

The TrueResourceCondition returns true. That's all it does.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:true"
    }
  ],
  ...
}

AllModsLoadedResourceCondition

This one returns true if all mods(defined by id) listed in it are loaded(running in the current environment).
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:all_mods_loaded"
      "values": [
        "aether",
        "create"
      ]
    }
  ],
  ...
}

AnyModsLoadedResourceCondition

Returns true if any mods listed in it are loaded.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:any_mods_loaded"
      "values": [
        "energizedpower",
        "iljatech"
      ]
    }
  ],
  ...
}

TagsPopulatedResourceCondition

Returns true if all tags listed in it have members(not empty).
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:tags_populated",
      "registry": "minecraft:item",
      "values": [
        "minecraft:logs",
        "minecraft:planks"
      ]
    }
  ],
  ...
}

FeaturesEnabledResourceCondition

Returns true if all features listed in it are enabled.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:features_enabled"
      "features": [
        "minecraft:redstone_experiments"
      ]
    }
  ],
  ...
}

RegistryContainsResourceCondition

Returns true if the registry has the identifiers listed in it as entries.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:registry_contains"
      "registry": "minecraft:item"
      "values": [
        "minecraft:coal",
        "minecraft:diamond"
      ]
    }
  ],
  ...
}

NotResourceCondition

Returns true if the resource condition nested inside is false.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:not"
      "value": {
        "condition": "fabric:true"
      }
    }
  ],
  ...
}

OrResourceCondition

Returns true if any condition inside it is true.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:or"
      "values": [
        {
          "condition": "fabric:tags_populated",
          "registry": "minecraft:item",
          "values": [
            "minecraft:buttons"
          ]
        },
        {
          "condition": "fabric:features_enabled",
           "features": [
             "minecraft:redstone_experiments"
           ]
        },
        {
          "condition": "fabric:true"
        }
      ]
    }
  ],
  ...
}

AndResourceCondition

Returns true if all conditions are true.
Example:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:and"
      "values": [
        {
          "condition": "fabric:tags_populated",
          "registry": "minecraft:item",
          "values": [
            "minecraft:eggs"
          ]
        },
        {
          "condition": "fabric:features_enabled",
           "features": [
             "minecraft:minecart_improvements"
           ]
        },
        {
          "condition": "fabric:true"
        }
      ]
    }
  ],
  ...
}

Usage in Datagen

This section will assume you have already set up a basic datagen setup. It will use recipes as an example.

We will create a recipe that creates a minecart with copper if the minecart improvements experiment is enabled.

Next, we can go into our recipe provider and begin.

  1. public class ModRecipeProvider extends FabricRecipeProvider {
  2. ...
  3.  
  4. @Override
  5. protected RecipeProvider createRecipeProvider(HolderLookup.Provider provider, RecipeOutput output) {
  6. return new RecipeProvider(provider, output) {
  7. @Override
  8. public void buildRecipes() {
  9. shaped(RecipeCategory.MISC, Items.MINECART)
  10. .pattern("c c")
  11. .pattern("ccc")
  12. .define('c', Items.COPPER_INGOT)
  13. .unlockedBy(getHasName(Items.COPPER_INGOT), has(Items.COPPER_INGOT))
  14. .save(withConditions(output, new FeaturesEnabledResourceCondition(Identifier.withDefaultNamespace("minecart_improvements");
  15. };
  16. }
  17. }

The important part of this is when we call the save function. We can wrap our RecipeOutput with the withConditions method provided by FabricRecipeProvider, which allows us to place as many conditions as we want. The result will be this:

{
  "fabric:load_conditions": [
    {
      "condition": "fabric:features_enabled",
      "features": [
        "minecraft:minecart_improvements"
      ] 
    }
  ],
  "type": "minecraft:crafting_shaped",
  "category": "misc",
  "key": {
    "c": "minecraft:copper_ingot",
  },
  "pattern": [
    "c c",
    "ccc"
  ],
  "result": {
    "count": 1,
    "id": "minecraft:minecart"
  }
}

Making A Custom Condition

There are two things you need to do to make a custom condition: 1. Create the class and logic for it. 2. Register it.

We are going to make a FalseResourceCondition. To begin, we must have our class implement ResourceCondition. We can make a codec through MapCodec.unit, and we will return to the getType method. The test method is where all the logic happens. It passes in a RegistryInfoLookup, which can get you a RegistryInfo from a ResourceKey. For our use, we do not need it. We can just return false. Your class should currently look something like this:

  1. public class FalseResourceCondition implements ResourceCondition {
  2. public static final MapCodec<FalseResourceCondition> CODEC = MapCodec.unit(FalseResourceCondition::new);
  3.  
  4. public ResourceConditionType<?> getType() {
  5. return TYPE_HERE;
  6. }
  7.  
  8. public boolean test(RegistryOps.@Nullable RegistryInfoLookup registryInfo) {
  9. return false;
  10. }
  11. }

Now, we must register the condition. You can refer to DefaultResourceConditionTypes to see how they are done. A register method will look something like this:

protected static <T extends ResourceCondition> ResourceConditionType<T> createResourceConditionType(String name, MapCodec<T> codec) {
	return ResourceConditionType.create(Identifier.fromNamespaceAndPath("tutorial", name), codec);
}

For name, we can pass in “false”, and codec is our FalseResourceCondition.CODEC. In your ModInitializer, do something like this:

public static ResourceConditionType<FalseResourceCondition> FALSE;
 
@Override
public void onInitialize() {
	FALSE = createResourceConditionType("false", FalseResourceCondition.CODEC)
	// ...
}
 
protected static <T extends ResourceCondition> ResourceConditionType<T> createResourceConditionType(String name, MapCodec<T> codec) {
	return ResourceConditionType.create(Identifier.fromNamespaceAndPath("tutorial", name), codec);
}
 
// ...

Now, replace TYPE_HERE with the new condition type.

drafts/resourceconditions.txt · Last modified: 2026/03/20 17:27 by infinitychances