Skip to content

Instantly share code, notes, and snippets.

@CriticalAngle
Last active January 24, 2023 01:14
Show Gist options
  • Save CriticalAngle/694ea3c7fad5abaa070213d142e63d78 to your computer and use it in GitHub Desktop.
Save CriticalAngle/694ea3c7fad5abaa070213d142e63d78 to your computer and use it in GitHub Desktop.
A simple class for managing a variable of any type.
// ReSharper disable MemberCanBePrivate.Global
using System;
using System.Collections.Generic;
namespace CriticalAngleStudios
{
/// <summary>
/// A simple class for managing a variable of any type.
/// </summary>
/// <typeparam name="T">The variable type.</typeparam>
public class Variable<T>
{
/// <summary>
/// Determines whether or not the onValueChangedCallbacks should be called if the new value is the same as the previous
/// value.
/// </summary>
private readonly bool isDirty;
/// <summary>
/// A list of actions that will be called when the value of this variable is changed.
/// </summary>
private readonly List<Action<CallbackContext>> onValueChangedCallbacks;
/// <summary>
/// An internal variable that holds the value of the user-defined variable.
/// </summary>
private T value;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="isDirty">
/// Determines whether or not the onValueChangedCallbacks should be called if the new value is the
/// same as the previous value.
/// </param>
public Variable(bool isDirty)
{
// Initialize variables
this.onValueChangedCallbacks = new List<Action<CallbackContext>>();
this.isDirty = isDirty;
this.value = default;
}
/// <summary>
/// A property that calls the value change callbacks when the user changes the value.
/// </summary>
public T Value
{
// Gets the current value.
get => this.value;
set
{
// Gets a reference to the current value before changing it, making the reference the previous value.
var previousValue = this.value;
// Check if the new value equals the previous value, and if this variable is dirty, then proceed.
if (previousValue.Equals(value) && !this.isDirty) return;
// Changes the value to the user's newly requested value.
this.value = value;
// Calls the internal function when the value is changed.
this.OnValueChanged_Internal(previousValue, this.value);
}
}
/// <summary>
/// Adds callback methods that sign up to when the value is changed.
/// </summary>
public event Action<CallbackContext> OnValueChanged
{
add => this.onValueChangedCallbacks.Add(value);
remove => this.onValueChangedCallbacks.Remove(value);
}
/// <summary>
/// Called by the `Value` property when the value is changed.
/// </summary>
/// <param name="previousValue">The value before the value is changed.</param>
/// <param name="currentValue">The value after the value is changed.</param>
private void OnValueChanged_Internal(T previousValue, T currentValue)
{
// Creates a context that holds the previous value and current value.
var context = new CallbackContext(previousValue, currentValue);
// Loops through and calls each action callback with the created CallbackContext.
foreach (var action in this.onValueChangedCallbacks)
action(context);
}
/// <summary>
/// A struct to hold the previous value and current value.
/// </summary>
public struct CallbackContext
{
/// <summary>
/// The previous value.
/// </summary>
public T PreviousValue;
/// <summary>
/// The current value.
/// </summary>
public T CurrentValue;
/// <summary>
/// The default constructor.
/// </summary>
/// <param name="previousValue">The previous value.</param>
/// <param name="currentValue">The current value.</param>
public CallbackContext(T previousValue, T currentValue)
{
this.PreviousValue = previousValue;
this.CurrentValue = currentValue;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment