123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
-
- namespace Unity.VisualScripting
- {
- [SerializationVersion("A")]
- 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;
- }
-
- #region Elements
-
- [DoNotSerialize]
- public GraphElementCollection<IState> states { get; internal set; }
-
- [DoNotSerialize]
- public GraphConnectionCollection<IStateTransition, IState, IState> transitions { get; internal set; }
-
- [DoNotSerialize]
- public GraphElementCollection<GraphGroup> groups { get; internal set; }
-
- [DoNotSerialize]
- public GraphElementCollection<StickyNote> sticky { get; private set; }
- #endregion
-
-
- #region Lifecycle
-
- // 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;
- }
-
- #endregion
-
-
- 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;
- }
- }
- }
|