NavMeshSurfaceInPrefabTests.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. //#define KEEP_ARTIFACTS_FOR_INSPECTION
  2. //#define ENABLE_TEST_LOGS
  3. using System;
  4. using System.Collections;
  5. using System.IO;
  6. using NUnit.Framework;
  7. using UnityEditor;
  8. using UnityEditor.AI;
  9. using UnityEditor.Experimental.SceneManagement;
  10. using UnityEditor.SceneManagement;
  11. using UnityEngine;
  12. using UnityEngine.AI;
  13. using UnityEngine.SceneManagement;
  14. using UnityEngine.TestTools;
  15. using Object = UnityEngine.Object;
  16. [Category("PrefabsWithNavMeshComponents")]
  17. public class NavMeshSurfaceInPrefabTests
  18. {
  19. const string k_AutoSaveKey = "AutoSave";
  20. const string k_ParentFolder = "Assets/Tests/Editor";
  21. const string k_TempFolderName = "TempPrefab";
  22. string m_TempFolder = k_ParentFolder + "/" + k_TempFolderName;
  23. string m_PrefabPath;
  24. string m_PreviousScenePath;
  25. string m_TempScenePath;
  26. int m_TestCounter;
  27. const int k_GrayArea = 7;
  28. const int k_BrownArea = 10;
  29. const int k_RedArea = 18;
  30. const int k_OrangeArea = 26;
  31. const int k_YellowArea = 30;
  32. const int k_PrefabDefaultArea = k_YellowArea;
  33. [OneTimeSetUp]
  34. public void OneTimeSetup()
  35. {
  36. AssetDatabase.DeleteAsset(m_TempFolder);
  37. var folderGUID = AssetDatabase.CreateFolder(k_ParentFolder, k_TempFolderName);
  38. m_TempFolder = AssetDatabase.GUIDToAssetPath(folderGUID);
  39. SessionState.SetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave());
  40. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(false);
  41. StageUtility.GoToMainStage();
  42. m_PreviousScenePath = SceneManager.GetActiveScene().path;
  43. m_TempScenePath = Path.Combine(m_TempFolder, "NavMeshSurfacePrefabTestsScene.unity");
  44. var tempScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
  45. EditorSceneManager.SaveScene(tempScene, m_TempScenePath);
  46. EditorSceneManager.OpenScene(m_TempScenePath);
  47. }
  48. [OneTimeTearDown]
  49. public void OneTimeTearDown()
  50. {
  51. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(SessionState.GetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave()));
  52. StageUtility.GoToMainStage();
  53. EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
  54. if (string.IsNullOrEmpty(m_PreviousScenePath))
  55. {
  56. EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
  57. }
  58. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  59. AssetDatabase.DeleteAsset(m_TempFolder);
  60. #endif
  61. }
  62. [UnitySetUp]
  63. public IEnumerator Setup()
  64. {
  65. var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
  66. plane.name = "NavMeshSurface" + (++m_TestCounter) + "Prefab";
  67. var surface = plane.AddComponent<NavMeshSurface>();
  68. surface.collectObjects = CollectObjects.Children;
  69. m_PrefabPath = Path.Combine(m_TempFolder, plane.name + ".prefab");
  70. var planePrefab = PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
  71. Object.DestroyImmediate(plane);
  72. AssetDatabase.OpenAsset(planePrefab);
  73. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  74. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  75. yield return BakeNavMeshAsync(() => prefabSurface, k_PrefabDefaultArea);
  76. PrefabSavingUtil.SavePrefab(prefabStage);
  77. StageUtility.GoToMainStage();
  78. NavMesh.RemoveAllNavMeshData();
  79. yield return null;
  80. }
  81. [UnityTearDown]
  82. public IEnumerator TearDown()
  83. {
  84. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  85. if (prefabStage != null)
  86. prefabStage.ClearDirtiness();
  87. StageUtility.GoToMainStage();
  88. yield return null;
  89. }
  90. static void TestNavMeshExistsAloneAtPosition(int expectedArea, Vector3 pos)
  91. {
  92. var expectedAreaMask = 1 << expectedArea;
  93. #if ENABLE_TEST_LOGS
  94. var areaExists = HasNavMeshAtPosition(pos, expectedAreaMask);
  95. var otherAreasExist = HasNavMeshAtPosition(pos, ~expectedAreaMask);
  96. Debug.Log(" mask=" + expectedAreaMask.ToString("x8") + " area " + expectedArea +
  97. " Exists=" + areaExists + " otherAreasExist=" + otherAreasExist + " at position " + pos);
  98. if (otherAreasExist)
  99. {
  100. for (var i = 0; i < 32; i++)
  101. {
  102. if (i == expectedArea)
  103. continue;
  104. var thisOtherAreaExists = HasNavMeshAtPosition(pos, 1 << i);
  105. if (thisOtherAreaExists)
  106. {
  107. Debug.Log(" _another area that exists here " + i);
  108. }
  109. }
  110. }
  111. #endif
  112. Assert.IsTrue(HasNavMeshAtPosition(pos, expectedAreaMask), "Expected NavMesh with area {0} at position {1}.", expectedArea, pos);
  113. Assert.IsFalse(HasNavMeshAtPosition(pos, ~expectedAreaMask), "A NavMesh with an area other than {0} exists at position {1}.", expectedArea, pos);
  114. }
  115. [Test]
  116. public void NavMeshSurfacePrefab_WhenOpenedInPrefabMode_DoesNotActivateItsNavMesh()
  117. {
  118. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  119. AssetDatabase.OpenAsset(prefab);
  120. NavMeshHit hit;
  121. NavMesh.SamplePosition(Vector3.zero, out hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
  122. Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active under any circumstances.");
  123. }
  124. [UnityTest]
  125. public IEnumerator NavMeshSurfacePrefab_AfterBakingInPrefabMode_DoesNotActivateItsNavMesh()
  126. {
  127. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  128. AssetDatabase.OpenAsset(prefab);
  129. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  130. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  131. NavMeshAssetManager.instance.ClearSurfaces(new Object[] { prefabSurface });
  132. PrefabSavingUtil.SavePrefab(prefabStage);
  133. yield return BakeNavMeshAsync(() => prefabSurface, k_RedArea);
  134. NavMeshHit hit;
  135. NavMesh.SamplePosition(Vector3.zero, out hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
  136. Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active after baking the surface.");
  137. prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  138. PrefabSavingUtil.SavePrefab(prefabStage);
  139. NavMesh.SamplePosition(Vector3.zero, out hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
  140. Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active after baking the surface.");
  141. }
  142. [UnityTest]
  143. public IEnumerator NavMeshSurfacePrefab_AfterBakingInPrefabMode_LeavesMainSceneUntouched()
  144. {
  145. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero));
  146. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  147. AssetDatabase.OpenAsset(prefab);
  148. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  149. Assert.IsNotNull(prefabStage);
  150. Assert.IsNotNull(prefabStage.prefabContentsRoot);
  151. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  152. var initialPrefabNavMeshData = prefabSurface.navMeshData;
  153. yield return BakeNavMeshAsync(() => prefabSurface, k_RedArea);
  154. Assert.AreNotSame(initialPrefabNavMeshData, prefabSurface.navMeshData);
  155. PrefabSavingUtil.SavePrefab(prefabStage);
  156. StageUtility.GoToMainStage();
  157. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, NavMesh.AllAreas, 0, 1000.0f));
  158. yield return null;
  159. }
  160. [UnityTest]
  161. public IEnumerator NavMeshSurfacePrefab_WhenInstantiated_ReferencesTheSameNavMeshData()
  162. {
  163. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  164. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  165. Assert.IsNotNull(instance);
  166. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  167. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  168. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  169. Assert.IsNotNull(instanceSurface);
  170. var instanceNavMeshData = instanceSurface.navMeshData;
  171. var clonePosition = new Vector3(20, 0, 0);
  172. var instanceClone = Object.Instantiate(instance, clonePosition, Quaternion.identity);
  173. Assert.IsNotNull(instanceClone);
  174. instanceClone.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
  175. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  176. Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask));
  177. Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
  178. var instanceCloneSurface = instanceClone.GetComponent<NavMeshSurface>();
  179. Assert.IsNotNull(instanceCloneSurface);
  180. var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
  181. AssetDatabase.OpenAsset(prefab);
  182. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  183. Assert.IsNotNull(prefabStage);
  184. Assert.IsNotNull(prefabStage.prefabContentsRoot);
  185. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  186. var prefabNavMeshData = prefabSurface.navMeshData;
  187. Assert.AreSame(prefabNavMeshData, instanceNavMeshData);
  188. Assert.AreSame(prefabNavMeshData, instanceCloneNavMeshData);
  189. StageUtility.GoToMainStage();
  190. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  191. Object.DestroyImmediate(instance);
  192. Object.DestroyImmediate(instanceClone);
  193. #endif
  194. yield return null;
  195. }
  196. [UnityTest]
  197. public IEnumerator NavMeshSurfacePrefab_WhenEmptyAndInstantiated_InstanceHasEmptyNavMeshData()
  198. {
  199. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  200. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  201. Assert.IsNotNull(instance);
  202. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  203. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  204. Assert.IsTrue(instanceSurface.navMeshData != null, "NavMeshSurface in prefab instance must have NavMeshData.");
  205. AssetDatabase.OpenAsset(prefab);
  206. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  207. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  208. NavMeshAssetManager.instance.ClearSurfaces(new Object[] { prefabSurface });
  209. PrefabSavingUtil.SavePrefab(prefabStage);
  210. StageUtility.GoToMainStage();
  211. Assert.IsTrue(instanceSurface.navMeshData == null,
  212. "After the NavMeshSurface in the prefab has been cleared the prefab instance should no longer hold NavMeshData.");
  213. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  214. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
  215. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  216. Object.DestroyImmediate(instance);
  217. #endif
  218. yield return null;
  219. }
  220. [UnityTest]
  221. public IEnumerator NavMeshSurfacePrefab_WhenBakesNewNavMesh_UpdatesTheInstance()
  222. {
  223. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  224. var instanceOne = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  225. Assert.IsNotNull(instanceOne);
  226. instanceOne.name = "Surface" + m_TestCounter + "PrefabInstanceOne";
  227. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  228. AssetDatabase.OpenAsset(prefab);
  229. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  230. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  231. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  232. yield return BakeNavMeshAsync(() => prefabSurface, k_RedArea);
  233. PrefabSavingUtil.SavePrefab(prefabStage);
  234. StageUtility.GoToMainStage();
  235. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  236. var instanceOneSurface = instanceOne.GetComponent<NavMeshSurface>();
  237. yield return BakeNavMeshAsync(() => instanceOneSurface, k_BrownArea);
  238. var instanceTwo = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  239. Assert.IsNotNull(instanceTwo);
  240. instanceTwo.name = "Surface" + m_TestCounter + "PrefabInstanceTwo";
  241. // reactivate the object to apply the change of position immediately
  242. instanceTwo.SetActive(false);
  243. instanceTwo.transform.position = new Vector3(20, 0, 0);
  244. instanceTwo.SetActive(true);
  245. TestNavMeshExistsAloneAtPosition(k_BrownArea, Vector3.zero);
  246. TestNavMeshExistsAloneAtPosition(k_RedArea, instanceTwo.transform.position);
  247. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  248. Object.DestroyImmediate(instanceOne);
  249. Object.DestroyImmediate(instanceTwo);
  250. #endif
  251. yield return null;
  252. }
  253. [UnityTest]
  254. public IEnumerator NavMeshSurfacePrefab_WhenInstanceRebaked_HasDifferentNavMeshData()
  255. {
  256. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  257. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  258. Assert.IsNotNull(instance);
  259. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  260. var clonePosition = new Vector3(20, 0, 0);
  261. var instanceClone = Object.Instantiate(instance, clonePosition, Quaternion.identity);
  262. Assert.IsNotNull(instanceClone);
  263. instanceClone.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
  264. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  265. Assert.IsNotNull(instanceSurface);
  266. yield return BakeNavMeshAsync(() => instanceSurface, k_RedArea);
  267. var instanceNavMeshData = instanceSurface.navMeshData;
  268. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  269. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  270. Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask));
  271. Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
  272. var instanceCloneSurface = instanceClone.GetComponent<NavMeshSurface>();
  273. Assert.IsNotNull(instanceCloneSurface);
  274. var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
  275. AssetDatabase.OpenAsset(prefab);
  276. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  277. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  278. var prefabNavMeshData = prefabSurface.navMeshData;
  279. Assert.AreNotSame(instanceNavMeshData, prefabNavMeshData);
  280. Assert.AreNotSame(instanceNavMeshData, instanceCloneNavMeshData);
  281. Assert.AreSame(prefabNavMeshData, instanceCloneNavMeshData);
  282. StageUtility.GoToMainStage();
  283. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  284. Object.DestroyImmediate(instance);
  285. Object.DestroyImmediate(instanceClone);
  286. #endif
  287. yield return null;
  288. }
  289. [UnityTest]
  290. public IEnumerator NavMeshSurfacePrefab_WhenInstanceCleared_InstanceHasEmptyNavMeshData()
  291. {
  292. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  293. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  294. Assert.IsNotNull(instance);
  295. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  296. var clonePosition = new Vector3(20, 0, 0);
  297. var instanceClone = Object.Instantiate(instance, clonePosition, Quaternion.identity);
  298. Assert.IsNotNull(instanceClone);
  299. instanceClone.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
  300. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  301. Assert.IsNotNull(instanceSurface);
  302. NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
  303. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  304. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
  305. Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask));
  306. Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
  307. var instanceCloneSurface = instanceClone.GetComponent<NavMeshSurface>();
  308. Assert.IsNotNull(instanceCloneSurface);
  309. var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
  310. AssetDatabase.OpenAsset(prefab);
  311. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  312. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  313. var prefabNavMeshData = prefabSurface.navMeshData;
  314. Assert.AreNotSame(prefabNavMeshData, instanceSurface.navMeshData);
  315. Assert.AreNotSame(instanceCloneNavMeshData, instanceSurface.navMeshData);
  316. Assert.AreSame(prefabNavMeshData, instanceCloneNavMeshData);
  317. StageUtility.GoToMainStage();
  318. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  319. Object.DestroyImmediate(instance);
  320. Object.DestroyImmediate(instanceClone);
  321. #endif
  322. yield return null;
  323. }
  324. [UnityTest]
  325. public IEnumerator NavMeshSurfacePrefab_WhenInstanceCleared_PrefabKeepsNavMeshData()
  326. {
  327. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  328. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  329. Assert.IsNotNull(instance);
  330. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  331. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  332. Assert.IsNotNull(instanceSurface);
  333. var initialPrefabNavMeshData = instanceSurface.navMeshData;
  334. NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
  335. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  336. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
  337. AssetDatabase.OpenAsset(prefab);
  338. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  339. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  340. var prefabNavMeshData = prefabSurface.navMeshData;
  341. Assert.IsTrue(prefabNavMeshData != null,
  342. "NavMeshSurface in the prefab must still have NavMeshData even though the instance was cleared.");
  343. Assert.AreSame(initialPrefabNavMeshData, prefabNavMeshData);
  344. StageUtility.GoToMainStage();
  345. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  346. Object.DestroyImmediate(instance);
  347. #endif
  348. yield return null;
  349. }
  350. [UnityTest]
  351. public IEnumerator NavMeshSurfacePrefab_WhenRebakedButInstanceModified_DoesNotChangeInstance()
  352. {
  353. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  354. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  355. Assert.IsNotNull(instance);
  356. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  357. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  358. Assert.IsNotNull(instanceSurface);
  359. yield return BakeNavMeshAsync(() => instanceSurface, k_RedArea);
  360. var instanceNavMeshData = instanceSurface.navMeshData;
  361. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  362. AssetDatabase.OpenAsset(prefab);
  363. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  364. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  365. var initialPrefabNavMeshData = prefabSurface.navMeshData;
  366. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  367. PrefabSavingUtil.SavePrefab(prefabStage);
  368. StageUtility.GoToMainStage();
  369. AssetDatabase.OpenAsset(prefab);
  370. var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
  371. var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
  372. var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
  373. Assert.IsTrue(prefabNavMeshData != null,
  374. "NavMeshSurface in prefab must have NavMeshData after baking, saving, closing and reopening.");
  375. Assert.AreNotSame(instanceNavMeshData, prefabNavMeshData);
  376. Assert.AreNotSame(initialPrefabNavMeshData, prefabNavMeshData);
  377. StageUtility.GoToMainStage();
  378. Assert.AreSame(instanceNavMeshData, instanceSurface.navMeshData);
  379. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  380. Object.DestroyImmediate(instance);
  381. #endif
  382. yield return null;
  383. }
  384. [UnityTest]
  385. public IEnumerator NavMeshSurfacePrefab_WhenRebakedButNotSaved_RevertsToTheInitialNavMeshData()
  386. {
  387. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  388. AssetDatabase.OpenAsset(prefab);
  389. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  390. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  391. var initialPrefabNavMeshData = prefabSurface.navMeshData;
  392. var initialPrefabNavMeshAssetPath = AssetDatabase.GetAssetPath(initialPrefabNavMeshData);
  393. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  394. var rebuiltPrefabNavMeshData = prefabSurface.navMeshData;
  395. Assert.IsTrue(rebuiltPrefabNavMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  396. Assert.AreNotSame(initialPrefabNavMeshData, rebuiltPrefabNavMeshData);
  397. prefabStage.ClearDirtiness();
  398. StageUtility.GoToMainStage();
  399. AssetDatabase.OpenAsset(prefab);
  400. var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
  401. var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
  402. var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
  403. Assert.AreSame(initialPrefabNavMeshData, prefabNavMeshData);
  404. Assert.AreNotSame(rebuiltPrefabNavMeshData, prefabNavMeshData);
  405. var prefabNavMeshAssetPath = AssetDatabase.GetAssetPath(prefabNavMeshData);
  406. StringAssert.AreEqualIgnoringCase(initialPrefabNavMeshAssetPath, prefabNavMeshAssetPath,
  407. "The NavMeshData asset referenced by the prefab should remain the same when exiting prefab mode without saving.");
  408. StageUtility.GoToMainStage();
  409. yield return null;
  410. }
  411. [UnityTest]
  412. public IEnumerator NavMeshSurfacePrefab_WhenRebakedButNotSaved_TheRebakedAssetNoLongerExists()
  413. {
  414. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  415. AssetDatabase.OpenAsset(prefab);
  416. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  417. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  418. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  419. var rebakedAssetPath = AssetDatabase.GetAssetPath(prefabSurface.navMeshData);
  420. Assert.IsTrue(File.Exists(rebakedAssetPath), "NavMeshData file must exist. ({0})", rebakedAssetPath);
  421. prefabStage.ClearDirtiness();
  422. StageUtility.GoToMainStage();
  423. Assert.IsFalse(File.Exists(rebakedAssetPath), "NavMeshData file still exists after discarding the changes. ({0})", rebakedAssetPath);
  424. yield return null;
  425. }
  426. [UnityTest]
  427. public IEnumerator NavMeshSurfacePrefab_WhenRebaked_TheOldAssetExistsUntilSavingAndNotAfter()
  428. {
  429. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  430. AssetDatabase.OpenAsset(prefab);
  431. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  432. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  433. var initialNavMeshData = prefabSurface.navMeshData;
  434. var initialAssetPath = AssetDatabase.GetAssetPath(prefabSurface.navMeshData);
  435. // Assert.IsNull cannot verify correctly that an UnityEngine.Object is null
  436. Assert.IsTrue(initialNavMeshData != null, "Prefab must have some NavMeshData.");
  437. Assert.IsTrue(File.Exists(initialAssetPath), "NavMeshData file must exist. ({0})", initialAssetPath);
  438. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  439. Assert.IsTrue(initialNavMeshData != null, "The initial NavMeshData must still exist immediately after prefab re-bake.");
  440. Assert.IsTrue(File.Exists(initialAssetPath), "The initial NavMeshData file must exist after prefab re-bake. ({0})", initialAssetPath);
  441. Assert.IsTrue(prefabSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  442. var unsavedRebakedNavMeshData = prefabSurface.navMeshData;
  443. yield return BakeNavMeshAsync(() => prefabSurface, k_OrangeArea);
  444. Assert.IsTrue(unsavedRebakedNavMeshData == null, "An unsaved NavMeshData should not exist after a re-bake.");
  445. Assert.IsTrue(prefabSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  446. PrefabSavingUtil.SavePrefab(prefabStage);
  447. Assert.IsFalse(File.Exists(initialAssetPath), "NavMeshData file still exists after saving. ({0})", initialAssetPath);
  448. Assert.IsTrue(initialNavMeshData == null, "The initial NavMeshData must no longer exist after saving the prefab.");
  449. // ReSharper disable once HeuristicUnreachableCode - initialNavMeshData is affected by BakeNavMeshAsync()
  450. StageUtility.GoToMainStage();
  451. yield return null;
  452. }
  453. [UnityTest]
  454. public IEnumerator NavMeshSurfacePrefab_WhenRebakedAndAutoSaved_InstanceHasTheNewNavMeshData()
  455. {
  456. var wasAutoSave = PrefabStageAutoSavingUtil.GetPrefabStageAutoSave();
  457. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(true);
  458. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  459. AssetDatabase.OpenAsset(prefab);
  460. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  461. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  462. var initialPrefabNavMeshData = prefabSurface.navMeshData;
  463. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  464. var rebuiltPrefabNavMeshData = prefabSurface.navMeshData;
  465. Assert.IsTrue(rebuiltPrefabNavMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  466. Assert.AreNotSame(initialPrefabNavMeshData, rebuiltPrefabNavMeshData);
  467. StageUtility.GoToMainStage();
  468. AssetDatabase.OpenAsset(prefab);
  469. var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
  470. var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
  471. var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
  472. Assert.AreNotSame(initialPrefabNavMeshData, prefabNavMeshData);
  473. Assert.AreSame(rebuiltPrefabNavMeshData, prefabNavMeshData);
  474. StageUtility.GoToMainStage();
  475. PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(wasAutoSave);
  476. yield return null;
  477. }
  478. [Ignore("Currently the deletion of the old asset must be done manually.")]
  479. [UnityTest]
  480. public IEnumerator NavMeshSurfacePrefab_AfterModifiedInstanceAppliedBack_TheOldAssetNoLongerExists()
  481. {
  482. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  483. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  484. Assert.IsNotNull(instance);
  485. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  486. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  487. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  488. Assert.IsNotNull(instanceSurface);
  489. var initialInstanceAssetPath = AssetDatabase.GetAssetPath(instanceSurface.navMeshData);
  490. Assert.IsTrue(File.Exists(initialInstanceAssetPath), "Prefab's NavMeshData file must exist. ({0})", initialInstanceAssetPath);
  491. yield return BakeNavMeshAsync(() => instanceSurface, k_RedArea);
  492. Assert.IsTrue(File.Exists(initialInstanceAssetPath),
  493. "Prefab's NavMeshData file exists after the instance has changed. ({0})", initialInstanceAssetPath);
  494. PrefabUtility.ApplyPrefabInstance(instance, InteractionMode.AutomatedAction);
  495. Assert.IsFalse(File.Exists(initialInstanceAssetPath),
  496. "Prefab's NavMeshData file still exists after the changes from the instance have been applied back to the prefab. ({0})",
  497. initialInstanceAssetPath);
  498. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  499. Object.DestroyImmediate(instance);
  500. #endif
  501. yield return null;
  502. }
  503. [UnityTest]
  504. public IEnumerator NavMeshSurfacePrefab_AfterModifiedInstanceAppliedBack_UpdatedAccordingToInstance()
  505. {
  506. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  507. var instanceOne = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  508. Assert.IsNotNull(instanceOne);
  509. instanceOne.name = "Surface" + m_TestCounter + "PrefabInstanceOne";
  510. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  511. var instanceTwo = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  512. Assert.IsNotNull(instanceTwo);
  513. instanceTwo.name = "Surface" + m_TestCounter + "PrefabInstanceTwo";
  514. // reactivate the object to apply the change of position immediately
  515. instanceTwo.SetActive(false);
  516. instanceTwo.transform.position = new Vector3(20, 0, 0);
  517. instanceTwo.SetActive(true);
  518. var instanceOneSurface = instanceOne.GetComponent<NavMeshSurface>();
  519. Assert.IsNotNull(instanceOneSurface);
  520. yield return BakeNavMeshAsync(() => instanceOneSurface, k_RedArea);
  521. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  522. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, instanceTwo.transform.position);
  523. PrefabUtility.ApplyPrefabInstance(instanceOne, InteractionMode.AutomatedAction);
  524. TestNavMeshExistsAloneAtPosition(k_RedArea, instanceTwo.transform.position);
  525. AssetDatabase.OpenAsset(prefab);
  526. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  527. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  528. yield return BakeNavMeshAsync(() => prefabSurface, k_GrayArea);
  529. PrefabSavingUtil.SavePrefab(prefabStage);
  530. StageUtility.GoToMainStage();
  531. TestNavMeshExistsAloneAtPosition(k_GrayArea, Vector3.zero);
  532. TestNavMeshExistsAloneAtPosition(k_GrayArea, instanceTwo.transform.position);
  533. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  534. Object.DestroyImmediate(instanceOne);
  535. Object.DestroyImmediate(instanceTwo);
  536. #endif
  537. yield return null;
  538. }
  539. [UnityTest]
  540. public IEnumerator NavMeshSurfacePrefab_AfterClearedInstanceAppliedBack_HasEmptyData()
  541. {
  542. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  543. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  544. Assert.IsNotNull(instance);
  545. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  546. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  547. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  548. Assert.IsNotNull(instanceSurface);
  549. NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
  550. var expectedAreaMask = 1 << k_PrefabDefaultArea;
  551. Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
  552. PrefabUtility.ApplyPrefabInstance(instance, InteractionMode.AutomatedAction);
  553. AssetDatabase.OpenAsset(prefab);
  554. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  555. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  556. Assert.IsTrue(prefabSurface.navMeshData == null,
  557. "Prefab should have empty NavMeshData when empty data has been applied back from the instance.");
  558. StageUtility.GoToMainStage();
  559. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  560. Object.DestroyImmediate(instance);
  561. #endif
  562. yield return null;
  563. }
  564. [UnityTest]
  565. public IEnumerator NavMeshSurfacePrefab_WhenInstanceRevertsBack_InstanceIsLikePrefab()
  566. {
  567. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  568. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  569. Assert.IsNotNull(instance);
  570. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  571. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  572. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  573. Assert.IsNotNull(instanceSurface);
  574. yield return BakeNavMeshAsync(() => instanceSurface, k_RedArea);
  575. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  576. PrefabUtility.RevertPrefabInstance(instance, InteractionMode.AutomatedAction);
  577. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  578. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  579. Object.DestroyImmediate(instance);
  580. #endif
  581. yield return null;
  582. }
  583. [Ignore("Deletion of the old asset is expected to be done manually for the time being.")]
  584. [UnityTest]
  585. public IEnumerator NavMeshSurfacePrefab_WhenInstanceRevertsBack_TheInstanceAssetNoLongerExists()
  586. {
  587. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  588. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  589. Assert.IsNotNull(instance);
  590. instance.name = "Surface" + m_TestCounter + "PrefabInstance";
  591. TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
  592. var instanceSurface = instance.GetComponent<NavMeshSurface>();
  593. Assert.IsNotNull(instanceSurface);
  594. yield return BakeNavMeshAsync(() => instanceSurface, k_RedArea);
  595. var instanceAssetPath = AssetDatabase.GetAssetPath(instanceSurface.navMeshData);
  596. Assert.IsTrue(File.Exists(instanceAssetPath), "Instance's NavMeshData file must exist. ({0})", instanceAssetPath);
  597. PrefabUtility.RevertPrefabInstance(instance, InteractionMode.AutomatedAction);
  598. Assert.IsFalse(File.Exists(instanceAssetPath), "Instance's NavMeshData file still exists after revert. ({0})", instanceAssetPath);
  599. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  600. Object.DestroyImmediate(instance);
  601. #endif
  602. yield return null;
  603. }
  604. [Ignore("The expected behaviour has not been decided.")]
  605. [UnityTest]
  606. public IEnumerator NavMeshSurfacePrefab_WhenDeleted_InstancesMakeCopiesOfData()
  607. {
  608. yield return null;
  609. Assert.Fail("not implemented yet");
  610. }
  611. [UnityTest]
  612. public IEnumerator NavMeshSurfacePrefab_WhenBakingInPreviewScene_CollectsOnlyPreviewSceneObjects()
  613. {
  614. var mainScenePlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
  615. mainScenePlane.transform.localScale = new Vector3(100, 1, 100);
  616. var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  617. AssetDatabase.OpenAsset(prefab);
  618. var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  619. var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  620. prefabSurface.collectObjects = CollectObjects.All;
  621. yield return BakeNavMeshAsync(() => prefabSurface, k_RedArea);
  622. PrefabSavingUtil.SavePrefab(prefabStage);
  623. StageUtility.GoToMainStage();
  624. var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
  625. Assert.IsNotNull(instance);
  626. TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
  627. var posNearby = new Vector3(20,0,0);
  628. Assert.IsFalse(HasNavMeshAtPosition(posNearby, 1 << k_RedArea),
  629. "NavMesh with the prefab's area exists at position {1}, outside the prefab's plane. ({0})",
  630. k_RedArea, posNearby);
  631. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  632. Object.DestroyImmediate(instance);
  633. Object.DestroyImmediate(mainScenePlane);
  634. #endif
  635. yield return null;
  636. }
  637. public static bool HasNavMeshAtPosition(Vector3 pos, int areaMask = NavMesh.AllAreas, int agentTypeId = 0, float range = 0.1f)
  638. {
  639. NavMeshHit hit;
  640. var filter = new NavMeshQueryFilter
  641. {
  642. areaMask = areaMask,
  643. agentTypeID = agentTypeId
  644. };
  645. return NavMesh.SamplePosition(pos, out hit, range, filter);
  646. }
  647. static IEnumerator BakeNavMeshAsync(Func<NavMeshSurface> getSurface, int defaultArea)
  648. {
  649. var surface = getSurface();
  650. surface.defaultArea = defaultArea;
  651. NavMeshAssetManager.instance.StartBakingSurfaces(new Object[] { surface });
  652. yield return new WaitWhile(() => NavMeshAssetManager.instance.IsSurfaceBaking(surface));
  653. }
  654. }