説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

NavMeshSurfaceInPrefabTests.cs 42KB

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