Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SubgraphUnit.cs 6.5KB

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