A game about forced loneliness, made by TACStudios
1using System; 2using System.ComponentModel; 3 4namespace Unity.VisualScripting 5{ 6 [TypeIcon(typeof(FlowGraph))] 7 [UnitCategory("Nesting")] 8 [UnitTitle("Subgraph")] 9 [RenamedFrom("Bolt.SuperUnit")] 10 [RenamedFrom("Unity.VisualScripting.SuperUnit")] 11 [DisplayName("Subgraph Node")] 12 public sealed class SubgraphUnit : NesterUnit<FlowGraph, ScriptGraphAsset>, IGraphEventListener, IGraphElementWithData 13 { 14 public sealed class Data : IGraphElementData 15 { 16 public bool isListening; 17 } 18 19 public IGraphElementData CreateData() 20 { 21 return new Data(); 22 } 23 24 public SubgraphUnit() : base() { } 25 26 public SubgraphUnit(ScriptGraphAsset macro) : base(macro) { } 27 28 public static SubgraphUnit WithInputOutput() 29 { 30 var superUnit = new SubgraphUnit(); 31 superUnit.nest.source = GraphSource.Embed; 32 superUnit.nest.embed = FlowGraph.WithInputOutput(); 33 return superUnit; 34 } 35 36 public static SubgraphUnit WithStartUpdate() 37 { 38 var superUnit = new SubgraphUnit(); 39 superUnit.nest.source = GraphSource.Embed; 40 superUnit.nest.embed = FlowGraph.WithStartUpdate(); 41 return superUnit; 42 } 43 44 public override FlowGraph DefaultGraph() 45 { 46 return FlowGraph.WithInputOutput(); 47 } 48 49 protected override void Definition() 50 { 51 isControlRoot = true; // TODO: Infer relations instead 52 53 // Using portDefinitions and type checks instead of specific definition collections 54 // to avoid duplicates. Iterating only once for speed. 55 56 foreach (var definition in nest.graph.validPortDefinitions) 57 { 58 if (definition is ControlInputDefinition) 59 { 60 var controlInputDefinition = (ControlInputDefinition)definition; 61 var key = controlInputDefinition.key; 62 63 ControlInput(key, (flow) => 64 { 65 foreach (var unit in nest.graph.units) 66 { 67 if (unit is GraphInput) 68 { 69 var inputUnit = (GraphInput)unit; 70 71 flow.stack.EnterParentElement(this); 72 73 return inputUnit.controlOutputs[key]; 74 } 75 } 76 77 return null; 78 }); 79 } 80 else if (definition is ValueInputDefinition) 81 { 82 var valueInputDefinition = (ValueInputDefinition)definition; 83 var key = valueInputDefinition.key; 84 var type = valueInputDefinition.type; 85 var hasDefaultValue = valueInputDefinition.hasDefaultValue; 86 var defaultValue = valueInputDefinition.defaultValue; 87 88 var port = ValueInput(type, key); 89 90 if (hasDefaultValue) 91 { 92 port.SetDefaultValue(defaultValue); 93 } 94 } 95 else if (definition is ControlOutputDefinition) 96 { 97 var controlOutputDefinition = (ControlOutputDefinition)definition; 98 var key = controlOutputDefinition.key; 99 100 ControlOutput(key); 101 } 102 else if (definition is ValueOutputDefinition) 103 { 104 var valueOutputDefinition = (ValueOutputDefinition)definition; 105 var key = valueOutputDefinition.key; 106 var type = valueOutputDefinition.type; 107 108 ValueOutput(type, key, (flow) => 109 { 110 flow.stack.EnterParentElement(this); 111 112 // Manual looping to avoid LINQ allocation 113 // Also removing check for multiple output nodes for speed 114 // (The first output node will be used without any error) 115 116 foreach (var unit in nest.graph.units) 117 { 118 if (unit is GraphOutput) 119 { 120 var outputUnit = (GraphOutput)unit; 121 122 var value = flow.GetValue(outputUnit.valueInputs[key]); 123 124 flow.stack.ExitParentElement(); 125 126 return value; 127 } 128 } 129 130 flow.stack.ExitParentElement(); 131 132 throw new InvalidOperationException("Missing output node when to get value."); 133 }); 134 } 135 } 136 } 137 138 public void StartListening(GraphStack stack) 139 { 140 if (stack.TryEnterParentElement(this)) 141 { 142 nest.graph.StartListening(stack); 143 stack.ExitParentElement(); 144 } 145 146 stack.GetElementData<Data>(this).isListening = true; 147 } 148 149 public void StopListening(GraphStack stack) 150 { 151 stack.GetElementData<Data>(this).isListening = false; 152 153 if (stack.TryEnterParentElement(this)) 154 { 155 nest.graph.StopListening(stack); 156 stack.ExitParentElement(); 157 } 158 } 159 160 public bool IsListening(GraphPointer pointer) 161 { 162 return pointer.GetElementData<Data>(this).isListening; 163 } 164 165 #region Editing 166 167 public override void AfterAdd() 168 { 169 base.AfterAdd(); 170 171 nest.beforeGraphChange += StopWatchingPortDefinitions; 172 nest.afterGraphChange += StartWatchingPortDefinitions; 173 174 StartWatchingPortDefinitions(); 175 } 176 177 public override void BeforeRemove() 178 { 179 base.BeforeRemove(); 180 181 StopWatchingPortDefinitions(); 182 183 nest.beforeGraphChange -= StopWatchingPortDefinitions; 184 nest.afterGraphChange -= StartWatchingPortDefinitions; 185 } 186 187 private void StopWatchingPortDefinitions() 188 { 189 if (nest.graph != null) 190 { 191 nest.graph.onPortDefinitionsChanged -= Define; 192 } 193 } 194 195 private void StartWatchingPortDefinitions() 196 { 197 if (nest.graph != null) 198 { 199 nest.graph.onPortDefinitionsChanged += Define; 200 } 201 } 202 203 #endregion 204 } 205}