UnityNavMeshAdapterInspector.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #if UNITY_NAVIGATION_COMPONENTS
  2. using DunGen.Editor;
  3. using System.Collections.Generic;
  4. using Unity.AI.Navigation.Editor;
  5. using UnityEditor;
  6. using UnityEditorInternal;
  7. using UnityEngine;
  8. namespace DunGen.Adapters
  9. {
  10. [CustomEditor(typeof(UnityNavMeshAdapter))]
  11. public class UnityNavMeshAdapterInspector : UnityEditor.Editor
  12. {
  13. #region Constants
  14. private static readonly GUIContent bakeModeLabel = new GUIContent("Runtime Bake Mode", "Determine what to do as the runtime baking process");
  15. private static readonly GUIContent layerMaskLabel = new GUIContent("Layer Mask", "Objects on these layers will be considered when generating the navmesh. This setting will NOT override the layer mask of any existing nav mesh surface, it will only apply to any new surfaces that need to be made");
  16. private static readonly GUIContent addNavMeshLinksBetweenRoomsLabel = new GUIContent("Link Rooms", "If checked, NavMeshLinks will be formed to connect rooms in the dungeon");
  17. private static readonly GUIContent navMeshAgentTypesLabel = new GUIContent("Agent Types Link Info", "Per-agent information about how to create NavMeshLinks between rooms");
  18. private static readonly GUIContent navMeshLinkDistanceFromDoorwayLabel = new GUIContent("Distance from Doorway", "The distance on either side of each doorway that the NavMeshLink positions will be placed");
  19. private static readonly GUIContent disableLinkWhenDoorIsClosedLabel = new GUIContent("Disable When Door is Closed", "If true, the link will only be active when the corresponding door is open");
  20. private static readonly GUIContent autoGenerateFullRebakeSurfacesLabel = new GUIContent("Auto-Generate Surfaces", "If checked, a new surface will be generated for each agent type using some default settings. Uncheck this if you want to specify your own settings");
  21. private static readonly GUIContent fullRebakeTargetsLabel = new GUIContent("Target Surfaces", "The surfaces to use when doing a full dungeon bake. Only used when 'Auto-Generate Surfaces' is unchecked");
  22. private static readonly GUIContent useAutomaticLinkDistanceLabel = new GUIContent("Auto-Calculate Link Points", "Try to calculate the appropriate start and end points for the nav mesh link. If unchecked, the start and end points will be generated a specified distance apart");
  23. private static readonly GUIContent automaticLinkDistanceOffsetLabel = new GUIContent("Link Offset Distance", "A small offset applied to the automatic link point calculation to guarantee that the endpoints overlap the navigation mesh appropriately");
  24. private static readonly Dictionary<UnityNavMeshAdapter.RuntimeNavMeshBakeMode, string> bakeModeHelpLabels = new Dictionary<UnityNavMeshAdapter.RuntimeNavMeshBakeMode, string>()
  25. {
  26. { UnityNavMeshAdapter.RuntimeNavMeshBakeMode.PreBakedOnly, "Uses only existing baked surfaces found in the dungeon tiles, no runtime baking is performed" },
  27. { UnityNavMeshAdapter.RuntimeNavMeshBakeMode.AddIfNoSurfaceExists, "Uses existing baked surfaces in the tiles if any are found, otherwise new surfaces will be added and baked at runtime" },
  28. { UnityNavMeshAdapter.RuntimeNavMeshBakeMode.AlwaysRebake, "Adds new surfaces where they don't already exist. Rebakes all at runtime" },
  29. { UnityNavMeshAdapter.RuntimeNavMeshBakeMode.FullDungeonBake, "Bakes a single surface for the entire dungeon at runtime. No room links will be made. Openable doors will have to have NavMesh Obstacle components" },
  30. };
  31. #endregion
  32. private SerializedProperty priorityProp;
  33. private SerializedProperty bakeModeProp;
  34. private SerializedProperty layerMaskProp;
  35. private SerializedProperty addNavMeshLinksBetweenRoomsProp;
  36. private SerializedProperty navMeshAgentTypesProp;
  37. private SerializedProperty navMeshLinkDistanceFromDoorwayProp;
  38. private SerializedProperty autoGenerateFullRebakeSurfacesProp;
  39. private SerializedProperty useAutomaticLinkDistanceProp;
  40. private SerializedProperty automaticLinkDistanceOffsetProp;
  41. private ReorderableList fullRebakeTargetsList;
  42. private void OnEnable()
  43. {
  44. priorityProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.Priority));
  45. bakeModeProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.BakeMode));
  46. layerMaskProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.LayerMask));
  47. addNavMeshLinksBetweenRoomsProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.AddNavMeshLinksBetweenRooms));
  48. navMeshAgentTypesProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.NavMeshAgentTypes));
  49. navMeshLinkDistanceFromDoorwayProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.NavMeshLinkDistanceFromDoorway));
  50. autoGenerateFullRebakeSurfacesProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.AutoGenerateFullRebakeSurfaces));
  51. useAutomaticLinkDistanceProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.UseAutomaticLinkDistance));
  52. automaticLinkDistanceOffsetProp = serializedObject.FindProperty(nameof(UnityNavMeshAdapter.AutomaticLinkDistanceOffset));
  53. fullRebakeTargetsList = new ReorderableList(serializedObject, serializedObject.FindProperty("FullRebakeTargets"), true, true, true, true);
  54. fullRebakeTargetsList.drawElementCallback = DrawFullRebakeTargetsEntry;
  55. fullRebakeTargetsList.drawHeaderCallback = (rect) => EditorGUI.LabelField(rect, fullRebakeTargetsLabel);
  56. }
  57. public override void OnInspectorGUI()
  58. {
  59. var data = target as UnityNavMeshAdapter;
  60. if (data == null)
  61. return;
  62. serializedObject.Update();
  63. EditorGUILayout.Space();
  64. EditorGUILayout.PropertyField(priorityProp, InspectorConstants.AdapterPriorityLabel);
  65. EditorGUILayout.PropertyField(bakeModeProp, bakeModeLabel);
  66. // Show layer mask here unless this is a full rebake or pre-baked only
  67. if (data.BakeMode != UnityNavMeshAdapter.RuntimeNavMeshBakeMode.FullDungeonBake && data.BakeMode != UnityNavMeshAdapter.RuntimeNavMeshBakeMode.PreBakedOnly)
  68. EditorGUILayout.PropertyField(layerMaskProp, layerMaskLabel);
  69. string bakeModeHelpLabel;
  70. if (bakeModeHelpLabels.TryGetValue((UnityNavMeshAdapter.RuntimeNavMeshBakeMode)bakeModeProp.enumValueIndex, out bakeModeHelpLabel))
  71. EditorGUILayout.HelpBox(bakeModeHelpLabel, MessageType.Info, true);
  72. EditorGUILayout.Space();
  73. if (data.BakeMode == UnityNavMeshAdapter.RuntimeNavMeshBakeMode.FullDungeonBake)
  74. {
  75. EditorGUILayout.PropertyField(autoGenerateFullRebakeSurfacesProp, autoGenerateFullRebakeSurfacesLabel);
  76. EditorGUI.BeginDisabledGroup(!data.AutoGenerateFullRebakeSurfaces);
  77. EditorGUILayout.PropertyField(layerMaskProp, layerMaskLabel);
  78. EditorGUI.EndDisabledGroup();
  79. EditorGUI.BeginDisabledGroup(data.AutoGenerateFullRebakeSurfaces);
  80. fullRebakeTargetsList.DoLayoutList();
  81. EditorGUI.EndDisabledGroup();
  82. }
  83. EditorGUI.BeginDisabledGroup(bakeModeProp.enumValueIndex == (int)UnityNavMeshAdapter.RuntimeNavMeshBakeMode.FullDungeonBake);
  84. DrawLinksGUI();
  85. EditorGUI.EndDisabledGroup();
  86. serializedObject.ApplyModifiedProperties();
  87. }
  88. private void DrawFullRebakeTargetsEntry(Rect rect, int index, bool isActive, bool isFocused)
  89. {
  90. var element = fullRebakeTargetsList.serializedProperty.GetArrayElementAtIndex(index);
  91. EditorGUI.PropertyField(rect, element);
  92. }
  93. private void DrawLinksGUI()
  94. {
  95. addNavMeshLinksBetweenRoomsProp.isExpanded = EditorGUILayout.Foldout(addNavMeshLinksBetweenRoomsProp.isExpanded, "Room Links");
  96. if (addNavMeshLinksBetweenRoomsProp.isExpanded)
  97. {
  98. EditorGUILayout.BeginVertical("box");
  99. EditorGUI.indentLevel++;
  100. EditorGUILayout.PropertyField(addNavMeshLinksBetweenRoomsProp, addNavMeshLinksBetweenRoomsLabel);
  101. using (new EditorGUI.DisabledScope(!addNavMeshLinksBetweenRoomsProp.boolValue))
  102. {
  103. EditorGUILayout.PropertyField(useAutomaticLinkDistanceProp, useAutomaticLinkDistanceLabel);
  104. if (useAutomaticLinkDistanceProp.boolValue)
  105. EditorGUILayout.PropertyField(automaticLinkDistanceOffsetProp, automaticLinkDistanceOffsetLabel);
  106. else
  107. EditorGUILayout.PropertyField(navMeshLinkDistanceFromDoorwayProp, navMeshLinkDistanceFromDoorwayLabel);
  108. EditorGUILayout.Space();
  109. EditorGUILayout.Space();
  110. EditorGUILayout.BeginVertical("box");
  111. EditorGUILayout.BeginHorizontal();
  112. EditorGUILayout.LabelField(navMeshAgentTypesLabel);
  113. if (GUILayout.Button("Add New"))
  114. navMeshAgentTypesProp.InsertArrayElementAtIndex(navMeshAgentTypesProp.arraySize);
  115. EditorGUILayout.EndHorizontal();
  116. int indexToRemove = -1;
  117. for (int i = 0; i < navMeshAgentTypesProp.arraySize; i++)
  118. {
  119. EditorGUILayout.BeginVertical("box");
  120. if (GUILayout.Button("x", EditorStyles.miniButton, GUILayout.Width(18)))
  121. indexToRemove = i;
  122. var elementProp = navMeshAgentTypesProp.GetArrayElementAtIndex(i);
  123. var agentTypeID = elementProp.FindPropertyRelative("AgentTypeID");
  124. var areaTypeID = elementProp.FindPropertyRelative("AreaTypeID");
  125. var disableWhenDoorIsClosed = elementProp.FindPropertyRelative("DisableLinkWhenDoorIsClosed");
  126. NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", agentTypeID);
  127. NavMeshComponentsGUIUtility.AreaPopup("Area", areaTypeID);
  128. EditorGUILayout.PropertyField(disableWhenDoorIsClosed, disableLinkWhenDoorIsClosedLabel);
  129. EditorGUILayout.EndVertical();
  130. }
  131. EditorGUILayout.EndVertical();
  132. if (indexToRemove >= 0 && indexToRemove < navMeshAgentTypesProp.arraySize)
  133. navMeshAgentTypesProp.DeleteArrayElementAtIndex(indexToRemove);
  134. }
  135. EditorGUI.indentLevel--;
  136. EditorGUILayout.EndVertical();
  137. }
  138. }
  139. }
  140. }
  141. #endif