Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using UnityEngine;
  3. namespace Unity.VisualScripting
  4. {
  5. /* Implementation note:
  6. * Using an abstract base class works as a type unification workaround.
  7. * https://stackoverflow.com/questions/22721763
  8. * https://stackoverflow.com/a/7664919
  9. *
  10. * However, this forces us to use concrete classes for connections
  11. * instead of interfaces. In other words, no IControlConnection / IValueConnection.
  12. * If we did use interfaces, there would be ambiguity that needs to be resolved
  13. * at every reference to the source or destination.
  14. *
  15. * However, using a disambiguator hack seems to confuse even recent Mono runtime versions of Unity
  16. * and breaks its vtable. Sometimes, method pointers are just plain wrong.
  17. * I'm guessing this is specifically due to InvalidConnection, which actually
  18. * does unify the types; what the C# warning warned about.
  19. * https://stackoverflow.com/q/50051657/154502
  20. *
  21. * THEREFORE, IUnitConnection has to be implemented at the concrete class level,
  22. * because at that point the type unification warning is moot, because the type arguments are
  23. * provided.
  24. */
  25. public abstract class UnitConnection<TSourcePort, TDestinationPort> : GraphElement<FlowGraph>, IConnection<TSourcePort, TDestinationPort>
  26. where TSourcePort : class, IUnitOutputPort
  27. where TDestinationPort : class, IUnitInputPort
  28. {
  29. [Obsolete(Serialization.ConstructorWarning)]
  30. protected UnitConnection() { }
  31. protected UnitConnection(TSourcePort source, TDestinationPort destination)
  32. {
  33. Ensure.That(nameof(source)).IsNotNull(source);
  34. Ensure.That(nameof(destination)).IsNotNull(destination);
  35. if (source.unit.graph != destination.unit.graph)
  36. {
  37. throw new NotSupportedException("Cannot create connections across graphs.");
  38. }
  39. if (source.unit == destination.unit)
  40. {
  41. throw new InvalidConnectionException("Cannot create connections on the same unit.");
  42. }
  43. sourceUnit = source.unit;
  44. sourceKey = source.key;
  45. destinationUnit = destination.unit;
  46. destinationKey = destination.key;
  47. }
  48. public virtual IGraphElementDebugData CreateDebugData()
  49. {
  50. return new UnitConnectionDebugData();
  51. }
  52. #region Ports
  53. [Serialize]
  54. protected IUnit sourceUnit { get; private set; }
  55. [Serialize]
  56. protected string sourceKey { get; private set; }
  57. [Serialize]
  58. protected IUnit destinationUnit { get; private set; }
  59. [Serialize]
  60. protected string destinationKey { get; private set; }
  61. [DoNotSerialize]
  62. public abstract TSourcePort source { get; }
  63. [DoNotSerialize]
  64. public abstract TDestinationPort destination { get; }
  65. #endregion
  66. #region Dependencies
  67. public override int dependencyOrder => 1;
  68. public abstract bool sourceExists { get; }
  69. public abstract bool destinationExists { get; }
  70. protected void CopyFrom(UnitConnection<TSourcePort, TDestinationPort> source)
  71. {
  72. base.CopyFrom(source);
  73. }
  74. public override bool HandleDependencies()
  75. {
  76. // Replace the connection with an invalid connection if the ports are either missing or incompatible.
  77. // If the ports are missing, create invalid ports if required.
  78. var valid = true;
  79. IUnitOutputPort source;
  80. IUnitInputPort destination;
  81. if (!sourceExists)
  82. {
  83. if (!sourceUnit.invalidOutputs.Contains(sourceKey))
  84. {
  85. sourceUnit.invalidOutputs.Add(new InvalidOutput(sourceKey));
  86. }
  87. source = sourceUnit.invalidOutputs[sourceKey];
  88. valid = false;
  89. }
  90. else
  91. {
  92. source = this.source;
  93. }
  94. if (!destinationExists)
  95. {
  96. if (!destinationUnit.invalidInputs.Contains(destinationKey))
  97. {
  98. destinationUnit.invalidInputs.Add(new InvalidInput(destinationKey));
  99. }
  100. destination = destinationUnit.invalidInputs[destinationKey];
  101. valid = false;
  102. }
  103. else
  104. {
  105. destination = this.destination;
  106. }
  107. if (!source.CanValidlyConnectTo(destination))
  108. {
  109. valid = false;
  110. }
  111. if (!valid && source.CanInvalidlyConnectTo(destination))
  112. {
  113. source.InvalidlyConnectTo(destination);
  114. // Silence this warning if a unit with a missing type is involved (as it will not have any defined ports).
  115. // This is to avoid drowning users in warning and error messages if a unit's script goes missing.
  116. if (source.unit.GetType() != typeof(MissingType) && destination.unit.GetType() != typeof(MissingType))
  117. {
  118. Debug.LogWarning($"Could not load connection between '{source.key}' of '{sourceUnit}' and '{destination.key}' of '{destinationUnit}'.");
  119. }
  120. }
  121. return valid;
  122. }
  123. #endregion
  124. #region Analytics
  125. public override AnalyticsIdentifier GetAnalyticsIdentifier()
  126. {
  127. return null;
  128. }
  129. #endregion
  130. }
  131. }