File size: 4,657 Bytes
18a519f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 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;
}
}
}
|