290 lines
14 KiB
C#
290 lines
14 KiB
C#
|
#if UNITY_EDITOR || UNITY_STANDALONE
|
||
|
//#define KEEP_ARTIFACTS_FOR_INSPECTION
|
||
|
|
||
|
using System.Collections;
|
||
|
using System.IO;
|
||
|
using NUnit.Framework;
|
||
|
using UnityEditor;
|
||
|
using UnityEditor.SceneManagement;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.AI;
|
||
|
using UnityEngine.SceneManagement;
|
||
|
using UnityEngine.TestTools;
|
||
|
using Object = UnityEngine.Object;
|
||
|
|
||
|
namespace Unity.AI.Navigation.Editor.Tests
|
||
|
{
|
||
|
[Category("PrefabsWithNavMeshComponents")]
|
||
|
class NavMeshSurfaceInPrefabVariantTests
|
||
|
{
|
||
|
const string k_AutoSaveKey = "AutoSave";
|
||
|
const string k_ParentFolder = "Assets";
|
||
|
const string k_TempFolderName = "TempPrefabVariants";
|
||
|
static readonly string k_TempFolder = Path.Combine(k_ParentFolder, k_TempFolderName);
|
||
|
|
||
|
const int k_GrayArea = 7;
|
||
|
const int k_BrownArea = 10;
|
||
|
const int k_RedArea = 18;
|
||
|
const int k_OrangeArea = 26;
|
||
|
const int k_YellowArea = 30;
|
||
|
|
||
|
const int k_PrefabDefaultArea = k_YellowArea;
|
||
|
|
||
|
static bool s_EnterPlayModeOptionsEnabled;
|
||
|
static EnterPlayModeOptions s_EnterPlayModeOptions;
|
||
|
|
||
|
[SerializeField]
|
||
|
string m_PrefabPath;
|
||
|
[SerializeField]
|
||
|
string m_PrefabVariantPath;
|
||
|
[SerializeField]
|
||
|
string m_PreviousScenePath;
|
||
|
[SerializeField]
|
||
|
string m_TempScenePath;
|
||
|
[SerializeField]
|
||
|
int m_TestCounter;
|
||
|
|
||
|
#if KEEP_ARTIFACTS_FOR_INSPECTION
|
||
|
const bool k_KeepSceneObjects = true;
|
||
|
#else
|
||
|
const bool k_KeepSceneObjects = false;
|
||
|
#endif
|
||
|
[OneTimeSetUp]
|
||
|
public void OneTimeSetup()
|
||
|
{
|
||
|
if (EditorApplication.isPlaying)
|
||
|
return;
|
||
|
|
||
|
AssetDatabase.DeleteAsset(k_TempFolder);
|
||
|
|
||
|
var folderGUID = AssetDatabase.CreateFolder(k_ParentFolder, k_TempFolderName);
|
||
|
Assume.That(folderGUID, Is.Not.Empty);
|
||
|
|
||
|
SessionState.SetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave());
|
||
|
PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(false);
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
m_PreviousScenePath = SceneManager.GetActiveScene().path;
|
||
|
m_TempScenePath = Path.Combine(k_TempFolder, "NavMeshSurfacePrefabVariantTestsScene.unity");
|
||
|
var tempScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||
|
EditorSceneManager.SaveScene(tempScene, m_TempScenePath);
|
||
|
EditorSceneManager.OpenScene(m_TempScenePath);
|
||
|
|
||
|
s_EnterPlayModeOptionsEnabled = EditorSettings.enterPlayModeOptionsEnabled;
|
||
|
s_EnterPlayModeOptions = EditorSettings.enterPlayModeOptions;
|
||
|
|
||
|
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||
|
EditorSettings.enterPlayModeOptions = EnterPlayModeOptions.DisableDomainReload | EnterPlayModeOptions.DisableSceneReload;
|
||
|
}
|
||
|
|
||
|
[OneTimeTearDown]
|
||
|
public void OneTimeTearDown()
|
||
|
{
|
||
|
if (EditorApplication.isPlaying)
|
||
|
return;
|
||
|
|
||
|
PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(SessionState.GetBool(k_AutoSaveKey, PrefabStageAutoSavingUtil.GetPrefabStageAutoSave()));
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||
|
|
||
|
if (string.IsNullOrEmpty(m_PreviousScenePath))
|
||
|
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||
|
|
||
|
EditorSettings.enterPlayModeOptionsEnabled = s_EnterPlayModeOptionsEnabled;
|
||
|
EditorSettings.enterPlayModeOptions = s_EnterPlayModeOptions;
|
||
|
|
||
|
#if !KEEP_ARTIFACTS_FOR_INSPECTION
|
||
|
AssetDatabase.DeleteAsset(k_TempFolder);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
[UnitySetUp]
|
||
|
public IEnumerator SetupVariantOfPrefabWithNavMesh()
|
||
|
{
|
||
|
if (EditorApplication.isPlaying)
|
||
|
yield break;
|
||
|
|
||
|
var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||
|
plane.name = "NavMeshSurfacePrefab" + (++m_TestCounter);
|
||
|
var surface = plane.AddComponent<NavMeshSurface>();
|
||
|
surface.collectObjects = CollectObjects.Children;
|
||
|
|
||
|
m_PrefabPath = Path.Combine(k_TempFolder, plane.name + ".prefab");
|
||
|
m_PrefabVariantPath = Path.Combine(k_TempFolder, plane.name + "Variant.prefab");
|
||
|
|
||
|
var planePrefab = PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
|
||
|
Object.DestroyImmediate(plane);
|
||
|
|
||
|
AssetDatabase.OpenAsset(planePrefab);
|
||
|
var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||
|
var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||
|
yield return TestUtility.BakeNavMeshAsync(theOriginalPrefabSurface, k_PrefabDefaultArea);
|
||
|
PrefabSavingUtil.SavePrefab(theOriginalPrefabStage);
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
var instanceForVariant = PrefabUtility.InstantiatePrefab(planePrefab) as GameObject;
|
||
|
PrefabUtility.SaveAsPrefabAsset(instanceForVariant, m_PrefabVariantPath);
|
||
|
|
||
|
instanceForVariant!.name += "_Saved";
|
||
|
|
||
|
TestUtility.EliminateFromScene(ref instanceForVariant, k_KeepSceneObjects);
|
||
|
|
||
|
NavMesh.RemoveAllNavMeshData();
|
||
|
|
||
|
yield return null;
|
||
|
}
|
||
|
|
||
|
[UnityTearDown]
|
||
|
public IEnumerator TearDown()
|
||
|
{
|
||
|
if (EditorApplication.isPlaying)
|
||
|
yield return new ExitPlayMode();
|
||
|
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
yield return null;
|
||
|
}
|
||
|
|
||
|
[UnityTest]
|
||
|
public IEnumerator NavMeshSurfacePrefabVariant_WhenFreshAndRebaked_ParentAssetUnchanged(
|
||
|
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||
|
RunMode runMode)
|
||
|
{
|
||
|
var theOriginalPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||
|
AssetDatabase.OpenAsset(theOriginalPrefab);
|
||
|
|
||
|
if (runMode == RunMode.PlayMode)
|
||
|
yield return new EnterPlayMode();
|
||
|
|
||
|
var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||
|
var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||
|
var theOriginalPrefabNavMeshData = theOriginalPrefabSurface.navMeshData;
|
||
|
var theOriginalPrefabAssetPath = AssetDatabase.GetAssetPath(theOriginalPrefabSurface.navMeshData);
|
||
|
|
||
|
Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must have some NavMeshData.");
|
||
|
Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file must exist for the original prefab. ({0})", theOriginalPrefabAssetPath);
|
||
|
|
||
|
var prefabVariant = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabVariantPath);
|
||
|
AssetDatabase.OpenAsset(prefabVariant);
|
||
|
var prefabVariantStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||
|
var prefabVariantSurface = prefabVariantStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||
|
var initialVariantNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
var initialVariantAssetPath = AssetDatabase.GetAssetPath(prefabVariantSurface.navMeshData);
|
||
|
|
||
|
Assert.AreEqual(theOriginalPrefabNavMeshData, initialVariantNavMeshData, "Fresh variant must have the same NavMeshData as the original prefab.");
|
||
|
|
||
|
Assert.IsTrue(initialVariantNavMeshData != null, "Prefab must have some NavMeshData.");
|
||
|
Assert.IsTrue(File.Exists(initialVariantAssetPath), "NavMeshData file must exist. ({0})", initialVariantAssetPath);
|
||
|
|
||
|
yield return TestUtility.BakeNavMeshAsync(prefabVariantSurface, k_GrayArea);
|
||
|
|
||
|
Assert.IsTrue(initialVariantNavMeshData != null, "The initial NavMeshData (from original prefab) must still exist immediately after prefab variant re-bake.");
|
||
|
Assert.IsTrue(File.Exists(initialVariantAssetPath), "The initial NavMeshData file (from original prefab) must exist after prefab variant re-bake. ({0})", initialVariantAssetPath);
|
||
|
|
||
|
Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||
|
var unsavedRebakedNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
|
||
|
yield return TestUtility.BakeNavMeshAsync(prefabVariantSurface, k_BrownArea);
|
||
|
|
||
|
Assert.IsTrue(unsavedRebakedNavMeshData == null, "An unsaved NavMeshData should not exist after a re-bake.");
|
||
|
Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||
|
|
||
|
PrefabSavingUtil.SavePrefab(prefabVariantStage);
|
||
|
|
||
|
var theNewVariantNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
var theNewVariantAssetPath = AssetDatabase.GetAssetPath(theNewVariantNavMeshData);
|
||
|
|
||
|
Assert.IsTrue(File.Exists(theNewVariantAssetPath), "Variant's own NavMeshData exists in a file after saving. ({0})", theNewVariantAssetPath);
|
||
|
Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file of the original prefab still exists after saving the variant. ({0})", theOriginalPrefabAssetPath);
|
||
|
Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must still have NavMeshData.");
|
||
|
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
yield return null;
|
||
|
|
||
|
if (EditorApplication.isPlaying)
|
||
|
yield return new ExitPlayMode();
|
||
|
}
|
||
|
|
||
|
[UnityTest]
|
||
|
public IEnumerator NavMeshSurfacePrefabVariant_WhenCustomizedAndRebaked_OldAssetDiscardedAndParentAssetUnchanged(
|
||
|
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||
|
RunMode runMode)
|
||
|
{
|
||
|
var prefabVariant = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabVariantPath);
|
||
|
var theOriginalPrefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefabVariant);
|
||
|
var theOriginalPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(theOriginalPrefabPath);
|
||
|
|
||
|
AssetDatabase.OpenAsset(theOriginalPrefab);
|
||
|
|
||
|
if (runMode == RunMode.PlayMode)
|
||
|
yield return new EnterPlayMode();
|
||
|
|
||
|
var theOriginalPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||
|
var theOriginalPrefabSurface = theOriginalPrefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||
|
var theOriginalPrefabNavMeshData = theOriginalPrefabSurface.navMeshData;
|
||
|
var theOriginalPrefabAssetPath = AssetDatabase.GetAssetPath(theOriginalPrefabSurface.navMeshData);
|
||
|
|
||
|
Assert.IsTrue(theOriginalPrefabNavMeshData != null, "Original prefab must have some NavMeshData.");
|
||
|
Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file must exist for the original prefab. ({0})", theOriginalPrefabAssetPath);
|
||
|
|
||
|
AssetDatabase.OpenAsset(prefabVariant);
|
||
|
var prefabVariantStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||
|
var prefabVariantSurface = prefabVariantStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||
|
|
||
|
yield return TestUtility.BakeNavMeshAsync(prefabVariantSurface, k_GrayArea);
|
||
|
PrefabSavingUtil.SavePrefab(prefabVariantStage);
|
||
|
|
||
|
var modifiedVariantNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
var modifiedVariantAssetPath = AssetDatabase.GetAssetPath(prefabVariantSurface.navMeshData);
|
||
|
|
||
|
Assert.IsTrue(modifiedVariantNavMeshData != null, "Prefab must have some NavMeshData.");
|
||
|
Assert.IsTrue(File.Exists(modifiedVariantAssetPath), "NavMeshData file for modifier variant must exist. ({0})", modifiedVariantAssetPath);
|
||
|
Assert.AreNotEqual(theOriginalPrefabNavMeshData, modifiedVariantNavMeshData, "Modified variant must have a NavMeshData different than that of the original prefab.");
|
||
|
|
||
|
yield return TestUtility.BakeNavMeshAsync(prefabVariantSurface, k_OrangeArea);
|
||
|
|
||
|
Assert.IsTrue(modifiedVariantNavMeshData != null, "The initial NavMeshData of a modified variant must still exist immediately after prefab variant re-bake.");
|
||
|
Assert.IsTrue(File.Exists(modifiedVariantAssetPath), "The initial NavMeshData file of a modified variant must exist after prefab variant re-bake. ({0})", modifiedVariantAssetPath);
|
||
|
|
||
|
Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||
|
var unsavedRebakedNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
|
||
|
yield return TestUtility.BakeNavMeshAsync(prefabVariantSurface, k_RedArea);
|
||
|
Assert.IsTrue(unsavedRebakedNavMeshData == null, "An unsaved NavMeshData should not exist after a re-bake.");
|
||
|
Assert.IsTrue(prefabVariantSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||
|
|
||
|
PrefabSavingUtil.SavePrefab(prefabVariantStage);
|
||
|
var theNewVariantNavMeshData = prefabVariantSurface.navMeshData;
|
||
|
var theNewVariantAssetPath = AssetDatabase.GetAssetPath(theNewVariantNavMeshData);
|
||
|
|
||
|
if (EditorApplication.isPlaying)
|
||
|
{
|
||
|
Assert.IsTrue(modifiedVariantNavMeshData != null, "Playmode: Initial NavMeshData of the modified variant must still exist until the end of playmode.");
|
||
|
|
||
|
Assert.IsTrue(File.Exists(modifiedVariantAssetPath), "Playmode: Initial NavMeshData file of the modified and saved variant must still exist after saving the variant during playmode. ({0})", modifiedVariantAssetPath);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Assert.IsTrue(modifiedVariantNavMeshData == null, "Editmode: Initial NavMeshData of the modified variant must no longer exist after saving the variant.");
|
||
|
|
||
|
// This code is still reachable because modifiedVariantNavMeshData has been affected by BakeNavMeshAsync()
|
||
|
Assert.IsFalse(File.Exists(modifiedVariantAssetPath), "Editmode: Initial NavMeshData file of the modified and saved variant must no longer exist after saving the variant. ({0})", modifiedVariantAssetPath);
|
||
|
}
|
||
|
|
||
|
Assert.IsTrue(File.Exists(theNewVariantAssetPath), "Variant's own NavMeshData exists in a file after saving. ({0})", theNewVariantAssetPath);
|
||
|
Assert.IsTrue(File.Exists(theOriginalPrefabAssetPath), "NavMeshData file of the original prefab still exists after saving the variant. ({0})", theOriginalPrefabAssetPath);
|
||
|
Assert.AreNotEqual(theOriginalPrefabNavMeshData, theNewVariantNavMeshData, "Re-baked modified variant must have a NavMeshData different than that of the original prefab.");
|
||
|
|
||
|
StageUtility.GoToMainStage();
|
||
|
|
||
|
yield return null;
|
||
|
|
||
|
if (EditorApplication.isPlaying)
|
||
|
yield return new ExitPlayMode();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|