using System; using System.Linq; using UnityEngine; namespace Unity.VisualScripting { [UnitCategory("Graphs/Graph Nodes")] public abstract class HasGraph : Unit where TGraph : class, IGraph, new() where TMacro : Macro where TMachine : Machine { /// /// The entry point for the node. /// [DoNotSerialize] [PortLabelHidden] public ControlInput enter { get; private set; } /// /// The GameObject or the Machine where to look for the graph. /// [DoNotSerialize] [PortLabelHidden] [NullMeansSelf] public ValueInput target { get; private set; } /// /// The Graph to look for. /// [DoNotSerialize] [PortLabel("Graph")] [PortLabelHidden] public ValueInput graphInput { get; private set; } /// /// True if a Graph if found. /// [DoNotSerialize] [PortLabel("Has Graph")] [PortLabelHidden] public ValueOutput hasGraphOutput { get; private set; } /// /// The action to execute once the graph has been set. /// [DoNotSerialize] [PortLabelHidden] public ControlOutput exit { get; private set; } protected abstract bool isGameObject { get; } Type targetType => isGameObject ? typeof(GameObject) : typeof(TMachine); protected override void Definition() { enter = ControlInput(nameof(enter), TriggerHasGraph); target = ValueInput(targetType, nameof(target)).NullMeansSelf(); target.SetDefaultValue(targetType.PseudoDefault()); graphInput = ValueInput(nameof(graphInput), null); hasGraphOutput = ValueOutput(nameof(hasGraphOutput), OutputHasGraph); exit = ControlOutput(nameof(exit)); Requirement(graphInput, enter); Assignment(enter, hasGraphOutput); Succession(enter, exit); } ControlOutput TriggerHasGraph(Flow flow) { flow.SetValue(hasGraphOutput, OutputHasGraph(flow)); return exit; } bool OutputHasGraph(Flow flow) { var macro = flow.GetValue(graphInput); var targetValue = flow.GetValue(target, targetType); if (targetValue is GameObject gameObject) { if (gameObject != null) { var stateMachines = gameObject.GetComponents(); macro = flow.GetValue(graphInput); return stateMachines .Where(currentMachine => currentMachine != null) .Any(currentMachine => currentMachine.graph != null && currentMachine.graph.Equals(macro.graph)); } } else { TMachine machine = flow.GetValue(target); if (machine.graph != null && machine.graph.Equals(macro.graph)) { return true; } } return false; } } }