chore: initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
|
||||
namespace Animancer.FSM
|
||||
{
|
||||
/// <summary>A static access point for the details of a state change in a <see cref="StateMachine{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/StateChange_1
|
||||
///
|
||||
public struct StateChange<TState> : IDisposable
|
||||
where TState : class, IState
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[ThreadStatic]
|
||||
private static StateChange<TState> _Current;
|
||||
|
||||
private StateMachine<TState> _StateMachine;
|
||||
private TState _PreviousState;
|
||||
private TState _NextState;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Is a <see cref="StateChange{TState}"/> of this type currently occurring?</summary>
|
||||
public static bool IsActive
|
||||
=> _Current._StateMachine != null;
|
||||
|
||||
/// <summary>The <see cref="StateMachine{TState}"/> in which the current change is occurring.</summary>
|
||||
/// <remarks>This will be null if no change is currently occurring.</remarks>
|
||||
public static StateMachine<TState> StateMachine
|
||||
=> _Current._StateMachine;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>The state currently 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 TState PreviousState
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_ASSERTIONS
|
||||
if (!IsActive)
|
||||
throw new InvalidOperationException(
|
||||
StateExtensions.GetChangeError(typeof(TState), typeof(StateMachine<>)));
|
||||
#endif
|
||||
return _Current._PreviousState;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>The state 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 TState NextState
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_ASSERTIONS
|
||||
if (!IsActive)
|
||||
throw new InvalidOperationException(
|
||||
StateExtensions.GetChangeError(typeof(TState), typeof(StateMachine<>)));
|
||||
#endif
|
||||
return _Current._NextState;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>[Internal]
|
||||
/// Assigns the parameters as the details of the currently active change and creates a new
|
||||
/// <see cref="StateChange{TState}"/> 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 StateChange<TState>(stateMachine, previousState, nextState))
|
||||
/// {
|
||||
/// // Do the actual state change.
|
||||
/// }
|
||||
/// </code></remarks>
|
||||
internal StateChange(StateMachine<TState> stateMachine, TState previousState, TState nextState)
|
||||
{
|
||||
this = _Current;
|
||||
|
||||
_Current._StateMachine = stateMachine;
|
||||
_Current._PreviousState = previousState;
|
||||
_Current._NextState = nextState;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <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="StateChange{TState}"/>.</summary>
|
||||
public override readonly string ToString()
|
||||
=> IsActive
|
||||
? $"{nameof(StateChange<TState>)}<{typeof(TState).FullName}" +
|
||||
$">({nameof(PreviousState)}='{_PreviousState}'" +
|
||||
$", {nameof(NextState)}='{_NextState}')"
|
||||
: $"{nameof(StateChange<TState>)}<{typeof(TState).FullName}(Not Currently Active)";
|
||||
|
||||
/// <summary>Returns a string describing the contents of the current <see cref="StateChange{TState}"/>.</summary>
|
||||
public static string CurrentToString()
|
||||
=> _Current.ToString();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user