123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- using System;
- namespace Animancer.FSM
- {
- /// <summary>A static access point for the details of a key change in a <see cref="StateMachine{TKey, TState}"/>.</summary>
- /// <remarks>
- /// This system is thread-safe.
- /// <para></para>
- /// <strong>Documentation:</strong>
- /// <see href="https://kybernetik.com.au/animancer/docs/manual/fsm/changing-states">
- /// Changing States</see>
- /// </remarks>
- /// https://kybernetik.com.au/animancer/api/Animancer.FSM/KeyChange_1
- ///
- public struct KeyChange<TKey> : IDisposable
- {
- /************************************************************************************************************************/
- [ThreadStatic]
- private static KeyChange<TKey> _Current;
- private IKeyedStateMachine<TKey> _StateMachine;
- private TKey _PreviousKey;
- private TKey _NextKey;
- /************************************************************************************************************************/
- /// <summary>Is a <see cref="KeyChange{TKey}"/> of this type currently occurring?</summary>
- public static bool IsActive => _Current._StateMachine != null;
- /// <summary>The <see cref="KeyChange{TKey}"/> in which the current change is occurring.</summary>
- /// <remarks>This will be null if no change is currently occurring.</remarks>
- public static IKeyedStateMachine<TKey> StateMachine => _Current._StateMachine;
- /************************************************************************************************************************/
- /// <summary>The key being changed from.</summary>
- /// <exception cref="InvalidOperationException">[Assert-Only]
- /// <see cref="IsActive"/> is false so this property is likely being accessed on the wrong generic type.
- /// </exception>
- public static TKey PreviousKey
- {
- get
- {
- #if UNITY_ASSERTIONS
- if (!IsActive)
- throw new InvalidOperationException(StateExtensions.GetChangeError(typeof(TKey), typeof(StateMachine<,>), "Key"));
- #endif
- return _Current._PreviousKey;
- }
- }
- /************************************************************************************************************************/
- /// <summary>The key being changed into.</summary>
- /// <exception cref="InvalidOperationException">[Assert-Only]
- /// <see cref="IsActive"/> is false so this property is likely being accessed on the wrong generic type.
- /// </exception>
- public static TKey NextKey
- {
- get
- {
- #if UNITY_ASSERTIONS
- if (!IsActive)
- throw new InvalidOperationException(StateExtensions.GetChangeError(typeof(TKey), typeof(StateMachine<,>), "Key"));
- #endif
- return _Current._NextKey;
- }
- }
- /************************************************************************************************************************/
- /// <summary>[Internal]
- /// Assigns the parameters as the details of the currently active change and creates a new
- /// <see cref="KeyChange{TKey}"/> containing the details of the previously active change so that disposing
- /// it will re-assign those previous details to be current again in case of recursive state changes.
- /// </summary>
- ///
- /// <remarks>
- /// <strong>Example:</strong><code>
- /// using (new KeyChange<TState>(previousKey, nextKey))
- /// {
- /// // Do the actual key change.
- /// }
- /// </code></remarks>
- ///
- internal KeyChange(IKeyedStateMachine<TKey> stateMachine, TKey previousKey, TKey nextKey)
- {
- this = _Current;
- _Current._StateMachine = stateMachine;
- _Current._PreviousKey = previousKey;
- _Current._NextKey = nextKey;
- }
- /************************************************************************************************************************/
- /// <summary>[<see cref="IDisposable"/>]
- /// Re-assigns the values of this change (which were the previous values from when it was created) to be the
- /// currently active change. See the constructor for recommended usage.
- /// </summary>
- /// <remarks>
- /// Usually this will be returning to default values (nulls), but if one state change causes another then the
- /// second one ending will return to the first which will then return to the defaults.
- /// </remarks>
- public readonly void Dispose()
- {
- _Current = this;
- }
- /************************************************************************************************************************/
- /// <summary>Returns a string describing the contents of this <see cref="KeyChange{TKey}"/>.</summary>
- public override readonly string ToString() => IsActive
- ? $"{nameof(KeyChange<TKey>)}<{typeof(TKey).FullName}" +
- $">({nameof(PreviousKey)}={PreviousKey}" +
- $", {nameof(NextKey)}={NextKey})"
- : $"{nameof(KeyChange<TKey>)}<{typeof(TKey).FullName}(Not Currently Active)";
- /// <summary>Returns a string describing the contents of the current <see cref="KeyChange{TKey}"/>.</summary>
- public static string CurrentToString()
- => _Current.ToString();
- /************************************************************************************************************************/
- }
- }
|