diff --git a/src/Base/IActionable.cs b/src/Base/IActionable.cs index 5482e62..7e86635 100644 --- a/src/Base/IActionable.cs +++ b/src/Base/IActionable.cs @@ -9,6 +9,7 @@ public interface IActionable { void OnAction(TEvent trigger); void OnAction(TEvent trigger, TData data); + bool HasAction(TEvent trigger); } /// diff --git a/src/StateMachine/HybridStateMachine.cs b/src/StateMachine/HybridStateMachine.cs index bea33d8..665237a 100644 --- a/src/StateMachine/HybridStateMachine.cs +++ b/src/StateMachine/HybridStateMachine.cs @@ -96,6 +96,12 @@ public override void OnAction(TEvent trigger, TData data) base.OnAction(trigger, data); } + public override bool HasAction(TEvent trigger) + { + return (actionStorage?.HasAction(trigger) ?? false) + || base.HasAction(trigger); + } + /// /// Adds an action that can be called with OnAction(). Actions are like the builtin events /// OnEnter / OnLogic / ... but are defined by the user. diff --git a/src/StateMachine/StateMachine.cs b/src/StateMachine/StateMachine.cs index ff07521..3dd157e 100644 --- a/src/StateMachine/StateMachine.cs +++ b/src/StateMachine/StateMachine.cs @@ -781,6 +781,17 @@ public virtual void OnAction(TEvent trigger, TData data) (activeState as IActionable)?.OnAction(trigger, data); } + /// + /// Checks if currently active state has this action. + /// + /// Name of the action. + /// + public virtual bool HasAction(TEvent trigger) + { + EnsureIsInitializedFor("Running HasAction of the active state"); + return (activeState as IActionable)?.HasAction(trigger) ?? false; + } + public StateBase GetState(TStateId name) { StateBundle bundle; diff --git a/src/States/ActionState.cs b/src/States/ActionState.cs index aa646c8..ddf05e3 100644 --- a/src/States/ActionState.cs +++ b/src/States/ActionState.cs @@ -67,6 +67,14 @@ public void OnAction(TEvent trigger) /// Type of the data parameter. public void OnAction(TEvent trigger, TData data) => actionStorage?.RunAction(trigger, data); + + /// + /// Checks if this action is defined / has been added. + /// + /// Name of the action. + /// + public bool HasAction(TEvent trigger) + => actionStorage?.HasAction(trigger) ?? false; } /// diff --git a/src/States/ActionStorage.cs b/src/States/ActionStorage.cs index 5d4a15e..c775fbc 100644 --- a/src/States/ActionStorage.cs +++ b/src/States/ActionStorage.cs @@ -89,5 +89,13 @@ public void RunAction(TEvent trigger) /// Type of the data parameter. public void RunAction(TEvent trigger, TData data) => TryGetAndCastAction>(trigger)?.Invoke(data); + + /// + /// Checks if this action is defined / has been added. + /// + /// Name of the action. + /// + public bool HasAction(TEvent trigger) + => actionsByEvent.ContainsKey(trigger); } } diff --git a/src/States/DecoratedState.cs b/src/States/DecoratedState.cs index 6e2b51d..9f28ad2 100644 --- a/src/States/DecoratedState.cs +++ b/src/States/DecoratedState.cs @@ -94,6 +94,11 @@ public void OnAction(TEvent trigger, TData data) (state as IActionable)?.OnAction(trigger, data); } + public bool HasAction(TEvent trigger) + { + return (state as IActionable)?.HasAction(trigger) ?? false; + } + public override string GetActiveHierarchyPath() { return state.GetActiveHierarchyPath(); diff --git a/src/States/ParallelStates.cs b/src/States/ParallelStates.cs index 1c8ef6b..5a1246b 100644 --- a/src/States/ParallelStates.cs +++ b/src/States/ParallelStates.cs @@ -193,6 +193,16 @@ public void OnAction(TEvent trigger, TData data) } } + public bool HasAction(TEvent trigger) + { + foreach (var state in states) + { + if ((state as IActionable)?.HasAction(trigger) ?? false) + return true; + } + return false; + } + public void StateCanExit() { // Try to exit as soon as any one of the child states can exit, unless the exit behaviour