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.

BroadcastHubDrawer.cs 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System;
  4. using System.Linq;
  5. using UnityEditor.SceneManagement;
  6. namespace MLAgents
  7. {
  8. /// <summary>
  9. /// PropertyDrawer for BroadcastHub. Used to display the BroadcastHub in the Inspector.
  10. /// </summary>
  11. [CustomPropertyDrawer(typeof(BroadcastHub))]
  12. public class BroadcastHubDrawer : PropertyDrawer
  13. {
  14. private BroadcastHub _hub;
  15. // The height of a line in the Unity Inspectors
  16. private const float LineHeight = 17f;
  17. // The vertical space left below the BroadcastHub UI.
  18. private const float ExtraSpaceBelow = 10f;
  19. // The horizontal size of the Control checkbox
  20. private const int ControlSize = 80;
  21. /// <summary>
  22. /// Computes the height of the Drawer depending on the property it is showing
  23. /// </summary>
  24. /// <param name="property">The property that is being drawn.</param>
  25. /// <param name="label">The label of the property being drawn.</param>
  26. /// <returns>The vertical space needed to draw the property.</returns>
  27. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  28. {
  29. LazyInitializeHub(property, label);
  30. var numLines = _hub.Count + 2 + (_hub.Count > 0 ? 1 : 0);
  31. return (numLines) * LineHeight + ExtraSpaceBelow;
  32. }
  33. /// <inheritdoc />
  34. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  35. {
  36. LazyInitializeHub(property, label);
  37. position.height = LineHeight;
  38. EditorGUI.LabelField(position, new GUIContent(label.text,
  39. "The Broadcast Hub helps you define which Brains you want to expose to " +
  40. "the external process"));
  41. position.y += LineHeight;
  42. EditorGUI.BeginProperty(position, label, property);
  43. EditorGUI.indentLevel++;
  44. DrawAddRemoveButtons(position);
  45. position.y += LineHeight;
  46. // This is the labels for each columns
  47. var brainWidth = position.width - ControlSize;
  48. var brainRect = new Rect(
  49. position.x, position.y, brainWidth, position.height);
  50. var controlRect = new Rect(
  51. position.x + brainWidth, position.y, ControlSize, position.height);
  52. if (_hub.Count > 0)
  53. {
  54. EditorGUI.LabelField(brainRect, "Brains");
  55. brainRect.y += LineHeight;
  56. EditorGUI.LabelField(controlRect, "Control");
  57. controlRect.y += LineHeight;
  58. controlRect.x += 15;
  59. }
  60. DrawBrains(brainRect, controlRect);
  61. EditorGUI.indentLevel--;
  62. EditorGUI.EndProperty();
  63. }
  64. /// <summary>
  65. /// Draws the Add and Remove buttons.
  66. /// </summary>
  67. /// <param name="position">The position at which to draw.</param>
  68. private void DrawAddRemoveButtons(Rect position)
  69. {
  70. // This is the rectangle for the Add button
  71. var addButtonRect = position;
  72. addButtonRect.x += 20;
  73. if (_hub.Count > 0)
  74. {
  75. addButtonRect.width /= 2;
  76. addButtonRect.width -= 24;
  77. var buttonContent = new GUIContent(
  78. "Add New", "Add a new Brain to the Broadcast Hub");
  79. if (GUI.Button(addButtonRect, buttonContent, EditorStyles.miniButton))
  80. {
  81. MarkSceneAsDirty();
  82. AddBrain();
  83. }
  84. // This is the rectangle for the Remove button
  85. var removeButtonRect = position;
  86. removeButtonRect.x = position.width / 2 + 15;
  87. removeButtonRect.width = addButtonRect.width - 18;
  88. buttonContent = new GUIContent(
  89. "Remove Last", "Remove the last Brain from the Broadcast Hub");
  90. if (GUI.Button(removeButtonRect, buttonContent, EditorStyles.miniButton))
  91. {
  92. MarkSceneAsDirty();
  93. RemoveLastBrain();
  94. }
  95. }
  96. else
  97. {
  98. addButtonRect.width -= 50;
  99. var buttonContent = new GUIContent(
  100. "Add Brain to Broadcast Hub", "Add a new Brain to the Broadcast Hub");
  101. if (GUI.Button(addButtonRect, buttonContent, EditorStyles.miniButton))
  102. {
  103. MarkSceneAsDirty();
  104. AddBrain();
  105. }
  106. }
  107. }
  108. /// <summary>
  109. /// Draws the Brain and Control checkbox for the brains contained in the BroadCastHub.
  110. /// </summary>
  111. /// <param name="brainRect">The Rect to draw the Brains.</param>
  112. /// <param name="controlRect">The Rect to draw the control checkbox.</param>
  113. private void DrawBrains(Rect brainRect, Rect controlRect)
  114. {
  115. for (var index = 0; index < _hub.Count; index++)
  116. {
  117. var exposedBrains = _hub.broadcastingBrains;
  118. var brain = exposedBrains[index];
  119. // This is the rectangle for the brain
  120. EditorGUI.BeginChangeCheck();
  121. var newBrain = EditorGUI.ObjectField(
  122. brainRect, brain, typeof(Brain), true) as Brain;
  123. brainRect.y += LineHeight;
  124. if (EditorGUI.EndChangeCheck())
  125. {
  126. MarkSceneAsDirty();
  127. _hub.broadcastingBrains.RemoveAt(index);
  128. var brainToInsert = exposedBrains.Contains(newBrain) ? null : newBrain;
  129. exposedBrains.Insert(index, brainToInsert);
  130. break;
  131. }
  132. // This is the Rectangle for the control checkbox
  133. EditorGUI.BeginChangeCheck();
  134. if (brain is LearningBrain)
  135. {
  136. var isTraining = _hub.IsControlled(brain);
  137. isTraining = EditorGUI.Toggle(controlRect, isTraining);
  138. _hub.SetControlled(brain, isTraining);
  139. }
  140. controlRect.y += LineHeight;
  141. if (EditorGUI.EndChangeCheck())
  142. {
  143. MarkSceneAsDirty();
  144. }
  145. }
  146. }
  147. /// <summary>
  148. /// Lazy initializes the Drawer with the property to be drawn.
  149. /// </summary>
  150. /// <param name="property">The SerializedProperty of the BroadcastHub
  151. /// to make the custom GUI for.</param>
  152. /// <param name="label">The label of this property.</param>
  153. private void LazyInitializeHub(SerializedProperty property, GUIContent label)
  154. {
  155. if (_hub != null)
  156. {
  157. return;
  158. }
  159. var target = property.serializedObject.targetObject;
  160. _hub = fieldInfo.GetValue(target) as BroadcastHub;
  161. if (_hub == null)
  162. {
  163. _hub = new BroadcastHub();
  164. fieldInfo.SetValue(target, _hub);
  165. }
  166. }
  167. /// <summary>
  168. /// Signals that the property has been modified and requires the scene to be saved for
  169. /// the changes to persist. Only works when the Editor is not playing.
  170. /// </summary>
  171. private static void MarkSceneAsDirty()
  172. {
  173. if (!EditorApplication.isPlaying)
  174. {
  175. EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
  176. }
  177. }
  178. /// <summary>
  179. /// Removes the last Brain from the BroadcastHub
  180. /// </summary>
  181. private void RemoveLastBrain()
  182. {
  183. if (_hub.Count > 0)
  184. {
  185. _hub.broadcastingBrains.RemoveAt(_hub.broadcastingBrains.Count - 1);
  186. }
  187. }
  188. /// <summary>
  189. /// Adds a new Brain to the BroadcastHub. The value of this brain will not be initialized.
  190. /// </summary>
  191. private void AddBrain()
  192. {
  193. _hub.broadcastingBrains.Add(null);
  194. }
  195. }
  196. }