NavMeshModifierVolumeInPrefabTests.cs 9.7 KB

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