Skip to content

Callback Generator

Scriptable Values comes with a source generator and analyzer to help you automatically generate event boilerplate code. This is especially useful for large projects where you have a lot of events and want to avoid writing the same code over and over again. You can generate callbacks for values, events, lists, dictionaries, and pools.

The source generator supports inheritance in the sense that it will call base methods if it detects that any of the base classes has the marker attribute. It does not support creating protected or virtual callback methods. You will need to create your own overridable methods and call those from the generated methods.

In order for the source generator to generate anything, your type that contains your callbacks must have the GenerateScriptableCallbacks attirbute.

Marker Attribute Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public class Player : MonoBehaviour
{
// This will now allow the source generator to generate the callbacks for this class.
}

The source generator supports non-static class and struct. It does not support record of these types. It does not support readonly struct.

The generator supports marking both fields and properties with the attributes.

Supported Types Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public class InstanceClass
{
// This will work
}
[GenerateScriptableCallbacks]
public struct StructType
{
// This will work
}
[GenerateScriptableCallbacks]
public static class StaticClass
{
// This will not work.
}
[GenerateScriptableCallbacks]
public record RecordClass
{
// This will not work.
}
[GenerateScriptableCallbacks]
public readonly struct ReadonlyStruct
{
// This will not work.
}
[GenerateScriptableCallbacks]
public record struct RecordStruct
{
// This will not work.
}

You need to call the subscribe and unsubscribe methods yourself. It’s recommended to call these in Awake/OnEnable and OnDestroy/OnDisable respectively. The source generator will generate the methods for you, so you don’t have to worry about the method names.

The subscribe and unsubscribe methods will subscribe/unsubscribe to/from all types with callback attributes.

The methods also keep track of what types you have subscribed to so it won’t subscribe multiple times.

Subscribe and Unsubscribe Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateValueCallback]
public ScriptableInt playerHealth;
private void OnEnable()
{
SubscribeToAllScriptableCallbacks();
}
private void OnDisable()
{
UnsubscribeFromAllScriptableCallbacks();
}
// ...
}

For scriptable values you use the GenerateValueCallback attribute. This attribute works on both ScriptableValue and ValueReference. The callback method requires two parameters of the type T and returns void. The generated method will be named On<FieldName>Changed where <FieldName> is the name of the field you have the attribute on. The method will be generated in the same class as the field.

GenerateValueCallback Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateValueCallback]
public ScriptableInt playerHealth;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnPlayerHealthChanged(int oldValue, int newValue)
{
// Do something with the new value.
}
}

If you’re using a modern IDE, it will give you an error if the method is not implemented, along with a code fix to quickly implement it. You don’t have to guess the name of the generated method!

With scriptable values, you can subscribe to the value changing and value changed event. You can also specify this in the attribute. The default is to subscribe to the value changed event. You can specify this by using the ValueCallbackType enum.

ValueCallbackType Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateValueCallback(ValueCallbackType.Changing)]
// You can specify multiple attributes on the same field.
[GenerateValueCallback(ValueCallbackType.Changed)]
public ScriptableInt playerHealth;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnPlayerHealthChanging(int oldValue, int newValue) { }
private partial void OnPlayerHealthChanged(int oldValue, int newValue) { }
}

You can also use the GenerateValueCallback attribute on a ValueReference. This will generate the same methods as for a ScriptableValue.

Value Reference Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateValueCallback]
public ValueReference playerHealth;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnPlayerHealthChanged(int oldValue, int newValue) { }
}

For scriptable events you use the GenerateEventCallback attribute. The callback method requires two parameters, one object sender and one of the type T and returns void. The generated method will be named On<FieldName>Invoked where <FieldName> is the name of the field you have the attribute on. The method will be generated in the same class as the field.

GenerateEventCallback Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateEventCallback]
public ScriptableIntEvent playerHealthChanged;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnPlayerHealthChangedInvoked(object sender, int newValue) { }
}

If you’re using a modern IDE, it will give you an error if the method is not implemented, along with a code fix to quickly implement it. You don’t have to guess the name of the generated method!

You can also use the GenerateEventCallback attribute on a non-generic event. This will generate the same methods as for a generic event, but instead of a generic type as args, you will just get the standard System.EventArgs.

Non-Generic Event Example
using System;
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class HealthUI : MonoBehaviour
{
[GenerateEventCallback]
public ScriptableEvent playerHealthChanged;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnPlayerHealthChangedInvoked(object sender, EventArgs args) { }
}

For scriptable pools you use the GeneratePoolCallback attribute. The callback method requires two parameters, one PoolAction and one of the type T and returns void. The generated method will be named On<FieldName>Changed where <FieldName> is the name of the field you have the attribute on. The method will be generated in the same class as the field. The attribute works on all types that derive from the ScriptablePool<T> class.

GeneratePoolCallback Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class EnemyManager : MonoBehaviour
{
[GeneratePoolCallback]
public ScriptablePool<Enemy> enemyPool;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnEnemyPoolChanged(PoolAction action, Enemy item) { }
}

If you’re using a modern IDE, it will give you an error if the method is not implemented, along with a code fix to quickly implement it. You don’t have to guess the name of the generated method!

For scriptable lists you use the GenerateCollectionCallback attribute. The callback method requires one parameter of type CollectionChangedArgs<T> and returns void. The generated method will be named On<FieldName>Changed where <FieldName> is the name of the field you have the attribute on. The method will be generated in the same class as the field. The attribute works on all types that derive from the ScriptableList<T> class.

GenerateCollectionCallback Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class Inventory : MonoBehaviour
{
[GenerateCollectionCallback]
public ScriptableList<Item> items;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnItemsChanged(CollectionChangedArgs<Item> args) { }
}

If you’re using a modern IDE, it will give you an error if the method is not implemented, along with a code fix to quickly implement it. You don’t have to guess the name of the generated method!

For scriptable dictionaries you use the GenerateCollectionCallback attribute. The callback method requires one parameter of type CollectionChangedArgs<KeyValuePair<TKey, TValue>> and returns void. The generated method will be named On<FieldName>Changed where <FieldName> is the name of the field you have the attribute on. The method will be generated in the same class as the field. The attribute works on all types that derive from the ScriptableDictionary<TKey, TValue> class.

GenerateCollectionCallback Example
using UnityEngine;
using Hertzole.ScriptableValues;
[GenerateScriptableCallbacks]
public partial class Inventory : MonoBehaviour
{
[GenerateCollectionCallback]
public ScriptableDictionary<string, Item> items;
// Call subscribe/unsubscribe methods
// This will be generated for you.
private partial void OnItemsChanged(CollectionChangedArgs<KeyValuePair<string, Item>> args) { }
}

If you’re using a modern IDE, it will give you an error if the method is not implemented, along with a code fix to quickly implement it. You don’t have to guess the name of the generated method!