2. Value Providers

  06. Initialization No Comments

What is a Value Provider?

Value providers are a highly flexible system that can be used to provide Init arguments dynamically at runtime.

Value providers are any objects that implement IValueProvider<TValue> or IValueByTypeProvider (or their asynchronous counterparts, IValueProviderAsync<TValue> or IValueByTypeProviderAsync).

Use Cases

There are a lot of possible use cases for value providers – here are a few examples to get your imagination running:

  • Addressables – value providers can be used to load addressable assets asynchronously before passing them to clients, all ready to be used. The initializer will automatically make sure that the client remains disabled until the addressable has been loaded.
  • Localization – value providers to localize all texts before passing them to clients. All your various client components don’t need to worry about which localization solution you happen to be using in the project.
  • Randomization – randomize any Init arguments you want – names, color palettes, character customization options… you name it!
  • Databases – Value providers can be used to fetch values from databases at runtime.
  • Per-Client Services – Make sure that different instances of the same type get provided for all clients.
  • Dropdown menu items – The [ValueProviderMenu] attribute can be used to add new items into Init argument dropdown menus for easily assigning value providers into them.

Scriptable Object Value Providers

Value providers are most typically scriptable objects. Only scriptable object value providers can be integrated into the context menu using the [ValueProviderMenu] attribute.

To make a new scriptable object value provider, create a class that derives from ScriptableObject and implements IValueProvider<TValue>.

To create an asset from the value provider, also add the [CreateAssetMenu] attribute to it.

At a minimum a value provider has to implement the Value property from the IValueProvider<TValue> interface.

For maximal flexibility, and an optimal Inspector experience in Edit Mode, it can sometimes also be useful to provide custom implementations for the TryGetFor and HasValueFor methods. If no custom implementations are provided for these method, then by default their return value will be determined based on whether or not the Value property returns a non-null value or not.

using Sisus.Init;
using UnityEngine;

[CreateAssetMenu]
class RandomNameProvider : ScriptableObject, IValueProvider<string>
{
    [SerializeField] string[] names = { };

    public string Value => names.Length is 0 ? null : names[Random.Range(0, names.Length)];

    public bool TryGetFor(Component client, out string value)
    {
        if(names.Length is 0)
        {
            value = null;
            return false;
        }

        value = names[Random.Range(0, names.Length)];
        return true;
    }

    public bool HasValueFor(Component client) => names.Length > 0;
}

To use a scriptable object value provider, simply drag-and-drop an asset created from one into an initializer (or Any<TValue>) field in the Inspector window.

You can also create a new Init argument context menu item for the value provider by adding the [ValueProviderMenu] attribute to it.

[ValueProviderMenu(typeof(string)), CreateAssetMenu]
class RandomNameProvider : ScriptableObject, IValueProvider<string>
{
    public string Value => Random.Range(0, 5) switch
    {
        0 => "Alice",
        1 => "Bob",
        2 => "Charlie",
        3 => "Diana",
        _ => "Eve",
    };
}

Leave a Reply

Your email address will not be published. Required fields are marked *