No Description
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.

NavMeshModifierVolumeInPrefabTests.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //#define KEEP_ARTIFACTS_FOR_INSPECTION
  2. using System.Collections;
  3. using System.IO;
  4. using NUnit.Framework;
  5. using UnityEditor;
  6. #if !UNITY_2021_2_OR_NEWER
  7. using UnityEditor.Experimental.SceneManagement;
  8. #endif
  9. using UnityEditor.SceneManagement;
  10. using UnityEngine;
  11. using UnityEngine.AI;
  12. using UnityEngine.SceneManagement;
  13. using UnityEngine.TestTools;
  14. using Object = UnityEngine.Object;
  15. namespace Unity.AI.Navigation.Editor.Tests
  16. {
  17. [Category("PrefabsWithNavMeshModifierVolume")]
  18. class NavMeshModifierVolumeInPrefabTests
  19. {
  20. const string k_AutoSaveKey = "AutoSave";
  21. const string k_ParentFolder = "Assets";
  22. const string k_TempFolderName = "TempPrefabAndModifiers";
  23. static readonly string k_TempFolder = Path.Combine(k_ParentFolder, k_TempFolderName);
  24. const int k_PinkArea = 3;
  25. const int k_GreenArea = 4;
  26. const int k_RedArea = 18;
  27. const int k_PrefabDefaultArea = k_GreenArea;
  28. static readonly NavMeshQueryFilter k_QueryAnyArea = new() { agentTypeID = 0, areaMask = NavMesh.AllAreas };
  29. static bool s_EnterPlayModeOptionsEnabled;
  30. static EnterPlayModeOptions s_EnterPlayModeOptions;
  31. [SerializeField]
  32. string m_PrefabPath;
  33. [SerializeField]
  34. string m_PreviousScenePath;
  35. [SerializeField]
  36. string m_TempScenePath;
  37. [SerializeField]
  38. int m_TestCounter;
  39. [SerializeField]
  40. GameObject m_SurfaceInstance;
  41. [SerializeField]
  42. GameObject m_ModVolInstance;
  43. #if KEEP_ARTIFACTS_FOR_INSPECTION
  44. const bool k_KeepSceneObjects = true;
  45. #else
  46. const bool k_KeepSceneObjects = false;
  47. #endif
  48. [OneTimeSetUp]
  49. public void OneTimeSetup()
  50. {
  51. if (EditorApplication.isPlaying)
  52. return;
  53. AssetDatabase.DeleteAsset(k_TempFolder);
  54. var folderGUID = AssetDatabase.CreateFolder(k_ParentFolder, k_TempFolderName);
  55. Assume.That(folderGUID, Is.Not.Empty);
  56. SessionState.SetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave());
  57. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(false);
  58. StageUtility.GoToMainStage();
  59. m_PreviousScenePath = SceneManager.GetActiveScene().path;
  60. m_TempScenePath = Path.Combine(k_TempFolder, "NavMeshModifierVolumePrefabTestsScene.unity");
  61. var tempScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
  62. EditorSceneManager.SaveScene(tempScene, m_TempScenePath);
  63. AssetDatabase.Refresh();
  64. EditorSceneManager.OpenScene(m_TempScenePath);
  65. s_EnterPlayModeOptionsEnabled = EditorSettings.enterPlayModeOptionsEnabled;
  66. s_EnterPlayModeOptions = EditorSettings.enterPlayModeOptions;
  67. EditorSettings.enterPlayModeOptionsEnabled = true;
  68. EditorSettings.enterPlayModeOptions = EnterPlayModeOptions.DisableDomainReload | EnterPlayModeOptions.DisableSceneReload;
  69. }
  70. [OneTimeTearDown]
  71. public void OneTimeTearDown()
  72. {
  73. if (EditorApplication.isPlaying)
  74. return;
  75. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(SessionState.GetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave()));
  76. StageUtility.GoToMainStage();
  77. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  78. if (string.IsNullOrEmpty(m_PreviousScenePath))
  79. EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
  80. EditorSettings.enterPlayModeOptionsEnabled = s_EnterPlayModeOptionsEnabled;
  81. EditorSettings.enterPlayModeOptions = s_EnterPlayModeOptions;
  82. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  83. AssetDatabase.DeleteAsset(k_TempFolder);
  84. #endif
  85. }
  86. [SetUp]
  87. public void SetupNewPrefabWithEmptyNavMesh()
  88. {
  89. if (EditorApplication.isPlaying)
  90. return;
  91. var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
  92. plane.name = "SurfaceSeekingModVol" + ++m_TestCounter + "Prefab";
  93. var surface = plane.AddComponent<NavMeshSurface>();
  94. surface.collectObjects = CollectObjects.All;
  95. m_PrefabPath = Path.Combine(k_TempFolder, plane.name + ".prefab");
  96. PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
  97. Object.DestroyImmediate(plane);
  98. NavMesh.RemoveAllNavMeshData();
  99. }
  100. [UnityTearDown]
  101. public IEnumerator TearDownAndReturnToMainStage()
  102. {
  103. if (EditorApplication.isPlaying)
  104. yield return new ExitPlayMode();
  105. StageUtility.GoToMainStage();
  106. TestUtility.EliminateFromScene(ref m_ModVolInstance, k_KeepSceneObjects);
  107. TestUtility.EliminateFromScene(ref m_SurfaceInstance, k_KeepSceneObjects);
  108. yield return null;
  109. }
  110. [UnityTest]
  111. public IEnumerator ModifierVolume_WhenInsidePrefabMode_ModifiesTheNavMeshInPrefab(
  112. [Values(RunMode.EditMode, RunMode.PlayMode)]
  113. RunMode runMode)
  114. {
  115. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  116. m_SurfaceInstance = TestUtility.InstantiatePrefab(prefab, "SurfaceSeekingModVol" + m_TestCounter + "PrefabInstance");
  117. NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
  118. Assume.That(hit.hit, Is.False, "Prefab should not have a NavMesh in the beginning.");
  119. if (runMode == RunMode.PlayMode)
  120. {
  121. yield return new EnterPlayMode();
  122. prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  123. }
  124. AssetDatabase.OpenAsset(prefab);
  125. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  126. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  127. var modifierVolume = prefabStage.prefabContentsRoot.AddComponent<NavMeshModifierVolume>();
  128. modifierVolume.area = k_RedArea;
  129. modifierVolume.center = Vector3.zero;
  130. modifierVolume.size = Vector3.one;
  131. yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_PrefabDefaultArea);
  132. PrefabSavingUtil.SavePrefab(prefabStage);
  133. StageUtility.GoToMainStage();
  134. if (EditorApplication.isPlaying)
  135. yield return new ExitPlayMode();
  136. NavMesh.SamplePosition(Vector3.zero, out var hitCenter, 0.1f, k_QueryAnyArea);
  137. Assume.That(hitCenter.hit, Is.True, "A NavMesh should have been baked in the center of the prefab.");
  138. Assert.That(hitCenter.mask, Is.EqualTo(1 << k_RedArea),
  139. "Area type (0x{0:x8}) found in the center should be 0x{1:x8}.", hitCenter.mask, 1 << k_RedArea);
  140. NavMesh.SamplePosition(new Vector3(0.6f, 0, 0.6f), out var hitSides, 0.1f, k_QueryAnyArea);
  141. Assume.That(hitSides.hit, Is.True, "A NavMesh should have been baked in the outer sides of the prefab.");
  142. Assert.That(hitSides.mask, Is.EqualTo(1 << k_PrefabDefaultArea),
  143. "Area type (0x{0:x8}) found on the sides should be 0x{1:x8}.", hitSides.mask, 1 << k_PrefabDefaultArea);
  144. Assert.That(hitCenter.mask, Is.Not.EqualTo(hitSides.mask),
  145. "Area type (0x{0:x8}) in the center should be different than on the sides.", hitCenter.mask);
  146. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  147. }
  148. [UnityTest]
  149. public IEnumerator ModifierVolume_WhenInsidePrefabMode_DoesNotAffectTheNavMeshInMainScene(
  150. [Values(RunMode.EditMode, RunMode.PlayMode)]
  151. RunMode runMode)
  152. {
  153. m_SurfaceInstance = GameObject.CreatePrimitive(PrimitiveType.Plane);
  154. m_SurfaceInstance.name = "SurfaceOutsidePrefab" + m_TestCounter;
  155. var mainSceneSurface = m_SurfaceInstance.AddComponent<NavMeshSurface>();
  156. mainSceneSurface.defaultArea = k_PinkArea;
  157. mainSceneSurface.agentTypeID = 0;
  158. mainSceneSurface.collectObjects = CollectObjects.All;
  159. NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
  160. Assume.That(hit.hit, Is.False, "The main scene should not have a NavMesh in the beginning.");
  161. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  162. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  163. AssetDatabase.OpenAsset(prefab);
  164. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  165. var prefabModVol = prefabStage.prefabContentsRoot.AddComponent<NavMeshModifierVolume>();
  166. prefabModVol.area = k_PrefabDefaultArea;
  167. prefabModVol.center = Vector3.zero;
  168. prefabModVol.size = new Vector3(100, 100, 100);
  169. // Bake the NavMeshSurface from the main scene while the prefab mode is open
  170. if (runMode == RunMode.PlayMode)
  171. yield return new EnterPlayMode();
  172. mainSceneSurface = m_SurfaceInstance.GetComponent<NavMeshSurface>();
  173. prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  174. yield return TestUtility.BakeNavMeshAsync(mainSceneSurface, mainSceneSurface.defaultArea);
  175. PrefabSavingUtil.SavePrefab(prefabStage);
  176. if (!EditorApplication.isPlaying)
  177. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  178. StageUtility.GoToMainStage();
  179. NavMesh.SamplePosition(Vector3.zero, out hit, 0.1f, k_QueryAnyArea);
  180. Assert.That(hit.hit, Is.True, "A NavMesh should have been baked by the surface in the main scene.");
  181. Assert.That(hit.mask, Is.EqualTo(1 << mainSceneSurface.defaultArea),
  182. "NavMesh has the area type 0x{0:x8} instead of the expected 0x{1:x8}.", hit.mask, 1 << mainSceneSurface.defaultArea);
  183. if (EditorApplication.isPlaying)
  184. yield return new ExitPlayMode();
  185. }
  186. [UnityTest]
  187. public IEnumerator ModifierVolume_WhenOutsidePrefabMode_DoesNotAffectTheNavMeshInPrefab(
  188. [Values(RunMode.EditMode, RunMode.PlayMode)]
  189. RunMode runMode)
  190. {
  191. m_ModVolInstance = new GameObject("ModifierVolumeOutsidePrefab" + m_TestCounter);
  192. var modifierVolume = m_ModVolInstance.AddComponent<NavMeshModifierVolume>();
  193. modifierVolume.area = k_RedArea;
  194. modifierVolume.center = Vector3.zero;
  195. modifierVolume.size = new Vector3(20, 20, 20);
  196. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  197. m_SurfaceInstance = TestUtility.InstantiatePrefab(prefab, "SurfaceSeekingModVol" + m_TestCounter + "PrefabInstance");
  198. NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
  199. Assume.That(hit.hit, Is.False, "Prefab should not have a NavMesh in the beginning.");
  200. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  201. if (runMode == RunMode.PlayMode)
  202. {
  203. yield return new EnterPlayMode();
  204. prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  205. }
  206. AssetDatabase.OpenAsset(prefab);
  207. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  208. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  209. yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_PrefabDefaultArea);
  210. PrefabSavingUtil.SavePrefab(prefabStage);
  211. StageUtility.GoToMainStage();
  212. if (EditorApplication.isPlaying)
  213. yield return new ExitPlayMode();
  214. NavMesh.SamplePosition(Vector3.zero, out hit, 0.1f, k_QueryAnyArea);
  215. Assume.That(hit.hit, Is.True, "A NavMesh should have been baked in the prefab.");
  216. Assert.That(hit.mask, Is.EqualTo(1 << k_PrefabDefaultArea),
  217. "A different area type (0x{0:x8}) was found instead of the expected one (0x{1:x8}).", hit.mask, 1 << k_PrefabDefaultArea);
  218. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  219. }
  220. }
  221. }