using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using UnityEngine; namespace Unity.VisualScripting { [SerializationVersion("A")] [DisplayName("Script Graph")] public sealed class FlowGraph : Graph, IGraphWithVariables, IGraphEventListener { public FlowGraph() { units = new GraphElementCollection(this); controlConnections = new GraphConnectionCollection(this); valueConnections = new GraphConnectionCollection(this); invalidConnections = new GraphConnectionCollection(this); groups = new GraphElementCollection(this); sticky = new GraphElementCollection(this); elements.Include(units); elements.Include(controlConnections); elements.Include(valueConnections); elements.Include(invalidConnections); elements.Include(groups); elements.Include(sticky); controlInputDefinitions = new UnitPortDefinitionCollection(); controlOutputDefinitions = new UnitPortDefinitionCollection(); valueInputDefinitions = new UnitPortDefinitionCollection(); valueOutputDefinitions = new UnitPortDefinitionCollection(); variables = new VariableDeclarations(); } public override IGraphData CreateData() { return new FlowGraphData(this); } public void StartListening(GraphStack stack) { stack.GetGraphData().isListening = true; foreach (var unit in units) { (unit as IGraphEventListener)?.StartListening(stack); } } public void StopListening(GraphStack stack) { foreach (var unit in units) { (unit as IGraphEventListener)?.StopListening(stack); } stack.GetGraphData().isListening = false; } public bool IsListening(GraphPointer pointer) { return pointer.GetGraphData().isListening; } #region Variables [Serialize] public VariableDeclarations variables { get; private set; } public IEnumerable GetDynamicVariableNames(VariableKind kind, GraphReference reference) { return units.OfType() .Where(v => v.kind == kind && Flow.CanPredict(v.name, reference)) .Select(v => Flow.Predict(v.name, reference)) .Where(name => !StringUtility.IsNullOrWhiteSpace(name)) .Distinct() .OrderBy(name => name); } #endregion #region Elements [DoNotSerialize] public GraphElementCollection units { get; private set; } [DoNotSerialize] public GraphConnectionCollection controlConnections { get; private set; } [DoNotSerialize] public GraphConnectionCollection valueConnections { get; private set; } [DoNotSerialize] public GraphConnectionCollection invalidConnections { get; private set; } [DoNotSerialize] public GraphElementCollection groups { get; private set; } [DoNotSerialize] public GraphElementCollection sticky { get; private set; } #endregion #region Definition private const string DefinitionRemoveWarningTitle = "Remove Port Definition"; private const string DefinitionRemoveWarningMessage = "Removing this definition will break any existing connection to this port. Are you sure you want to continue?"; [Serialize] [InspectorLabel("Trigger Inputs")] [InspectorWide(true)] [WarnBeforeRemoving(DefinitionRemoveWarningTitle, DefinitionRemoveWarningMessage)] public UnitPortDefinitionCollection controlInputDefinitions { get; private set; } [Serialize] [InspectorLabel("Trigger Outputs")] [InspectorWide(true)] [WarnBeforeRemoving(DefinitionRemoveWarningTitle, DefinitionRemoveWarningMessage)] public UnitPortDefinitionCollection controlOutputDefinitions { get; private set; } [Serialize] [InspectorLabel("Data Inputs")] [InspectorWide(true)] [WarnBeforeRemoving(DefinitionRemoveWarningTitle, DefinitionRemoveWarningMessage)] public UnitPortDefinitionCollection valueInputDefinitions { get; private set; } [Serialize] [InspectorLabel("Data Outputs")] [InspectorWide(true)] [WarnBeforeRemoving(DefinitionRemoveWarningTitle, DefinitionRemoveWarningMessage)] public UnitPortDefinitionCollection valueOutputDefinitions { get; private set; } public IEnumerable validPortDefinitions => LinqUtility.Concat(controlInputDefinitions, controlOutputDefinitions, valueInputDefinitions, valueOutputDefinitions) .Where(upd => upd.isValid) .DistinctBy(upd => upd.key); public event Action onPortDefinitionsChanged; public void PortDefinitionsChanged() { onPortDefinitionsChanged?.Invoke(); } #endregion public static FlowGraph WithInputOutput() { return new FlowGraph() { units = { new GraphInput() { position = new Vector2(-250, -30) }, new GraphOutput() { position = new Vector2(105, -30) } } }; } public static FlowGraph WithStartUpdate() { return new FlowGraph() { units = { new Start() { position = new Vector2(-204, -144) }, new Update() { position = new Vector2(-204, 60) } } }; } } }