RelayNode.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using GraphProcessor;
  5. using System.Linq;
  6. using System;
  7. [System.Serializable, NodeMenuItem("Utils/Relay")]
  8. public class RelayNode : BaseNode
  9. {
  10. const string packIdentifier = "_Pack";
  11. [HideInInspector]
  12. public struct PackedRelayData
  13. {
  14. public List<object> values;
  15. public List<string> names;
  16. public List<Type> types;
  17. }
  18. [Input(name = "In")]
  19. public PackedRelayData input;
  20. [Output(name = "Out")]
  21. public PackedRelayData output;
  22. public bool unpackOutput = false;
  23. public bool packInput = false;
  24. public int inputEdgeCount = 0;
  25. [System.NonSerialized]
  26. int outputIndex = 0;
  27. SerializableType inputType = new SerializableType(typeof(object));
  28. const int k_MaxPortSize = 14;
  29. protected override void Process()
  30. {
  31. outputIndex = 0;
  32. output = input;
  33. }
  34. public override string layoutStyle => "GraphProcessorStyles/RelayNode";
  35. [CustomPortInput(nameof(input), typeof(object), true)]
  36. public void GetInputs(List< SerializableEdge > edges)
  37. {
  38. inputEdgeCount = edges.Count;
  39. // If the relay is only connected to another relay:
  40. if (edges.Count == 1 && edges.First().outputNode.GetType() == typeof(RelayNode))
  41. {
  42. if (edges.First().passThroughBuffer != null)
  43. input = (PackedRelayData)edges.First().passThroughBuffer;
  44. }
  45. else
  46. {
  47. input.values = edges.Select(e => e.passThroughBuffer).ToList();
  48. input.names = edges.Select(e => e.outputPort.portData.displayName).ToList();
  49. input.types = edges.Select(e => e.outputPort.portData.displayType ?? e.outputPort.fieldInfo.FieldType).ToList();
  50. }
  51. }
  52. [CustomPortOutput(nameof(output), typeof(object), true)]
  53. public void PushOutputs(List< SerializableEdge > edges, NodePort outputPort)
  54. {
  55. if (inputPorts.Count == 0)
  56. return;
  57. var inputPortEdges = inputPorts[0].GetEdges();
  58. if (outputPort.portData.identifier != packIdentifier && outputIndex >= 0 && (unpackOutput || inputPortEdges.Count == 1))
  59. {
  60. if (output.values == null)
  61. return;
  62. // When we unpack the output, there is one port per type of data in output
  63. // That means that this function will be called the same number of time than the output port count
  64. // Thus we use a class field to keep the index.
  65. object data = output.values[outputIndex++];
  66. foreach (var edge in edges)
  67. {
  68. var inputRelay = edge.inputNode as RelayNode;
  69. edge.passThroughBuffer = inputRelay != null && !inputRelay.packInput ? output : data;
  70. }
  71. }
  72. else
  73. {
  74. foreach (var edge in edges)
  75. edge.passThroughBuffer = output;
  76. }
  77. }
  78. [CustomPortBehavior(nameof(input))]
  79. IEnumerable< PortData > InputPortBehavior(List< SerializableEdge > edges)
  80. {
  81. // When the node is initialized, the input ports is empty because it's this function that generate the ports
  82. int sizeInPixel = 0;
  83. if (inputPorts.Count != 0)
  84. {
  85. // Add the size of all input edges:
  86. var inputEdges = inputPorts[0]?.GetEdges();
  87. sizeInPixel = inputEdges.Sum(e => Mathf.Max(0, e.outputPort.portData.sizeInPixel - 8));
  88. }
  89. if (edges.Count == 1 && !packInput)
  90. inputType.type = edges[0].outputPort.portData.displayType;
  91. else
  92. inputType.type = typeof(object);
  93. yield return new PortData {
  94. displayName = "",
  95. displayType = inputType.type,
  96. identifier = "0",
  97. acceptMultipleEdges = true,
  98. sizeInPixel = Mathf.Min(k_MaxPortSize, sizeInPixel + 8),
  99. };
  100. }
  101. [CustomPortBehavior(nameof(output))]
  102. IEnumerable< PortData > OutputPortBehavior(List< SerializableEdge > edges)
  103. {
  104. if (inputPorts.Count == 0)
  105. {
  106. // Default dummy port to avoid having a relay without any output:
  107. yield return new PortData {
  108. displayName = "",
  109. displayType = typeof(object),
  110. identifier = "0",
  111. acceptMultipleEdges = true,
  112. };
  113. yield break;
  114. }
  115. var inputPortEdges = inputPorts[0].GetEdges();
  116. var underlyingPortData = GetUnderlyingPortDataList();
  117. if (unpackOutput && inputPortEdges.Count == 1)
  118. {
  119. yield return new PortData
  120. {
  121. displayName = "Pack",
  122. identifier = packIdentifier,
  123. displayType = inputType.type,
  124. acceptMultipleEdges = true,
  125. sizeInPixel = Mathf.Min(k_MaxPortSize, Mathf.Max(underlyingPortData.Count, 1) + 7), // TODO: function
  126. };
  127. // We still keep the packed data as output when unpacking just in case we want to continue the relay after unpacking
  128. for (int i = 0; i < underlyingPortData.Count; i++)
  129. {
  130. yield return new PortData {
  131. displayName = underlyingPortData?[i].name ?? "",
  132. displayType = underlyingPortData?[i].type ?? typeof(object),
  133. identifier = i.ToString(),
  134. acceptMultipleEdges = true,
  135. sizeInPixel = 0,
  136. };
  137. }
  138. }
  139. else
  140. {
  141. yield return new PortData {
  142. displayName = "",
  143. displayType = inputType.type,
  144. identifier = "0",
  145. acceptMultipleEdges = true,
  146. sizeInPixel = Mathf.Min(k_MaxPortSize, Mathf.Max(underlyingPortData.Count, 1) + 7),
  147. };
  148. }
  149. }
  150. static List<(Type, string)> s_empty = new List<(Type, string)>();
  151. public List<(Type type, string name)> GetUnderlyingPortDataList()
  152. {
  153. // get input edges:
  154. if (inputPorts.Count == 0)
  155. return s_empty;
  156. var inputEdges = GetNonRelayEdges();
  157. if (inputEdges != null)
  158. return inputEdges.Select(e => (e.outputPort.portData.displayType ?? e.outputPort.fieldInfo.FieldType, e.outputPort.portData.displayName)).ToList();
  159. return s_empty;
  160. }
  161. public List<SerializableEdge> GetNonRelayEdges()
  162. {
  163. var inputEdges = inputPorts?[0]?.GetEdges();
  164. // Iterate until we don't have a relay node in input
  165. while (inputEdges.Count == 1 && inputEdges.First().outputNode.GetType() == typeof(RelayNode))
  166. inputEdges = inputEdges.First().outputNode.inputPorts[0]?.GetEdges();
  167. return inputEdges;
  168. }
  169. }