Value Reference
Value Reference is a special type that allows you to pick between a constant value or a scriptable value. They are used in the same way as a Scriptable Value, but in the editor they can be set to either a constant value or a scriptable value. This is useful for when you want to support both.

Using a Value Reference in your code is really straight forward. You can use the Value property to get or set the value of the Value Reference. For example:
using Hertzole.ScriptableValues;using UnityEngine;
public class PlayerHealth : MonoBehaviour{ // Can be either constant or a scriptable value public ValueReference<int> health;
public void TakeDamage(int damage) { health.Value -= damage; }}Then you can use the events to get notified when the value changes. For example:
using Hertzole.ScriptableValues;using UnityEngine;using UnityEngine.UI;
public class HealthUI : MonoBehaviour{ // Can be either constant or a scriptable value public ValueReference<int> health; public Text healthText;
private void OnEnable() { health.OnValueChanged += OnHealthChanged; }
private void OnDisable() { health.OnValueChanged -= OnHealthChanged; }
private void OnHealthChanged(int oldValue, int newValue) { healthText.text = "Health: " + newValue.ToString(); }}Remember to unsubscribe from events when you no longer need them. See the events section for more information.
Addressable Support
Section titled “Addressable Support”ValueReference<T> supports addressable references, if the addressables package is installed, along with the normal references.
using Hertzole.ScriptableValues;using UnityEngine;using UnityEngine.AddressableAssets;
public class PlayerHealth : MonoBehaviour{ // Can be either constant or a scriptable value public ValueReference<int> health;
private void Start() { // Need to check if the value reference is addressable if (health.IsAddressable) { // LoadAddressableAssetAsync will return an // AsyncOperationHandle<ScriptableValue<T>> // You can use it however you want, including awaiting it // in newer versions of Unity or using UniTask health.LoadAddressableAssetAsync(OnLoaded); } }
private void OnDestroy() { // No need to check if the value reference is addressable // Unload the addressable asset when the object is destroyed health.ReleaseAddressableAsset(); }
// Called when the addressable asset is loaded private void OnLoaded(AsyncOperationHandle<ScriptableValue<int>> handle) { // Check the handle status, it may fail if (handle.Status == AsyncOperationStatus.Succeeded) { handle.Result.Value = 100; } }}You can always subscribe to the OnValueChanging and OnValueChanged events, even if the addressable asset isn’t loaded yet. The events will be automatically applied to the addressable asset when it’s loaded.
using Hertzole.ScriptableValues;using UnityEngine;
public class PlayerHealth : MonoBehaviour{ // Can be either constant or a scriptable value public ValueReference<int> health;
private void Start() { // Need to check if the value reference is addressable if (health.IsAddressable) { health.LoadAddressableAssetAsync(); } }
private void OnEnable() { // Subscribe to the value changed event health.OnValueChanged += OnHealthChanged; }
private void OnDisable() { // Unsubscribe from the value changed event health.OnValueChanged -= OnHealthChanged; }
private void OnDestroy() { // No need to check if the value reference is addressable // Unload the addressable asset when the object is destroyed health.ReleaseAddressableAsset(); }
private void OnHealthChanged(int oldValue, int newValue) { Debug.Log("Health changed from " + oldValue + " to " + newValue); }You can not set the Value before the addressable asset is loaded. This will result in a warning.
using Hertzole.ScriptableValues;using UnityEngine;
public class TimeManager : MonoBehaviour{ // Can be either constant or a scriptable value public ValueReference<float> time;
private void Start() { // Need to check if the value reference is addressable if (time.IsAddressable) { time.LoadAddressableAssetAsync(); } }
private void OnDestroy() { // No need to check if the value reference is addressable // Unload the addressable asset when the object is destroyed time.ReleaseAddressableAsset(); }
private void Update() { if (time.IsAddressableLoaded) { // Can set the value now time.Value = Time.time; } }}IsAddressable is always present, even if the addressables package is not installed. If the package is not installed, it will always return false. If the package is installed, it will return true if the value reference is set to addressable.
IsAddressableLoaded is always present, even if the addressables package is not installed. If the package is not installed, it will always return true. If the package is installed, it will return true if the addressable asset is loaded. It will also return true if the value reference is not set to addressable.