NavMeshSurfaceInPrefabVariantTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. //#define KEEP_ARTIFACTS_FOR_INSPECTION
  2. using System;
  3. using System.Collections;
  4. using System.IO;
  5. using NUnit.Framework;
  6. using UnityEditor;
  7. using UnityEditor.AI;
  8. using UnityEditor.Experimental.SceneManagement;
  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. [Category("PrefabsWithNavMeshComponents")]
  16. public class NavMeshSurfaceInPrefabVariantTests
  17. {
  18. const string k_AutoSaveKey = "AutoSave";
  19. const string k_ParentFolder = "Assets/Tests/Editor";
  20. const string k_TempFolderName = "TempPrefabVariants";
  21. string m_TempFolder = k_ParentFolder + "/" + k_TempFolderName;
  22. string m_PrefabPath;
  23. string m_PrefabVariantPath;
  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, "NavMeshSurfacePrefabVariantTestsScene.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 = "NavMeshSurfacePrefab" + (++m_TestCounter);
  67. var surface = plane.AddComponent<NavMeshSurface>();
  68. surface.collectObjects = CollectObjects.Children;
  69. m_PrefabPath = Path.Combine(m_TempFolder, plane.name + ".prefab");
  70. m_PrefabVariantPath = Path.Combine(m_TempFolder, plane.name + "Variant.prefab");
  71. var planePrefab = PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
  72. Object.DestroyImmediate(plane);
  73. AssetDatabase.OpenAsset(planePrefab);
  74. var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  75. var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  76. yield return BakeNavMeshAsync(() => theOriginalPrefabSurface, k_PrefabDefaultArea);
  77. PrefabSavingUtil.SavePrefab(theOriginalPrefabStage);
  78. StageUtility.GoToMainStage();
  79. var instanceForVariant = PrefabUtility.InstantiatePrefab(planePrefab) as GameObject;
  80. PrefabUtility.SaveAsPrefabAsset(instanceForVariant, m_PrefabVariantPath);
  81. #if !KEEP_ARTIFACTS_FOR_INSPECTION
  82. Object.DestroyImmediate(instanceForVariant);
  83. #endif
  84. NavMesh.RemoveAllNavMeshData();
  85. yield return null;
  86. }
  87. [UnityTearDown]
  88. public IEnumerator TearDown()
  89. {
  90. StageUtility.GoToMainStage();
  91. yield return null;
  92. }
  93. [UnityTest]
  94. public IEnumerator NavMeshSurfacePrefabVariant_WhenFreshAndRebaked_ParentAssetUnchanged()
  95. {
  96. var theOriginalPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
  97. AssetDatabase.OpenAsset(theOriginalPrefab);
  98. var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  99. var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  100. var theOriginalPrefabNavMeshData = theOriginalPrefabSurface.navMeshData;
  101. var theOriginalPrefabAssetPath = AssetDatabase.GetAssetPath(theOriginalPrefabSurface.navMeshData);
  102. Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must have some NavMeshData.");
  103. Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file must exist for the original prefab. ({0})", theOriginalPrefabAssetPath);
  104. var prefabVariant = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabVariantPath);
  105. AssetDatabase.OpenAsset(prefabVariant);
  106. var prefabVariantStage = PrefabStageUtility.GetCurrentPrefabStage();
  107. var prefabVariantSurface = prefabVariantStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  108. var initialVariantNavMeshData = prefabVariantSurface.navMeshData;
  109. var initialVariantAssetPath = AssetDatabase.GetAssetPath(prefabVariantSurface.navMeshData);
  110. Assert.AreEqual(theOriginalPrefabNavMeshData, initialVariantNavMeshData, "Fresh variant must have the same NavMeshData as the original prefab.");
  111. Assert.IsTrue(initialVariantNavMeshData != null, "Prefab must have some NavMeshData.");
  112. Assert.IsTrue(File.Exists(initialVariantAssetPath), "NavMeshData file must exist. ({0})", initialVariantAssetPath);
  113. yield return BakeNavMeshAsync(() => prefabVariantSurface, k_GrayArea);
  114. Assert.IsTrue(initialVariantNavMeshData != null, "The initial NavMeshData (from original prefab) must still exist immediately after prefab variant re-bake.");
  115. Assert.IsTrue(File.Exists(initialVariantAssetPath), "The initial NavMeshData file (from original prefab) must exist after prefab variant re-bake. ({0})", initialVariantAssetPath);
  116. Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  117. var unsavedRebakedNavMeshData = prefabVariantSurface.navMeshData;
  118. yield return BakeNavMeshAsync(() => prefabVariantSurface, k_BrownArea);
  119. Assert.IsTrue(unsavedRebakedNavMeshData == null, "An unsaved NavMeshData should not exist after a re-bake.");
  120. Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  121. PrefabSavingUtil.SavePrefab(prefabVariantStage);
  122. var theNewVariantNavMeshData = prefabVariantSurface.navMeshData;
  123. var theNewVariantAssetPath = AssetDatabase.GetAssetPath(theNewVariantNavMeshData);
  124. Assert.IsTrue(File.Exists(theNewVariantAssetPath), "Variant's own NavMeshData exists in a file after saving. ({0})", theNewVariantAssetPath);
  125. Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file of the original prefab still exists after saving the variant. ({0})", theOriginalPrefabAssetPath);
  126. Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must still have NavMeshData.");
  127. StageUtility.GoToMainStage();
  128. yield return null;
  129. }
  130. [UnityTest]
  131. public IEnumerator NavMeshSurfacePrefabVariant_WhenCustomizedAndRebaked_OldAssetDiscardedAndParentAssetUnchanged()
  132. {
  133. var prefabVariant = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabVariantPath);
  134. var theOriginalPrefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefabVariant);
  135. var theOriginalPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(theOriginalPrefabPath);
  136. AssetDatabase.OpenAsset(theOriginalPrefab);
  137. var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
  138. var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  139. var theOriginalPrefabNavMeshData = theOriginalPrefabSurface.navMeshData;
  140. var theOriginalPrefabAssetPath = AssetDatabase.GetAssetPath(theOriginalPrefabSurface.navMeshData);
  141. Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must have some NavMeshData.");
  142. Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file must exist for the original prefab. ({0})", theOriginalPrefabAssetPath);
  143. AssetDatabase.OpenAsset(prefabVariant);
  144. var prefabVariantStage = PrefabStageUtility.GetCurrentPrefabStage();
  145. var prefabVariantSurface = prefabVariantStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
  146. yield return BakeNavMeshAsync(() => prefabVariantSurface, k_GrayArea);
  147. PrefabSavingUtil.SavePrefab(prefabVariantStage);
  148. var modifiedVariantNavMeshData = prefabVariantSurface.navMeshData;
  149. var modifiedVariantAssetPath = AssetDatabase.GetAssetPath(prefabVariantSurface.navMeshData);
  150. Assert.IsTrue(modifiedVariantNavMeshData != null, "Prefab must have some NavMeshData.");
  151. Assert.IsTrue(File.Exists(modifiedVariantAssetPath), "NavMeshData file for modifier variant must exist. ({0})", modifiedVariantAssetPath);
  152. Assert.AreNotEqual(theOriginalPrefabNavMeshData, modifiedVariantNavMeshData, "Modified variant must have a NavMeshData different than that of the original prefab.");
  153. yield return BakeNavMeshAsync(() => prefabVariantSurface, k_OrangeArea);
  154. Assert.IsTrue(modifiedVariantNavMeshData != null, "The initial NavMeshData of a modified variant must still exist immediately after prefab variant re-bake.");
  155. Assert.IsTrue(File.Exists(modifiedVariantAssetPath), "The initial NavMeshData file of a modified variant must exist after prefab variant re-bake. ({0})", modifiedVariantAssetPath);
  156. Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  157. var unsavedRebakedNavMeshData = prefabVariantSurface.navMeshData;
  158. yield return BakeNavMeshAsync(() => prefabVariantSurface, k_RedArea);
  159. Assert.IsTrue(unsavedRebakedNavMeshData == null, "An unsaved NavMeshData should not exist after a re-bake.");
  160. Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
  161. PrefabSavingUtil.SavePrefab(prefabVariantStage);
  162. var theNewVariantNavMeshData = prefabVariantSurface.navMeshData;
  163. var theNewVariantAssetPath = AssetDatabase.GetAssetPath(theNewVariantNavMeshData);
  164. Assert.IsTrue(modifiedVariantNavMeshData == null, "Initial NavMeshData of the modified variant must no longer exist after saving the variant.");
  165. // ReSharper disable once HeuristicUnreachableCode - modifiedVariantNavMeshData is affected by BakeNavMeshAsync()
  166. Assert.IsFalse(File.Exists(modifiedVariantAssetPath), "Initial NavMeshData file of the modified and saved variant must no longer exist after saving the variant. ({0})", modifiedVariantAssetPath);
  167. Assert.IsTrue(File.Exists(theNewVariantAssetPath), "Variant's own NavMeshData exists in a file after saving. ({0})", theNewVariantAssetPath);
  168. Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file of the original prefab still exists after saving the variant. ({0})", theOriginalPrefabAssetPath);
  169. Assert.AreNotEqual(theOriginalPrefabNavMeshData, theNewVariantNavMeshData, "Re-baked modified variant must have a NavMeshData different than that of the original prefab.");
  170. StageUtility.GoToMainStage();
  171. yield return null;
  172. }
  173. static IEnumerator BakeNavMeshAsync(Func<NavMeshSurface> getSurface, int defaultArea)
  174. {
  175. var surface = getSurface();
  176. surface.defaultArea = defaultArea;
  177. NavMeshAssetManager.instance.StartBakingSurfaces(new Object[] { surface });
  178. yield return new WaitWhile(() => NavMeshAssetManager.instance.IsSurfaceBaking(surface));
  179. }
  180. }