123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace Animancer.FSM
- {
-
-
-
-
-
-
- public interface IStateMachine
- {
-
-
- object CurrentState { get; }
-
- object PreviousState { get; }
-
- object NextState { get; }
-
-
-
-
-
- bool CanSetState(object state);
-
- object CanSetState(IList states);
-
-
-
-
-
- bool TrySetState(object state);
-
-
-
-
-
-
-
- bool TrySetState(IList states);
-
-
-
-
-
- bool TryResetState(object state);
-
-
-
-
-
-
-
- bool TryResetState(IList states);
-
-
-
-
-
-
-
-
- void ForceSetState(object state);
- #if UNITY_ASSERTIONS
-
-
- bool AllowNullStates { get; }
- #endif
-
- void SetAllowNullStates(bool allow = true);
-
- #if UNITY_EDITOR
-
-
- int GUILineCount { get; }
-
- void DoGUI();
-
- void DoGUI(ref Rect area);
-
- #endif
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
- [HelpURL(StateExtensions.APIDocumentationURL + nameof(StateMachine<TState>) + "_1")]
- [Serializable]
- public partial class StateMachine<TState> : IStateMachine
- where TState : class, IState
- {
-
- [SerializeField]
- private TState _CurrentState;
-
- public TState CurrentState => _CurrentState;
-
-
- public TState PreviousState => StateChange<TState>.PreviousState;
-
- public TState NextState => StateChange<TState>.NextState;
-
-
- public StateMachine() { }
-
-
- public StateMachine(TState state)
- {
- #if UNITY_ASSERTIONS
- if (state == null)
- throw new ArgumentNullException(nameof(state), NullNotAllowed);
- #endif
- using (new StateChange<TState>(this, null, state))
- {
- _CurrentState = state;
- state.OnEnterState();
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public virtual void InitializeAfterDeserialize()
- {
- if (_CurrentState != null)
- using (new StateChange<TState>(this, null, _CurrentState))
- _CurrentState.OnEnterState();
- }
-
-
-
-
-
-
- public bool CanSetState(TState state)
- {
- #if UNITY_ASSERTIONS
- if (state == null && !AllowNullStates)
- throw new ArgumentNullException(nameof(state), NullNotAllowed);
- #endif
- using (new StateChange<TState>(this, _CurrentState, state))
- {
- if (_CurrentState != null && !_CurrentState.CanExitState)
- return false;
- if (state != null && !state.CanEnterState)
- return false;
- return true;
- }
- }
-
-
-
-
-
-
-
- public TState CanSetState(IList<TState> states)
- {
-
-
- var count = states.Count;
- for (int i = 0; i < count; i++)
- {
- var state = states[i];
- if (CanSetState(state))
- return state;
- }
- return null;
- }
-
-
-
-
-
-
- public bool TrySetState(TState state)
- {
- if (_CurrentState == state)
- {
- #if UNITY_ASSERTIONS
- if (state == null && !AllowNullStates)
- throw new ArgumentNullException(nameof(state), NullNotAllowed);
- #endif
- return true;
- }
- return TryResetState(state);
- }
-
-
-
-
-
-
-
- public bool TrySetState(IList<TState> states)
- {
- var count = states.Count;
- for (int i = 0; i < count; i++)
- if (TrySetState(states[i]))
- return true;
- return false;
- }
-
-
-
-
-
-
- public bool TryResetState(TState state)
- {
- if (!CanSetState(state))
- return false;
- ForceSetState(state);
- return true;
- }
-
-
-
-
-
-
-
- public bool TryResetState(IList<TState> states)
- {
- var count = states.Count;
- for (int i = 0; i < count; i++)
- if (TryResetState(states[i]))
- return true;
- return false;
- }
-
-
-
-
-
-
-
-
-
- public void ForceSetState(TState state)
- {
- #if UNITY_ASSERTIONS
- if (state == null)
- {
- if (!AllowNullStates)
- throw new ArgumentNullException(nameof(state), NullNotAllowed);
- }
- else if (state is IOwnedState<TState> owned && owned.OwnerStateMachine != this)
- {
- throw new InvalidOperationException(
- $"Attempted to use a state in a machine that is not its owner." +
- $"\n State: {state}" +
- $"\n Machine: {this}");
- }
- #endif
- using (new StateChange<TState>(this, _CurrentState, state))
- {
- _CurrentState?.OnExitState();
- _CurrentState = state;
- state?.OnEnterState();
- }
- }
-
-
- public override string ToString() => $"{GetType().Name} -> {_CurrentState}";
-
- #if UNITY_ASSERTIONS
-
-
- public bool AllowNullStates { get; private set; }
-
- private const string NullNotAllowed =
- "This " + nameof(StateMachine<TState>) + " does not allow its state to be set to null." +
- " Use " + nameof(SetAllowNullStates) + " to allow it if this is intentional.";
- #endif
-
- [System.Diagnostics.Conditional("UNITY_ASSERTIONS")]
- public void SetAllowNullStates(bool allow = true)
- {
- #if UNITY_ASSERTIONS
- AllowNullStates = allow;
- #endif
- }
-
- #region GUI
-
- #if UNITY_EDITOR
-
-
- public virtual int GUILineCount => 1;
-
-
- public void DoGUI()
- {
- var spacing = UnityEditor.EditorGUIUtility.standardVerticalSpacing;
- var lines = GUILineCount;
- var height =
- UnityEditor.EditorGUIUtility.singleLineHeight * lines +
- spacing * (lines - 1);
- var area = GUILayoutUtility.GetRect(0, height);
- area.height -= spacing;
- DoGUI(ref area);
- }
-
-
- public virtual void DoGUI(ref Rect area)
- {
- area.height = UnityEditor.EditorGUIUtility.singleLineHeight;
- UnityEditor.EditorGUI.BeginChangeCheck();
- var state = StateMachineUtilities.DoGenericField(area, "Current State", _CurrentState);
- if (UnityEditor.EditorGUI.EndChangeCheck())
- {
- if (Event.current.control)
- ForceSetState(state);
- else
- TrySetState(state);
- }
- StateMachineUtilities.NextVerticalArea(ref area);
- }
-
- #endif
- #endregion
-
- #region IStateMachine
-
-
- object IStateMachine.CurrentState => _CurrentState;
-
- object IStateMachine.PreviousState => PreviousState;
-
- object IStateMachine.NextState => NextState;
-
- object IStateMachine.CanSetState(IList states) => CanSetState((List<TState>)states);
-
- bool IStateMachine.CanSetState(object state) => CanSetState((TState)state);
-
- void IStateMachine.ForceSetState(object state) => ForceSetState((TState)state);
-
- bool IStateMachine.TryResetState(IList states) => TryResetState((List<TState>)states);
-
- bool IStateMachine.TryResetState(object state) => TryResetState((TState)state);
-
- bool IStateMachine.TrySetState(IList states) => TrySetState((List<TState>)states);
-
- bool IStateMachine.TrySetState(object state) => TrySetState((TState)state);
-
- void IStateMachine.SetAllowNullStates(bool allow) => SetAllowNullStates(allow);
-
- #endregion
-
- }
- }
|