Maze / Library /PackageCache /com.unity.visualscripting@1.8.0 /Runtime /VisualScripting.State /StateGraph.cs
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using UnityEngine; | |
| namespace Unity.VisualScripting | |
| { | |
| [] | |
| public sealed class StateGraph : Graph, IGraphEventListener | |
| { | |
| public StateGraph() | |
| { | |
| states = new GraphElementCollection<IState>(this); | |
| transitions = new GraphConnectionCollection<IStateTransition, IState, IState>(this); | |
| groups = new GraphElementCollection<GraphGroup>(this); | |
| sticky = new GraphElementCollection<StickyNote>(this); | |
| elements.Include(states); | |
| elements.Include(transitions); | |
| elements.Include(groups); | |
| elements.Include(sticky); | |
| } | |
| public override IGraphData CreateData() | |
| { | |
| return new StateGraphData(this); | |
| } | |
| public void StartListening(GraphStack stack) | |
| { | |
| stack.GetGraphData<StateGraphData>().isListening = true; | |
| var activeStates = GetActiveStatesNoAlloc(stack); | |
| foreach (var state in activeStates) | |
| { | |
| (state as IGraphEventListener)?.StartListening(stack); | |
| } | |
| activeStates.Free(); | |
| } | |
| public void StopListening(GraphStack stack) | |
| { | |
| var activeStates = GetActiveStatesNoAlloc(stack); | |
| foreach (var state in activeStates) | |
| { | |
| (state as IGraphEventListener)?.StopListening(stack); | |
| } | |
| activeStates.Free(); | |
| stack.GetGraphData<StateGraphData>().isListening = false; | |
| } | |
| public bool IsListening(GraphPointer pointer) | |
| { | |
| return pointer.GetGraphData<StateGraphData>().isListening; | |
| } | |
| [] | |
| public GraphElementCollection<IState> states { get; internal set; } | |
| [] | |
| public GraphConnectionCollection<IStateTransition, IState, IState> transitions { get; internal set; } | |
| [] | |
| public GraphElementCollection<GraphGroup> groups { get; internal set; } | |
| [] | |
| public GraphElementCollection<StickyNote> sticky { get; private set; } | |
| // Active state detection happens twice: | |
| // | |
| // 1. Before the enumeration, because any state | |
| // that becomes active during an update shouldn't | |
| // be updated until the next update | |
| // | |
| // 2. Inside the update method, because a state | |
| // that was active during enumeration and no longer | |
| // is shouldn't be updated. | |
| private HashSet<IState> GetActiveStatesNoAlloc(GraphPointer pointer) | |
| { | |
| var activeStates = HashSetPool<IState>.New(); | |
| foreach (var state in states) | |
| { | |
| var stateData = pointer.GetElementData<State.Data>(state); | |
| if (stateData.isActive) | |
| { | |
| activeStates.Add(state); | |
| } | |
| } | |
| return activeStates; | |
| } | |
| public void Start(Flow flow) | |
| { | |
| flow.stack.GetGraphData<StateGraphData>().isListening = true; | |
| foreach (var state in states.Where(s => s.isStart)) | |
| { | |
| try | |
| { | |
| state.OnEnter(flow, StateEnterReason.Start); | |
| } | |
| catch (Exception ex) | |
| { | |
| state.HandleException(flow.stack, ex); | |
| throw; | |
| } | |
| } | |
| } | |
| public void Stop(Flow flow) | |
| { | |
| var activeStates = GetActiveStatesNoAlloc(flow.stack); | |
| foreach (var state in activeStates) | |
| { | |
| try | |
| { | |
| state.OnExit(flow, StateExitReason.Stop); | |
| } | |
| catch (Exception ex) | |
| { | |
| state.HandleException(flow.stack, ex); | |
| throw; | |
| } | |
| } | |
| activeStates.Free(); | |
| flow.stack.GetGraphData<StateGraphData>().isListening = false; | |
| } | |
| public static StateGraph WithStart() | |
| { | |
| var stateGraph = new StateGraph(); | |
| var startState = FlowState.WithEnterUpdateExit(); | |
| startState.isStart = true; | |
| startState.nest.embed.title = "Start"; | |
| startState.position = new Vector2(-86, -15); | |
| stateGraph.states.Add(startState); | |
| return stateGraph; | |
| } | |
| } | |
| } | |