Created
March 18, 2026 17:51
-
-
Save KevinRoussel/b682d107ed71e08742c80579dbd27eb4 to your computer and use it in GitHub Desktop.
Petit helper pour la mise en place d'alteration à une stat / Vector3 etc.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| /// <summary> | |
| /// Opaque identifier returned when registering an alteration. | |
| /// It can later be used to remove that specific alteration. | |
| /// </summary> | |
| public interface IAlterationID { } | |
| /// <summary> | |
| /// Stores a base value and applies a layered set of transformations to produce a final altered value. | |
| /// </summary> | |
| /// <typeparam name="T">Type of value transformed by the registered alterations.</typeparam> | |
| public class Alterable<T> | |
| { | |
| sealed class AlterationID : IAlterationID { } | |
| readonly struct AlterationEntry | |
| { | |
| public readonly IAlterationID Id; | |
| public readonly Func<T, T> Alteration; | |
| public readonly int Layer; | |
| public readonly string Name; | |
| public AlterationEntry(IAlterationID id, Func<T, T> alteration, int layer, string name) | |
| { | |
| Id = id; | |
| Alteration = alteration; | |
| Layer = layer; | |
| Name = name; | |
| } | |
| } | |
| readonly T _defaultValue; | |
| readonly List<AlterationEntry> _effects; | |
| /// <summary> | |
| /// Invoked after a new alteration has been added. | |
| /// </summary> | |
| public event Action<IAlterationID> OnNewAlteration; | |
| /// <summary> | |
| /// Invoked just before an existing alteration is removed. | |
| /// </summary> | |
| public event Action<IAlterationID> OnBeforeRemovedAlteration; | |
| /// <summary> | |
| /// Invoked after an alteration has been removed. | |
| /// </summary> | |
| public event Action<IAlterationID> OnRemovedAlteration; | |
| /// <summary> | |
| /// Invoked after all registered alterations have been cleared. | |
| /// </summary> | |
| public event Action OnAllAlterationsRemoved; | |
| /// <summary> | |
| /// Returns a lightweight debug view of the currently registered alterations. | |
| /// </summary> | |
| public IEnumerable<string> DebugStrings => _effects.Select(i => $"{i.Name} Layer: {i.Layer}"); | |
| /// <summary> | |
| /// Creates a new alterable value container. | |
| /// </summary> | |
| /// <param name="defaultValue">Base value used when calling <see cref="Value()"/> or <see cref="AllAlterations()"/>.</param> | |
| public Alterable(T defaultValue) | |
| { | |
| _defaultValue = defaultValue; | |
| _effects = new List<AlterationEntry>(); | |
| } | |
| /// <summary> | |
| /// Computes the current value by applying all registered alterations to the default value. | |
| /// </summary> | |
| public T Value() => Value(_defaultValue); | |
| /// <summary> | |
| /// Computes the current value by applying all registered alterations to the provided reference value. | |
| /// </summary> | |
| /// <param name="referenceValue">Starting value used before applying the alterations.</param> | |
| /// <returns>The final value after all alterations have been applied in layer order.</returns> | |
| public T Value(T referenceValue) | |
| { | |
| T tmpValue = referenceValue; | |
| for (var i = 0; i < _effects.Count; i++) | |
| { | |
| tmpValue = _effects[i].Alteration(tmpValue); | |
| } | |
| return tmpValue; | |
| } | |
| /// <summary> | |
| /// Enumerates the intermediate values produced when applying each alteration to the default value. | |
| /// The first yielded value is the unmodified default value. | |
| /// </summary> | |
| public IEnumerable<T> AllAlterations() => AllAlterations(_defaultValue); | |
| /// <summary> | |
| /// Enumerates the intermediate values produced when applying each alteration to the provided reference value. | |
| /// The first yielded value is the unmodified reference value. | |
| /// </summary> | |
| /// <param name="referenceValue">Starting value used before applying the alterations.</param> | |
| public IEnumerable<T> AllAlterations(T referenceValue) | |
| { | |
| yield return referenceValue; | |
| T tmpValue = referenceValue; | |
| for (var i = 0; i < _effects.Count; i++) | |
| { | |
| tmpValue = _effects[i].Alteration(tmpValue); | |
| yield return tmpValue; | |
| } | |
| } | |
| /// <summary> | |
| /// Adds a custom alteration to the collection. | |
| /// Alterations are applied in ascending layer order. | |
| /// </summary> | |
| /// <param name="alteration">Transformation applied to the current value.</param> | |
| /// <param name="layer">Execution order of the alteration. Lower layers are applied first.</param> | |
| /// <param name="alterationName">Optional debug name used by <see cref="DebugStrings"/>.</param> | |
| /// <returns>An identifier that can later be used to remove this alteration.</returns> | |
| public IAlterationID AddCustomAlteration(Func<T, T> alteration, int layer = 1, string alterationName = "") | |
| { | |
| if (alteration == null) throw new ArgumentNullException(nameof(alteration)); | |
| IAlterationID id = new AlterationID(); | |
| var insertIndex = _effects.FindIndex(effect => layer < effect.Layer); | |
| if (insertIndex >= 0) | |
| { | |
| _effects.Insert(insertIndex, new AlterationEntry(id, alteration, layer, alterationName)); | |
| } | |
| else | |
| { | |
| _effects.Add(new AlterationEntry(id, alteration, layer, alterationName)); | |
| } | |
| OnNewAlteration?.Invoke(id); | |
| return id; | |
| } | |
| /// <summary> | |
| /// Removes a previously registered alteration. | |
| /// </summary> | |
| /// <param name="alteration">Identifier of the alteration to remove.</param> | |
| /// <returns><c>true</c> if the alteration was found and removed; otherwise <c>false</c>.</returns> | |
| public bool RemoveAlteration(IAlterationID alteration) | |
| { | |
| for (var i = 0; i < _effects.Count; i++) | |
| { | |
| if (_effects[i].Id != alteration) continue; | |
| OnBeforeRemovedAlteration?.Invoke(alteration); | |
| var removedAlteration = alteration; | |
| _effects.RemoveAt(i); | |
| OnRemovedAlteration?.Invoke(removedAlteration); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// <summary> | |
| /// Removes a previously registered alteration and clears the provided identifier reference when successful. | |
| /// </summary> | |
| /// <param name="alteration">Identifier of the alteration to remove. Set to <c>null</c> when removal succeeds.</param> | |
| /// <returns><c>true</c> if the alteration was found and removed; otherwise <c>false</c>.</returns> | |
| public bool TryRemoveAndClear(ref IAlterationID alteration) | |
| { | |
| if (!RemoveAlteration(alteration)) return false; | |
| alteration = null; | |
| return true; | |
| } | |
| /// <summary> | |
| /// Removes every registered alteration. | |
| /// </summary> | |
| public void RemoveAllAlterations() | |
| { | |
| _effects.Clear(); | |
| OnAllAlterationsRemoved?.Invoke(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment