---
title: Result Providers
---

<Callout>
Added in Fzzy Config 0.5.3
</Callout>

The Result Provider system is a framework for retrieving values from a config without directly interacting with that config in-code.

A straightforward example is a loot table with a configurable drop chance for a loot pool. Traditionally, the only way to modify this would be to override the loot table with a data pack. Result Providers let us define a new loot number provider that draws its value from a config, allowing the drop chance to be altered in-game from a config GUI.

### Result Provider
A result provider is an interface with one job: provide a result based on a passed config `scope`. The [Translation](../config-concepts/Translation#example) page has an overview of what `scope` is in Fzzy Config's context.

<CodeTabs>

```java !!tabs Java
ResultProvider<Boolean> myProvider = TODO();

public boolean getMyResult() {
    return myProvider.getResult("my_mod.my_config.mySetting");
}
```

```kotlin !!tabs Kotlin
val myProvider: ResultProvider<Boolean> = TODO()

fun getMyResult(): Boolean {
    return myProvider.getResult("my_mod.my_config.mySetting")
}
```

</CodeTabs>

#### Creating a Provider
Create an implementation of a Result Provider using the <a target="_blank" rel="noopener" href="https://fzzyhmstrs.github.io/fconfig/-fzzy%20-config/me.fzzyhmstrs.fzzy_config.result.api/-result-api/index.html">`ResultApi` 🗗</a> via `ConfigApi.result()` or `ConfigApiJava.result()`

Using the example from above, let's now add a simple provider. This system requires a fallback (false in this case).

<CodeTabs>

```java !!tabs Java
ResultProvider<Boolean> myProvider = ConfigApiJava.result().createSimpleResultProvider(false, Boolean.class);

public boolean getMyResult() {
    return myProvider.getResult("my_mod.my_config.mySetting");
}
```

```kotlin !!tabs Kotlin
val myProvider: ResultProvider<Boolean> = ConfigApi.result().createSimpleResultProvider(false, Boolean::class)

fun getMyResult(): Boolean {
    return myProvider.getResult("my_mod.my_config.mySetting")
}
```

</CodeTabs>

#### Using the Provider
The above examples show a simple usage example. 

<Callout variant="info">
The scope requested is dynamic; it can point to any valid boolean-producing setting in any registered config. **Including configs of other mods**.
</Callout>

This makes result providers a convenient way to interface with another mod without having to depend on it in-code. If for example, you are an addon to another mod, interfacing with a config setting this way is a change-robust way of retrieving the value you need. The parent config can add 5000 other settings, change package name, class name, and so on, and the value retrieval will still work. In the case that the scope becomes invalid, fzzy config will fail soft; throwing a log error and using your fallback approach.

<CodeTabs>

```java !!tabs Java
//both of these are valid targets for the boolean provider created above
boolean mySetting = false;
ValidatedBoolean mySetting2 = new ValidatedBoolean(false);
```

```kotlin !!tabs Kotlin
//both of these are valid targets for the boolean provider created above
val mySetting = false
val mySetting2 = ValidatedBoolean(false)
```

</CodeTabs>

### Example: Loot Table with dynamic drop chance
Below is an example loot table. It includes a rare drop that is valuable for mod progression, like a wither skeleton skull.

Currently, the drop is hard-wired to exactly the same random chance as a skull.

Using result providers we can make this table dynamically linked with a config.

```json
{
  "type": "minecraft:entity",
  "pools": [
    {
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:redstone"
        }
      ],
      "rolls": 1.0
    },
    {
      "conditions": [
        {
          "chance": 0.025,
          "condition": "minecraft:random_chance_with_looting",
          "looting_multiplier": 0.01
        }
      ],
      "entries": [
        {
          "type": "minecraft:item",
          "name": "my_mod:important_progression_item"
        }
      ],
      "rolls": 1.0
    }
  ]
}
```

#### Float Provider
To make this table dynamic, we will need a provider of float values to feed into our loot number provider. 

<Callout>
This provider could be improved to accept any number type, but that is beyond the scope of this example
</Callout>

<CodeTabs>

```java !!tabs Java
ResultProvider<Float> floatProvider = ConfigApi.result().createSimpleResultProvider(0f, Float.class);
```

```kotlin !!tabs Kotlin
val floatProvider = ConfigApi.result().createSimpleResultProvider(0f, Float::class)
```

</CodeTabs>

#### Number Provider
Next we wire this provider into a `LootNumberProvider`. Note the scope param. This is the scope passed in from the loot table definition that we will be providing from our config.

<Callout>
Methods that are unnecessary to illustrate this example are excluded. Assume that things like codec, type, and so on are implemented.
</Callout>

<CodeTabs>

```java !!tabs Java
public class ConfigLootNumberProvider implements LootNumberProvider {

    private final String scope;
	
    public ConfigLootNumberProvider(String scope) {
		this.scope = scope;
    }
	
    @Overrride
    float nextFloat(LootContext context) {
		return floatProvider.getResult(scope);
	}

	//getType, registration of the type, codec, etc. are assumed

private static final ResultProvider<Float> floatProvider = ConfigApiJava.result().createSimpleResultProvider(0f, Float.class);
}
```

```kotlin !!tabs Kotlin
class ConfigLootNumberProvider(private val scope: String): LootNumberProvider {

    override fun nextFloat(context: LootContext): Float {
        return floatProvider.getResult(scope)
    }
    
    //getType, registration of the type, codec, etc. are assumed
    
    companion object {
        private val floatProvider = ConfigApi.result().createSimpleResultProvider(0f, Float::class)
    }
}
```

</CodeTabs>

#### Json Integration
Let's assume our type and codec are registered under `my_mod:chance_provider` and accepts one string `scope`. The number provider json would look like:
```json
{
  "type": "my_mod:chance_provider",
  "scope": "my_mod.my_config.progressionDropChance"
}
```

#### The Config
Our config, registered under the identifier `my_mod:my_config` needs the setting(s) we want to refer to.

It might also be a good idea to include the looting multiplier. _(And an even better idea to move these into a separate section/object/group for organization)_

<CodeTabs>

```java !!tabs Java
public class MyConfig extends Config {
    
    public MyConfig() {
		super(Identifier.of("my_mod", "my_config"));
    }

    @ValidatedFloat.Restrict(min = 0f, max = 1f)
    float progressionDropChance = 0.025f;

    @ValidatedFloat.Restrict(min = 0f, max = 1f)
    float progressionLootingMultiplier = 0.01f;
}
```

```kotlin !!tabs Kotlin
class MyConfig : Config(Identifier.of("my_mod", "my_config")) {
    
    @ValidatedFloat.Restrict(0f, 1f)
    var progressionDropChance = 0.025f

    @ValidatedFloat.Restrict(0f, 1f)
    var progressionLootingMultiplier = 0.01f
}
```

</CodeTabs>

#### Table Integration
The pieces can now be tied together; the new provider condition can be used in loot tables.

This table will now have its chance dynamically updated from the config definition. Updates to the config values will be applied right away, no resource reload needed.
```json
{
  "type": "minecraft:entity",
  "pools": [
    {
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:redstone"
        }
      ],
      "rolls": 1.0
    },
    {
      "conditions": [
        {
          "chance": {
            "type": "my_mod:chance_provider",
            "scope": "my_mod.my_config.progressionDropChance"
          },
          "condition": "minecraft:random_chance_with_looting",
          "looting_multiplier": {
            "type": "my_mod:chance_provider",
            "scope": "my_mod.my_config.progressionLootingMultiplier"
          }
        }
      ],
      "entries": [
        {
          "type": "minecraft:item",
          "name": "my_mod:important_progression_item"
        }
      ],
      "rolls": 1.0
    }
  ]
}
```