first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 276ab4071255d9f49931e6a8373248e1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 585e4d2e85b344909fd03397aa977b50
|
||||
timeCreated: 1641493617
|
||||
@@ -0,0 +1,118 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using Unity.AI.Navigation.Updater;
|
||||
#pragma warning disable CS0618 // UnityEditor.AI.NavMeshBuilder is necessary in this implementation
|
||||
using NavMeshBuilder = UnityEditor.AI.NavMeshBuilder;
|
||||
#pragma warning restore CS0618
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[Description("Tests suite related to the systems used to convert editor data from the legacy NavMesh systems to the modern component-based navigation extension")]
|
||||
class NavMeshConverterTests
|
||||
{
|
||||
const string k_RootFolder = "Assets";
|
||||
const string k_TestFolder = "ConverterTests";
|
||||
const string k_TestFolderPath = k_RootFolder + "/" + k_TestFolder;
|
||||
const string k_TestScenePath = k_TestFolderPath + "/ConverterTestsScene.unity";
|
||||
const string k_BuildHeightMeshPropertyName = "m_BuildSettings.buildHeightMesh";
|
||||
|
||||
bool m_BuildHeightMeshPreviousValue;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder(k_TestFolderPath))
|
||||
AssetDatabase.CreateFolder(k_RootFolder, k_TestFolder);
|
||||
Assume.That(AssetDatabase.IsValidFolder(k_TestFolderPath));
|
||||
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
|
||||
var planeGameObject = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
#pragma warning disable 618
|
||||
GameObjectUtility.SetStaticEditorFlags(planeGameObject, StaticEditorFlags.NavigationStatic);
|
||||
#pragma warning restore 618
|
||||
EditorSceneManager.SaveScene(scene, k_TestScenePath);
|
||||
|
||||
// Enable desired build settings (build HeightMesh)
|
||||
var settingsObject = new SerializedObject(NavMeshBuilder.navMeshSettingsObject);
|
||||
Assume.That(settingsObject, Is.Not.Null, "Unable to get the build settings object");
|
||||
var buildHeightMeshProperty = settingsObject.FindProperty(k_BuildHeightMeshPropertyName);
|
||||
Assume.That(buildHeightMeshProperty, Is.Not.Null, "Unable to get the buildHeightMesh property from the build settings object");
|
||||
m_BuildHeightMeshPreviousValue = buildHeightMeshProperty.boolValue;
|
||||
buildHeightMeshProperty.boolValue = true;
|
||||
settingsObject.ApplyModifiedProperties();
|
||||
Assume.That(buildHeightMeshProperty.boolValue, Is.True, "buildHeightMesh property from the build settings object should be true");
|
||||
|
||||
NavMeshBuilder.BuildNavMesh();
|
||||
EditorSceneManager.SaveScene(scene, k_TestScenePath);
|
||||
|
||||
Assume.That(NavMeshUpdaterUtility.IsSceneReferencingLegacyNavMesh(k_TestScenePath));
|
||||
|
||||
NavMeshUpdaterUtility.ConvertScene(k_TestScenePath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Converter_AfterConversion_SceneNavMeshAssetIsGone()
|
||||
{
|
||||
var navMeshOwnedByScene = NavMeshUpdaterUtility.IsSceneReferencingLegacyNavMesh(k_TestScenePath);
|
||||
Assert.IsFalse(navMeshOwnedByScene, "Converted scene should not own a NavMesh after conversion");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Converter_AfterConversion_NavMeshSurfaceIsPresent()
|
||||
{
|
||||
var surface = Object.FindAnyObjectByType<NavMeshSurface>();
|
||||
Assert.IsNotNull(surface, "Unable to find a NavMesh surface, it should have been created by the conversion");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Converter_AfterConversion_NavMeshIsPresent()
|
||||
{
|
||||
var sampleSuccess = NavMesh.SamplePosition(Vector3.zero, out var hit, 1.0f, NavMesh.AllAreas);
|
||||
Assert.IsTrue(sampleSuccess && hit.hit, "NavMesh should still be present after conversion");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Converter_AfterConversion_NoNavigationStaticGameObjects()
|
||||
{
|
||||
var gameObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
|
||||
foreach (var gameObject in gameObjects)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
Assert.IsFalse(GameObjectUtility.AreStaticEditorFlagsSet(gameObject, StaticEditorFlags.NavigationStatic), "Objects should not be flagged as NavigationStatic after conversion");
|
||||
#pragma warning restore 618
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Converter_AfterConversion_HeightMeshIsPresent()
|
||||
{
|
||||
var surface = Object.FindAnyObjectByType<NavMeshSurface>();
|
||||
Assume.That(surface, Is.Not.Null, "Unable to find a NavMesh surface, it should have been created by the conversion");
|
||||
Assert.IsTrue(surface.buildHeightMesh, "A scene NavMesh built with HeightMesh should be converted to a surface with the buildHeightMesh option enabled");
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
|
||||
if (AssetDatabase.IsValidFolder(k_TestFolderPath))
|
||||
AssetDatabase.DeleteAsset(k_TestFolderPath);
|
||||
|
||||
// Restore build settings value
|
||||
var settingsObject = new SerializedObject(NavMeshBuilder.navMeshSettingsObject);
|
||||
Assume.That(settingsObject, Is.Not.Null, "Unable to get the build settings object");
|
||||
var buildHeightMeshProperty = settingsObject.FindProperty(k_BuildHeightMeshPropertyName);
|
||||
Assume.That(buildHeightMeshProperty, Is.Not.Null, "Unable to get the buildHeightMesh property from the build settings object");
|
||||
buildHeightMeshProperty.boolValue = m_BuildHeightMeshPreviousValue;
|
||||
settingsObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 726f4ec00efc48ab9ab7f5647c4c2f7a
|
||||
timeCreated: 1641493654
|
||||
@@ -0,0 +1,870 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.AI.Navigation.Updater;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
#pragma warning disable 618
|
||||
internal class OffMeshLinkConverterTests
|
||||
{
|
||||
string m_TestFolderName;
|
||||
string m_TestFolderPath;
|
||||
|
||||
struct OffMeshLinkData
|
||||
{
|
||||
public bool activated;
|
||||
public bool autoUpdatePositions;
|
||||
public bool biDirectional;
|
||||
public float costOverride;
|
||||
public Transform startTransform;
|
||||
public Transform endTransform;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(m_TestFolderPath) && AssetDatabase.IsValidFolder(m_TestFolderPath))
|
||||
{
|
||||
AssetDatabase.DeleteAsset(m_TestFolderPath);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_TestFolderName = System.IO.Path.GetRandomFileName();
|
||||
AssetDatabase.CreateFolder("Assets", m_TestFolderName);
|
||||
m_TestFolderPath = "Assets/" + m_TestFolderName;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_InvalidGuid_NoConversion()
|
||||
{
|
||||
const string invalidGuid = "InvalidGuid";
|
||||
var convertList = new List<string> { invalidGuid };
|
||||
OffMeshLinkUpdaterUtility.Convert(convertList, out var failedConversions);
|
||||
|
||||
Assert.That(failedConversions.Count, Is.EqualTo(1), "Should have failed to convert the invalid GUID.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_PrefabWithOML_ConverterFindsPrefab()
|
||||
{
|
||||
var omlPrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
Assume.That(omlPrefab.GetComponent<OffMeshLink>(), Is.Not.Null, "Prefab should have OffMeshLink component");
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
Assert.That(foundPrefabs.Count, Is.EqualTo(1), "Should have found 1 prefab with OffMeshLink component.");
|
||||
Assert.That(GuidToPrefab(foundPrefabs[0]) == omlPrefab, "Should have found the prefab with OffMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_PrefabWithoutOML_ConverterDoesNotFindPrefab()
|
||||
{
|
||||
CreatePrefabWithComponent<SpriteRenderer>(m_TestFolderPath + "/SpriteRendererPrefab.prefab");
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
Assert.That(foundPrefabs.Count, Is.EqualTo(0), "Should not have found any prefabs with OffMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_ConverterLookingInEmptyFolder_NoItemsFound()
|
||||
{
|
||||
CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
var randomFolderName = System.IO.Path.GetRandomFileName();
|
||||
var randomFolderPath = "Assets/" + randomFolderName;
|
||||
AssetDatabase.CreateFolder("Assets", randomFolderName);
|
||||
try
|
||||
{
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { randomFolderPath });
|
||||
Assert.That(foundPrefabs.Count, Is.EqualTo(0), "Should not have found any prefabs with OffMeshLink component.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.DeleteAsset(randomFolderPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabIsReadOnly_NoConversion()
|
||||
{
|
||||
var prefabPath = m_TestFolderPath + "/OffMeshLinkPrefab.prefab";
|
||||
CreatePrefabWithComponent<OffMeshLink>(prefabPath);
|
||||
var attributes = System.IO.File.GetAttributes(prefabPath);
|
||||
System.IO.File.SetAttributes(prefabPath, attributes | System.IO.FileAttributes.ReadOnly);
|
||||
|
||||
var foundPrefabs = new List<string> { AssetDatabase.AssetPathToGUID(prefabPath) };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out var failedConversions);
|
||||
|
||||
Assert.That(foundPrefabs.Count, Is.Zero, "Prefab should have been removed from conversion list.");
|
||||
Assert.That(failedConversions.Count, Is.EqualTo(1), "Should have failed to convert the prefab.");
|
||||
Assert.That(failedConversions[0].failureMessage, Is.Not.Empty, "Should have a failure message.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_PrefabWithOMLOnChild_ConverterFindsPrefab()
|
||||
{
|
||||
var parent = new GameObject("Parent");
|
||||
var child = new GameObject("Child");
|
||||
child.transform.parent = parent.transform;
|
||||
child.AddComponent<OffMeshLink>();
|
||||
CreatePrefabFromGameObject(parent, m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
Assert.That(foundPrefabs.Count, Is.EqualTo(1), "Should have found 1 prefab with OffMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabWithOML_PrefabConverted()
|
||||
{
|
||||
CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(foundPrefabs[0]);
|
||||
Assert.That(convertedPrefab.GetComponent<OffMeshLink>(), Is.Null, "Prefab should not have OffMeshLink component after conversion.");
|
||||
Assert.That(convertedPrefab.GetComponent<NavMeshLink>(), Is.Not.Null, "Prefab should have NavMeshLink component after conversion.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabWithOMLOnChild_ChildConverted()
|
||||
{
|
||||
var parent = new GameObject("Parent");
|
||||
var child = new GameObject("Child");
|
||||
child.transform.parent = parent.transform;
|
||||
child.AddComponent<OffMeshLink>();
|
||||
CreatePrefabFromGameObject(parent, m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
var objectsToConvert = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab") };
|
||||
OffMeshLinkUpdaterUtility.Convert(objectsToConvert, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(objectsToConvert[0]);
|
||||
Assert.That(convertedPrefab.transform.GetChild(0).GetComponent<OffMeshLink>(), Is.Null, "Prefab should not have OffMeshLink component after conversion.");
|
||||
Assert.That(convertedPrefab.transform.GetChild(0).GetComponent<NavMeshLink>(), Is.Not.Null, "Prefab should have NavMeshLink component after conversion.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_SceneWithOML_ConverterFindsScene()
|
||||
{
|
||||
var scene = CreateSceneWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
|
||||
var gameObjects = scene.GetRootGameObjects();
|
||||
var omlGameObject = Array.Find(gameObjects, x => x.TryGetComponent<OffMeshLink>(out _));
|
||||
Assume.That(omlGameObject, Is.Not.Null, "A GameObject in the scene should have an OffMeshLink component.");
|
||||
|
||||
var foundObjects = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
Assert.That(foundObjects.Count, Is.EqualTo(1), "Should have found 1 scene with OffMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_SceneWithPrefabInstance_ConverterFindsCorrectNumberToConvert()
|
||||
{
|
||||
CreateSceneWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
// Open the scene and instantiate the prefab
|
||||
var scene = EditorSceneManager.OpenScene(m_TestFolderPath + "/OffMeshLinkScene.unity", OpenSceneMode.Additive);
|
||||
PrefabUtility.InstantiatePrefab(prefab);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
|
||||
var foundObjects = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
Assert.That(foundObjects.Count, Is.EqualTo(2), "Should have found 2 objects to convert.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_SceneWithOML_InstanceInSceneConverted()
|
||||
{
|
||||
CreateSceneWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
var foundObjects = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
OffMeshLinkUpdaterUtility.Convert(foundObjects, out _);
|
||||
|
||||
var pathToObject = AssetDatabase.GUIDToAssetPath(foundObjects[0]);
|
||||
var scene = EditorSceneManager.OpenScene(pathToObject, OpenSceneMode.Additive);
|
||||
var convertedGameObject = scene.GetRootGameObjects()[0];
|
||||
|
||||
Assert.That(convertedGameObject.transform.GetComponent<OffMeshLink>(), Is.Null, "Prefab should not have OffMeshLink component after conversion.");
|
||||
Assert.That(convertedGameObject.transform.GetComponent<NavMeshLink>(), Is.Not.Null, "Prefab should have NavMeshLink component after conversion.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_SceneIsReadOnly_NoConversion()
|
||||
{
|
||||
var scenePath = m_TestFolderPath + "/OffMeshLinkScene.unity";
|
||||
CreateSceneWithComponent<OffMeshLink>(scenePath);
|
||||
var attributes = System.IO.File.GetAttributes(scenePath);
|
||||
System.IO.File.SetAttributes(scenePath, attributes | System.IO.FileAttributes.ReadOnly);
|
||||
|
||||
var foundItems = new List<string> { AssetDatabase.AssetPathToGUID(scenePath) };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundItems, out var failedConversions);
|
||||
|
||||
Assert.That(foundItems.Count, Is.Zero, "Scene should have been removed from conversion list.");
|
||||
Assert.That(failedConversions.Count, Is.EqualTo(1), "Should have failed to convert the scene.");
|
||||
Assert.That(failedConversions[0].failureMessage, Is.Not.Empty, "Should have a failure message.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_SceneWithOMLOnChild_ChildConverted()
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
|
||||
SceneManager.SetActiveScene(scene);
|
||||
|
||||
var parent = new GameObject("Parent");
|
||||
var child = new GameObject("Child");
|
||||
child.transform.parent = parent.transform;
|
||||
child.AddComponent<OffMeshLink>();
|
||||
|
||||
EditorSceneManager.SaveScene(scene, m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
|
||||
var foundObjects = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkScene.unity") };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundObjects, out _);
|
||||
|
||||
var pathToObject = AssetDatabase.GUIDToAssetPath(foundObjects[0]);
|
||||
scene = EditorSceneManager.OpenScene(pathToObject, OpenSceneMode.Additive);
|
||||
var convertedGameObject = scene.GetRootGameObjects()[0];
|
||||
|
||||
Assert.That(convertedGameObject.transform.GetChild(0).GetComponent<OffMeshLink>(), Is.Null, "GameObject should not have OffMeshLink component after conversion.");
|
||||
Assert.That(convertedGameObject.transform.GetChild(0).GetComponent<NavMeshLink>(), Is.Not.Null, "GameObject should have NavMeshLink component after conversion.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_SceneWithPrefabInstance_PrefabAndInstanceConverted()
|
||||
{
|
||||
CreateSceneWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
// Open the scene and instantiate the prefab
|
||||
var scene = EditorSceneManager.OpenScene(m_TestFolderPath + "/OffMeshLinkScene.unity", OpenSceneMode.Additive);
|
||||
PrefabUtility.InstantiatePrefab(prefab);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
|
||||
var foundObjects = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkScene.unity")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundObjects, out _);
|
||||
|
||||
// Validate the converted prefab
|
||||
var convertedPrefab = GuidToPrefab(foundObjects[0]);
|
||||
Assume.That(convertedPrefab.GetComponent<OffMeshLink>(), Is.Null, "Prefab should not have OffMeshLink component after conversion.");
|
||||
Assume.That(convertedPrefab.GetComponent<NavMeshLink>(), Is.Not.Null, "Prefab should have NavMeshLink component after conversion.");
|
||||
Assert.That(convertedPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Prefab should have only one NavMeshLink component after conversion.");
|
||||
|
||||
// Validate the converted scene
|
||||
scene = EditorSceneManager.OpenScene(AssetDatabase.GUIDToAssetPath(foundObjects[1]), OpenSceneMode.Additive);
|
||||
var rootGameObjects = scene.GetRootGameObjects();
|
||||
foreach (var sceneGo in rootGameObjects)
|
||||
{
|
||||
Assume.That(sceneGo.GetComponent<OffMeshLink>(), Is.Null, $"{sceneGo.name} should not have OffMeshLink component after conversion.");
|
||||
Assume.That(sceneGo.GetComponent<NavMeshLink>(), Is.Not.Null, $"{sceneGo.name} Prefab should have NavMeshLink component after conversion.");
|
||||
Assert.That(sceneGo.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), $"{sceneGo.name} Prefab should have only one NavMeshLink component after conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabWithCustomValues_ValuesAreCopiedOver()
|
||||
{
|
||||
var testData = new OffMeshLinkData()
|
||||
{
|
||||
activated = false,
|
||||
autoUpdatePositions = false,
|
||||
biDirectional = false,
|
||||
costOverride = 123f
|
||||
};
|
||||
|
||||
var gameObject = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var oml = gameObject.GetComponent<OffMeshLink>();
|
||||
oml.activated = testData.activated;
|
||||
oml.autoUpdatePositions = testData.autoUpdatePositions;
|
||||
oml.biDirectional = testData.biDirectional;
|
||||
oml.costOverride = testData.costOverride;
|
||||
oml.startTransform = testData.startTransform;
|
||||
oml.endTransform = testData.endTransform;
|
||||
|
||||
var foundPrefabs = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab") };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(foundPrefabs[0]);
|
||||
AssertValuesAreEqual(testData, convertedPrefab.GetComponent<NavMeshLink>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_NestedPrefabWithCustomValuesOnChild_ValuesAreCopiedOver([Values(true, false)] bool shouldFlipPrefabOrder)
|
||||
{
|
||||
var testData = new OffMeshLinkData()
|
||||
{
|
||||
activated = false,
|
||||
autoUpdatePositions = false,
|
||||
biDirectional = false,
|
||||
costOverride = 123f
|
||||
};
|
||||
|
||||
var parentPrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/ParentPrefab.prefab");
|
||||
var childPrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/ChildPrefab.prefab");
|
||||
|
||||
NestPrefabs(parentPrefab, childPrefab);
|
||||
|
||||
var oml = childPrefab.GetComponent<OffMeshLink>();
|
||||
oml.activated = testData.activated;
|
||||
oml.autoUpdatePositions = testData.autoUpdatePositions;
|
||||
oml.biDirectional = testData.biDirectional;
|
||||
oml.costOverride = testData.costOverride;
|
||||
oml.startTransform = testData.startTransform;
|
||||
oml.endTransform = testData.endTransform;
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
if (shouldFlipPrefabOrder)
|
||||
foundPrefabs.Reverse();
|
||||
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
var convertedPrefabs = GuidsToPrefabs(foundPrefabs);
|
||||
|
||||
var convertedPrefab = convertedPrefabs.Find(x => x.name == childPrefab.name);
|
||||
Assume.That(convertedPrefab, Is.Not.Null, "Could not find child prefab.");
|
||||
AssertValuesAreEqual(testData, convertedPrefab.GetComponent<NavMeshLink>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_NestedPrefabWithOverriddenValues_ValuesAreOverriddenAfterConversion()
|
||||
{
|
||||
const float overrideValue = 321f;
|
||||
|
||||
var parentPrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/ParentPrefab.prefab");
|
||||
var childPrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/ChildPrefab.prefab");
|
||||
|
||||
NestPrefabs(parentPrefab, childPrefab);
|
||||
|
||||
var parentInstance = PrefabUtility.InstantiatePrefab(parentPrefab) as GameObject;
|
||||
var childInstance = parentInstance.transform.GetChild(0);
|
||||
|
||||
var oml = childInstance.GetComponent<OffMeshLink>();
|
||||
oml.costOverride = overrideValue;
|
||||
oml.activated = false;
|
||||
oml.autoUpdatePositions = false;
|
||||
oml.biDirectional = false;
|
||||
oml.startTransform = oml.transform;
|
||||
oml.endTransform = oml.transform;
|
||||
|
||||
PrefabUtility.ApplyPrefabInstance(parentInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/ParentPrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/ChildPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
var convertedPrefabs = GuidsToPrefabs(foundPrefabs);
|
||||
|
||||
var convertedParentPrefab = convertedPrefabs.Find(x => x.name == parentPrefab.name);
|
||||
var convertedChildPrefab = convertedParentPrefab.transform.GetChild(0).gameObject;
|
||||
|
||||
var hasAnyOverrides = PrefabUtility.HasPrefabInstanceAnyOverrides(convertedChildPrefab, false);
|
||||
Assume.That(hasAnyOverrides, Is.True, "Child prefab should have overrides.");
|
||||
|
||||
var propertyModifications = PrefabUtility.GetPropertyModifications(convertedChildPrefab);
|
||||
Assume.That(propertyModifications.Length, Is.GreaterThan(0), "Child prefab should have property modifications.");
|
||||
|
||||
var propertyModification = Array.Find(propertyModifications, x => x.propertyPath == "m_CostModifier" && x.target?.GetType() == typeof(NavMeshLink));
|
||||
Assume.That(propertyModification, Is.Not.Null, "Property modification for cost override should exist.");
|
||||
Assert.That(propertyModification.value, Is.EqualTo(overrideValue.ToString()), "Property modification value should be equal to the override value.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_SceneWithOverriddenPrefabInstance_ValuesAreOverriddenAfterConversion()
|
||||
{
|
||||
const float overrideValue = 42f;
|
||||
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
CreateSceneWithPrefabInstance(prefab, m_TestFolderPath + "/OffMeshLinkScene.unity");
|
||||
|
||||
// Open the scene and override prefab instance values
|
||||
var scene = EditorSceneManager.OpenScene(m_TestFolderPath + "/OffMeshLinkScene.unity", OpenSceneMode.Additive);
|
||||
var rootGameObjects = scene.GetRootGameObjects();
|
||||
var prefabInstance = Array.Find(rootGameObjects, x => x.GetComponent<OffMeshLink>());
|
||||
var oml = prefabInstance.GetComponent<OffMeshLink>();
|
||||
oml.costOverride = overrideValue;
|
||||
oml.activated = false;
|
||||
oml.autoUpdatePositions = false;
|
||||
oml.biDirectional = false;
|
||||
oml.startTransform = oml.transform;
|
||||
oml.endTransform = oml.transform;
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
|
||||
var foundObjects = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkScene.unity")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundObjects, out _);
|
||||
|
||||
Assume.That(foundObjects.Count, Is.EqualTo(2));
|
||||
|
||||
scene = EditorSceneManager.OpenScene(m_TestFolderPath + "/OffMeshLinkScene.unity", OpenSceneMode.Additive);
|
||||
rootGameObjects = scene.GetRootGameObjects();
|
||||
prefabInstance = Array.Find(rootGameObjects, x => x.GetComponent<NavMeshLink>());
|
||||
|
||||
var hasAnyOverrides = PrefabUtility.HasPrefabInstanceAnyOverrides(prefabInstance, false);
|
||||
Assume.That(hasAnyOverrides, Is.True, "Prefab instance should have overrides.");
|
||||
|
||||
var propertyModifications = PrefabUtility.GetPropertyModifications(prefabInstance);
|
||||
Assume.That(propertyModifications.Length, Is.GreaterThan(0), "Prefab instance should have property modifications.");
|
||||
|
||||
var propertyModification = Array.Find(propertyModifications, x => x.propertyPath == "m_CostModifier" && x.target?.GetType() == typeof(NavMeshLink));
|
||||
Assume.That(propertyModification, Is.Not.Null, "Property modification for cost override should exist.");
|
||||
Assert.That(propertyModification.value, Is.EqualTo(overrideValue.ToString()), "Property modification value should be equal to the override value.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(2)]
|
||||
[TestCase(4)]
|
||||
[TestCase(16)]
|
||||
public void Convert_PrefabWithMultipleOML_ConvertedToMultipleNML(int noOfComponets)
|
||||
{
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
// Start at 1 since we already have one component
|
||||
for (var i = 1; i < noOfComponets; ++i)
|
||||
prefab.AddComponent<OffMeshLink>();
|
||||
PrefabUtility.SavePrefabAsset(prefab);
|
||||
|
||||
var foundPrefabs = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab") };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(foundPrefabs[0]);
|
||||
Assert.That(convertedPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(noOfComponets), "Should have converted all OffMeshLink components to NavMeshLink components.");
|
||||
Assert.That(convertedPrefab.GetComponents<OffMeshLink>().Length, Is.Zero, "Should not have any OffMeshLink components left.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabWithOMLAndNML_PrefabConvertedAndHasOriginalNML()
|
||||
{
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
prefab.AddComponent<NavMeshLink>();
|
||||
PrefabUtility.SavePrefabAsset(prefab);
|
||||
|
||||
var foundPrefabs = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab") };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(foundPrefabs[0]);
|
||||
Assert.That(convertedPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(2), "Should have converted all OffMeshLink components to NavMeshLink components.");
|
||||
Assert.That(convertedPrefab.GetComponents<OffMeshLink>().Length, Is.Zero, "Should not have any OffMeshLink components left.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_PrefabWithOMLAndNML_ValuesAreCopiedOverToCorrectNML()
|
||||
{
|
||||
var testData = new OffMeshLinkData()
|
||||
{
|
||||
activated = false,
|
||||
autoUpdatePositions = false,
|
||||
biDirectional = false,
|
||||
costOverride = 123f
|
||||
};
|
||||
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var oml = prefab.GetComponent<OffMeshLink>();
|
||||
oml.activated = testData.activated;
|
||||
oml.autoUpdatePositions = testData.autoUpdatePositions;
|
||||
oml.biDirectional = testData.biDirectional;
|
||||
oml.costOverride = testData.costOverride;
|
||||
oml.startTransform = testData.startTransform;
|
||||
oml.endTransform = testData.endTransform;
|
||||
|
||||
var existingNml = prefab.AddComponent<NavMeshLink>();
|
||||
|
||||
PrefabUtility.SavePrefabAsset(prefab);
|
||||
|
||||
var foundPrefabs = new List<string> { AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab") };
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var convertedPrefab = GuidToPrefab(foundPrefabs[0]);
|
||||
var links = convertedPrefab.GetComponents<NavMeshLink>();
|
||||
var convertedNml = Array.Find(links, x => x != existingNml);
|
||||
AssertValuesAreEqual(testData, convertedNml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabWithOml_VariantConverted()
|
||||
{
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
var convertedSourcePrefab = prefabs.Find(x => !PrefabUtility.IsPartOfVariantPrefab(x));
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been converted.");
|
||||
|
||||
Assert.That(convertedVariantPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Variant prefab should have one NavMeshLink component.");
|
||||
Assert.That(convertedSourcePrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Source prefab should have one NavMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabWithOverrides_ValuesAreOverriddenAfterConversion()
|
||||
{
|
||||
const float costOverride = 42f;
|
||||
|
||||
var prefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
|
||||
variantPrefab.GetComponent<OffMeshLink>().costOverride = costOverride;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
Assume.That(prefab.GetComponent<OffMeshLink>().costOverride, Is.EqualTo(-1), "Source prefab should have a cost override equal to -1.");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
var convertedSourcePrefab = prefabs.Find(x => !PrefabUtility.IsPartOfVariantPrefab(x));
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been converted.");
|
||||
Assume.That(convertedVariantPrefab.GetComponent<NavMeshLink>(), Is.Not.Null, "Variant prefab should have NavMeshLink component.");
|
||||
|
||||
Assert.That(convertedVariantPrefab.GetComponent<NavMeshLink>().costModifier, Is.EqualTo(costOverride), $"Variant prefab should have a cost modifier equal to {costOverride}.");
|
||||
Assert.That(convertedSourcePrefab.GetComponent<NavMeshLink>().costModifier, Is.EqualTo(-1), "Source prefab should have a cost modifier equal to -1.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabWithAddedOML_VariantConvertedWithAddedNMLAndOriginalNML()
|
||||
{
|
||||
var sourcePrefab = CreatePrefabFromGameObject(new GameObject(), m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
variantPrefab.AddComponent<OffMeshLink>();
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been converted.");
|
||||
Assert.That(convertedVariantPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Variant prefab should have one NavMeshLink components.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindObjectsToConvert_VariantPrefabRemovedOML_ConverterFindsVariant()
|
||||
{
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
Object.DestroyImmediate(variantPrefab.GetComponent<OffMeshLink>());
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = OffMeshLinkUpdaterUtility.FindObjectsToConvert(new[] { m_TestFolderPath });
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var foundVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
Assume.That(foundPrefabs.Count, Is.EqualTo(2), "Should have found 2 prefabs.");
|
||||
Assert.That(foundVariantPrefab, Is.Not.Null, "Variant prefab should have been found.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabRemovedOML_SourceConvertedToNML()
|
||||
{
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
Object.DestroyImmediate(variantPrefab.GetComponent<OffMeshLink>());
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedSourcePrefab = prefabs.Find(x => !PrefabUtility.IsPartOfVariantPrefab(x));
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been found.");
|
||||
Assume.That(convertedSourcePrefab, Is.Not.Null, "Source prefab should have been found.");
|
||||
Assert.That(convertedVariantPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(0), "Variant prefab should not have any NavMeshLink components.");
|
||||
Assert.That(convertedSourcePrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Source prefab should have one NavMeshLink components.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabRemovedOneKeptOneOML_ConvertedWithOneNML()
|
||||
{
|
||||
const float costOverrideValue = 1234f;
|
||||
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var secondaryOml = sourcePrefab.AddComponent<OffMeshLink>();
|
||||
secondaryOml.costOverride = costOverrideValue;
|
||||
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
var omlToDestroy = Array.Find(variantPrefab.GetComponents<OffMeshLink>(), x => !Mathf.Approximately(x.costOverride, costOverrideValue));
|
||||
Object.DestroyImmediate(omlToDestroy);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been found.");
|
||||
|
||||
var convertedNavMeshLink = convertedVariantPrefab.GetComponent<NavMeshLink>();
|
||||
Assume.That(convertedNavMeshLink, Is.Not.Null, "Variant prefab should have one NavMeshLink components.");
|
||||
|
||||
Assert.That(convertedNavMeshLink.costModifier, Is.EqualTo(costOverrideValue).Within(Mathf.Epsilon), "Cost modifier should be equal to the cost override value.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_VariantPrefabRemovedOMLAndAddNewOML_ConvertedWithOneNML()
|
||||
{
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
var variantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
Object.DestroyImmediate(variantPrefab.GetComponent<OffMeshLink>());
|
||||
variantPrefab.AddComponent<OffMeshLink>();
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(variantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(variantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariant.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedSourcePrefab = prefabs.Find(x => !PrefabUtility.IsPartOfVariantPrefab(x));
|
||||
var convertedVariantPrefab = prefabs.Find(PrefabUtility.IsPartOfVariantPrefab);
|
||||
Assume.That(convertedVariantPrefab, Is.Not.Null, "Variant prefab should have been found.");
|
||||
Assume.That(convertedSourcePrefab, Is.Not.Null, "Source prefab should have been found.");
|
||||
Assert.That(convertedVariantPrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Variant prefab should have one NavMeshLink components.");
|
||||
Assert.That(convertedSourcePrefab.GetComponents<NavMeshLink>().Length, Is.EqualTo(1), "Source prefab should have one NavMeshLink components.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_TwoVariantsWithOverrides_VariantsKeepTheirOverridesAfterConversion()
|
||||
{
|
||||
const float firstCostOverride = 42f;
|
||||
const float secondCostOverride = 1234f;
|
||||
|
||||
var sourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/OffMeshLinkPrefab.prefab");
|
||||
|
||||
var firstVariantPrefab = PrefabUtility.InstantiatePrefab(sourcePrefab) as GameObject;
|
||||
firstVariantPrefab.GetComponent<OffMeshLink>().costOverride = firstCostOverride;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(firstVariantPrefab);
|
||||
var firstVariantPrefabAsset = PrefabUtility.SaveAsPrefabAsset(firstVariantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariantOne.prefab");
|
||||
|
||||
var secondVariantPrefab = PrefabUtility.InstantiatePrefab(firstVariantPrefabAsset) as GameObject;
|
||||
secondVariantPrefab.GetComponent<OffMeshLink>().costOverride = secondCostOverride;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(secondVariantPrefab);
|
||||
PrefabUtility.SaveAsPrefabAsset(secondVariantPrefab, m_TestFolderPath + "/OffMeshLinkPrefabVariantTwo.prefab");
|
||||
|
||||
Assume.That(sourcePrefab.GetComponent<OffMeshLink>().costOverride, Is.EqualTo(-1), "Source prefab should have a cost override equal to -1.");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariantOne.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefabVariantTwo.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/OffMeshLinkPrefab.prefab")
|
||||
};
|
||||
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var convertedVariantPrefabOne = prefabs.Find(x => x.name == "OffMeshLinkPrefabVariantOne");
|
||||
var convertedVariantPrefabTwo = prefabs.Find(x => x.name == "OffMeshLinkPrefabVariantTwo");
|
||||
var convertedSourcePrefab = prefabs.Find(x => x.name == "OffMeshLinkPrefab");
|
||||
|
||||
Assume.That(convertedVariantPrefabOne, Is.Not.Null, "Variant prefab one should have been found.");
|
||||
Assume.That(convertedVariantPrefabTwo, Is.Not.Null, "Variant prefab two should have been found.");
|
||||
Assume.That(convertedSourcePrefab, Is.Not.Null, "Source prefab should have been found.");
|
||||
Assume.That(convertedVariantPrefabOne.GetComponent<NavMeshLink>(), Is.Not.Null, "Variant prefab one should have a NavMeshLink component.");
|
||||
Assume.That(convertedVariantPrefabTwo.GetComponent<NavMeshLink>(), Is.Not.Null, "Variant prefab two should have a NavMeshLink component.");
|
||||
Assume.That(convertedSourcePrefab.GetComponent<NavMeshLink>(), Is.Not.Null, "Source prefab should have a NavMeshLink component.");
|
||||
|
||||
Assert.That(convertedVariantPrefabOne.GetComponent<NavMeshLink>().costModifier, Is.EqualTo(firstCostOverride), $"Variant prefab one should have a cost modifier equal to {firstCostOverride}.");
|
||||
Assert.That(convertedVariantPrefabTwo.GetComponent<NavMeshLink>().costModifier, Is.EqualTo(secondCostOverride), $"Variant prefab two should have a cost modifier equal to {secondCostOverride}.");
|
||||
Assert.That(convertedSourcePrefab.GetComponent<NavMeshLink>().costModifier, Is.EqualTo(-1), "Source prefab should have a cost modifier equal to -1.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_TwoVariantsSameSource_VariantsAreSuccessfullyConverted()
|
||||
{
|
||||
var topSourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/TopSourcePrefab.prefab");
|
||||
|
||||
var midSourcePrefab = PrefabUtility.InstantiatePrefab(topSourcePrefab) as GameObject;
|
||||
var midSourcePrefabAsset = PrefabUtility.SaveAsPrefabAsset(midSourcePrefab, m_TestFolderPath + "/MidSourcePrefab.prefab");
|
||||
|
||||
var firstLeafPrefab = PrefabUtility.InstantiatePrefab(midSourcePrefabAsset) as GameObject;
|
||||
PrefabUtility.SaveAsPrefabAsset(firstLeafPrefab, m_TestFolderPath + "/FirstLeafPrefab.prefab");
|
||||
|
||||
var secondLeafPrefab = PrefabUtility.InstantiatePrefab(midSourcePrefabAsset) as GameObject;
|
||||
PrefabUtility.SaveAsPrefabAsset(secondLeafPrefab, m_TestFolderPath + "/SecondLeafPrefab.prefab");
|
||||
|
||||
var foundPrefabs = new List<string>
|
||||
{
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/FirstLeafPrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/MidSourcePrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/SecondLeafPrefab.prefab"),
|
||||
AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/TopSourcePrefab.prefab")
|
||||
};
|
||||
|
||||
OffMeshLinkUpdaterUtility.Convert(foundPrefabs, out _);
|
||||
|
||||
var prefabs = GuidsToPrefabs(foundPrefabs);
|
||||
var firstLeaf = prefabs.Find(x => x.name == "FirstLeafPrefab");
|
||||
var secondLeaf = prefabs.Find(x => x.name == "SecondLeafPrefab");
|
||||
var midSource = prefabs.Find(x => x.name == "MidSourcePrefab");
|
||||
var topSource = prefabs.Find(x => x.name == "TopSourcePrefab");
|
||||
|
||||
Assume.That(firstLeaf, Is.Not.Null, "First leaf prefab should have been found.");
|
||||
Assume.That(secondLeaf, Is.Not.Null, "Second leaf prefab should have been found.");
|
||||
Assume.That(midSource, Is.Not.Null, "Mid source prefab should have been found.");
|
||||
Assume.That(topSource, Is.Not.Null, "Top source prefab should have been found.");
|
||||
Assert.That(firstLeaf.GetComponent<NavMeshLink>(), Is.Not.Null, "First leaf prefab should have a NavMeshLink component.");
|
||||
Assert.That(secondLeaf.GetComponent<NavMeshLink>(), Is.Not.Null, "Second leaf prefab should have a NavMeshLink component.");
|
||||
Assert.That(midSource.GetComponent<NavMeshLink>(), Is.Not.Null, "Mid source prefab should have a NavMeshLink component.");
|
||||
Assert.That(topSource.GetComponent<NavMeshLink>(), Is.Not.Null, "Top source prefab should have a NavMeshLink component.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_VariantsAndScene_ConversionOrderIsDeterministic()
|
||||
{
|
||||
var topSourcePrefab = CreatePrefabWithComponent<OffMeshLink>(m_TestFolderPath + "/TopSourcePrefab.prefab");
|
||||
|
||||
var midSourcePrefab = PrefabUtility.InstantiatePrefab(topSourcePrefab) as GameObject;
|
||||
var midSourcePrefabAsset = PrefabUtility.SaveAsPrefabAsset(midSourcePrefab, m_TestFolderPath + "/MidSourcePrefab.prefab");
|
||||
|
||||
var firstLeafPrefab = PrefabUtility.InstantiatePrefab(midSourcePrefabAsset) as GameObject;
|
||||
PrefabUtility.SaveAsPrefabAsset(firstLeafPrefab, m_TestFolderPath + "/FirstLeafPrefab.prefab");
|
||||
|
||||
var secondLeafPrefab = PrefabUtility.InstantiatePrefab(midSourcePrefabAsset) as GameObject;
|
||||
PrefabUtility.SaveAsPrefabAsset(secondLeafPrefab, m_TestFolderPath + "/SecondLeafPrefab.prefab");
|
||||
|
||||
CreateSceneWithComponent<OffMeshLink>("Assets/OffMeshLinkScene.unity");
|
||||
|
||||
var firstLeafGuid = AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/FirstLeafPrefab.prefab");
|
||||
var secondLeafGuid = AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/SecondLeafPrefab.prefab");
|
||||
var midSourceGuid = AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/MidSourcePrefab.prefab");
|
||||
var topSourceGuid = AssetDatabase.AssetPathToGUID(m_TestFolderPath + "/TopSourcePrefab.prefab");
|
||||
var sceneGuid = AssetDatabase.AssetPathToGUID("Assets/OffMeshLinkScene.unity");
|
||||
|
||||
var assetsToConvert = new List<string>
|
||||
{
|
||||
firstLeafGuid,
|
||||
midSourceGuid,
|
||||
secondLeafGuid,
|
||||
topSourceGuid,
|
||||
sceneGuid
|
||||
};
|
||||
OffMeshLinkUpdaterUtility.Convert(assetsToConvert, out _);
|
||||
|
||||
Assume.That(assetsToConvert.Count, Is.EqualTo(5), "Should have 5 assets to convert.");
|
||||
Assert.That(assetsToConvert[0], Is.EqualTo(topSourceGuid));
|
||||
Assert.That(assetsToConvert[1], Is.EqualTo(midSourceGuid));
|
||||
Assert.That(assetsToConvert[2], Is.EqualTo(firstLeafGuid));
|
||||
Assert.That(assetsToConvert[3], Is.EqualTo(secondLeafGuid));
|
||||
Assert.That(assetsToConvert[4], Is.EqualTo(sceneGuid));
|
||||
}
|
||||
|
||||
static GameObject CreatePrefabWithComponent<T>(string savePath) where T : Component
|
||||
{
|
||||
var go = new GameObject();
|
||||
go.AddComponent<T>();
|
||||
return CreatePrefabFromGameObject(go, savePath);
|
||||
}
|
||||
|
||||
static GameObject CreatePrefabFromGameObject(GameObject go, string savePath)
|
||||
{
|
||||
var prefabGo = PrefabUtility.SaveAsPrefabAsset(go, savePath);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
Object.DestroyImmediate(go);
|
||||
return prefabGo;
|
||||
}
|
||||
|
||||
static Scene CreateSceneWithComponent<T>(string savePath) where T : Component
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
|
||||
SceneManager.SetActiveScene(scene);
|
||||
|
||||
var go = new GameObject();
|
||||
go.AddComponent<T>();
|
||||
|
||||
EditorSceneManager.SaveScene(scene, savePath);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
return scene;
|
||||
}
|
||||
|
||||
static Scene CreateSceneWithPrefabInstance(GameObject prefab, string savePath)
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
|
||||
SceneManager.SetActiveScene(scene);
|
||||
|
||||
var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
|
||||
EditorSceneManager.SaveScene(scene, savePath);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
static void NestPrefabs(GameObject parentPrefab, GameObject childPrefab)
|
||||
{
|
||||
var parentInstance = PrefabUtility.InstantiatePrefab(parentPrefab) as GameObject;
|
||||
PrefabUtility.InstantiatePrefab(childPrefab, parentInstance.transform);
|
||||
PrefabUtility.ApplyPrefabInstance(parentInstance, InteractionMode.AutomatedAction);
|
||||
}
|
||||
|
||||
static GameObject GuidToPrefab(string guid)
|
||||
{
|
||||
var pathToObject = AssetDatabase.GUIDToAssetPath(guid);
|
||||
return AssetDatabase.LoadAssetAtPath<GameObject>(pathToObject);
|
||||
}
|
||||
|
||||
static List<GameObject> GuidsToPrefabs(List<string> guids)
|
||||
{
|
||||
var gameObjects = new List<GameObject>();
|
||||
foreach (var guid in guids)
|
||||
gameObjects.Add(GuidToPrefab(guid));
|
||||
return gameObjects;
|
||||
}
|
||||
|
||||
static void AssertValuesAreEqual(OffMeshLinkData expectedData, NavMeshLink navMeshLink)
|
||||
{
|
||||
Assert.That(navMeshLink.activated, Is.EqualTo(expectedData.activated), "Expected activated to be equal.");
|
||||
Assert.That(navMeshLink.autoUpdate, Is.EqualTo(expectedData.autoUpdatePositions), "Expected autoUpdate to be equal.");
|
||||
Assert.That(navMeshLink.bidirectional, Is.EqualTo(expectedData.biDirectional), "Expected bidirectional to be equal.");
|
||||
Assert.That(navMeshLink.costModifier, Is.EqualTo(expectedData.costOverride), "Expected costModifier to be equal.");
|
||||
Assert.That(navMeshLink.startTransform, Is.EqualTo(expectedData.startTransform), "Expected startTransform to be equal.");
|
||||
Assert.That(navMeshLink.endTransform, Is.EqualTo(expectedData.endTransform), "Expected endTransform to be equal.");
|
||||
}
|
||||
}
|
||||
#pragma warning restore 618
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0ec7ba7e5444cf7b7fa8ea5e2f8c4f5
|
||||
timeCreated: 1710247468
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
internal abstract class DomainReloadTestBase
|
||||
{
|
||||
struct OptionSet
|
||||
{
|
||||
public bool enterPlayModeOptionsEnabled;
|
||||
public EnterPlayModeOptions enterPlayModeOptions;
|
||||
}
|
||||
OptionSet m_OriginalOptions;
|
||||
|
||||
[SerializeField] protected GameObject m_TestGo;
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator TearDown()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
if (m_TestGo != null)
|
||||
{
|
||||
Object.DestroyImmediate(m_TestGo);
|
||||
m_TestGo = null;
|
||||
}
|
||||
}
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
return;
|
||||
|
||||
m_OriginalOptions = new OptionSet()
|
||||
{
|
||||
enterPlayModeOptions = EditorSettings.enterPlayModeOptions,
|
||||
enterPlayModeOptionsEnabled = EditorSettings.enterPlayModeOptionsEnabled
|
||||
};
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
return;
|
||||
|
||||
EditorSettings.enterPlayModeOptions = m_OriginalOptions.enterPlayModeOptions;
|
||||
EditorSettings.enterPlayModeOptionsEnabled = m_OriginalOptions.enterPlayModeOptionsEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c69ffaa78fdb4e7796dc916a104d99ba
|
||||
timeCreated: 1700481896
|
||||
@@ -0,0 +1,105 @@
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
internal class InspectorWindowWrapper
|
||||
{
|
||||
readonly EditorWindow m_InspectorWindow;
|
||||
readonly bool m_OriginalInspectorThrottling;
|
||||
readonly bool m_OriginalPanelThrottling;
|
||||
|
||||
public InspectorWindowWrapper()
|
||||
{
|
||||
EditorApplication.ExecuteMenuItem("Window/General/Inspector");
|
||||
var windows = Resources.FindObjectsOfTypeAll<EditorWindow>();
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.GetType().Name != "InspectorWindow")
|
||||
continue;
|
||||
|
||||
m_InspectorWindow = window;
|
||||
break;
|
||||
}
|
||||
|
||||
Assume.That(m_InspectorWindow, Is.Not.Null, "Inspector window not found");
|
||||
m_OriginalInspectorThrottling = GetDisableInspectorElementThrottling();
|
||||
m_OriginalPanelThrottling = GetDisablePanelThrottling();
|
||||
|
||||
SetDisableInspectorElementThrottling(true);
|
||||
SetDisablePanelThrottling(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the inspector's element throttling, by accessing and setting its internal disabledThrottling property.
|
||||
/// The throttling is there to collect calls to UI Toolkit and execute them in batch.
|
||||
/// Disabling the throttling means that calls will be executed at the next available time.
|
||||
/// </summary>
|
||||
/// <param name="enabled">True means that throttling is disabled.</param>
|
||||
static void SetDisableInspectorElementThrottling(bool enabled)
|
||||
{
|
||||
var throttlingPropertyInfo = GetDisableInspectorElementThrottlingPropertyInfo();
|
||||
throttlingPropertyInfo?.SetValue(null, enabled);
|
||||
}
|
||||
|
||||
static bool GetDisableInspectorElementThrottling()
|
||||
{
|
||||
var throttlingPropertyInfo = GetDisableInspectorElementThrottlingPropertyInfo();
|
||||
return (bool)throttlingPropertyInfo?.GetValue(null);
|
||||
}
|
||||
|
||||
static PropertyInfo GetDisableInspectorElementThrottlingPropertyInfo()
|
||||
{
|
||||
return typeof(InspectorElement).GetProperty("disabledThrottling", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the inspector's panel throttling, by accessing and setting its internal TimerEventScheduler's disableThrottling property.
|
||||
/// The throttling is there to reduce the number of times a UI panel is refreshed in a given interval.
|
||||
/// Disabling the throttling means that the refresh will happen as frequently as the system allows it to refresh.
|
||||
/// </summary>
|
||||
/// <param name="enabled">True means that throttling is disabled.</param>
|
||||
void SetDisablePanelThrottling(bool enabled)
|
||||
{
|
||||
var disableThrottlingPropInfo = GetDisablePanelThrottlingPropertyInfo(out var scheduler);
|
||||
disableThrottlingPropInfo?.SetValue(scheduler, enabled);
|
||||
}
|
||||
|
||||
bool GetDisablePanelThrottling()
|
||||
{
|
||||
var disableThrottlingPropInfo = GetDisablePanelThrottlingPropertyInfo(out var scheduler);
|
||||
return (bool)disableThrottlingPropInfo.GetValue(scheduler);
|
||||
}
|
||||
|
||||
FieldInfo GetDisablePanelThrottlingPropertyInfo(out object scheduler)
|
||||
{
|
||||
var panel = GetRootVisualElement().panel;
|
||||
var schedulerPropInfo = panel.GetType().GetProperty("scheduler", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
scheduler = schedulerPropInfo?.GetValue(panel);
|
||||
|
||||
Assume.That(scheduler?.GetType().Name, Is.EqualTo("TimerEventScheduler"), "Scheduler is not a TimerEventScheduler");
|
||||
return scheduler?.GetType().GetField("disableThrottling", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
public void RepaintImmediately()
|
||||
{
|
||||
var repaintMethodInfo = m_InspectorWindow.GetType().GetMethod("RepaintImmediately", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
repaintMethodInfo?.Invoke(m_InspectorWindow, null);
|
||||
}
|
||||
|
||||
public void Focus() => m_InspectorWindow.Focus();
|
||||
|
||||
public void Close()
|
||||
{
|
||||
SetDisablePanelThrottling(m_OriginalPanelThrottling);
|
||||
SetDisableInspectorElementThrottling(m_OriginalInspectorThrottling);
|
||||
m_InspectorWindow.Close();
|
||||
}
|
||||
|
||||
public VisualElement GetRootVisualElement() => m_InspectorWindow.rootVisualElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fade91be62f4426eb39af79472c77206
|
||||
timeCreated: 1717659840
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8061144b555b4fbbb5226d6e18f4dd50
|
||||
timeCreated: 1717509602
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class NavMeshLinkInspectorTests
|
||||
{
|
||||
GameObject m_TestGameObject;
|
||||
InspectorWindowWrapper m_InspectorWindowWrapper;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_TestGameObject = new GameObject("Test GameObject", typeof(NavMeshLink));
|
||||
m_InspectorWindowWrapper = new InspectorWindowWrapper();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_TestGameObject);
|
||||
m_InspectorWindowWrapper?.Close();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ShowNavMeshLinkInInspector_NoErrorsOrWarnings()
|
||||
{
|
||||
Selection.objects = new Object[] { m_TestGameObject };
|
||||
yield return WaitAmountOfMs(100);
|
||||
|
||||
m_InspectorWindowWrapper.Focus();
|
||||
m_InspectorWindowWrapper.RepaintImmediately();
|
||||
yield return WaitAmountOfMs(100);
|
||||
|
||||
// Validate that the inspector is showing the NavMeshLink component
|
||||
var rootVisualElement = m_InspectorWindowWrapper.GetRootVisualElement();
|
||||
Assume.That(rootVisualElement, Is.Not.Null, "Root visual element not found");
|
||||
var headerElement = rootVisualElement.Q<IMGUIContainer>("NavMesh LinkHeader");
|
||||
Assume.That(headerElement, Is.Not.Null, "NavMesh Link header element not found");
|
||||
|
||||
LogAssert.NoUnexpectedReceived();
|
||||
}
|
||||
|
||||
static IEnumerator WaitAmountOfMs(int ms)
|
||||
{
|
||||
var startTime = GetTimeSinceStartupMs();
|
||||
while (GetTimeSinceStartupMs() < startTime + ms)
|
||||
yield return null;
|
||||
}
|
||||
|
||||
static long GetTimeSinceStartupMs() => (long)(Time.realtimeSinceStartup * 1000f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24d54ced0c104fe8a73ca517313d3dda
|
||||
timeCreated: 1717509626
|
||||
@@ -0,0 +1,552 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
using Matrix4x4 = UnityEngine.Matrix4x4;
|
||||
using Quaternion = UnityEngine.Quaternion;
|
||||
using Vector3 = UnityEngine.Vector3;
|
||||
using From = Unity.AI.Navigation.Editor.Tests.NavMeshLinkEditorTests.LinkEndType;
|
||||
using To = Unity.AI.Navigation.Editor.Tests.NavMeshLinkEditorTests.LinkEndType;
|
||||
|
||||
// Note: To pause and inspect the state during these editor tests,
|
||||
// run them in playmode from the NavMeshLinkEditorTestsInPlaymode class
|
||||
// in the Unity.AI.Navigation.Editor.Tests.InPlaymode namespace.
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
public class NavMeshLinkEditorTests
|
||||
{
|
||||
List<UnityEngine.Object> m_TestObjects = new();
|
||||
GameObject m_LinkGameObject;
|
||||
GameObject m_Start;
|
||||
GameObject m_End;
|
||||
NavMeshLink m_Link;
|
||||
NavMeshLink m_LinkSibling1;
|
||||
NavMeshLink m_LinkSibling2;
|
||||
GameObject m_StartOnNavMesh;
|
||||
GameObject m_EndOnNavMesh;
|
||||
const int k_NotWalkable = 1;
|
||||
const int k_Walkable = 0;
|
||||
|
||||
static readonly Vector3EqualityComparer k_DefaultThreshold = Vector3EqualityComparer.Instance;
|
||||
|
||||
GameObject CreateTestObject(string name, params Type[] components)
|
||||
{
|
||||
var go = new GameObject(name, components);
|
||||
m_TestObjects.Add(go);
|
||||
return go;
|
||||
}
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_LinkGameObject = new GameObject("Link");
|
||||
m_Link = m_LinkGameObject.AddComponent<NavMeshLink>();
|
||||
m_Start = new GameObject("Start");
|
||||
m_End = new GameObject("End");
|
||||
|
||||
m_StartOnNavMesh = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_StartOnNavMesh.gameObject.transform.position = new Vector3(20.0f, 0.0f, 20.0f);
|
||||
|
||||
m_EndOnNavMesh = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_EndOnNavMesh.gameObject.transform.position = new Vector3(20.0f, 0.0f, 40.0f);
|
||||
|
||||
var surface = m_StartOnNavMesh.gameObject.AddComponent<NavMeshSurface>();
|
||||
surface.BuildNavMesh();
|
||||
|
||||
// To debug, add these components, only to show icons for them in the scene
|
||||
//m_Start.AddComponent<NavMeshSurface>().enabled = false;
|
||||
//m_End.AddComponent<NavMeshModifier>().enabled = false;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
if (m_LinkGameObject != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_LinkGameObject);
|
||||
if (m_Start != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_Start);
|
||||
if (m_End != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_End);
|
||||
if (m_StartOnNavMesh != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_StartOnNavMesh);
|
||||
if (m_EndOnNavMesh != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_EndOnNavMesh);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.area = k_Walkable;
|
||||
m_Link.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
|
||||
m_Link.transform.localScale = Vector3.one;
|
||||
m_Link.startPoint = Vector3.left;
|
||||
m_Link.endPoint = Vector3.right;
|
||||
}
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (m_LinkSibling1 != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_LinkSibling1);
|
||||
|
||||
if (m_LinkSibling2 != null)
|
||||
UnityEngine.Object.DestroyImmediate(m_LinkSibling2);
|
||||
|
||||
foreach (var obj in m_TestObjects)
|
||||
{
|
||||
if (obj != null)
|
||||
UnityEngine.Object.DestroyImmediate(obj);
|
||||
}
|
||||
|
||||
m_TestObjects.Clear();
|
||||
}
|
||||
|
||||
protected static readonly Vector3[] k_ReverseDirectionPositions =
|
||||
{ Vector3.zero, new(1f, 2f, 3f), new(1f, -2f, 3f) };
|
||||
protected static readonly Quaternion[] k_ReverseDirectionOrientations =
|
||||
{ Quaternion.identity, new(0f, 0.7071067812f, 0f, 0.7071067812f) };
|
||||
protected static readonly Vector3[] k_ReverseDirectionScales =
|
||||
{ Vector3.one, new(0.5f, 1f, 2f), new(0.5f, -1f, 2f) };
|
||||
|
||||
[Test]
|
||||
public void ReverseDirection_SwapsStartAndEndPoints(
|
||||
[ValueSource(nameof(k_ReverseDirectionPositions))]
|
||||
Vector3 position,
|
||||
[ValueSource(nameof(k_ReverseDirectionOrientations))]
|
||||
Quaternion orientation,
|
||||
[ValueSource(nameof(k_ReverseDirectionScales))]
|
||||
Vector3 scale
|
||||
)
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.transform.SetPositionAndRotation(position, orientation);
|
||||
m_Link.transform.localScale = scale;
|
||||
m_Link.startPoint = new Vector3(2f, 0f, 0f);
|
||||
m_Link.endPoint = new Vector3(0f, 0f, 2f);
|
||||
}
|
||||
|
||||
NavMeshLinkEditor.ReverseDirection(m_Link);
|
||||
|
||||
Assert.That(
|
||||
(m_Link.startPoint, m_Link.endPoint),
|
||||
Is.EqualTo((new Vector3(0f, 0f, 2f), new Vector3(2f, 0f, 0f))),
|
||||
"Start and end points did not swap."
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReverseDirection_SwapsStartAndEndPoints_TargetTransformsDoNotAffect(
|
||||
[ValueSource(nameof(k_ReverseDirectionPositions))]
|
||||
Vector3 position,
|
||||
[ValueSource(nameof(k_ReverseDirectionOrientations))]
|
||||
Quaternion orientation,
|
||||
[ValueSource(nameof(k_ReverseDirectionScales))]
|
||||
Vector3 scale
|
||||
)
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startTransform = CreateTestObject("Start").transform;
|
||||
m_Link.endTransform = CreateTestObject("End").transform;
|
||||
m_Link.transform.SetPositionAndRotation(position, orientation);
|
||||
m_Link.transform.localScale = scale;
|
||||
m_Link.startPoint = new Vector3(2f, 0f, 0f);
|
||||
m_Link.endPoint = new Vector3(0f, 0f, 2f);
|
||||
}
|
||||
|
||||
NavMeshLinkEditor.ReverseDirection(m_Link);
|
||||
|
||||
Assert.That(
|
||||
(m_Link.startPoint, m_Link.endPoint),
|
||||
Is.EqualTo((new Vector3(0f, 0f, 2f), new Vector3(2f, 0f, 0f))),
|
||||
"Start and end points did not swap."
|
||||
);
|
||||
}
|
||||
|
||||
protected static readonly TestCaseData[] k_LinkEnabledInitially =
|
||||
{
|
||||
new TestCaseData(true).SetName("Enabled before setting Not Walkable"),
|
||||
new TestCaseData(false).SetName("Disabled before setting Not Walkable")
|
||||
};
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(nameof(k_LinkEnabledInitially))]
|
||||
public void NavMeshLink_AfterSwitchingFromNonWalkableAreaType_BecomesWalkable(bool enabledInitially)
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startTransform = m_StartOnNavMesh.transform;
|
||||
m_Link.endTransform = m_EndOnNavMesh.transform;
|
||||
m_Link.area = k_Walkable;
|
||||
}
|
||||
|
||||
var navMeshLinkObject = new SerializedObject(m_Link.GetComponent<NavMeshLink>());
|
||||
var navMeshLinkEnabled = navMeshLinkObject.FindProperty("m_Enabled");
|
||||
var areaTypeProperty = navMeshLinkObject.FindProperty("m_Area");
|
||||
|
||||
var path = new NavMeshPath();
|
||||
|
||||
NavMesh.CalculatePath(m_StartOnNavMesh.transform.position, m_EndOnNavMesh.transform.position, NavMesh.AllAreas, path);
|
||||
Assume.That(path.status, Is.EqualTo(NavMeshPathStatus.PathComplete));
|
||||
|
||||
navMeshLinkEnabled.boolValue = enabledInitially;
|
||||
navMeshLinkObject.ApplyModifiedProperties();
|
||||
|
||||
areaTypeProperty.intValue = k_NotWalkable;
|
||||
navMeshLinkObject.ApplyModifiedProperties();
|
||||
|
||||
NavMesh.CalculatePath(m_StartOnNavMesh.transform.position, m_EndOnNavMesh.transform.position, NavMesh.AllAreas, path);
|
||||
Assume.That(path.status, Is.Not.EqualTo(NavMeshPathStatus.PathComplete));
|
||||
|
||||
navMeshLinkEnabled.boolValue = true;
|
||||
navMeshLinkObject.ApplyModifiedProperties();
|
||||
|
||||
areaTypeProperty.intValue = k_Walkable;
|
||||
navMeshLinkObject.ApplyModifiedProperties();
|
||||
|
||||
NavMesh.CalculatePath(m_StartOnNavMesh.transform.position, m_EndOnNavMesh.transform.position, NavMesh.AllAreas, path);
|
||||
Assert.That(path.status, Is.EqualTo(NavMeshPathStatus.PathComplete));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReverseDirection_SwapsStartAndEndTransforms()
|
||||
{
|
||||
var start = m_Link.startTransform = CreateTestObject("Start").transform;
|
||||
var end = m_Link.endTransform = CreateTestObject("End").transform;
|
||||
|
||||
NavMeshLinkEditor.ReverseDirection(m_Link);
|
||||
|
||||
Assert.That(
|
||||
(m_Link.startTransform, m_Link.endTransform),
|
||||
Is.EqualTo((end, start)),
|
||||
"Start and end transform did not swap."
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReverseDirection_OneTransformIsNotSet_SwapsStartAndEndTransforms()
|
||||
{
|
||||
var start = m_Link.startTransform = CreateTestObject("Start").transform;
|
||||
var end = m_Link.endTransform;
|
||||
|
||||
NavMeshLinkEditor.ReverseDirection(m_Link);
|
||||
|
||||
Assert.That(
|
||||
(m_Link.startTransform, m_Link.endTransform),
|
||||
Is.EqualTo((end, start)),
|
||||
"Start and end transform did not swap."
|
||||
);
|
||||
}
|
||||
|
||||
static readonly Vector3 k_Offset101 = new(1, 1, 1);
|
||||
static readonly Vector3 k_Offset103 = new(1, 1, 3);
|
||||
static readonly Quaternion k_DoNotRotate = Quaternion.identity;
|
||||
static readonly Quaternion k_FlipToRight = Quaternion.Euler(0, 0, -90);
|
||||
static readonly Quaternion k_UpSideDown = Quaternion.Euler(0, 0, 180);
|
||||
|
||||
//TestCaseData( startType, endType, transformRotation,
|
||||
// expectedPosition, expectedForward)
|
||||
protected static readonly TestCaseData[] k_PointsOnly =
|
||||
{
|
||||
new(From.Point, To.Point, k_DoNotRotate,
|
||||
new Vector3(1, 1, 2), Vector3.back),
|
||||
|
||||
new(From.Point, To.Point, k_UpSideDown,
|
||||
new Vector3(-1, -1, 2), Vector3.back),
|
||||
};
|
||||
protected static readonly TestCaseData[] k_PointAndTransforms =
|
||||
{
|
||||
new(From.Point, To.Transform, k_DoNotRotate,
|
||||
new Vector3(1, 2, 2), Vector3.back),
|
||||
|
||||
new(From.Point, To.Transform, k_FlipToRight,
|
||||
new Vector3(1, 1, 2), Quaternion.Euler(-116.565f, 0, -90) * Vector3.forward),
|
||||
|
||||
new(From.Transform, To.Point, k_DoNotRotate,
|
||||
new Vector3(1, 2, 2), Vector3.back),
|
||||
|
||||
new(From.Transform, To.Point, k_FlipToRight,
|
||||
new Vector3(1, 1, 2), Quaternion.Euler(116.565f, 0, -90) * Vector3.forward),
|
||||
|
||||
new(From.Transform, To.Transform, k_DoNotRotate,
|
||||
new Vector3(1, 3, 2), Vector3.back),
|
||||
|
||||
new(From.Transform, To.Transform, k_UpSideDown,
|
||||
new Vector3(1, 3, 2), Vector3.back),
|
||||
};
|
||||
protected static readonly TestCaseData[] k_ChildTransforms =
|
||||
{
|
||||
new(From.TransformChild, To.TransformChild, k_FlipToRight,
|
||||
new Vector3(3, -1, 2), Vector3.back),
|
||||
};
|
||||
|
||||
void ConfigureLinkForTest(From startType, To endType, Quaternion transformRotation)
|
||||
{
|
||||
m_Start.transform.position = k_Offset103 + 2f * Vector3.up;
|
||||
m_End.transform.position = k_Offset101 + 2f * Vector3.up;
|
||||
m_Start.transform.parent = startType == From.TransformChild ? m_Link.transform : null;
|
||||
m_End.transform.parent = endType == To.TransformChild ? m_Link.transform : null;
|
||||
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startPoint = k_Offset103;
|
||||
m_Link.endPoint = k_Offset101;
|
||||
m_Link.startTransform = startType != From.Point ? m_Start.transform : null;
|
||||
m_Link.endTransform = endType != To.Point ? m_End.transform : null;
|
||||
|
||||
m_Link.transform.rotation = transformRotation;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(k_PointsOnly))]
|
||||
[TestCaseSource(nameof(k_PointAndTransforms))]
|
||||
[TestCaseSource(nameof(k_ChildTransforms))]
|
||||
public void AlignTransformToEndPoints_MovesTransformInTheMiddle(
|
||||
From startType, To endType, Quaternion transformRotation,
|
||||
Vector3 expectedPosition, Vector3 _)
|
||||
{
|
||||
ConfigureLinkForTest(startType, endType, transformRotation);
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assert.That(m_Link.transform.position, Is.EqualTo(expectedPosition).Using(k_DefaultThreshold),
|
||||
"The Link object should be in the middle between the endpoints.");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(k_PointsOnly))]
|
||||
[TestCaseSource(nameof(k_PointAndTransforms))]
|
||||
[Description("When the endpoints remain at the same world position it means that the local points must have been adjusted correctly.")]
|
||||
public void AlignTransformToEndPoints_EndpointsWorldPositionsRemainUnchanged(
|
||||
From startType, To endType, Quaternion transformRotation,
|
||||
Vector3 _, Vector3 __)
|
||||
{
|
||||
ConfigureLinkForTest(startType, endType, transformRotation);
|
||||
|
||||
var initialEndpointsMatrix = LocalToWorldUnscaled(m_Link);
|
||||
var initialStartWorld = initialEndpointsMatrix.MultiplyPoint3x4(m_Link.startPoint);
|
||||
var initialEndWorld = initialEndpointsMatrix.MultiplyPoint3x4(m_Link.endPoint);
|
||||
var initialStartLocal = m_Link.startPoint;
|
||||
var initialEndLocal = m_Link.endPoint;
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assume.That(m_Link.startPoint, Is.Not.EqualTo(initialStartLocal).Using(k_DefaultThreshold),
|
||||
"The local position of Start point should have been adjusted.");
|
||||
|
||||
Assert.That(m_Link.endPoint, Is.Not.EqualTo(initialEndLocal).Using(k_DefaultThreshold),
|
||||
"The local position of End point should have been adjusted.");
|
||||
|
||||
var endpointsMatrix = LocalToWorldUnscaled(m_Link);
|
||||
var startWorld = endpointsMatrix.MultiplyPoint3x4(m_Link.startPoint);
|
||||
var endWorld = endpointsMatrix.MultiplyPoint3x4(m_Link.endPoint);
|
||||
|
||||
Assert.That(startWorld, Is.EqualTo(initialStartWorld).Using(k_DefaultThreshold),
|
||||
"The world position of Start should remain unchanged.");
|
||||
|
||||
Assert.That(endWorld, Is.EqualTo(initialEndWorld).Using(k_DefaultThreshold),
|
||||
"The world position of End should remain unchanged.");
|
||||
}
|
||||
|
||||
static Matrix4x4 LocalToWorldUnscaled(NavMeshLink link)
|
||||
{
|
||||
return Matrix4x4.TRS(link.transform.position, link.transform.rotation, Vector3.one);
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(k_PointAndTransforms))]
|
||||
[TestCaseSource(nameof(k_ChildTransforms))]
|
||||
public void AlignTransformToEndPoints_EndsTransformsRemainUnchanged(
|
||||
From startType, To endType, Quaternion transformRotation,
|
||||
Vector3 _, Vector3 __)
|
||||
{
|
||||
ConfigureLinkForTest(startType, endType, transformRotation);
|
||||
|
||||
var initialStartPosition = m_Link.startTransform != null ? m_Link.startTransform.position : Vector3.negativeInfinity;
|
||||
var initialEndPosition = m_Link.endTransform != null ? m_Link.endTransform.position : Vector3.negativeInfinity;
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
if (m_Link.startTransform != null)
|
||||
Assert.That(m_Link.startTransform.position, Is.EqualTo(initialStartPosition).Using(k_DefaultThreshold),
|
||||
"The Link start transform should not have moved.");
|
||||
|
||||
if (m_Link.endTransform != null)
|
||||
Assert.That(m_Link.endTransform.position, Is.EqualTo(initialEndPosition).Using(k_DefaultThreshold),
|
||||
"The Link end transform should not have moved.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Explicit("Functionality not implemented yet for child game objects")]
|
||||
public void AlignTransformToEndPoints_ChildGameObjectsRetainWorldPositions()
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startPoint = k_Offset103;
|
||||
m_Link.endPoint = k_Offset101;
|
||||
m_Link.startTransform = null;
|
||||
m_Link.endTransform = null;
|
||||
|
||||
m_Link.transform.rotation = k_FlipToRight;
|
||||
}
|
||||
|
||||
var child1 = CreateTestObject("Child 1").GetComponent<Transform>();
|
||||
var child2 = CreateTestObject("Child 2").GetComponent<Transform>();
|
||||
var grandchild = CreateTestObject("Grandchild").GetComponent<Transform>();
|
||||
child2.rotation = Quaternion.Euler(0, 90, 0);
|
||||
child1.parent = m_Link.transform;
|
||||
child2.parent = m_Link.transform;
|
||||
grandchild.parent = child2.transform;
|
||||
|
||||
child1.position = new Vector3(2, 1, 3);
|
||||
child2.position = new Vector3(-0.5f, 0.6f, 0.7f);
|
||||
grandchild.position = new Vector3(-3, 2, 1);
|
||||
var child1Earlier = child1.position;
|
||||
var child2Earlier = child2.position;
|
||||
var grandchildEarlier = grandchild.position;
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assert.That(child1.position, Is.EqualTo(child1Earlier).Using(k_DefaultThreshold),
|
||||
"Child object 1 should not have moved.");
|
||||
Assert.That(child2.position, Is.EqualTo(child2Earlier).Using(k_DefaultThreshold),
|
||||
"Child object 2 should not have moved.");
|
||||
Assert.That(grandchild.position, Is.EqualTo(grandchildEarlier).Using(k_DefaultThreshold),
|
||||
"Grandchild object should not have moved.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlignTransformToEndPoints_EndpointsWorldPositionsRemainUnchanged_InSiblingLinks()
|
||||
{
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startPoint = k_Offset103;
|
||||
m_Link.endPoint = k_Offset101;
|
||||
m_Link.startTransform = null;
|
||||
m_Link.endTransform = null;
|
||||
|
||||
m_Link.transform.rotation = k_FlipToRight;
|
||||
}
|
||||
|
||||
m_LinkSibling1 = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
m_LinkSibling2 = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
m_LinkSibling1.startPoint = m_Link.endPoint;
|
||||
m_LinkSibling1.endPoint = m_Link.startPoint;
|
||||
m_LinkSibling2.startPoint = m_Link.endPoint;
|
||||
m_LinkSibling2.endPoint = m_Link.startPoint;
|
||||
|
||||
var initialStartLocal = m_Link.startPoint;
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assume.That(m_Link.startPoint, Is.Not.EqualTo(initialStartLocal).Using(k_DefaultThreshold));
|
||||
|
||||
Assert.That(m_LinkSibling1.startPoint, Is.EqualTo(m_Link.endPoint).Using(k_DefaultThreshold),
|
||||
"The sibling 1 Start point should have been adjusted.");
|
||||
Assert.That(m_LinkSibling1.endPoint, Is.EqualTo(m_Link.startPoint).Using(k_DefaultThreshold),
|
||||
"The sibling 1 End point should have been adjusted.");
|
||||
|
||||
Assert.That(m_LinkSibling2.startPoint, Is.EqualTo(m_Link.endPoint).Using(k_DefaultThreshold),
|
||||
"The sibling 2 Start point should have been adjusted.");
|
||||
Assert.That(m_LinkSibling2.endPoint, Is.EqualTo(m_Link.startPoint).Using(k_DefaultThreshold),
|
||||
"The sibling 2 End point should have been adjusted.");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(k_PointsOnly))]
|
||||
[TestCaseSource(nameof(k_PointAndTransforms))]
|
||||
[TestCaseSource(nameof(k_ChildTransforms))]
|
||||
public void AlignTransformToEndPoints_UpVectorRemainsUnchanged(
|
||||
From startType, To endType, Quaternion transformRotation,
|
||||
Vector3 _, Vector3 __)
|
||||
{
|
||||
ConfigureLinkForTest(startType, endType, transformRotation);
|
||||
|
||||
var initialUp = m_Link.transform.up;
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assert.That(m_Link.transform.up, Is.EqualTo(initialUp).Using(k_DefaultThreshold),
|
||||
"The Link's up vector should remain unchanged.");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(k_PointsOnly))]
|
||||
[TestCaseSource(nameof(k_PointAndTransforms))]
|
||||
[TestCaseSource(nameof(k_ChildTransforms))]
|
||||
public void AlignTransformToEndPoints_OrientsForwardVectorFromStartToEndInXZPlane(
|
||||
From startType, To endType, Quaternion transformRotation,
|
||||
Vector3 _, Vector3 expectedForward)
|
||||
{
|
||||
ConfigureLinkForTest(startType, endType, transformRotation);
|
||||
|
||||
NavMeshLinkEditor.AlignTransformToEndPoints(m_Link);
|
||||
|
||||
Assert.That(m_Link.transform.forward, Is.EqualTo(expectedForward).Using(k_DefaultThreshold),
|
||||
"The Link's forward vector should point from the start towards the end of the link.");
|
||||
}
|
||||
|
||||
static readonly Vector3 k_ForwardRightDiagonal = Quaternion.Euler(0, 45, 0) * Vector3.forward;
|
||||
static readonly Quaternion k_RotatedX90 = Quaternion.Euler(90, 0, 0);
|
||||
static readonly Quaternion k_RotatedY180 = Quaternion.Euler(0, 180, 0);
|
||||
static readonly Quaternion k_RotatedZ90 = Quaternion.Euler(0, 0, 90);
|
||||
static readonly Quaternion k_RotatedZ180 = Quaternion.Euler(0, 0, 180);
|
||||
protected static readonly TestCaseData[] k_RotateToChangeLinkDirectionLocally =
|
||||
{
|
||||
new TestCaseData(Quaternion.identity, Vector3.right, Vector3.one)
|
||||
.SetName("Link aligned to World axes"),
|
||||
|
||||
new TestCaseData(k_RotatedX90, Vector3.zero, new Vector3(1, 1, -1))
|
||||
.SetName("Endpoints following the Up direction")
|
||||
.SetDescription("The right vector cannot be properly defined in this case"),
|
||||
|
||||
new TestCaseData(k_RotatedY180, Vector3.forward, new Vector3(-1, 1, -1))
|
||||
.SetName("Endpoints following Right direction"),
|
||||
|
||||
new TestCaseData(k_RotatedZ90, Vector3.right, new Vector3(1, -1, 1))
|
||||
.SetName("Link tipped to the left"),
|
||||
|
||||
new TestCaseData(k_RotatedZ180, k_ForwardRightDiagonal, new Vector3(-1, -1, 1))
|
||||
.SetName("Link rotated freely")
|
||||
.SetDescription("The rotation has been chosen to produce a Right vector easy to identify and verify."),
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(k_RotateToChangeLinkDirectionLocally))]
|
||||
[Description("The link's direction changes because the end transform moves in local space when the game object rotates.")]
|
||||
public void CalcLinkRight_ReturnsLocalRightIn2D(
|
||||
Quaternion transformRotation,
|
||||
Vector3 expectedLocalRight, Vector3 expectedEnd)
|
||||
{
|
||||
m_Link.transform.SetPositionAndRotation(Vector3.one, transformRotation);
|
||||
m_Link.transform.localScale = 2f * Vector3.one;
|
||||
m_End.transform.position = 2f * Vector3.one;
|
||||
|
||||
using (new NavMeshLinkEditor.DeferredLinkUpdateScope(m_Link))
|
||||
{
|
||||
m_Link.startPoint = new Vector3(1, -1, -1);
|
||||
m_Link.endTransform = m_End.transform;
|
||||
|
||||
m_Link.startTransform = null;
|
||||
m_Link.endPoint = Vector3.negativeInfinity;
|
||||
}
|
||||
|
||||
var linkRight = NavMeshLinkEditor.GetLocalDirectionRight(m_Link, out var localStart, out var localEnd);
|
||||
|
||||
Assume.That(localStart, Is.EqualTo(m_Link.startPoint).Using(k_DefaultThreshold), "Wrong local Start reported.");
|
||||
Assume.That(localEnd, Is.EqualTo(expectedEnd).Using(k_DefaultThreshold), "Wrong local End reported.");
|
||||
|
||||
Assert.That(linkRight, Is.EqualTo(expectedLocalRight).Using(k_DefaultThreshold),
|
||||
"Wrong Right vector relative to the direction from start to end.");
|
||||
}
|
||||
|
||||
public enum LinkEndType
|
||||
{
|
||||
Point,
|
||||
Transform,
|
||||
TransformChild
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6edd135750744d2ba70784191858ba6e
|
||||
timeCreated: 1707859138
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
class NavMeshLinkInPrefabTests
|
||||
{
|
||||
[Test]
|
||||
public void NavMeshLink_DifferentGOActiveState_PromotedToPrefab_InstanceHasNoOverrides([Values]bool isActive)
|
||||
{
|
||||
var assetPath = $"Assets/{GUID.Generate()}.prefab";
|
||||
NavMeshLink nml = null;
|
||||
try
|
||||
{
|
||||
var go = new GameObject("NavMesh Link");
|
||||
go.SetActive(isActive);
|
||||
nml = go.AddComponent<NavMeshLink>();
|
||||
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(nml.gameObject, assetPath, InteractionMode.AutomatedAction);
|
||||
|
||||
var sp = new SerializedObject(nml).GetIterator();
|
||||
var overrides = new List<string>();
|
||||
while (sp.NextVisible(true))
|
||||
{
|
||||
if (!sp.isDefaultOverride && sp.prefabOverride)
|
||||
overrides.Add(sp.propertyPath);
|
||||
}
|
||||
Assert.That(overrides, Is.Empty, "Newly promoted prefab instance overrides one or more properties.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (nml != null)
|
||||
Object.DestroyImmediate(nml.gameObject);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5b652cf08f54e3bae634658f9a4e119
|
||||
timeCreated: 1710416712
|
||||
@@ -0,0 +1,179 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions.Comparers;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
internal class NavMeshLinkTests : DomainReloadTestBase
|
||||
{
|
||||
const string k_TrackedListFieldName = "s_Tracked";
|
||||
|
||||
[SerializeField] NavMeshLink m_Link;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackedList_AddOneItemToListInEditMode_TrackedListSetToZeroInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var listVar = GetTrackedList();
|
||||
Assume.That(listVar, Is.Not.Null);
|
||||
Assume.That(listVar.Count, Is.Zero);
|
||||
|
||||
listVar.Add(null);
|
||||
Assume.That(listVar.Count, Is.Not.Zero);
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
listVar = GetTrackedList();
|
||||
Assert.That(listVar.Count, Is.Zero);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackedList_CreateAutoUpdatedNavMeshLinkInEditMode_NavMeshLinkRemainsInTrackedListInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var trackedList = GetTrackedList();
|
||||
Assume.That(trackedList, Is.Not.Null);
|
||||
Assume.That(trackedList.Count, Is.Zero);
|
||||
|
||||
// Create a link during edit mode.
|
||||
// Setting it up so that it gets added to the tracked list.
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshLink));
|
||||
m_Link = m_TestGo.GetComponent<NavMeshLink>();
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
trackedList = GetTrackedList();
|
||||
Assume.That(trackedList, Is.Not.Null);
|
||||
Assume.That(trackedList.Count, Is.EqualTo(1));
|
||||
Assume.That(trackedList[0], Is.EqualTo(m_Link));
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
trackedList = GetTrackedList();
|
||||
Assert.That(trackedList.Count, Is.EqualTo(1));
|
||||
Assert.That(trackedList[0], Is.EqualTo(m_Link));
|
||||
}
|
||||
|
||||
static List<NavMeshLink> GetTrackedList()
|
||||
{
|
||||
var field = typeof(NavMeshLink).GetField(k_TrackedListFieldName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||
Assume.That(field, Is.Not.Null, $"Cannot find field '{k_TrackedListFieldName}' in class {nameof(NavMeshLink)}.");
|
||||
return field?.GetValue(null) as List<NavMeshLink>;
|
||||
}
|
||||
|
||||
[TestCase(0, 0, true, TestName = "CostModifier at 0 should override cost and return 0.")]
|
||||
[TestCase(1, 1, true, TestName = "CostModifier at 1 should override cost and return 1.")]
|
||||
[TestCase(-1, 1, false, TestName = "CostModifier at -1 should not override cost and return 1.")]
|
||||
[TestCase(42, 42, true, TestName = "CostModifier at 42 should override cost and return 42.")]
|
||||
[TestCase(-42, 42, false, TestName = "CostModifier at -42 should not override cost and return 42.")]
|
||||
public void CostModifier_SetValue_SerializedPropertyIsTheSame(int costModifier, float expectedCostValue, bool expectedOverrideValue)
|
||||
{
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshLink));
|
||||
m_Link = m_TestGo.GetComponent<NavMeshLink>();
|
||||
m_Link.costModifier = costModifier;
|
||||
|
||||
var serializedObject = new SerializedObject(m_Link);
|
||||
var costModifierProperty = serializedObject.FindProperty("m_CostModifier");
|
||||
var isOverridingCostProperty = serializedObject.FindProperty("m_IsOverridingCost");
|
||||
|
||||
Assume.That(costModifierProperty, Is.Not.Null, "Cannot find property 'm_CostModifier' in NavMeshLink.");
|
||||
Assume.That(isOverridingCostProperty, Is.Not.Null, "Cannot find property 'm_IsOverridingCost' in NavMeshLink.");
|
||||
|
||||
Assert.That(costModifierProperty.floatValue, Is.EqualTo(expectedCostValue).Using(FloatComparer.s_ComparerWithDefaultTolerance));
|
||||
Assert.That(isOverridingCostProperty.boolValue, Is.EqualTo(expectedOverrideValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CostModifier_Reset_CostModifierRunsThroughUpgrader()
|
||||
{
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshLink));
|
||||
m_Link = m_TestGo.GetComponent<NavMeshLink>();
|
||||
m_Link.costModifier = 42;
|
||||
|
||||
var serializedObject = new SerializedObject(m_Link);
|
||||
var costModifierProperty = serializedObject.FindProperty("m_CostModifier");
|
||||
var isOverridingCostProperty = serializedObject.FindProperty("m_IsOverridingCost");
|
||||
|
||||
Assume.That(costModifierProperty.floatValue, Is.EqualTo(42f), "Cost modifier is not 42.");
|
||||
Assume.That(isOverridingCostProperty.boolValue, Is.True, "Is overriding cost is false.");
|
||||
|
||||
Unsupported.SmartReset(m_Link);
|
||||
serializedObject.Update();
|
||||
|
||||
Assume.That(costModifierProperty, Is.Not.Null, "Cannot find property 'm_CostModifier' in NavMeshLink.");
|
||||
Assume.That(isOverridingCostProperty, Is.Not.Null, "Cannot find property 'm_IsOverridingCost' in NavMeshLink.");
|
||||
|
||||
Assert.That(costModifierProperty.floatValue, Is.EqualTo(1f), "Cost modifier is not 1.");
|
||||
Assert.That(isOverridingCostProperty.boolValue, Is.False, "Is overriding cost is true.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NavMeshLink_Reset_NavMeshLinkHasDefaultValues()
|
||||
{
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshLink));
|
||||
m_Link = m_TestGo.GetComponent<NavMeshLink>();
|
||||
m_Link.costModifier = 42;
|
||||
|
||||
Unsupported.SmartReset(m_Link);
|
||||
|
||||
AssertNavMeshLinkHasDefaultValues(m_Link);
|
||||
}
|
||||
|
||||
static void AssertNavMeshLinkHasDefaultValues(NavMeshLink link)
|
||||
{
|
||||
var serializedObject = new SerializedObject(link);
|
||||
serializedObject.Update();
|
||||
|
||||
var serializedVersionProperty = serializedObject.FindProperty("m_SerializedVersion");
|
||||
var agentTypeIdProperty = serializedObject.FindProperty("m_AgentTypeID");
|
||||
var startPointProperty = serializedObject.FindProperty("m_StartPoint");
|
||||
var endPointProperty = serializedObject.FindProperty("m_EndPoint");
|
||||
var startTransformProperty = serializedObject.FindProperty("m_StartTransform");
|
||||
var endTransformProperty = serializedObject.FindProperty("m_EndTransform");
|
||||
var activatedProperty = serializedObject.FindProperty("m_Activated");
|
||||
var widthProperty = serializedObject.FindProperty("m_Width");
|
||||
var costModifierProperty = serializedObject.FindProperty("m_CostModifier");
|
||||
var isOverridingCostProperty = serializedObject.FindProperty("m_IsOverridingCost");
|
||||
var bidirectionalProperty = serializedObject.FindProperty("m_Bidirectional");
|
||||
var autoUpdatePositionProperty = serializedObject.FindProperty("m_AutoUpdatePosition");
|
||||
var areaProperty = serializedObject.FindProperty("m_Area");
|
||||
|
||||
Assume.That(serializedVersionProperty, Is.Not.Null, "Cannot find property 'm_SerializedVersion' in NavMeshLink.");
|
||||
Assume.That(agentTypeIdProperty, Is.Not.Null, "Cannot find property 'm_AgentTypeID' in NavMeshLink.");
|
||||
Assume.That(startPointProperty, Is.Not.Null, "Cannot find property 'm_StartPoint' in NavMeshLink.");
|
||||
Assume.That(endPointProperty, Is.Not.Null, "Cannot find property 'm_EndPoint' in NavMeshLink.");
|
||||
Assume.That(startTransformProperty, Is.Not.Null, "Cannot find property 'm_StartTransform' in NavMeshLink.");
|
||||
Assume.That(endTransformProperty, Is.Not.Null, "Cannot find property 'm_EndTransform' in NavMeshLink.");
|
||||
Assume.That(activatedProperty, Is.Not.Null, "Cannot find property 'm_Activated' in NavMeshLink.");
|
||||
Assume.That(widthProperty, Is.Not.Null, "Cannot find property 'm_Width' in NavMeshLink.");
|
||||
Assume.That(costModifierProperty, Is.Not.Null, "Cannot find property 'm_CostModifier' in NavMeshLink.");
|
||||
Assume.That(isOverridingCostProperty, Is.Not.Null, "Cannot find property 'm_IsOverridingCost' in NavMeshLink.");
|
||||
Assume.That(bidirectionalProperty, Is.Not.Null, "Cannot find property 'm_Bidirectional' in NavMeshLink.");
|
||||
Assume.That(autoUpdatePositionProperty, Is.Not.Null, "Cannot find property 'm_AutoUpdatePosition' in NavMeshLink.");
|
||||
Assume.That(areaProperty, Is.Not.Null, "Cannot find property 'm_Area' in NavMeshLink.");
|
||||
|
||||
Assert.That(serializedVersionProperty.intValue, Is.EqualTo(1), "Serialized version is not 1.");
|
||||
Assert.That(agentTypeIdProperty.intValue, Is.EqualTo(0), "Agent type ID is not 0.");
|
||||
Assert.That(startPointProperty.vector3Value, Is.EqualTo(new Vector3(0f, 0f, -2.50f)), "Start point is not at (0, 0, -2.50).");
|
||||
Assert.That(endPointProperty.vector3Value, Is.EqualTo(new Vector3(0f, 0f, 2.50f)), "End point is not at (0, 0, 2.50).");
|
||||
Assert.That(startTransformProperty.objectReferenceValue, Is.Null, "Start transform is not null.");
|
||||
Assert.That(endTransformProperty.objectReferenceValue, Is.Null, "End transform is not null.");
|
||||
Assert.That(activatedProperty.boolValue, Is.True, "Link is not activated.");
|
||||
Assert.That(widthProperty.floatValue, Is.Zero, "Width is not 0.");
|
||||
Assert.That(bidirectionalProperty.boolValue, Is.True, "Link is not bidirectional.");
|
||||
Assert.That(autoUpdatePositionProperty.boolValue, Is.False, "Auto update position is true.");
|
||||
Assert.That(areaProperty.intValue, Is.EqualTo(0), "Area is not 0.");
|
||||
|
||||
Assert.That(costModifierProperty.floatValue, Is.EqualTo(1f), "Cost modifier is not 1.");
|
||||
Assert.That(isOverridingCostProperty.boolValue, Is.False, "Is overriding cost is true.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 612fb35aac99445d9d7560fe6ad2c4f4
|
||||
timeCreated: 1700481746
|
||||
@@ -0,0 +1,167 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
//#define KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
class NavMeshLinkUpgradeInPrefabTests
|
||||
{
|
||||
// Adjust these tests whenever you change the content of the prefab
|
||||
const string k_PrefabName = "TestBundleWithAllLinks.prefab";
|
||||
const string k_ParentFolder = "Assets";
|
||||
const string k_TempFolder = "TempLinkUpgrade";
|
||||
static readonly string k_TempFolderPath = Path.Combine(k_ParentFolder, k_TempFolder);
|
||||
static readonly string k_TestPrefabPath = Path.Combine(k_TempFolderPath, k_PrefabName);
|
||||
static readonly string k_PrebuiltPrefabPath = Path.Combine("Packages", "com.unity.ai.navigation", "Tests", "PrebuiltAssets~", k_PrefabName);
|
||||
|
||||
[SerializeField]
|
||||
string m_PreviousScenePath;
|
||||
|
||||
[SerializeField]
|
||||
GameObject m_LinkPrefab;
|
||||
GameObject m_PrefabInstance;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
AssetDatabase.DeleteAsset(k_TempFolderPath);
|
||||
var folderGUID = AssetDatabase.CreateFolder(k_ParentFolder, k_TempFolder);
|
||||
Assume.That(folderGUID, Is.Not.Empty);
|
||||
|
||||
File.Copy(k_PrebuiltPrefabPath, k_TestPrefabPath);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
m_LinkPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(k_TestPrefabPath);
|
||||
|
||||
m_PreviousScenePath = SceneManager.GetActiveScene().path;
|
||||
}
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator SetUp()
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_PrefabInstance);
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_PreviousScenePath))
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
else
|
||||
EditorSceneManager.OpenScene(m_PreviousScenePath);
|
||||
|
||||
#if !KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
AssetDatabase.DeleteAsset(k_TempFolderPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrefabLinkVersion2_0_0_Instantiated_WarnsAboutOutdatedFormat()
|
||||
{
|
||||
ForgetPastWarnings();
|
||||
|
||||
LogAssert.Expect(LogType.Warning, new Regex("A NavMesh Link component has an outdated format..*"));
|
||||
|
||||
m_PrefabInstance = TestUtility.InstantiatePrefab(m_LinkPrefab, "Links Prefab Instance");
|
||||
Assume.That(m_PrefabInstance, Is.Not.Null);
|
||||
|
||||
#if KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
var sceneWithPrefab = Path.Combine(k_TempFolderPath, "SceneWithPrefab1.unity");
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), sceneWithPrefab);
|
||||
#endif
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrefabLinkVersion2_0_0_WhenInstantiated_KeepsReferencesToOtherObjects()
|
||||
{
|
||||
m_PrefabInstance = TestUtility.InstantiatePrefab(m_LinkPrefab, "Links Prefab Instance");
|
||||
|
||||
#if KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
var sceneWithPrefab = Path.Combine(k_TempFolderPath, "SceneWithPrefab2.unity");
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), sceneWithPrefab);
|
||||
#endif
|
||||
var scaledParent = m_PrefabInstance.transform.Find("Scaled_Links_Root");
|
||||
Assume.That(scaledParent, Is.Not.Null, "There should be a Scaled_Links_Root object.");
|
||||
var objectWithLinks = scaledParent.transform.Find("Multiple NavMesh Links");
|
||||
Assume.That(objectWithLinks, Is.Not.Null, "There should be a Multiple NavMesh Links object.");
|
||||
var links = objectWithLinks.GetComponents<NavMeshLink>();
|
||||
Assume.That(links.Length, Is.EqualTo(4));
|
||||
|
||||
foreach (var navMeshLink in links)
|
||||
{
|
||||
// Differentiate links by width
|
||||
if (Math.Abs(navMeshLink.width - 1f) < 0.1f)
|
||||
{
|
||||
Assert.That(navMeshLink.startTransform, Is.Null,
|
||||
"Start Transform self-reference should have been removed in first link.");
|
||||
Assert.That(navMeshLink.endTransform, Is.Null,
|
||||
"End Transform self-reference should have been removed in first link.");
|
||||
}
|
||||
else if (Math.Abs(navMeshLink.width - 2f) < 0.1f)
|
||||
{
|
||||
Assert.That(navMeshLink.startTransform.name, Is.EqualTo("Bundle Plane 2"),
|
||||
"Start Transform should reference Bundle Plane 2 in second link.");
|
||||
Assert.That(navMeshLink.endTransform, Is.SameAs(navMeshLink.startTransform),
|
||||
"Start Transform and End Transform should reference the same object in second link.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Explicit("Entering playmode is rather slow and the situation being tested happens rarely")]
|
||||
public IEnumerator PrefabLinkVersion2_0_0_WhenInstantiatedInPlaymode_WarnsAboutOutdatedReferences()
|
||||
{
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
LogAssert.Expect(LogType.Warning, new Regex(
|
||||
"The NavMesh Link component does not reference the intended transforms.*"));
|
||||
|
||||
m_PrefabInstance = TestUtility.InstantiatePrefab(m_LinkPrefab, "Links Prefab Instance In Playmode");
|
||||
|
||||
var scaledObjectWithLinks = GameObject.Find("Multiple NavMesh Links");
|
||||
Assume.That(scaledObjectWithLinks, Is.Not.Null);
|
||||
var linksFromScaledObject = scaledObjectWithLinks.GetComponents<NavMeshLink>();
|
||||
Assume.That(linksFromScaledObject.Length, Is.EqualTo(4));
|
||||
|
||||
var unscaledObjectWithLinks = GameObject.Find("Unscaled Links");
|
||||
Assume.That(unscaledObjectWithLinks, Is.Not.Null);
|
||||
var linksFromUnscaledObject = unscaledObjectWithLinks.GetComponents<NavMeshLink>();
|
||||
Assume.That(linksFromUnscaledObject.Length, Is.EqualTo(3));
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
}
|
||||
|
||||
static void ForgetPastWarnings()
|
||||
{
|
||||
var lastWarnedPrefab = typeof(NavMeshLink).GetField("s_LastWarnedPrefab",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
Assume.That(lastWarnedPrefab, Is.Not.Null,
|
||||
"Correct the test script if NavMeshLink.s_LastWarnedPrefab has been renamed or removed.");
|
||||
lastWarnedPrefab?.SetValue(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bee8f0175a385304086f01e517a21ff8
|
||||
@@ -0,0 +1,228 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
//#define KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
class NavMeshLinkUpgradeTests
|
||||
{
|
||||
// Adjust these tests whenever you change the content of the scene
|
||||
const string k_SceneName = "Test_Links_Created_With_2_0_0.unity";
|
||||
const string k_ParentFolder = "Assets";
|
||||
const string k_TempFolder = "TempLinkUpgrade";
|
||||
static readonly string k_TempFolderPath = Path.Combine(k_ParentFolder, k_TempFolder);
|
||||
static readonly string k_TestScenePath = Path.Combine(k_TempFolderPath, k_SceneName);
|
||||
static readonly string k_PrebuiltScenePath = Path.Combine("Packages", "com.unity.ai.navigation", "Tests", "PrebuiltAssets~", k_SceneName);
|
||||
|
||||
string m_PreviousScenePath;
|
||||
bool m_DelayCallHappened;
|
||||
|
||||
GameObject m_ScaledObjectWithLinks;
|
||||
GameObject m_UnscaledObjectWithLinks;
|
||||
NavMeshLink[] m_LinksFromScaledObject;
|
||||
NavMeshLink[] m_LinksFromUnscaledObject;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
AssetDatabase.DeleteAsset(k_TempFolderPath);
|
||||
var folderGUID = AssetDatabase.CreateFolder(k_ParentFolder, k_TempFolder);
|
||||
Assume.That(folderGUID, Is.Not.Empty);
|
||||
|
||||
File.Copy(k_PrebuiltScenePath, k_TestScenePath);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
m_PreviousScenePath = SceneManager.GetActiveScene().path;
|
||||
var testScene = EditorSceneManager.OpenScene(k_TestScenePath);
|
||||
Assume.That(testScene, Is.Not.Null, "The test scene should exist under the Assets folder.");
|
||||
|
||||
m_ScaledObjectWithLinks = GameObject.Find("Multiple NavMesh Links");
|
||||
Assume.That(m_ScaledObjectWithLinks, Is.Not.Null);
|
||||
m_LinksFromScaledObject = m_ScaledObjectWithLinks.GetComponents<NavMeshLink>();
|
||||
Assume.That(m_LinksFromScaledObject.Length, Is.EqualTo(4));
|
||||
|
||||
m_UnscaledObjectWithLinks = GameObject.Find("Unscaled Links");
|
||||
Assume.That(m_UnscaledObjectWithLinks, Is.Not.Null);
|
||||
m_LinksFromUnscaledObject = m_UnscaledObjectWithLinks.GetComponents<NavMeshLink>();
|
||||
Assume.That(m_LinksFromUnscaledObject.Length, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator SetUp()
|
||||
{
|
||||
if (!m_DelayCallHappened)
|
||||
{
|
||||
// Allow for the Link upgrade to be completed by the delayCall
|
||||
EditorApplication.delayCall += () => m_DelayCallHappened = true;
|
||||
|
||||
yield return new WaitUntil(() => m_DelayCallHappened);
|
||||
yield return null;
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScaledLinkVersion2_0_0_WhenLoaded_HasCorrectStart([NUnit.Framework.Range(0, 3)] int i)
|
||||
{
|
||||
var link = m_LinksFromScaledObject[i];
|
||||
var desc = $"(scaled[{i}]_{link.width}_{link.costModifier})";
|
||||
|
||||
Assert.That(link.startTransform, Is.Null.Or.Not.SameAs(link.gameObject.transform),
|
||||
"The start transform should not point to the link GameObject itself. {0}", desc);
|
||||
|
||||
if (link.startTransform != null)
|
||||
{
|
||||
var startParent = link.startTransform.parent;
|
||||
if (startParent != null)
|
||||
{
|
||||
Assert.That(startParent.name, Is.EqualTo("Plane 2"),
|
||||
"The start transform should be a child of Plane 2. {0}", desc);
|
||||
Assert.That(link.startTransform.name, Contains.Substring($"Link Start {link.name}"),
|
||||
"The new start transform should be named after the link that uses it. {0}", desc);
|
||||
|
||||
Assert.That(link.startTransform.position, Is.Not.EqualTo(Vector3.zero),
|
||||
"The new start transform should be placed away from origin. {0}", desc);
|
||||
Assert.That(link.startTransform.position, Is.Not.EqualTo(startParent.position),
|
||||
"The new start transform should be placed away from the parent. {0}", desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(link.startPoint, Is.EqualTo(Vector3.zero).Using(new Vector3EqualityComparer(0.001f)),
|
||||
"Start Point should be around zero when start transform keeps the original reference. {0}", desc);
|
||||
Assert.That(link.startTransform.name, Is.EqualTo("NavMesh Surface"),
|
||||
"The upgraded link should keep referencing the GameObject NavMesh Surface. {0}", desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScaledLinkVersion2_0_0_WhenLoaded_HasCorrectEnd([NUnit.Framework.Range(0, 3)] int i)
|
||||
{
|
||||
var link = m_LinksFromScaledObject[i];
|
||||
var desc = $"(scaled[{i}]_{link.width}_{link.costModifier})";
|
||||
|
||||
Assert.That(link.endTransform, Is.Null.Or.Not.SameAs(link.gameObject.transform),
|
||||
"The end transform should not point to the link GameObject itself. {0}", desc);
|
||||
|
||||
if (link.endTransform != null)
|
||||
{
|
||||
var endParent = link.endTransform.parent;
|
||||
if (endParent != null)
|
||||
{
|
||||
Assert.That(link.endTransform.parent.name, Is.EqualTo("Plane 2"),
|
||||
"The end transform should be a child of Plane 2. {0}", desc);
|
||||
Assert.That(link.endTransform.name, Contains.Substring($"Link End {link.name}"),
|
||||
"The new end transform should be named after the link that uses it. {0}", desc);
|
||||
|
||||
Assert.That(link.endTransform.position, Is.Not.EqualTo(Vector3.zero),
|
||||
"The new end transform should be placed away from origin. {0}", desc);
|
||||
Assert.That(link.endTransform.position, Is.Not.EqualTo(endParent.position),
|
||||
"The new end transform should be placed away from the parent. {0}", desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(link.endPoint, Is.EqualTo(Vector3.zero).Using(new Vector3EqualityComparer(0.001f)),
|
||||
"End Point should be around zero when end transform keeps the original reference. {0}", desc);
|
||||
Assert.That(link.endTransform.name, Is.EqualTo("Plane 2"),
|
||||
"The upgraded link should keep referencing the GameObject Plane 2. {0}", desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnscaledLinkVersion2_0_0_WhenLoaded_HasCorrectStart([NUnit.Framework.Range(0, 2)] int i)
|
||||
{
|
||||
var link = m_LinksFromUnscaledObject[i];
|
||||
var desc = $"(unscaled[{i}]_{link.width}_{link.costModifier})";
|
||||
|
||||
Assert.That(link.startTransform, Is.Null.Or.Not.SameAs(link.gameObject.transform),
|
||||
"The start transform should not point to the link GameObject itself. {0}", desc);
|
||||
|
||||
if (link.startTransform != null)
|
||||
{
|
||||
var startParent = link.startTransform.parent;
|
||||
if (startParent != null)
|
||||
{
|
||||
Assert.That(startParent.name, Is.EqualTo("Plane 2"),
|
||||
"The start transform should be a child of Plane 2. {0}", desc);
|
||||
Assert.That(link.startTransform.name, Contains.Substring($"Link Start {link.name}"),
|
||||
"The new start transform should be named after the link that uses it. {0}", desc);
|
||||
|
||||
Assert.That(link.startTransform.position, Is.Not.EqualTo(Vector3.zero),
|
||||
"The new start transform should be placed away from origin. {0}", desc);
|
||||
Assert.That(link.startTransform.position, Is.Not.EqualTo(startParent.position),
|
||||
"The new start transform should be placed away from the parent. {0}", desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(link.startPoint, Is.EqualTo(Vector3.zero).Using(new Vector3EqualityComparer(0.001f)),
|
||||
"Start Point should be around zero when start transform keeps the original reference. {0}", desc);
|
||||
Assert.That(link.startTransform.name, Is.EqualTo("NavMesh Surface"),
|
||||
"The upgraded link should keep referencing the GameObject NavMesh Surface. {0}", desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnscaledLinkVersion2_0_0_WhenLoaded_HasCorrectEnd([NUnit.Framework.Range(0, 2)] int i)
|
||||
{
|
||||
var link = m_LinksFromUnscaledObject[i];
|
||||
var desc = $"(unscaled[{i}]_{link.width}_{link.costModifier})";
|
||||
|
||||
Assert.That(link.endTransform, Is.Null.Or.Not.SameAs(link.gameObject.transform),
|
||||
"The end transform should not point to the link GameObject itself. {0}", desc);
|
||||
|
||||
if (link.endTransform != null)
|
||||
{
|
||||
var endParent = link.endTransform.parent;
|
||||
if (endParent != null)
|
||||
{
|
||||
Assert.That(link.endTransform.parent.name, Is.EqualTo("Plane 2"),
|
||||
"The end transform should be a child of Plane 2. {0}", desc);
|
||||
Assert.That(link.endTransform.name, Contains.Substring($"Link End {link.name}"),
|
||||
"The new end transform should be named after the link that uses it. {0}", desc);
|
||||
|
||||
Assert.That(link.endTransform.position, Is.Not.EqualTo(Vector3.zero),
|
||||
"The new end transform should be placed away from origin. {0}", desc);
|
||||
Assert.That(link.endTransform.position, Is.Not.EqualTo(endParent.position),
|
||||
"The new end transform should be placed away from the parent. {0}", desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(link.endPoint, Is.EqualTo(Vector3.zero).Using(new Vector3EqualityComparer(0.001f)),
|
||||
"End Point should be around zero when end transform keeps the original reference. {0}", desc);
|
||||
Assert.That(link.endTransform.name, Is.EqualTo("Plane 2"),
|
||||
"The upgraded link should keep referencing the GameObject Plane 2. {0}", desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
Assume.That(SceneManager.GetActiveScene().isDirty, Is.False,
|
||||
"Scene should not have changed after it was saved in SetUp.");
|
||||
|
||||
if (string.IsNullOrEmpty(m_PreviousScenePath))
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
else
|
||||
EditorSceneManager.OpenScene(m_PreviousScenePath);
|
||||
|
||||
#if !KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
AssetDatabase.DeleteAsset(k_TempFolderPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ad450d9888c160469d649a7d37fe5f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
internal class NavMeshModifierTests : DomainReloadTestBase
|
||||
{
|
||||
[SerializeField] NavMeshModifier m_Modifier;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveModifiers_AddOneItemToListInEditMode_ModifierListSetToZeroInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeModifiers = NavMeshModifier.activeModifiers;
|
||||
Assume.That(activeModifiers, Is.Not.Null);
|
||||
Assume.That(activeModifiers.Count, Is.Zero);
|
||||
|
||||
activeModifiers.Add(null);
|
||||
Assume.That(activeModifiers.Count, Is.Not.Zero);
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
activeModifiers = NavMeshModifier.activeModifiers;
|
||||
Assert.That(activeModifiers.Count, Is.Zero);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveModifiers_CreateModifierInEditMode_ModifierRemainsInActiveModifiersInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeModifiers = NavMeshModifier.activeModifiers;
|
||||
Assume.That(activeModifiers, Is.Not.Null);
|
||||
Assume.That(activeModifiers.Count, Is.Zero);
|
||||
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshModifier));
|
||||
m_Modifier = m_TestGo.GetComponent<NavMeshModifier>();
|
||||
|
||||
activeModifiers = NavMeshModifier.activeModifiers;
|
||||
Assume.That(activeModifiers, Is.Not.Null);
|
||||
Assume.That(activeModifiers.Count, Is.EqualTo(1));
|
||||
Assume.That(activeModifiers[0], Is.EqualTo(m_Modifier));
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
activeModifiers = NavMeshModifier.activeModifiers;
|
||||
Assert.That(activeModifiers.Count, Is.EqualTo(1));
|
||||
Assert.That(activeModifiers[0], Is.EqualTo(m_Modifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8dd5168f86d4ab2b5f75d1991720402
|
||||
timeCreated: 1700482678
|
||||
@@ -0,0 +1,278 @@
|
||||
#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("PrefabsWithNavMeshModifierVolume")]
|
||||
class NavMeshModifierVolumeInPrefabTests
|
||||
{
|
||||
const string k_AutoSaveKey = "AutoSave";
|
||||
const string k_ParentFolder = "Assets";
|
||||
const string k_TempFolderName = "TempPrefabAndModifiers";
|
||||
static readonly string k_TempFolder = Path.Combine(k_ParentFolder, k_TempFolderName);
|
||||
|
||||
const int k_PinkArea = 3;
|
||||
const int k_GreenArea = 4;
|
||||
const int k_RedArea = 18;
|
||||
|
||||
const int k_PrefabDefaultArea = k_GreenArea;
|
||||
|
||||
static readonly NavMeshQueryFilter k_QueryAnyArea = new() { agentTypeID = 0, areaMask = NavMesh.AllAreas };
|
||||
|
||||
static bool s_EnterPlayModeOptionsEnabled;
|
||||
static EnterPlayModeOptions s_EnterPlayModeOptions;
|
||||
|
||||
[SerializeField]
|
||||
string m_PrefabPath;
|
||||
[SerializeField]
|
||||
string m_PreviousScenePath;
|
||||
[SerializeField]
|
||||
string m_TempScenePath;
|
||||
[SerializeField]
|
||||
int m_TestCounter;
|
||||
[SerializeField]
|
||||
GameObject m_SurfaceInstance;
|
||||
[SerializeField]
|
||||
GameObject m_ModVolInstance;
|
||||
|
||||
#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, "NavMeshModifierVolumePrefabTestsScene.unity");
|
||||
var tempScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
EditorSceneManager.SaveScene(tempScene, m_TempScenePath);
|
||||
AssetDatabase.Refresh();
|
||||
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
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetupNewPrefabWithEmptyNavMesh()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
return;
|
||||
|
||||
var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
plane.name = "SurfaceSeekingModVol" + ++m_TestCounter + "Prefab";
|
||||
var surface = plane.AddComponent<NavMeshSurface>();
|
||||
surface.collectObjects = CollectObjects.All;
|
||||
|
||||
m_PrefabPath = Path.Combine(k_TempFolder, plane.name + ".prefab");
|
||||
PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
|
||||
Object.DestroyImmediate(plane);
|
||||
|
||||
NavMesh.RemoveAllNavMeshData();
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator TearDownAndReturnToMainStage()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
TestUtility.EliminateFromScene(ref m_ModVolInstance, k_KeepSceneObjects);
|
||||
TestUtility.EliminateFromScene(ref m_SurfaceInstance, k_KeepSceneObjects);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ModifierVolume_WhenInsidePrefabMode_ModifiesTheNavMeshInPrefab(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_SurfaceInstance = TestUtility.InstantiatePrefab(prefab, "SurfaceSeekingModVol" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hit.hit, Is.False, "Prefab should not have a NavMesh in the beginning.");
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
{
|
||||
yield return new EnterPlayMode();
|
||||
prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
}
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var modifierVolume = prefabStage.prefabContentsRoot.AddComponent<NavMeshModifierVolume>();
|
||||
modifierVolume.area = k_RedArea;
|
||||
modifierVolume.center = Vector3.zero;
|
||||
modifierVolume.size = Vector3.one;
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_PrefabDefaultArea);
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hitCenter, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hitCenter.hit, Is.True, "A NavMesh should have been baked in the center of the prefab.");
|
||||
Assert.That(hitCenter.mask, Is.EqualTo(1 << k_RedArea),
|
||||
"Area type (0x{0:x8}) found in the center should be 0x{1:x8}.", hitCenter.mask, 1 << k_RedArea);
|
||||
|
||||
NavMesh.SamplePosition(new Vector3(0.6f, 0, 0.6f), out var hitSides, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hitSides.hit, Is.True, "A NavMesh should have been baked in the outer sides of the prefab.");
|
||||
Assert.That(hitSides.mask, Is.EqualTo(1 << k_PrefabDefaultArea),
|
||||
"Area type (0x{0:x8}) found on the sides should be 0x{1:x8}.", hitSides.mask, 1 << k_PrefabDefaultArea);
|
||||
|
||||
Assert.That(hitCenter.mask, Is.Not.EqualTo(hitSides.mask),
|
||||
"Area type (0x{0:x8}) in the center should be different than on the sides.", hitCenter.mask);
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ModifierVolume_WhenInsidePrefabMode_DoesNotAffectTheNavMeshInMainScene(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
m_SurfaceInstance = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_SurfaceInstance.name = "SurfaceOutsidePrefab" + m_TestCounter;
|
||||
var mainSceneSurface = m_SurfaceInstance.AddComponent<NavMeshSurface>();
|
||||
mainSceneSurface.defaultArea = k_PinkArea;
|
||||
mainSceneSurface.agentTypeID = 0;
|
||||
mainSceneSurface.collectObjects = CollectObjects.All;
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hit.hit, Is.False, "The main scene should not have a NavMesh in the beginning.");
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabModVol = prefabStage.prefabContentsRoot.AddComponent<NavMeshModifierVolume>();
|
||||
prefabModVol.area = k_PrefabDefaultArea;
|
||||
prefabModVol.center = Vector3.zero;
|
||||
prefabModVol.size = new Vector3(100, 100, 100);
|
||||
|
||||
// Bake the NavMeshSurface from the main scene while the prefab mode is open
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
mainSceneSurface = m_SurfaceInstance.GetComponent<NavMeshSurface>();
|
||||
prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(mainSceneSurface, mainSceneSurface.defaultArea);
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
if (!EditorApplication.isPlaying)
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out hit, 0.1f, k_QueryAnyArea);
|
||||
Assert.That(hit.hit, Is.True, "A NavMesh should have been baked by the surface in the main scene.");
|
||||
Assert.That(hit.mask, Is.EqualTo(1 << mainSceneSurface.defaultArea),
|
||||
"NavMesh has the area type 0x{0:x8} instead of the expected 0x{1:x8}.", hit.mask, 1 << mainSceneSurface.defaultArea);
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ModifierVolume_WhenOutsidePrefabMode_DoesNotAffectTheNavMeshInPrefab(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
m_ModVolInstance = new GameObject("ModifierVolumeOutsidePrefab" + m_TestCounter);
|
||||
var modifierVolume = m_ModVolInstance.AddComponent<NavMeshModifierVolume>();
|
||||
modifierVolume.area = k_RedArea;
|
||||
modifierVolume.center = Vector3.zero;
|
||||
modifierVolume.size = new Vector3(20, 20, 20);
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_SurfaceInstance = TestUtility.InstantiatePrefab(prefab, "SurfaceSeekingModVol" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hit.hit, Is.False, "Prefab should not have a NavMesh in the beginning.");
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
{
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
}
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_PrefabDefaultArea);
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out hit, 0.1f, k_QueryAnyArea);
|
||||
Assume.That(hit.hit, Is.True, "A NavMesh should have been baked in the prefab.");
|
||||
Assert.That(hit.mask, Is.EqualTo(1 << k_PrefabDefaultArea),
|
||||
"A different area type (0x{0:x8}) was found instead of the expected one (0x{1:x8}).", hit.mask, 1 << k_PrefabDefaultArea);
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd4d066d0a75d8446bc2852c3bc1d4bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
internal class NavMeshModifierVolumeTests : DomainReloadTestBase
|
||||
{
|
||||
[SerializeField] NavMeshModifierVolume m_Modifier;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveModifiers_AddOneItemToListInEditMode_ModifierListSetToZeroInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeModifiers = NavMeshModifierVolume.activeModifiers;
|
||||
Assume.That(activeModifiers, Is.Not.Null);
|
||||
Assume.That(activeModifiers.Count, Is.Zero);
|
||||
|
||||
activeModifiers.Add(null);
|
||||
Assume.That(activeModifiers.Count, Is.Not.Zero);
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
activeModifiers = NavMeshModifierVolume.activeModifiers;
|
||||
Assert.That(activeModifiers.Count, Is.Zero);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveModifiers_CreateModifierInEditMode_ModifierRemainsInActiveModifiersInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeModifiers = NavMeshModifierVolume.activeModifiers;
|
||||
Assume.That(activeModifiers, Is.Not.Null);
|
||||
Assume.That(activeModifiers.Count, Is.Zero);
|
||||
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshModifierVolume));
|
||||
m_Modifier = m_TestGo.GetComponent<NavMeshModifierVolume>();
|
||||
|
||||
Assume.That(activeModifiers.Count, Is.EqualTo(1));
|
||||
Assume.That(activeModifiers[0], Is.EqualTo(m_Modifier));
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
activeModifiers = NavMeshModifierVolume.activeModifiers;
|
||||
Assert.That(activeModifiers.Count, Is.EqualTo(1));
|
||||
Assert.That(activeModifiers[0], Is.EqualTo(m_Modifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3662a816aa4c42c98966d59a714ae215
|
||||
timeCreated: 1700483523
|
||||
@@ -0,0 +1,905 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
//#define KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
//#define ENABLE_TEST_LOGS
|
||||
|
||||
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 NavMeshSurfaceInPrefabTests
|
||||
{
|
||||
const string k_AutoSaveKey = "AutoSave";
|
||||
const string k_ParentFolder = "Assets";
|
||||
const string k_TempFolderName = "TempPrefab";
|
||||
|
||||
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_PreviousScenePath;
|
||||
[SerializeField]
|
||||
string m_TempScenePath;
|
||||
[SerializeField]
|
||||
int m_TestCounter;
|
||||
[SerializeField]
|
||||
GameObject m_MainInstance;
|
||||
[SerializeField]
|
||||
GameObject m_SecondInstance;
|
||||
|
||||
#if KEEP_ARTIFACTS_FOR_INSPECTION
|
||||
const bool k_KeepSceneObjects = true;
|
||||
#else
|
||||
const bool k_KeepSceneObjects = false;
|
||||
#endif
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
// Skip the entire setup phase that runs again each time an editor test enters playmode
|
||||
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, "NavMeshSurfacePrefabTestsScene.unity");
|
||||
var tempScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, 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 SetupNewPrefabWithNavMesh()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
yield break;
|
||||
|
||||
var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
plane.name = "NavMeshSurface" + (++m_TestCounter) + "Prefab";
|
||||
var surface = plane.AddComponent<NavMeshSurface>();
|
||||
surface.collectObjects = CollectObjects.Children;
|
||||
|
||||
m_PrefabPath = Path.Combine(k_TempFolder, plane.name + ".prefab");
|
||||
var planePrefab = PrefabUtility.SaveAsPrefabAsset(plane, m_PrefabPath);
|
||||
Object.DestroyImmediate(plane);
|
||||
|
||||
AssetDatabase.OpenAsset(planePrefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_PrefabDefaultArea);
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
NavMesh.RemoveAllNavMeshData();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator TearDownAndReturnToMainStage()
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage != null)
|
||||
prefabStage.ClearDirtiness();
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
TestUtility.EliminateFromScene(ref m_MainInstance, k_KeepSceneObjects);
|
||||
TestUtility.EliminateFromScene(ref m_SecondInstance, k_KeepSceneObjects);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
static void TestNavMeshExistsAloneAtPosition(int expectedArea, Vector3 pos)
|
||||
{
|
||||
var expectedAreaMask = 1 << expectedArea;
|
||||
|
||||
#if ENABLE_TEST_LOGS
|
||||
var areaExists = HasNavMeshAtPosition(pos, expectedAreaMask);
|
||||
var otherAreasExist = HasNavMeshAtPosition(pos, ~expectedAreaMask);
|
||||
Debug.Log(" mask=" + expectedAreaMask.ToString("x8") + " area " + expectedArea +
|
||||
" Exists=" + areaExists + " otherAreasExist=" + otherAreasExist + " at position " + pos);
|
||||
if (otherAreasExist)
|
||||
{
|
||||
for (var i = 0; i < 32; i++)
|
||||
{
|
||||
if (i == expectedArea)
|
||||
continue;
|
||||
|
||||
var thisOtherAreaExists = HasNavMeshAtPosition(pos, 1 << i);
|
||||
if (thisOtherAreaExists)
|
||||
{
|
||||
Debug.Log(" _another area that exists here " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Assert.IsTrue(HasNavMeshAtPosition(pos, expectedAreaMask), "Expected NavMesh with area {0} at position {1}.", expectedArea, pos);
|
||||
Assert.IsFalse(HasNavMeshAtPosition(pos, ~expectedAreaMask), "A NavMesh with an area other than {0} exists at position {1}.", expectedArea, pos);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenOpenedInPrefabMode_DoesNotActivateItsNavMesh(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
|
||||
Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active under any circumstances.");
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_AfterBakingInPrefabMode_DoesNotActivateItsNavMesh(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
NavMeshAssetManager.instance.ClearSurfaces(new Object[] { prefabSurface });
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_RedArea);
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
|
||||
Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active after baking the surface.");
|
||||
|
||||
prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out hit, 1000000f, new NavMeshQueryFilter { areaMask = NavMesh.AllAreas, agentTypeID = 0 });
|
||||
Assert.That(hit.hit, Is.False, "The NavMesh instance of a prefab opened for edit should not be active after baking the surface.");
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_AfterBakingInPrefabMode_LeavesMainSceneUntouched(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
Assume.That(HasNavMeshAtPosition(Vector3.zero), Is.False);
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
Assume.That(prefabStage, Is.Not.Null);
|
||||
Assume.That(prefabStage.prefabContentsRoot, Is.Not.Null);
|
||||
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var initialPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_RedArea);
|
||||
|
||||
Assert.AreNotSame(initialPrefabNavMeshData, prefabSurface.navMeshData);
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
|
||||
Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, NavMesh.AllAreas, 0, 1000.0f));
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstantiated_ReferencesTheSameNavMeshData(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
var instanceNavMeshData = instanceSurface.navMeshData;
|
||||
|
||||
var clonePosition = new Vector3(20, 0, 0);
|
||||
m_SecondInstance = Object.Instantiate(m_MainInstance, clonePosition, Quaternion.identity);
|
||||
Assume.That(m_SecondInstance, Is.Not.Null);
|
||||
m_SecondInstance.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
|
||||
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask));
|
||||
Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
|
||||
|
||||
var instanceCloneSurface = m_SecondInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceCloneSurface, Is.Not.Null);
|
||||
var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
|
||||
Assert.AreSame(instanceNavMeshData, instanceCloneNavMeshData);
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
Assume.That(prefabStage, Is.Not.Null);
|
||||
Assume.That(prefabStage.prefabContentsRoot, Is.Not.Null);
|
||||
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.AreSame(prefabNavMeshData, instanceNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstantiatedAndCleared_InstanceHasEmptyNavMeshData(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface.navMeshData != null, "NavMeshSurface in prefab instance must have NavMeshData.");
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
NavMeshAssetManager.instance.ClearSurfaces(new Object[] { prefabSurface });
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
}
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
Assert.IsTrue(instanceSurface.navMeshData == null,
|
||||
"After the NavMeshSurface in the prefab has been cleared the prefab instance should no longer hold NavMeshData.");
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenBakesNewNavMesh_UpdatesTheInstance(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstanceOne");
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, m_MainInstance.transform.position);
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, m_MainInstance.transform.position);
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_RedArea);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, m_MainInstance.transform.position);
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
m_SecondInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstanceTwo");
|
||||
|
||||
// Reactivate the object to apply the change of position immediately
|
||||
m_SecondInstance.SetActive(false);
|
||||
m_SecondInstance.transform.position = new Vector3(20, 0, 0);
|
||||
m_SecondInstance.SetActive(true);
|
||||
|
||||
// Check that the second prefab instance has the new prefab area type
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, m_SecondInstance.transform.position);
|
||||
|
||||
// Only in edit mode, check that the prefab change has been picked up by the first instance
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, m_MainInstance.transform.position);
|
||||
|
||||
// Modify the first instance
|
||||
var instanceOneSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceOneSurface, k_BrownArea);
|
||||
|
||||
// Check that the first prefab instance kept its modified area type
|
||||
TestNavMeshExistsAloneAtPosition(k_BrownArea, m_MainInstance.transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
// After the prefab has been saved the running prefab instance should still have the old NavMeshData
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, m_MainInstance.transform.position);
|
||||
}
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstanceRebaked_HasDifferentNavMeshData(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
var clonePosition = new Vector3(20, 0, 0);
|
||||
m_SecondInstance = Object.Instantiate(m_MainInstance, clonePosition, Quaternion.identity);
|
||||
Assume.That(m_SecondInstance, Is.Not.Null);
|
||||
m_SecondInstance.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
|
||||
|
||||
var mainSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(mainSurface, Is.Not.Null);
|
||||
yield return TestUtility.BakeNavMeshAsync(mainSurface, k_RedArea);
|
||||
var mainNavMeshData = mainSurface.navMeshData;
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, m_MainInstance.transform.position);
|
||||
|
||||
// For when multiple instances of the same NavMesh prefab modify their data in playmode the behavior is currently undefined
|
||||
if (runMode != RunMode.PlayMode)
|
||||
{
|
||||
var cloneSurface = m_SecondInstance.GetComponent<NavMeshSurface>();
|
||||
|
||||
Assert.IsTrue(cloneSurface.navMeshData != null, "The clone should still have NavMesh data.");
|
||||
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask), "The clone should still reference the prefab's data.");
|
||||
Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
|
||||
}
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.AreNotSame(mainNavMeshData, prefabNavMeshData);
|
||||
|
||||
if (runMode != RunMode.PlayMode)
|
||||
{
|
||||
var instanceCloneSurface = m_SecondInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceCloneSurface, Is.Not.Null);
|
||||
var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
|
||||
Assert.AreNotSame(instanceCloneNavMeshData, mainNavMeshData);
|
||||
Assert.That(instanceCloneNavMeshData, Is.EqualTo(prefabNavMeshData));
|
||||
}
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstanceCleared_InstanceHasEmptyNavMeshData()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
var clonePosition = new Vector3(20, 0, 0);
|
||||
m_SecondInstance = Object.Instantiate(m_MainInstance, clonePosition, Quaternion.identity);
|
||||
Assume.That(m_SecondInstance, Is.Not.Null);
|
||||
m_SecondInstance.name = "Surface" + m_TestCounter + "PrefabInstanceClone";
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
|
||||
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
|
||||
|
||||
Assert.IsTrue(HasNavMeshAtPosition(clonePosition, expectedAreaMask));
|
||||
Assert.IsFalse(HasNavMeshAtPosition(clonePosition, ~expectedAreaMask));
|
||||
|
||||
var instanceCloneSurface = m_SecondInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceCloneSurface, Is.Not.Null);
|
||||
var instanceCloneNavMeshData = instanceCloneSurface.navMeshData;
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.AreNotSame(prefabNavMeshData, instanceSurface.navMeshData);
|
||||
Assert.AreNotSame(instanceCloneNavMeshData, instanceSurface.navMeshData);
|
||||
Assert.AreSame(prefabNavMeshData, instanceCloneNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstanceCleared_PrefabKeepsNavMeshData()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
var initialPrefabNavMeshData = instanceSurface.navMeshData;
|
||||
NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
|
||||
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.IsTrue(prefabNavMeshData != null,
|
||||
"NavMeshSurface in the prefab must still have NavMeshData even though the instance was cleared.");
|
||||
Assert.AreSame(initialPrefabNavMeshData, prefabNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenRebakedButInstanceModified_DoesNotChangeDataReferencedByInstance(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceSurface, k_RedArea);
|
||||
var instanceNavMeshData = instanceSurface.navMeshData;
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var initialPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
|
||||
Assert.IsTrue(prefabNavMeshData != null,
|
||||
"NavMeshSurface in prefab must have NavMeshData after baking, saving, closing and reopening.");
|
||||
Assert.AreNotSame(instanceNavMeshData, prefabNavMeshData);
|
||||
Assert.AreNotSame(initialPrefabNavMeshData, prefabNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
Assert.AreSame(instanceNavMeshData, instanceSurface.navMeshData);
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenRebakedButNotSaved_RevertsToTheInitialNavMeshData()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var initialPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
var initialPrefabNavMeshAssetPath = AssetDatabase.GetAssetPath(initialPrefabNavMeshData);
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
var rebuiltPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.IsTrue(rebuiltPrefabNavMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||||
Assert.AreNotSame(initialPrefabNavMeshData, rebuiltPrefabNavMeshData);
|
||||
|
||||
prefabStage.ClearDirtiness();
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
|
||||
Assert.AreSame(initialPrefabNavMeshData, prefabNavMeshData);
|
||||
Assert.AreNotSame(rebuiltPrefabNavMeshData, prefabNavMeshData);
|
||||
var prefabNavMeshAssetPath = AssetDatabase.GetAssetPath(prefabNavMeshData);
|
||||
StringAssert.AreEqualIgnoringCase(initialPrefabNavMeshAssetPath, prefabNavMeshAssetPath,
|
||||
"The NavMeshData asset referenced by the prefab should remain the same when exiting prefab mode without saving.");
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenRebakedButNotSaved_TheRebakedAssetNoLongerExists()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
var rebakedAssetPath = AssetDatabase.GetAssetPath(prefabSurface.navMeshData);
|
||||
|
||||
Assert.IsTrue(File.Exists(rebakedAssetPath), "NavMeshData file must exist. ({0})", rebakedAssetPath);
|
||||
|
||||
prefabStage.ClearDirtiness();
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
Assert.IsFalse(File.Exists(rebakedAssetPath), "NavMeshData file still exists after discarding the changes. ({0})", rebakedAssetPath);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenRebaked_TheOldAssetExistsUntilSavingAndNotAfter()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var initialNavMeshData = prefabSurface.navMeshData;
|
||||
var initialAssetPath = AssetDatabase.GetAssetPath(prefabSurface.navMeshData);
|
||||
|
||||
Assume.That(initialNavMeshData != null, "Prefab must have some NavMeshData.");
|
||||
Assume.That(File.Exists(initialAssetPath), Is.True, "NavMeshData file must exist. ({0})", initialAssetPath);
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
|
||||
Assert.IsTrue(initialNavMeshData != null, "The initial NavMeshData must still exist immediately after prefab re-bake.");
|
||||
Assert.IsTrue(File.Exists(initialAssetPath), "The initial NavMeshData file must exist after prefab re-bake. ({0})", initialAssetPath);
|
||||
|
||||
Assert.IsTrue(prefabSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||||
var unsavedRebakedNavMeshData = prefabSurface.navMeshData;
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_OrangeArea);
|
||||
|
||||
// Assert.IsNull would return a wrong result here (e.g. Expected: null But was: <null>)
|
||||
Assert.IsTrue(unsavedRebakedNavMeshData == null,"An unsaved NavMeshData should not exist after a re-bake.");
|
||||
Assert.IsTrue(prefabSurface.navMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
Assert.IsFalse(File.Exists(initialAssetPath), "NavMeshData file still exists after saving. ({0})", initialAssetPath);
|
||||
Assert.IsTrue(initialNavMeshData == null, "The initial NavMeshData must no longer exist after saving the prefab.");
|
||||
|
||||
// This code is still reachable because initialNavMeshData has been affected by BakeNavMeshAsync()
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenRebakedAndAutoSaved_InstanceHasTheNewNavMeshData()
|
||||
{
|
||||
var wasAutoSave = PrefabStageAutoSavingUtil.GetPrefabStageAutoSave();
|
||||
PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(true);
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var initialPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
var rebuiltPrefabNavMeshData = prefabSurface.navMeshData;
|
||||
Assert.IsTrue(rebuiltPrefabNavMeshData != null, "NavMeshSurface must have NavMeshData after baking.");
|
||||
Assert.AreNotSame(initialPrefabNavMeshData, rebuiltPrefabNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStageReopened = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurfaceReopened = prefabStageReopened.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
var prefabNavMeshData = prefabSurfaceReopened.navMeshData;
|
||||
Assert.AreNotSame(initialPrefabNavMeshData, prefabNavMeshData);
|
||||
Assert.AreSame(rebuiltPrefabNavMeshData, prefabNavMeshData);
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
PrefabStageAutoSavingUtil.SetPrefabStageAutoSave(wasAutoSave);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[Ignore("Currently the deletion of the old asset must be done manually.")]
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_AfterModifiedInstanceAppliedBack_TheOldAssetNoLongerExists()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
|
||||
var initialInstanceAssetPath = AssetDatabase.GetAssetPath(instanceSurface.navMeshData);
|
||||
|
||||
Assert.IsTrue(File.Exists(initialInstanceAssetPath), "Prefab's NavMeshData file must exist. ({0})", initialInstanceAssetPath);
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceSurface, k_RedArea);
|
||||
|
||||
Assert.IsTrue(File.Exists(initialInstanceAssetPath),
|
||||
"Prefab's NavMeshData file exists after the instance has changed. ({0})", initialInstanceAssetPath);
|
||||
|
||||
PrefabUtility.ApplyPrefabInstance(m_MainInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
Assert.IsFalse(File.Exists(initialInstanceAssetPath),
|
||||
"Prefab's NavMeshData file still exists after the changes from the instance have been applied back to the prefab. ({0})",
|
||||
initialInstanceAssetPath);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_AfterModifiedInstanceAppliedBack_UpdatedAccordingToInstance()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstanceOne");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
m_SecondInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstanceTwo");
|
||||
|
||||
// reactivate the object to apply the change of position immediately
|
||||
m_SecondInstance.SetActive(false);
|
||||
m_SecondInstance.transform.position = new Vector3(20, 0, 0);
|
||||
m_SecondInstance.SetActive(true);
|
||||
|
||||
var instanceOneSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceOneSurface, Is.Not.Null);
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceOneSurface, k_RedArea);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, m_SecondInstance.transform.position);
|
||||
|
||||
PrefabUtility.ApplyPrefabInstance(m_MainInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, m_SecondInstance.transform.position);
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_GrayArea);
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_GrayArea, Vector3.zero);
|
||||
TestNavMeshExistsAloneAtPosition(k_GrayArea, m_SecondInstance.transform.position);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_AfterClearedInstanceAppliedBack_HasEmptyData()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
|
||||
NavMeshAssetManager.instance.ClearSurfaces(new Object[] { instanceSurface });
|
||||
|
||||
const int expectedAreaMask = 1 << k_PrefabDefaultArea;
|
||||
Assert.IsFalse(HasNavMeshAtPosition(Vector3.zero, expectedAreaMask));
|
||||
|
||||
PrefabUtility.ApplyPrefabInstance(m_MainInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
|
||||
Assert.IsTrue(prefabSurface.navMeshData == null,
|
||||
"Prefab should have empty NavMeshData when empty data has been applied back from the instance.");
|
||||
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstanceRevertsBack_InstanceIsLikePrefab()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceSurface, k_RedArea);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
|
||||
|
||||
PrefabUtility.RevertPrefabInstance(m_MainInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[Ignore("Deletion of the old asset is expected to be done manually for the time being.")]
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenInstanceRevertsBack_TheInstanceAssetNoLongerExists()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "Surface" + m_TestCounter + "PrefabInstance");
|
||||
TestNavMeshExistsAloneAtPosition(k_PrefabDefaultArea, Vector3.zero);
|
||||
|
||||
var instanceSurface = m_MainInstance.GetComponent<NavMeshSurface>();
|
||||
Assume.That(instanceSurface, Is.Not.Null);
|
||||
yield return TestUtility.BakeNavMeshAsync(instanceSurface, k_RedArea);
|
||||
|
||||
var instanceAssetPath = AssetDatabase.GetAssetPath(instanceSurface.navMeshData);
|
||||
|
||||
Assert.IsTrue(File.Exists(instanceAssetPath), "Instance's NavMeshData file must exist. ({0})", instanceAssetPath);
|
||||
|
||||
PrefabUtility.RevertPrefabInstance(m_MainInstance, InteractionMode.AutomatedAction);
|
||||
|
||||
Assert.IsFalse(File.Exists(instanceAssetPath), "Instance's NavMeshData file still exists after revert. ({0})", instanceAssetPath);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[Ignore("The expected behaviour has not been decided.")]
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenDeleted_InstancesMakeCopiesOfData(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
yield return null;
|
||||
Assert.Fail("not implemented yet");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshSurfacePrefab_WhenBakingInPrefabModeScene_CollectsOnlyPrefabModeSceneObjects(
|
||||
[Values(RunMode.EditMode, RunMode.PlayMode)]
|
||||
RunMode runMode)
|
||||
{
|
||||
m_SecondInstance = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
var goName = "MainScenePlane" + m_TestCounter;
|
||||
m_SecondInstance.name = goName;
|
||||
m_SecondInstance.transform.localScale = new Vector3(100, 1, 100);
|
||||
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
AssetDatabase.OpenAsset(prefab);
|
||||
|
||||
if (runMode == RunMode.PlayMode)
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
var prefabSurface = prefabStage.prefabContentsRoot.GetComponent<NavMeshSurface>();
|
||||
|
||||
prefabSurface.collectObjects = CollectObjects.All;
|
||||
|
||||
yield return TestUtility.BakeNavMeshAsync(prefabSurface, k_RedArea);
|
||||
|
||||
PrefabSavingUtil.SavePrefab(prefabStage);
|
||||
StageUtility.GoToMainStage();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
m_SecondInstance = GameObject.Find(goName);
|
||||
prefab = AssetDatabase.LoadAssetAtPath<GameObject>(m_PrefabPath);
|
||||
}
|
||||
|
||||
m_MainInstance = TestUtility.InstantiatePrefab(prefab, "PrefabInstance" + m_TestCounter);
|
||||
|
||||
TestNavMeshExistsAloneAtPosition(k_RedArea, Vector3.zero);
|
||||
|
||||
var posNearby = new Vector3(20, 0, 0);
|
||||
Assert.IsFalse(HasNavMeshAtPosition(posNearby, 1 << k_RedArea),
|
||||
"NavMesh with the prefab's area exists at position {1}, outside the prefab's plane. ({0})",
|
||||
k_RedArea, posNearby);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
public static bool HasNavMeshAtPosition(Vector3 pos, int areaMask = NavMesh.AllAreas, int agentTypeId = 0, float range = 0.1f)
|
||||
{
|
||||
var filter = new NavMeshQueryFilter
|
||||
{
|
||||
areaMask = areaMask,
|
||||
agentTypeID = agentTypeId
|
||||
};
|
||||
var result = NavMesh.SamplePosition(pos, out _, range, filter);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e570ad5b9d660a4bbeebf9f8b872eb4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,289 @@
|
||||
#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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84d904f3fbe3c1b4c8daab917453682f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
internal class NavMeshSurfacesTests : DomainReloadTestBase
|
||||
{
|
||||
[SerializeField] NavMeshSurface m_Surface;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveSurfaces_AddOneItemToListInEditMode_SurfaceListSetToZeroInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeSurfaces = NavMeshSurface.activeSurfaces;
|
||||
Assume.That(activeSurfaces, Is.Not.Null);
|
||||
Assume.That(activeSurfaces.Count, Is.Zero);
|
||||
|
||||
activeSurfaces.Add(null);
|
||||
Assume.That(activeSurfaces.Count, Is.Not.Zero);
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
activeSurfaces = NavMeshSurface.activeSurfaces;
|
||||
Assert.That(activeSurfaces.Count, Is.Zero);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActiveSurfaces_CreateSurfaceInEditMode_SurfaceRemainsInActiveSurfacesInPlayMode([Values(EnterPlayModeOptions.DisableDomainReload, EnterPlayModeOptions.None)] EnterPlayModeOptions option)
|
||||
{
|
||||
EditorSettings.enterPlayModeOptionsEnabled = true;
|
||||
EditorSettings.enterPlayModeOptions = option;
|
||||
|
||||
var activeSurfaces = NavMeshSurface.activeSurfaces;
|
||||
Assume.That(activeSurfaces, Is.Not.Null);
|
||||
Assume.That(activeSurfaces.Count, Is.Zero);
|
||||
|
||||
m_TestGo = new GameObject("TestObj", typeof(NavMeshSurface));
|
||||
m_Surface = m_TestGo.GetComponent<NavMeshSurface>();
|
||||
|
||||
activeSurfaces = NavMeshSurface.activeSurfaces;
|
||||
Assume.That(activeSurfaces, Is.Not.Null);
|
||||
Assume.That(activeSurfaces.Count, Is.EqualTo(1));
|
||||
Assume.That(activeSurfaces[0], Is.EqualTo(m_Surface));
|
||||
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
activeSurfaces = NavMeshSurface.activeSurfaces;
|
||||
Assert.That(activeSurfaces.Count, Is.EqualTo(1));
|
||||
Assert.That(activeSurfaces[0], Is.EqualTo(m_Surface));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02ce4f3c80e34778a448252aa86d70bc
|
||||
timeCreated: 1700483654
|
||||
@@ -0,0 +1,50 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Description("Verifies that the desired Navigation editor menus are accessible with the package.")]
|
||||
class NavigationPresenceInMenus
|
||||
{
|
||||
GameObject m_ComponentsReceiver;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
// Create an empty game object and select it in order for components menus to be available
|
||||
m_ComponentsReceiver = new GameObject("ComponentsReceiver");
|
||||
Selection.activeObject = m_ComponentsReceiver;
|
||||
}
|
||||
|
||||
static IEnumerable<string> NavigationMenuItemProvider()
|
||||
{
|
||||
yield return "Component/Navigation/Nav Mesh Agent";
|
||||
yield return "Component/Navigation/Nav Mesh Obstacle";
|
||||
yield return "Component/Navigation/NavMesh Surface";
|
||||
yield return "Component/Navigation/NavMesh Modifier Volume";
|
||||
yield return "Component/Navigation/NavMesh Modifier";
|
||||
yield return "Component/Navigation/NavMesh Link";
|
||||
yield return "Window/AI/Navigation";
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(nameof(NavigationMenuItemProvider))]
|
||||
public void MenuIsEnabled(string menuPath)
|
||||
{
|
||||
var menuEnabled = Menu.GetEnabled(menuPath);
|
||||
Assert.That(menuEnabled, Is.True, $"Navigation component menu '{menuPath}' should be available");
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_ComponentsReceiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 689549d6be484a1491705f5d24fc6240
|
||||
timeCreated: 1649814444
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
class PrefabSavingUtil
|
||||
{
|
||||
public static void SavePrefab(PrefabStage prefabStage)
|
||||
{
|
||||
if (prefabStage == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var savePrefabMethod = prefabStage.GetType().GetMethod("SavePrefab", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (savePrefabMethod == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
savePrefabMethod.Invoke(prefabStage, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4de45126199b4c84dbc8b9620cf3263d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
static class PrefabStageAutoSavingUtil
|
||||
{
|
||||
public static bool GetPrefabStageAutoSave()
|
||||
{
|
||||
var stageNavMgrInstance = GetStageNavigationManagerInstance();
|
||||
var autoSaveProperty = GetAutoSaveProperty(stageNavMgrInstance);
|
||||
return (bool) autoSaveProperty.GetValue(stageNavMgrInstance, null);
|
||||
}
|
||||
|
||||
public static void SetPrefabStageAutoSave(bool value)
|
||||
{
|
||||
var stageNavMgrInstance = GetStageNavigationManagerInstance();
|
||||
var autoSaveProperty = GetAutoSaveProperty(stageNavMgrInstance);
|
||||
autoSaveProperty.SetValue(stageNavMgrInstance, value, null);
|
||||
}
|
||||
|
||||
static object GetStageNavigationManagerInstance()
|
||||
{
|
||||
var editorAssemblyName = typeof(EditorWindow).Assembly.FullName;
|
||||
var t = Type.GetType("UnityEditor.SceneManagement.StageNavigationManager, " + editorAssemblyName, true, true);
|
||||
if (t == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
var instanceProperty = t.GetProperty("instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
|
||||
if (instanceProperty == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
var stageNavMgrInstance = instanceProperty.GetValue(null, null);
|
||||
return stageNavMgrInstance;
|
||||
}
|
||||
|
||||
static PropertyInfo GetAutoSaveProperty(object stageNavigationManagerInstance)
|
||||
{
|
||||
var autoSaveProperty = stageNavigationManagerInstance.GetType().GetProperty("autoSave", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (autoSaveProperty == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
return autoSaveProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cd905de8fe98d94a82de074adbd499d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.AI.Navigation.Editor.Tests
|
||||
{
|
||||
class TestUtility
|
||||
{
|
||||
[return: NotNull]
|
||||
public static GameObject InstantiatePrefab(GameObject prefab, string name)
|
||||
{
|
||||
GameObject result;
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
result = Object.Instantiate(prefab);
|
||||
else
|
||||
result = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
|
||||
|
||||
Assume.That(result, Is.Not.Null);
|
||||
|
||||
result!.name = name;
|
||||
return result!;
|
||||
}
|
||||
|
||||
public static IEnumerator BakeNavMeshAsync(NavMeshSurface surface, int defaultArea)
|
||||
{
|
||||
surface.defaultArea = defaultArea;
|
||||
NavMeshAssetManager.instance.StartBakingSurfaces(new Object[] { surface });
|
||||
yield return new WaitWhile(() => NavMeshAssetManager.instance.IsSurfaceBaking(surface));
|
||||
}
|
||||
|
||||
public static void EliminateFromScene(ref GameObject go, bool keepDeactivated = false)
|
||||
{
|
||||
if (go == null)
|
||||
return;
|
||||
|
||||
if (keepDeactivated)
|
||||
go.SetActive(false);
|
||||
else
|
||||
Object.DestroyImmediate(go);
|
||||
}
|
||||
}
|
||||
|
||||
enum RunMode
|
||||
{
|
||||
EditMode,
|
||||
PlayMode
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a69fe61f096bf843a85c885aabf5780
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "Unity.AI.Navigation.Editor.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a",
|
||||
"GUID:0acc523941302664db1f4e527237feb3",
|
||||
"GUID:8c4dd21966739024fbd72155091d199e",
|
||||
"GUID:86c9d8e67265f41469be06142c397d17",
|
||||
"GUID:1664e92176d434ccd902c1705fefe682"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 794824b4a8f003f47a92875e8342f790
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,853 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &519134644249346471
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4271906378904925157}
|
||||
- component: {fileID: 8212897370511830212}
|
||||
- component: {fileID: 8596281887684468867}
|
||||
- component: {fileID: 5890966754145026877}
|
||||
m_Layer: 0
|
||||
m_Name: Bundle NavMesh Surface
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4271906378904925157
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 519134644249346471}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &8212897370511830212
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 519134644249346471}
|
||||
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &8596281887684468867
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 519134644249346471}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &5890966754145026877
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 519134644249346471}
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 7a5ac11cc976e418e8d13136b07e1f52, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_CollectObjects: 0
|
||||
m_Size: {x: 10, y: 10, z: 10}
|
||||
m_Center: {x: 0, y: 2, z: 0}
|
||||
m_LayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_UseGeometry: 0
|
||||
m_DefaultArea: 0
|
||||
m_GenerateLinks: 0
|
||||
m_IgnoreNavMeshAgent: 1
|
||||
m_IgnoreNavMeshObstacle: 1
|
||||
m_OverrideTileSize: 0
|
||||
m_TileSize: 256
|
||||
m_OverrideVoxelSize: 0
|
||||
m_VoxelSize: 0.16666667
|
||||
m_MinRegionArea: 2
|
||||
m_NavMeshData: {fileID: 0}
|
||||
m_BuildHeightMesh: 0
|
||||
--- !u!1 &769986786307910025
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6480314771685140824}
|
||||
- component: {fileID: 2957784056397967524}
|
||||
- component: {fileID: 1096483578175528470}
|
||||
m_Layer: 0
|
||||
m_Name: Bundle Plane 2
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &6480314771685140824
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 769986786307910025}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 12, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &2957784056397967524
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 769986786307910025}
|
||||
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &1096483578175528470
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 769986786307910025}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!1 &2206811650915575901
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5235247620429186276}
|
||||
m_Layer: 0
|
||||
m_Name: Scaled InterCenters Link Start Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 7174288486110832750, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5235247620429186276
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2206811650915575901}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 4.3526, y: 0.5017, z: -1.75}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2411862089752181049
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7027408494437500396}
|
||||
m_Layer: 0
|
||||
m_Name: InterCenters Link End Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: -5938655980376293919, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &7027408494437500396
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2411862089752181049}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 12, y: 0, z: 0}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2759056808729940325
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6620030167200409806}
|
||||
m_Layer: 0
|
||||
m_Name: InterCenters Link Start Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 6519382022992737161, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &6620030167200409806
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2759056808729940325}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3799698425930382998
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3612743069469093135}
|
||||
- component: {fileID: 6183284072014405755}
|
||||
- component: {fileID: 5432432520571072814}
|
||||
- component: {fileID: 8593906665911883465}
|
||||
- component: {fileID: 7375800272983125944}
|
||||
m_Layer: 0
|
||||
m_Name: Multiple NavMesh Links
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3612743069469093135
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3799698425930382998}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0.53729963, z: 0, w: 0.8433915}
|
||||
m_LocalPosition: {x: 2.4, y: 0.2, z: -2}
|
||||
m_LocalScale: {x: 2, y: 2, z: 2}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2095176847815880072}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
|
||||
--- !u!114 &6183284072014405755
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3799698425930382998}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -0.3, y: -0.1, z: -2.5}
|
||||
m_EndPoint: {x: 0.3, y: 0.1, z: 2.5}
|
||||
m_StartTransform: {fileID: 3612743069469093135}
|
||||
m_EndTransform: {fileID: 3612743069469093135}
|
||||
m_Activated: 1
|
||||
m_Width: 1
|
||||
m_CostModifier: -1
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &5432432520571072814
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3799698425930382998}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -17.6, y: 1.23, z: 37.7}
|
||||
m_EndPoint: {x: 5.8, y: 0.05, z: 22.45}
|
||||
m_StartTransform: {fileID: 6480314771685140824}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 1
|
||||
m_Width: 2
|
||||
m_CostModifier: 2
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &8593906665911883465
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3799698425930382998}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -17.6, y: 1.23, z: 37.7}
|
||||
m_EndPoint: {x: 5.8, y: 0.05, z: 22.45}
|
||||
m_StartTransform: {fileID: 6480314771685140824}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 0
|
||||
m_Width: 2.5
|
||||
m_CostModifier: 2
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 1
|
||||
--- !u!114 &7375800272983125944
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3799698425930382998}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: 0.001, y: 0.001, z: 0.001}
|
||||
m_EndPoint: {x: -0.001, y: -0.001, z: -0.001}
|
||||
m_StartTransform: {fileID: 4271906378904925157}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 1
|
||||
m_Width: 0.5
|
||||
m_CostModifier: 3
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!1 &4145527836750073399
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8143012993110909644}
|
||||
m_Layer: 0
|
||||
m_Name: Scaled InterCenters Link End Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: -5442936267250999957, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8143012993110909644
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4145527836750073399}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 7.3478, y: 0.4983, z: -1.7515}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &4239459959405439086
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5632226390324501746}
|
||||
m_Layer: 0
|
||||
m_Name: First Link End Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 7148428337604731935, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5632226390324501746
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4239459959405439086}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 8.1926, y: 0.69996, z: -1.2160001}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &4552647711432885867
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8708194500741321703}
|
||||
m_Layer: 0
|
||||
m_Name: Second Link Start Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 8418204508859773708, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8708194500741321703
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4552647711432885867}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 2.9379, y: 0.69999, z: 2.9552}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &4797585877503007664
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3507495875724678348}
|
||||
m_Layer: 0
|
||||
m_Name: First Link Start Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 1206586993520771344, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3507495875724678348
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4797585877503007664}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 3.40742, y: 0.49997997, z: -2.7844}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &5574978382145436126
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2095176847815880072}
|
||||
m_Layer: 0
|
||||
m_Name: Scaled_Links_Root
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 7250588514170254948, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &2095176847815880072
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5574978382145436126}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 1, y: 0, z: 6}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 3612743069469093135}
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &5990160592295572745
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1467712365982528894}
|
||||
- component: {fileID: 7571120346557858792}
|
||||
- component: {fileID: 8971793099447168519}
|
||||
- component: {fileID: 6280812729872134344}
|
||||
- component: {fileID: 3857943089573655079}
|
||||
m_Layer: 0
|
||||
m_Name: TestBundleWithAllLinks
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1467712365982528894
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5990160592295572745}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4271906378904925157}
|
||||
- {fileID: 6480314771685140824}
|
||||
- {fileID: 2095176847815880072}
|
||||
- {fileID: 4222975083141804362}
|
||||
- {fileID: 3507495875724678348}
|
||||
- {fileID: 5632226390324501746}
|
||||
- {fileID: 8708194500741321703}
|
||||
- {fileID: 3952342784954718853}
|
||||
- {fileID: 6620030167200409806}
|
||||
- {fileID: 7027408494437500396}
|
||||
- {fileID: 5235247620429186276}
|
||||
- {fileID: 8143012993110909644}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &7571120346557858792
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5990160592295572745}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -9.05, y: 0.7, z: 2.96}
|
||||
m_EndPoint: {x: -3.21, y: 0.5, z: 1.05}
|
||||
m_StartTransform: {fileID: 6480314771685140824}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 1
|
||||
m_Width: 1.7
|
||||
m_CostModifier: 7
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &8971793099447168519
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5990160592295572745}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: 3.4193363, y: 0.4997115, z: -2.7743223}
|
||||
m_EndPoint: {x: 8.193943, y: 0.7000145, z: -1.2156277}
|
||||
m_StartTransform: {fileID: 1467712365982528894}
|
||||
m_EndTransform: {fileID: 1467712365982528894}
|
||||
m_Activated: 1
|
||||
m_Width: 1.8
|
||||
m_CostModifier: 8
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &6280812729872134344
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5990160592295572745}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: 3.4193363, y: 0.4997115, z: -2.7743223}
|
||||
m_EndPoint: {x: 8.193943, y: 0.7000145, z: -1.2156277}
|
||||
m_StartTransform: {fileID: 4271906378904925157}
|
||||
m_EndTransform: {fileID: 1467712365982528894}
|
||||
m_Activated: 1
|
||||
m_Width: 1.9
|
||||
m_CostModifier: -4
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &3857943089573655079
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5990160592295572745}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: 3.4193363, y: 0.4997115, z: -2.7743223}
|
||||
m_EndPoint: {x: 8.193943, y: 0.7000145, z: -1.2156277}
|
||||
m_StartTransform: {fileID: 1467712365982528894}
|
||||
m_EndTransform: {fileID: 4271906378904925157}
|
||||
m_Activated: 1
|
||||
m_Width: 1.95
|
||||
m_CostModifier: -4
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!1 &7410374023104900550
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3952342784954718853}
|
||||
m_Layer: 0
|
||||
m_Name: Second Link End Should Be Here
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 3306451490063965843, guid: 0000000000000000d000000000000000, type: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3952342784954718853
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7410374023104900550}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 8.79132, y: 0.50001, z: 1.04984}
|
||||
m_LocalScale: {x: 2, y: 3, z: 4}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &8073499793372499723
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4222975083141804362}
|
||||
- component: {fileID: 2015390662727589698}
|
||||
- component: {fileID: 6149203982048707568}
|
||||
- component: {fileID: 450827611633533040}
|
||||
m_Layer: 0
|
||||
m_Name: Unscaled Links
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4222975083141804362
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8073499793372499723}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: 0.53729963, z: -0, w: 0.8433915}
|
||||
m_LocalPosition: {x: 5.8, y: 0.6, z: -2}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1467712365982528894}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
|
||||
--- !u!114 &2015390662727589698
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8073499793372499723}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -0.3, y: -0.1, z: -2.5}
|
||||
m_EndPoint: {x: 0.3, y: 0.1, z: 2.5}
|
||||
m_StartTransform: {fileID: 4222975083141804362}
|
||||
m_EndTransform: {fileID: 4222975083141804362}
|
||||
m_Activated: 1
|
||||
m_Width: 1.5
|
||||
m_CostModifier: -1
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &6149203982048707568
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8073499793372499723}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: -9.05, y: 0.7, z: 2.96}
|
||||
m_EndPoint: {x: -3.21, y: 0.5, z: 1.05}
|
||||
m_StartTransform: {fileID: 6480314771685140824}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 1
|
||||
m_Width: 1.5
|
||||
m_CostModifier: 2
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
--- !u!114 &450827611633533040
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8073499793372499723}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6eeb5dc026fdf4b488bc7ae0138ab719, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_AgentTypeID: 0
|
||||
m_StartPoint: {x: 0.001, y: 0.001, z: 0.001}
|
||||
m_EndPoint: {x: -0.001, y: -0.001, z: -0.001}
|
||||
m_StartTransform: {fileID: 4271906378904925157}
|
||||
m_EndTransform: {fileID: 6480314771685140824}
|
||||
m_Activated: 1
|
||||
m_Width: 0.5
|
||||
m_CostModifier: 3
|
||||
m_Bidirectional: 0
|
||||
m_AutoUpdatePosition: 1
|
||||
m_Area: 2
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c62c6d05e86bc124c9f6f5d49c93c158
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ad99e7d0c24c3845a39ca29f7c1c5e6
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 077676819252b4349a7677a483a0a8f4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,252 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
public class NavMeshLinkTests
|
||||
{
|
||||
NavMeshLink m_NavMeshLink;
|
||||
Transform m_StartTransform;
|
||||
Transform m_EndTransform;
|
||||
GameObject m_ScaledSkewer;
|
||||
GameObject m_LinkImitator;
|
||||
GameObject m_LinkStartImitator;
|
||||
GameObject m_LinkEndImitator;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
m_NavMeshLink = new GameObject("NavMeshLink").AddComponent<NavMeshLink>();
|
||||
m_StartTransform = new GameObject("Start Transform").transform;
|
||||
m_EndTransform = new GameObject("End Transform").transform;
|
||||
m_ScaledSkewer = new GameObject("Unevenly Scaled Skewer");
|
||||
m_LinkImitator = new GameObject("Link Imitator");
|
||||
m_LinkStartImitator = new GameObject("Link Start Imitator");
|
||||
m_LinkEndImitator = new GameObject("Link End Imitator");
|
||||
|
||||
Assume.That(k_UnevenScale / k_UnevenScale.x, Is.Not.EqualTo(Vector3.one).Using(Vector3EqualityComparer.Instance));
|
||||
|
||||
m_ScaledSkewer.transform.localScale = k_UnevenScale;
|
||||
m_ScaledSkewer.transform.SetPositionAndRotation(new Vector3(2f, 1f, 1f), Quaternion.identity);
|
||||
m_LinkImitator.transform.parent = m_ScaledSkewer.transform;
|
||||
m_LinkStartImitator.transform.parent = m_LinkImitator.transform;
|
||||
m_LinkEndImitator.transform.parent = m_LinkImitator.transform;
|
||||
|
||||
// To debug, add these components to imitators, only to show icons for them in the scene
|
||||
//m_LinkStartImitator.AddComponent<NavMeshModifier>().enabled = false;
|
||||
//m_LinkEndImitator.AddComponent<NavMeshModifier>().enabled = false;
|
||||
//m_ScaledSkewer.AddComponent<NavMeshModifierVolume>().enabled = false;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_NavMeshLink.transform.parent = null;
|
||||
|
||||
// Note: Adjust the expected test return values if you change the setup
|
||||
m_NavMeshLink.startPoint = Vector3.back;
|
||||
m_NavMeshLink.endPoint = Vector3.forward;
|
||||
m_StartTransform.position = Vector3.left;
|
||||
m_EndTransform.position = Vector3.right;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
if (m_NavMeshLink != null)
|
||||
Object.DestroyImmediate(m_NavMeshLink.gameObject);
|
||||
if (m_StartTransform != null)
|
||||
Object.DestroyImmediate(m_StartTransform.gameObject);
|
||||
if (m_EndTransform != null)
|
||||
Object.DestroyImmediate(m_EndTransform.gameObject);
|
||||
if (m_LinkStartImitator != null)
|
||||
Object.DestroyImmediate(m_LinkStartImitator);
|
||||
if (m_LinkEndImitator != null)
|
||||
Object.DestroyImmediate(m_LinkEndImitator);
|
||||
if (m_LinkImitator != null)
|
||||
Object.DestroyImmediate(m_LinkImitator);
|
||||
if (m_ScaledSkewer != null)
|
||||
Object.DestroyImmediate(m_ScaledSkewer);
|
||||
}
|
||||
|
||||
static readonly Quaternion k_RotatedAroundYAxis = new(0f, 1f, 0f, 0f);
|
||||
static readonly Quaternion k_ArbitraryRotationAroundYAxis = Quaternion.Euler(0f, 25f, 0f);
|
||||
static readonly Vector3 k_UniformScale = new(2f, 2f, 2f);
|
||||
static readonly Vector3 k_UnevenScale = new(2f, 1f, 0.7f);
|
||||
|
||||
static readonly TestCaseData[] k_TestCases =
|
||||
{
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, Vector3.one, false, false)
|
||||
.SetName("At origin, use start and end points")
|
||||
.Returns((Vector3.back, Vector3.forward)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, Vector3.one, false, true)
|
||||
.SetName("At origin, use start point and end transform")
|
||||
.Returns((Vector3.back, Vector3.right)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, Vector3.one, true, false)
|
||||
.SetName("At origin, use start transform and end point")
|
||||
.Returns((Vector3.left, Vector3.forward)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, Vector3.one, true, true)
|
||||
.SetName("At origin, use start and end transforms")
|
||||
.Returns((Vector3.left, Vector3.right)),
|
||||
new TestCaseData(Vector3.one, Quaternion.identity, Vector3.one, false, false)
|
||||
.SetName("Offset from origin, use start and end points")
|
||||
.Returns((Vector3.one + Vector3.back, Vector3.one + Vector3.forward)),
|
||||
new TestCaseData(Vector3.one, Quaternion.identity, Vector3.one, false, true)
|
||||
.SetName("Offset from origin, use start point and end transform")
|
||||
.Returns((Vector3.one + Vector3.back, Vector3.right)),
|
||||
new TestCaseData(Vector3.one, Quaternion.identity, Vector3.one, true, false)
|
||||
.SetName("Offset from origin, use start transform and end point")
|
||||
.Returns((Vector3.left, Vector3.one + Vector3.forward)),
|
||||
new TestCaseData(Vector3.one, Quaternion.identity, Vector3.one, true, true)
|
||||
.SetName("Offset from origin, use start and end transforms")
|
||||
.Returns((Vector3.left, Vector3.right)),
|
||||
new TestCaseData(Vector3.zero, k_RotatedAroundYAxis, Vector3.one, false, false)
|
||||
.SetName("Rotated at origin, use start and end points")
|
||||
.Returns((Vector3.forward, Vector3.back)),
|
||||
new TestCaseData(Vector3.zero, k_RotatedAroundYAxis, Vector3.one, false, true)
|
||||
.SetName("Rotated at origin, use start point and end transform")
|
||||
.Returns((Vector3.forward, Vector3.right)),
|
||||
new TestCaseData(Vector3.zero, k_RotatedAroundYAxis, Vector3.one, true, false)
|
||||
.SetName("Rotated at origin, use start transform and end point")
|
||||
.Returns((Vector3.left, Vector3.back)),
|
||||
new TestCaseData(Vector3.zero, k_RotatedAroundYAxis, Vector3.one, true, true)
|
||||
.SetName("Rotated at origin, use start and end transforms")
|
||||
.Returns((Vector3.left, Vector3.right)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, k_UniformScale, false, false)
|
||||
.SetName("Scaled at origin, use start and end points")
|
||||
.Returns((Vector3.back, Vector3.forward)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, k_UniformScale, false, true)
|
||||
.SetName("Scaled at origin, use start point and end transform")
|
||||
.Returns((Vector3.back, Vector3.right)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, k_UniformScale, true, false)
|
||||
.SetName("Scaled at origin, use start transform and end point")
|
||||
.Returns((Vector3.left, Vector3.forward)),
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, k_UniformScale, true, true)
|
||||
.SetName("Scaled at origin, use start and end transforms")
|
||||
.Returns((Vector3.left, Vector3.right)),
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(k_TestCases))]
|
||||
public (Vector3 start, Vector3 end) GetWorldPositions_ReturnsExpectedResults(
|
||||
Vector3 transformPosition, Quaternion transformRotation, Vector3 transformScale,
|
||||
bool useStartTransform, bool useEndTransform
|
||||
)
|
||||
{
|
||||
m_NavMeshLink.transform.position = transformPosition;
|
||||
m_NavMeshLink.transform.rotation = transformRotation;
|
||||
m_NavMeshLink.transform.localScale = transformScale;
|
||||
m_NavMeshLink.startTransform = useStartTransform ? m_StartTransform : null;
|
||||
m_NavMeshLink.endTransform = useEndTransform ? m_EndTransform : null;
|
||||
|
||||
m_NavMeshLink.GetWorldPositions(out var worldStart, out var worldEnd);
|
||||
return (start: worldStart, end: worldEnd);
|
||||
}
|
||||
|
||||
// The expected values have been obtained by observing a correct result in the Editor
|
||||
static readonly TestCaseData[] k_SkewedTestCases =
|
||||
{
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, Vector3.one,
|
||||
new Vector3(2f, 1f, 0f), new Vector3(2f, 1f, 2f))
|
||||
.SetName("At parent origin"),
|
||||
|
||||
new TestCaseData(Vector3.zero, k_ArbitraryRotationAroundYAxis, Vector3.one,
|
||||
new Vector3(1.577382f, 1f, 0.09369224f), new Vector3(2.422618f, 1f, 1.906308f))
|
||||
.SetName("Rotated"),
|
||||
|
||||
new TestCaseData(Vector3.one, k_ArbitraryRotationAroundYAxis, Vector3.one,
|
||||
new Vector3(3.577382f, 2f, 0.7936923f), new Vector3(4.422618f, 2f, 2.606308f))
|
||||
.SetName("Offset from parent"),
|
||||
|
||||
new TestCaseData(Vector3.zero, Quaternion.identity, k_UniformScale,
|
||||
new Vector3(2f, 1f, 0f), new Vector3(2f, 1f, 2f))
|
||||
.SetName("Scaled"),
|
||||
|
||||
new TestCaseData(Vector3.one, k_ArbitraryRotationAroundYAxis, k_UniformScale,
|
||||
new Vector3(3.577382f, 2f, 0.7936923f), new Vector3(4.422618f, 2f, 2.606308f))
|
||||
.SetName("Rotated, scaled and with offset")
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(k_SkewedTestCases))]
|
||||
public void GetWorldPositionsForPoints_WhenLinkParentHasUnevenScale_ReturnsEndpointsNonSkewed(
|
||||
Vector3 transformPosition, Quaternion transformRotation, Vector3 transformScale,
|
||||
Vector3 expectedStart, Vector3 expectedEnd)
|
||||
{
|
||||
m_NavMeshLink.transform.parent = m_ScaledSkewer.transform;
|
||||
m_NavMeshLink.transform.localPosition = transformPosition;
|
||||
m_NavMeshLink.transform.localRotation = transformRotation;
|
||||
m_NavMeshLink.transform.localScale = transformScale;
|
||||
m_NavMeshLink.startTransform = null;
|
||||
m_NavMeshLink.endTransform = null;
|
||||
Assume.That(Vector3.zero, Is.Not.EqualTo(m_NavMeshLink.startPoint).Or.Not.EqualTo(m_NavMeshLink.endPoint),
|
||||
"At least one endpoint should be skewed away from the local origin.");
|
||||
|
||||
m_LinkImitator.transform.parent = m_ScaledSkewer.transform;
|
||||
m_LinkImitator.transform.localPosition = transformPosition;
|
||||
m_LinkImitator.transform.localRotation = transformRotation;
|
||||
m_LinkImitator.transform.localScale = transformScale;
|
||||
m_LinkStartImitator.transform.localPosition = m_NavMeshLink.startPoint;
|
||||
m_LinkEndImitator.transform.localPosition = m_NavMeshLink.endPoint;
|
||||
|
||||
Assume.That(m_LinkStartImitator.transform.position, Is.Not.EqualTo(expectedStart)
|
||||
.Using(Vector3EqualityComparer.Instance),
|
||||
"The wanted link start position should not be skewed along with the transform hierarchy.");
|
||||
|
||||
Assume.That(m_LinkEndImitator.transform.position, Is.Not.EqualTo(expectedEnd)
|
||||
.Using(Vector3EqualityComparer.Instance),
|
||||
"The wanted link end position should not be skewed along with the transform hierarchy.");
|
||||
|
||||
m_NavMeshLink.GetWorldPositions(out var worldStart, out var worldEnd);
|
||||
|
||||
// Uncomment to get the new expected values if you change the setup
|
||||
//Debug.Log($"(new Vector3({worldStart.x}f, {worldStart.y}f, {worldStart.z}f), new Vector3({worldEnd.x}f, {worldEnd.y}f, {worldEnd.z}f))");
|
||||
|
||||
Assert.That(worldStart, Is.EqualTo(expectedStart)
|
||||
.Using(Vector3EqualityComparer.Instance),
|
||||
"Start position should be at an unscaled offset from the Link.");
|
||||
|
||||
Assert.That(worldEnd, Is.EqualTo(expectedEnd)
|
||||
.Using(Vector3EqualityComparer.Instance),
|
||||
"End position should be at an unscaled offset from the Link.");
|
||||
}
|
||||
|
||||
static readonly Vector3 k_DoubleOne = 2f * Vector3.one;
|
||||
static readonly TestCaseData[] k_TestCasesForLocal =
|
||||
{
|
||||
new TestCaseData(false, false, Vector3.one, -Vector3.one)
|
||||
.SetName("From start and end points"),
|
||||
new TestCaseData(false, true, Vector3.one, -k_DoubleOne)
|
||||
.SetName("From start point and end transform"),
|
||||
new TestCaseData(true, false, k_DoubleOne, -Vector3.one)
|
||||
.SetName("From start transform and end point"),
|
||||
new TestCaseData(true, true, k_DoubleOne, -k_DoubleOne)
|
||||
.SetName("From start and end transforms")
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(k_TestCasesForLocal))]
|
||||
public void GetLocalPositions_ReturnsExpectedResults(
|
||||
bool useStartTransform, bool useEndTransform,
|
||||
Vector3 expectedStart, Vector3 expectedEnd)
|
||||
{
|
||||
var origin = Vector3.one;
|
||||
m_NavMeshLink.transform.SetPositionAndRotation(origin, Quaternion.Euler(90f, -90f, 90f));
|
||||
m_NavMeshLink.transform.localScale = k_DoubleOne;
|
||||
m_StartTransform.position = origin - k_DoubleOne;
|
||||
m_EndTransform.position = origin + k_DoubleOne;
|
||||
|
||||
m_NavMeshLink.enabled = false;
|
||||
m_NavMeshLink.startTransform = useStartTransform ? m_StartTransform : null;
|
||||
m_NavMeshLink.endTransform = useEndTransform ? m_EndTransform : null;
|
||||
m_NavMeshLink.startPoint = !useStartTransform ? Vector3.one : 100f * Vector3.one;
|
||||
m_NavMeshLink.endPoint = !useEndTransform ? -Vector3.one : -100f * Vector3.one;
|
||||
m_NavMeshLink.enabled = true;
|
||||
|
||||
m_NavMeshLink.GetLocalPositions(out var localStart, out var localEnd);
|
||||
|
||||
Assert.That(localStart, Is.EqualTo(expectedStart).Using(Vector3EqualityComparer.Instance),
|
||||
"Start should be reported at a different position.");
|
||||
Assert.That(localEnd, Is.EqualTo(expectedEnd).Using(Vector3EqualityComparer.Instance),
|
||||
"End should be reported at a different position.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a2ea6cc04d4a4333b94b04c4d51c56c
|
||||
@@ -0,0 +1,106 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
class NavMeshSurfaceAgentTests
|
||||
{
|
||||
NavMeshSurface m_Surface;
|
||||
NavMeshAgent m_Agent;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_Surface = GameObject.CreatePrimitive(PrimitiveType.Plane).AddComponent<NavMeshSurface>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_Agent.gameObject);
|
||||
Object.DestroyImmediate(m_Surface.gameObject);
|
||||
m_Agent = null;
|
||||
m_Surface = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AgentIdentifiesSurfaceOwner()
|
||||
{
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
Assert.AreEqual(m_Surface, m_Agent.navMeshOwner);
|
||||
Assert.IsTrue(m_Agent.isOnNavMesh);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("1012991 : Missing functionality for notifying the NavMeshAgent about the removal of the NavMesh.")]
|
||||
public void AgentDetachesAndAttachesToSurface()
|
||||
{
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
Assert.AreEqual(m_Surface, m_Agent.navMeshOwner);
|
||||
Assert.IsTrue(m_Agent.isOnNavMesh);
|
||||
|
||||
m_Surface.enabled = false;
|
||||
Assert.IsNull(m_Agent.navMeshOwner);
|
||||
Assert.IsFalse(m_Agent.isOnNavMesh);
|
||||
|
||||
m_Surface.enabled = true;
|
||||
Assert.AreEqual(m_Surface, m_Agent.navMeshOwner);
|
||||
Assert.IsTrue(m_Agent.isOnNavMesh);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[Test]
|
||||
public void AgentIsOnNavMeshWhenMatchingAgentTypeID()
|
||||
{
|
||||
m_Surface.agentTypeID = 1234;
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
Assert.IsFalse(m_Agent.isOnNavMesh);
|
||||
|
||||
m_Agent.agentTypeID = 1234;
|
||||
Assert.IsTrue(m_Agent.isOnNavMesh);
|
||||
}
|
||||
*/
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AgentAlignsToSurfaceNextFrame()
|
||||
{
|
||||
m_Surface.transform.rotation = new Quaternion(-0.679622f, 0.351242f, -0.373845f, 0.524388f);
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
|
||||
yield return null;
|
||||
|
||||
var residual = m_Surface.transform.up - m_Agent.transform.up;
|
||||
Assert.IsTrue(residual.magnitude < 0.01f);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AgentDoesNotAlignToSurfaceNextFrame()
|
||||
{
|
||||
m_Surface.transform.rotation = new Quaternion(-0.679622f, 0.351242f, -0.373845f, 0.524388f);
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
m_Agent.updateUpAxis = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var residual = Vector3.up - m_Agent.transform.up;
|
||||
Assert.IsTrue(residual.magnitude < 0.01f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45e898f1334e740678c21331ac30d746
|
||||
timeCreated: 1490606318
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[DefaultExecutionOrder(-1)]
|
||||
class NavMeshSurfaceBuildFromAwake : MonoBehaviour
|
||||
{
|
||||
public NavMeshSurface surface;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
surface.BuildNavMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6be2106b2f72df4199763945ec1f6ec
|
||||
@@ -0,0 +1,966 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class NavMeshSurfaceLinkTests
|
||||
{
|
||||
GameObject m_PlaneAtOrigin;
|
||||
GameObject m_PlaneOnTheSide;
|
||||
NavMeshLink m_Link;
|
||||
NavMeshSurface m_Surface;
|
||||
readonly Vector3 m_OffsetX = new(11f, 0f, 0f);
|
||||
readonly Vector3 m_OffsetZ = new(0f, 0f, 11f);
|
||||
readonly Vector3 m_DefaultEndpointOffset = new(0f, 0f, 2.5f);
|
||||
readonly int m_PandaTypeID = NavMesh.CreateSettings().agentTypeID;
|
||||
const int k_AreaTypeForPanda = 3;
|
||||
NavMeshAgent m_Agent;
|
||||
GameObject m_ExtraNavMesh;
|
||||
GameObject m_FarFromNavMesh;
|
||||
GameObject m_TempGO;
|
||||
GameObject m_PathfindingStart;
|
||||
GameObject m_PathfindingEnd;
|
||||
NavMeshDataInstance m_NavMeshClone;
|
||||
NavMeshDataInstance m_NavMeshForPanda;
|
||||
NavMeshSurface m_SurfaceForPanda;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
m_PlaneAtOrigin = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_PlaneOnTheSide = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_PlaneOnTheSide.transform.position = m_OffsetX;
|
||||
m_PlaneOnTheSide.transform.localScale = 0.4f * Vector3.one;
|
||||
m_PlaneAtOrigin.transform.localScale = 0.4f * Vector3.one;
|
||||
|
||||
m_Surface = new GameObject("Surface").AddComponent<NavMeshSurface>();
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
Assume.That(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide), Is.False);
|
||||
Assume.That(HasPathConnecting(m_PlaneOnTheSide, m_PlaneAtOrigin), Is.False);
|
||||
|
||||
m_Agent = new GameObject("Agent").AddComponent<NavMeshAgent>();
|
||||
m_Agent.transform.position = m_PlaneOnTheSide.transform.position - 2f * Vector3.back;
|
||||
m_Agent.enabled = false;
|
||||
m_Agent.acceleration = 100f;
|
||||
m_Agent.speed = 10f;
|
||||
Assume.That(m_Agent.speed, Is.LessThan(m_OffsetX.x),
|
||||
"Too high of a speed causes the agent to jump straight to the path's end.");
|
||||
|
||||
m_PathfindingStart = new GameObject("Path Start");
|
||||
m_PathfindingEnd = new GameObject("Path End");
|
||||
m_ExtraNavMesh = new GameObject("Origin of Additional NavMesh")
|
||||
{
|
||||
transform =
|
||||
{
|
||||
position = m_PlaneAtOrigin.transform.position + m_OffsetZ
|
||||
}
|
||||
};
|
||||
m_FarFromNavMesh = new GameObject("Position Far From NavMesh")
|
||||
{
|
||||
transform =
|
||||
{
|
||||
position = m_ExtraNavMesh.transform.position - 2f * m_OffsetX
|
||||
}
|
||||
};
|
||||
|
||||
m_NavMeshClone = NavMesh.AddNavMeshData(m_Surface.navMeshData, m_ExtraNavMesh.transform.position, Quaternion.identity);
|
||||
|
||||
m_SurfaceForPanda = m_Surface.gameObject.AddComponent<NavMeshSurface>();
|
||||
m_SurfaceForPanda.agentTypeID = m_PandaTypeID;
|
||||
m_SurfaceForPanda.defaultArea = k_AreaTypeForPanda;
|
||||
m_SurfaceForPanda.BuildNavMesh();
|
||||
m_SurfaceForPanda.enabled = false;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
// move m_Link to OneTimeSetup
|
||||
m_Link = new GameObject("Link").AddComponent<NavMeshLink>();
|
||||
m_Link.transform.position = Vector3.zero;
|
||||
m_Link.startPoint = m_PlaneAtOrigin.transform.position;
|
||||
m_Link.endPoint = m_PlaneOnTheSide.transform.position;
|
||||
m_Link.UpdateLink();
|
||||
|
||||
Assume.That(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide), Is.True);
|
||||
Assume.That(HasPathConnecting(m_PlaneOnTheSide, m_PlaneAtOrigin), Is.True);
|
||||
|
||||
if (m_Agent.isActiveAndEnabled)
|
||||
{
|
||||
m_Agent.ResetPath();
|
||||
m_Agent.Warp(m_PlaneOnTheSide.transform.position - 2f * Vector3.back);
|
||||
}
|
||||
|
||||
m_PathfindingStart.transform.position = m_Link.transform.position + m_Link.startPoint;
|
||||
m_PathfindingEnd.transform.position = m_Link.transform.position + m_Link.endPoint;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_Link.gameObject);
|
||||
if (m_TempGO != null)
|
||||
Object.DestroyImmediate(m_TempGO);
|
||||
if (m_NavMeshForPanda.valid)
|
||||
NavMesh.RemoveNavMeshData(m_NavMeshForPanda);
|
||||
m_Agent.enabled = false;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_Surface.gameObject);
|
||||
Object.DestroyImmediate(m_PlaneAtOrigin);
|
||||
Object.DestroyImmediate(m_PlaneOnTheSide);
|
||||
Object.DestroyImmediate(m_Agent);
|
||||
Object.DestroyImmediate(m_ExtraNavMesh);
|
||||
Object.DestroyImmediate(m_FarFromNavMesh);
|
||||
Object.DestroyImmediate(m_PathfindingStart);
|
||||
Object.DestroyImmediate(m_PathfindingEnd);
|
||||
if (m_NavMeshClone.valid)
|
||||
NavMesh.RemoveNavMeshData(m_NavMeshClone);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenCreated_HasDefaultEndpointOffsets()
|
||||
{
|
||||
var link = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
Assert.That(link.startPoint, Is.EqualTo(-m_DefaultEndpointOffset).Using(Vector3EqualityComparer.Instance),
|
||||
"Newly created NavMeshLink should have the start point located at an offset from the game object.");
|
||||
Assert.That(link.endPoint, Is.EqualTo(m_DefaultEndpointOffset).Using(Vector3EqualityComparer.Instance),
|
||||
"Newly created NavMeshLink should have the end point located at an offset from the game object.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenCreatedAtRuntime_HasNullStartAndEndTransforms()
|
||||
{
|
||||
var link = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
Assert.That(link.startTransform, Is.EqualTo(null),
|
||||
"A NavMeshLink newly created should have a null start transform.");
|
||||
Assert.That(link.endTransform, Is.EqualTo(null),
|
||||
"A NavMeshLink newly created should have a null end transform.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenCreated_HasTheExpectedValuesForProperties()
|
||||
{
|
||||
var link = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
|
||||
Assert.That(link.area, Is.EqualTo(0),
|
||||
"Newly created NavMeshLink should have the Walkable area type.");
|
||||
|
||||
Assert.That(link.agentTypeID, Is.EqualTo(0),
|
||||
"Newly created NavMeshLink should have the Humanoid agent type ID.");
|
||||
|
||||
Assert.That(link.bidirectional, Is.True,
|
||||
"Newly created NavMeshLink should have bidirectional switched on.");
|
||||
|
||||
Assert.That(link.costModifier, Is.Negative,
|
||||
"Newly created NavMeshLink should have a negative cost modifier, which means the cost from area type is not overridden.");
|
||||
|
||||
Assert.That(link.width, Is.EqualTo(0f),
|
||||
"Newly created NavMeshLink should have a width of zero.");
|
||||
|
||||
Assert.That(link.autoUpdate, Is.False,
|
||||
"Newly created NavMeshLink should have autoUpdate switched off.");
|
||||
|
||||
Assert.That(link.activated, Is.True,
|
||||
"Newly created NavMeshLink should be activated.");
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(-1)]
|
||||
[TestCase(42)]
|
||||
[TestCase(-42)]
|
||||
public void CostModifier_SetValue_GetValueIsTheSame(int costModifier)
|
||||
{
|
||||
m_Link.costModifier = costModifier;
|
||||
Assert.That(m_Link.costModifier, Is.EqualTo(costModifier));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WithValidParameters_ConnectsTwoSurfaces()
|
||||
{
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_OnScaledObject_DoesNotScaleEndPoints()
|
||||
{
|
||||
m_Link.enabled = false;
|
||||
m_Link.transform.localScale = new Vector3(1f, 1f, m_OffsetZ.z);
|
||||
m_Link.startPoint = m_PlaneAtOrigin.transform.position + Vector3.forward;
|
||||
m_Link.endPoint = m_PlaneOnTheSide.transform.position + Vector3.forward;
|
||||
m_Link.enabled = true;
|
||||
|
||||
m_PathfindingStart.transform.position = m_Link.transform.TransformPoint(m_Link.startPoint);
|
||||
m_PathfindingEnd.transform.position = m_Link.transform.TransformPoint(m_Link.endPoint);
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_PathfindingStart.transform.position = m_PlaneAtOrigin.transform.position;
|
||||
m_PathfindingEnd.transform.position = m_PlaneOnTheSide.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_OnUpdateLinkWhileDisabled_DoesNotEnableConnection()
|
||||
{
|
||||
m_Link.gameObject.SetActive(false);
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_Link.UpdateLink();
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_OnUpdateLink_AppliesChangesImmediately()
|
||||
{
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
|
||||
m_Link.UpdateLink();
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward, m_Link.area, m_Link.agentTypeID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenEnabled_AppliesChangesImmediately()
|
||||
{
|
||||
m_Link.enabled = false;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
AddNavMeshForPandaAgent();
|
||||
ReconfigureLinkForPandaAgent(m_Link);
|
||||
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position;
|
||||
m_PathfindingEnd.transform.position = m_PlaneAtOrigin.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.NoPath, m_Link.area, m_Link.agentTypeID);
|
||||
|
||||
m_Link.enabled = true;
|
||||
VerifyLinkConnection(ResultsIn.PathOnlyForward, m_Link.area, m_Link.agentTypeID);
|
||||
}
|
||||
|
||||
void ReconfigureLinkForPandaAgent(NavMeshLink link)
|
||||
{
|
||||
var wasEnabled = link.enabled;
|
||||
link.enabled = false;
|
||||
link.agentTypeID = m_PandaTypeID;
|
||||
link.area = k_AreaTypeForPanda;
|
||||
link.bidirectional = false;
|
||||
link.costModifier = 3f;
|
||||
link.width = 6f;
|
||||
link.startTransform = m_ExtraNavMesh.transform;
|
||||
link.endTransform = m_PlaneAtOrigin.transform;
|
||||
link.startPoint = 3f * Vector3.forward;
|
||||
link.endPoint = 3f * Vector3.forward + Vector3.right;
|
||||
link.enabled = wasEnabled;
|
||||
}
|
||||
|
||||
void AddNavMeshForPandaAgent()
|
||||
{
|
||||
m_NavMeshForPanda = NavMesh.AddNavMeshData(m_SurfaceForPanda.navMeshData,
|
||||
m_ExtraNavMesh.transform.position + 0.05f * Vector3.up, Quaternion.Euler(0f, 90f, 0f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenGameObjectTransformMoves_EndpointsMoveRelativeToLinkOnUpdate()
|
||||
{
|
||||
m_Link.transform.position += Vector3.forward;
|
||||
Assert.IsFalse(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position + Vector3.forward));
|
||||
Assert.IsFalse(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position + Vector3.forward));
|
||||
|
||||
m_Link.UpdateLink();
|
||||
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position + Vector3.forward));
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position + Vector3.forward));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyAreaChanges_UpdatesConnectionImmediately()
|
||||
{
|
||||
Assume.That(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide), Is.True);
|
||||
|
||||
m_Link.area = 4;
|
||||
var anyAreaExceptTheLinkArea = ~(1 << m_Link.area);
|
||||
Assert.IsFalse(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide, anyAreaExceptTheLinkArea));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyBidirectionalSwitchedOff_UpdatesConnectionImmediatelyToOneWay()
|
||||
{
|
||||
Assume.That(HasPathConnecting(m_PlaneOnTheSide, m_PlaneAtOrigin), Is.True);
|
||||
|
||||
m_Link.bidirectional = false;
|
||||
VerifyLinkConnection(ResultsIn.PathOnlyForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyBidirectionalSwitchedOn_UpdatesConnectionImmediatelyToBothWays()
|
||||
{
|
||||
m_Link.bidirectional = false;
|
||||
Assume.That(HasPathConnecting(m_PlaneOnTheSide, m_PlaneAtOrigin), Is.False);
|
||||
|
||||
m_Link.bidirectional = true;
|
||||
VerifyLinkConnection(ResultsIn.PathBothWays);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyCostModifierChanges_UpdatesConnectionImmediately()
|
||||
{
|
||||
m_Link.gameObject.SetActive(false);
|
||||
var fartherLink = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
fartherLink.startPoint = m_PlaneAtOrigin.transform.position + Vector3.forward;
|
||||
fartherLink.endPoint = m_PlaneOnTheSide.transform.position + Vector3.forward;
|
||||
m_Link.gameObject.SetActive(true);
|
||||
|
||||
Assume.That(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_Link.endPoint), Is.True);
|
||||
|
||||
m_Link.costModifier = 1000f;
|
||||
|
||||
Assert.IsFalse(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_Link.endPoint),
|
||||
"A path should not go through the connection with the higher cost, even if it's closer.");
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, fartherLink.endPoint),
|
||||
"A path should go through the connection with the lower cost, even if it's farther away.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyStartPointChanged_UpdatesConnectionImmediately()
|
||||
{
|
||||
m_Link.startPoint = m_OffsetZ;
|
||||
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyEndPointChanged_UpdatesConnectionImmediately()
|
||||
{
|
||||
m_Link.endPoint = m_OffsetZ;
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyWidthChanges_UpdatesConnectionImmediately()
|
||||
{
|
||||
m_Link.transform.position = 3f * Vector3.forward;
|
||||
m_Link.UpdateLink();
|
||||
Assume.That(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide), Is.False);
|
||||
|
||||
m_Link.width = 6f;
|
||||
Assert.IsTrue(HasPathConnecting(m_PlaneAtOrigin, m_PlaneOnTheSide));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenPropertyActivatedChanges_UpdatesConnectionImmediately()
|
||||
{
|
||||
m_Link.activated = false;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_Link.activated = true;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformAssignedAtStart_RetainsValueOfStartPoint()
|
||||
{
|
||||
m_TempGO = new GameObject("Link");
|
||||
var link = m_TempGO.AddComponent<NavMeshLink>();
|
||||
Assume.That(link.startPoint, Is.Not.EqualTo(Vector3.zero));
|
||||
var startPointBefore = link.startPoint;
|
||||
|
||||
link.startTransform = m_ExtraNavMesh.transform;
|
||||
link.UpdateLink();
|
||||
Assert.That(link.startPoint, Is.EqualTo(startPointBefore),
|
||||
"NavMeshLink should retain the start point after a start transform has been assigned to it.");
|
||||
Assume.That(link.endPoint, Is.Not.EqualTo(Vector3.zero), "End point should retain a default offset.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformAssignedAtEnd_RetainsValueOfEndPoint()
|
||||
{
|
||||
m_TempGO = new GameObject("Link");
|
||||
var link = m_TempGO.AddComponent<NavMeshLink>();
|
||||
Assume.That(link.endPoint, Is.Not.EqualTo(Vector3.zero));
|
||||
var endPointBefore = link.endPoint;
|
||||
|
||||
link.endTransform = m_ExtraNavMesh.transform;
|
||||
link.UpdateLink();
|
||||
Assert.That(link.endPoint, Is.EqualTo(endPointBefore),
|
||||
"NavMeshLink should preserve the end point after an end transform has been assigned to it.");
|
||||
Assume.That(link.startPoint, Is.Not.EqualTo(Vector3.zero), "Start point should keep a default offset.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformRemovedAtStart_KeepsStartPointUnchanged()
|
||||
{
|
||||
m_TempGO = new GameObject("Link");
|
||||
var pointBefore = new Vector3(1f, 2f, 3f);
|
||||
var link = m_TempGO.AddComponent<NavMeshLink>();
|
||||
link.startTransform = m_TempGO.transform;
|
||||
link.startPoint = pointBefore;
|
||||
|
||||
link.startTransform = null;
|
||||
|
||||
Assert.That(link.startPoint, Is.EqualTo(pointBefore),
|
||||
"NavMeshLink should retain the same start point after the start transform has been unassigned.");
|
||||
Assume.That(link.endPoint, Is.EqualTo(m_DefaultEndpointOffset),
|
||||
"End point should keep a default offset.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformRemovedAtEnd_KeepsEndPointUnchanged()
|
||||
{
|
||||
m_TempGO = new GameObject("Link");
|
||||
var pointBefore = new Vector3(1f, 2f, 3f);
|
||||
var link = m_TempGO.AddComponent<NavMeshLink>();
|
||||
link.endTransform = m_TempGO.transform;
|
||||
link.endPoint = pointBefore;
|
||||
|
||||
link.endTransform = null;
|
||||
|
||||
Assert.That(link.endPoint, Is.EqualTo(pointBefore),
|
||||
"NavMeshLink should retain the same end point after the end transform has been unassigned.");
|
||||
Assume.That(link.startPoint, Is.EqualTo(-m_DefaultEndpointOffset),
|
||||
"Start point should keep a default offset.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformAssignedAtStart_OverridesStartPointImmediately()
|
||||
{
|
||||
m_Link.startPoint = m_ExtraNavMesh.transform.position + m_OffsetX - m_Link.transform.position;
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position + m_OffsetX;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_Link.startTransform = m_ExtraNavMesh.transform;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformAssignedAtEnd_OverridesEndPointImmediately()
|
||||
{
|
||||
m_Link.endPoint = m_ExtraNavMesh.transform.position + m_OffsetX - m_Link.transform.position;
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position + m_OffsetX;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_Link.endTransform = m_ExtraNavMesh.transform;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformRemovedAtStart_FallsBackToStartPointImmediately()
|
||||
{
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
|
||||
m_Link.enabled = false;
|
||||
m_Link.startPoint = m_ExtraNavMesh.transform.position + m_OffsetX - m_Link.transform.position;
|
||||
m_Link.startTransform = m_TempGO.transform;
|
||||
m_Link.enabled = true;
|
||||
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position + m_OffsetX;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_Link.startTransform = null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenTransformRemovedAtEnd_FallsBackToEndPointImmediately()
|
||||
{
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
|
||||
m_Link.enabled = false;
|
||||
m_Link.endPoint = m_ExtraNavMesh.transform.position + m_OffsetX - m_Link.transform.position;
|
||||
m_Link.endTransform = m_TempGO.transform;
|
||||
m_Link.enabled = true;
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position + m_OffsetX;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_Link.endTransform = null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenBothTransformAndPointChangeAtStart_AppliesOnlyStartTransform()
|
||||
{
|
||||
m_Link.startTransform = m_ExtraNavMesh.transform;
|
||||
m_Link.startPoint = -2f * m_OffsetX;
|
||||
|
||||
m_PathfindingStart.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenBothTransformAndPointChangeAtEnd_AppliesOnlyEndTransform()
|
||||
{
|
||||
m_Link.endTransform = m_ExtraNavMesh.transform;
|
||||
m_Link.endPoint = -2f * m_OffsetX;
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Link_DuringAgentTraversal_ReportsIsOccupied_OtherwiseNotOccupied()
|
||||
{
|
||||
m_Agent.enabled = true;
|
||||
m_Agent.SetDestination(m_PlaneAtOrigin.transform.position + Vector3.back);
|
||||
|
||||
while (!m_Agent.isOnOffMeshLink)
|
||||
{
|
||||
Assert.IsFalse(m_Link.occupied, "Link is occupied, but the agent hasn't arrived to the link yet.");
|
||||
yield return null;
|
||||
}
|
||||
|
||||
var framesUntilComplete = 3;
|
||||
while (m_Agent.isOnOffMeshLink)
|
||||
{
|
||||
Assert.IsTrue(m_Link.occupied, "Link is not occupied, but the agent is on the link.");
|
||||
|
||||
if (--framesUntilComplete == 0)
|
||||
m_Agent.CompleteOffMeshLink();
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Assert.IsFalse(m_Link.occupied, "Link is occupied, but agent has left the link.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Link_WhenAutoUpdateSwitchedOn_UpdatesOnNextFrame_AndNotBefore()
|
||||
{
|
||||
Assume.That(m_Link.autoUpdate, Is.False);
|
||||
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Link_WhenAutoUpdateSwitchedOff_DoesNotApplyQueuedOrFutureChanges()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
yield return null;
|
||||
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
|
||||
Assume.That(m_PathfindingEnd.transform.position, Is.EqualTo(m_PlaneOnTheSide.transform.position).Using(Vector3EqualityComparer.Instance));
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_Link.autoUpdate = false;
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_Link.transform.SetPositionAndRotation(m_ExtraNavMesh.transform.position, Quaternion.identity);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenGameObjectMoves_UpdatesConnectionNextFrame()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
m_Link.transform.position += Vector3.forward;
|
||||
|
||||
Assert.IsFalse(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position + Vector3.forward));
|
||||
Assert.IsFalse(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position + Vector3.forward));
|
||||
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position + Vector3.forward));
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position + Vector3.forward));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOff_WhenGameObjectMoves_KeepsConnectionUnchanged()
|
||||
{
|
||||
m_Link.autoUpdate = false;
|
||||
|
||||
Assume.That(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position), Is.True);
|
||||
Assert.That(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position), Is.True);
|
||||
|
||||
m_Link.transform.position += Vector3.forward;
|
||||
|
||||
// Skip a few frames
|
||||
yield return null;
|
||||
yield return null;
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneAtOrigin.transform.position));
|
||||
Assert.IsTrue(HasPathConnectingViaPoint(m_PlaneAtOrigin, m_PlaneOnTheSide, m_PlaneOnTheSide.transform.position));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenGameObjectRotates_UpdatesConnectionNextFrame()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOff_WhenGameObjectRotates_KeepsConnectionUnchanged()
|
||||
{
|
||||
m_Link.autoUpdate = false;
|
||||
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
|
||||
// Skip a few frames
|
||||
yield return null;
|
||||
yield return null;
|
||||
yield return null;
|
||||
|
||||
Assume.That(m_PathfindingEnd.transform.position, Is.EqualTo(m_PlaneOnTheSide.transform.position).Using(Vector3EqualityComparer.Instance));
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenTransformAtStartMoves_UpdatesConnectionNextFrame()
|
||||
{
|
||||
m_TempGO = Object.Instantiate(m_FarFromNavMesh);
|
||||
m_Link.startTransform = m_TempGO.transform;
|
||||
m_Link.UpdateLink();
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
m_TempGO.transform.position += 2f * m_OffsetX;
|
||||
m_PathfindingStart.transform.position = m_TempGO.transform.position;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenTransformAtEndMoves_UpdatesConnectionNextFrame()
|
||||
{
|
||||
m_TempGO = Object.Instantiate(m_FarFromNavMesh);
|
||||
m_Link.endTransform = m_TempGO.transform;
|
||||
m_Link.UpdateLink();
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
m_TempGO.transform.position += 2f * m_OffsetX;
|
||||
m_PathfindingEnd.transform.position = m_TempGO.transform.position;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenTransformAtStartDestroyed_AppliesStartPointNextFrame()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
m_Link.enabled = false;
|
||||
m_Link.startTransform = m_TempGO.transform;
|
||||
m_Link.startPoint = m_PlaneOnTheSide.transform.position - m_Link.transform.position;
|
||||
m_Link.endTransform = null;
|
||||
m_Link.endPoint = Vector3.zero;
|
||||
m_Link.bidirectional = false;
|
||||
m_Link.enabled = true;
|
||||
|
||||
m_PathfindingStart.transform.position = m_TempGO.transform.position;
|
||||
m_PathfindingEnd.transform.position = m_PlaneAtOrigin.transform.position;
|
||||
|
||||
Object.DestroyImmediate(m_TempGO);
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_PathfindingStart.transform.position = m_PlaneOnTheSide.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOn_WhenTransformAtEndDestroyed_AppliesEndPointNextFrame()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
m_Link.enabled = false;
|
||||
m_Link.startTransform = null;
|
||||
m_Link.startPoint = m_PlaneOnTheSide.transform.position - m_Link.transform.position;
|
||||
m_Link.endTransform = m_TempGO.transform;
|
||||
m_Link.endPoint = Vector3.zero;
|
||||
m_Link.bidirectional = false;
|
||||
m_Link.enabled = true;
|
||||
|
||||
m_PathfindingStart.transform.position = m_PlaneOnTheSide.transform.position;
|
||||
m_PathfindingEnd.transform.position = m_TempGO.transform.position;
|
||||
|
||||
Object.DestroyImmediate(m_TempGO);
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
|
||||
m_PathfindingEnd.transform.position = m_PlaneAtOrigin.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOff_WhenTransformAtStartMoves_KeepsConnectionUnchanged()
|
||||
{
|
||||
m_Link.autoUpdate = false;
|
||||
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
m_Link.startTransform = m_TempGO.transform;
|
||||
m_Link.UpdateLink();
|
||||
|
||||
m_PathfindingStart.transform.position = m_TempGO.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_TempGO.transform.position += m_OffsetX;
|
||||
yield return null;
|
||||
yield return null;
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_PathfindingStart.transform.position = m_TempGO.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LinkWithAutoUpdateOff_WhenTransformAtEndMoves_KeepsConnectionUnchanged()
|
||||
{
|
||||
m_Link.autoUpdate = false;
|
||||
|
||||
m_TempGO = Object.Instantiate(m_ExtraNavMesh);
|
||||
m_Link.endTransform = m_TempGO.transform;
|
||||
m_Link.UpdateLink();
|
||||
|
||||
m_PathfindingEnd.transform.position = m_TempGO.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_TempGO.transform.position += m_OffsetX;
|
||||
yield return null;
|
||||
yield return null;
|
||||
yield return null;
|
||||
|
||||
VerifyLinkConnection(ResultsIn.PathForward);
|
||||
|
||||
m_PathfindingEnd.transform.position = m_TempGO.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.NoPath);
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618 // Test deprecated members
|
||||
[Test]
|
||||
public void Link_WhenCreated_HasTheExpectedValuesForDeprecatedProperties()
|
||||
{
|
||||
var link = m_Link.gameObject.AddComponent<NavMeshLink>();
|
||||
|
||||
Assert.That(link.biDirectional, Is.True,
|
||||
"Newly created NavMeshLink should have deprecated biDirectional switched on.");
|
||||
|
||||
Assert.That(link.autoUpdatePositions, Is.False,
|
||||
"Newly created NavMeshLink should have deprecated autoUpdatePositions switched off.");
|
||||
|
||||
Assert.That(link.costOverride, Is.Negative,
|
||||
"Newly created NavMeshLink should have a negative deprecated cost override, which means the cost from area type is not overridden.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenBidirectionalChanges_DeprecatedBiDirectionalChangesToo()
|
||||
{
|
||||
m_Link.bidirectional = false;
|
||||
Assert.That(m_Link.biDirectional, Is.False);
|
||||
|
||||
m_Link.bidirectional = true;
|
||||
Assert.That(m_Link.biDirectional, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenDeprecatedBiDirectionalChanges_BidirectionalChangesToo()
|
||||
{
|
||||
m_Link.biDirectional = false;
|
||||
Assert.That(m_Link.bidirectional, Is.False);
|
||||
|
||||
m_Link.biDirectional = true;
|
||||
Assert.That(m_Link.bidirectional, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenAutoUpdateChanges_DeprecatedAutoUpdatePositionsChangesToo()
|
||||
{
|
||||
m_Link.autoUpdate = true;
|
||||
Assert.That(m_Link.autoUpdatePositions, Is.True);
|
||||
|
||||
m_Link.autoUpdate = false;
|
||||
Assert.That(m_Link.autoUpdatePositions, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenDeprecatedAutoUpdatePositionsChanges_AutoUpdateChangesToo()
|
||||
{
|
||||
m_Link.autoUpdatePositions = true;
|
||||
Assert.That(m_Link.autoUpdate, Is.True);
|
||||
|
||||
m_Link.autoUpdatePositions = false;
|
||||
Assert.That(m_Link.autoUpdate, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenCostModifierChanges_DeprecatedCostOverrideChangesToo()
|
||||
{
|
||||
m_Link.costModifier = 1f;
|
||||
Assert.That(m_Link.costOverride, Is.EqualTo(1f));
|
||||
|
||||
m_Link.costModifier = 0f;
|
||||
Assert.That(m_Link.costOverride, Is.EqualTo(0f));
|
||||
|
||||
m_Link.costModifier = -4.123f;
|
||||
Assert.That(m_Link.costOverride, Is.EqualTo(-4.123f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_WhenDeprecatedCostOverrideChanges_CostModifierChangesToo()
|
||||
{
|
||||
m_Link.costOverride = 1f;
|
||||
Assert.That(m_Link.costModifier, Is.EqualTo(1f));
|
||||
|
||||
m_Link.costOverride = 0f;
|
||||
Assert.That(m_Link.costModifier, Is.EqualTo(0f));
|
||||
|
||||
m_Link.costOverride = -4.123f;
|
||||
Assert.That(m_Link.costModifier, Is.EqualTo(-4.123f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Link_OnDeprecatedUpdatePositions_AppliesChangesImmediately()
|
||||
{
|
||||
m_Link.transform.rotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
|
||||
m_Link.UpdatePositions();
|
||||
|
||||
m_PathfindingEnd.transform.position = m_ExtraNavMesh.transform.position;
|
||||
VerifyLinkConnection(ResultsIn.PathForward, m_Link.area, m_Link.agentTypeID);
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
|
||||
internal enum ResultsIn
|
||||
{
|
||||
PathForward,
|
||||
PathOnlyForward,
|
||||
PathBothWays,
|
||||
NoPath
|
||||
}
|
||||
|
||||
void VerifyLinkConnection(ResultsIn expected,
|
||||
int areaType = 0,
|
||||
int agentTypeID = 0)
|
||||
{
|
||||
var forwardWanted = expected != ResultsIn.NoPath;
|
||||
try
|
||||
{
|
||||
Assert.That(HasPathConnecting(m_PathfindingStart, m_PathfindingEnd, 1 << areaType, agentTypeID), Is.EqualTo(forwardWanted),
|
||||
forwardWanted ? "The NavMesh patches should be connected." : "The NavMesh patches should not be connected.");
|
||||
}
|
||||
catch (AssertionException)
|
||||
{
|
||||
Debug.Log($"The NavMesh patches at {m_PathfindingStart.transform.position} and {m_PathfindingEnd.transform.position} should {(forwardWanted ? "" : "not ")}be connected (agent={NavMesh.GetSettingsNameFromID(agentTypeID)}, area={areaType}).");
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (expected != ResultsIn.PathForward && expected != ResultsIn.NoPath)
|
||||
{
|
||||
var backwardWanted = expected == ResultsIn.PathBothWays;
|
||||
try
|
||||
{
|
||||
Assert.That(HasPathConnecting(m_PathfindingEnd, m_PathfindingStart, 1 << areaType, agentTypeID), Is.EqualTo(backwardWanted),
|
||||
backwardWanted ? "The NavMesh patches should be connected backward." : "The NavMesh patches should not be connected backward.");
|
||||
}
|
||||
catch (AssertionException)
|
||||
{
|
||||
Debug.Log($"The NavMesh patches at {m_PathfindingStart.transform.position} and {m_PathfindingEnd.transform.position} should {(backwardWanted ? "" : "not ")}be connected backward (agent={NavMesh.GetSettingsNameFromID(agentTypeID)}, area={areaType}).");
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool HasPathConnecting(GameObject a, GameObject b, int areaMask = NavMesh.AllAreas, int agentTypeID = 0)
|
||||
{
|
||||
var path = new NavMeshPath();
|
||||
var filter = new NavMeshQueryFilter
|
||||
{
|
||||
areaMask = areaMask,
|
||||
agentTypeID = agentTypeID
|
||||
};
|
||||
NavMesh.CalculatePath(a.transform.position, b.transform.position, filter, path);
|
||||
return path.status == NavMeshPathStatus.PathComplete;
|
||||
}
|
||||
|
||||
static bool HasPathConnectingViaPoint(GameObject a, GameObject b, Vector3 point, int areaMask = NavMesh.AllAreas, int agentTypeID = 0)
|
||||
{
|
||||
var path = new NavMeshPath();
|
||||
var filter = new NavMeshQueryFilter
|
||||
{
|
||||
areaMask = areaMask,
|
||||
agentTypeID = agentTypeID
|
||||
};
|
||||
NavMesh.CalculatePath(a.transform.position, b.transform.position, filter, path);
|
||||
if (path.status != NavMeshPathStatus.PathComplete)
|
||||
return false;
|
||||
|
||||
var pathCorners = path.corners;
|
||||
for (var i = 1; i < pathCorners.Length - 1; i++)
|
||||
{
|
||||
var corner = pathCorners[i];
|
||||
if (Vector3.Distance(corner, point) < 0.1f)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 264ca61ae1b6e4c16bcfc55f84300402
|
||||
timeCreated: 1490606318
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,133 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class NavMeshSurfaceModifierTests
|
||||
{
|
||||
NavMeshSurface m_Surface;
|
||||
NavMeshModifier m_Modifier;
|
||||
NavMeshSurfaceBuildFromAwake m_BuildOnAwake;
|
||||
|
||||
[SetUp]
|
||||
public void CreatePlaneWithModifier()
|
||||
{
|
||||
var plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
m_Surface = plane.AddComponent<NavMeshSurface>();
|
||||
m_Modifier = plane.AddComponent<NavMeshModifier>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void DestroyPlaneWithModifier()
|
||||
{
|
||||
Object.DestroyImmediate(m_Modifier.gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierIgnoreAffectsSelf()
|
||||
{
|
||||
m_Modifier.ignoreFromBuild = true;
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
Assert.IsFalse(NavMeshSurfaceTests.HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierIgnoreAffectsChild()
|
||||
{
|
||||
m_Modifier.ignoreFromBuild = true;
|
||||
m_Modifier.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
var childPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
childPlane.transform.SetParent(m_Modifier.transform);
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
Assert.IsFalse(NavMeshSurfaceTests.HasNavMeshAtOrigin());
|
||||
Object.DestroyImmediate(childPlane);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierIgnoreDoesNotAffectSibling()
|
||||
{
|
||||
m_Modifier.ignoreFromBuild = true;
|
||||
m_Modifier.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
var siblingPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin());
|
||||
Object.DestroyImmediate(siblingPlane);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierOverrideAreaAffectsSelf()
|
||||
{
|
||||
m_Modifier.area = 4;
|
||||
m_Modifier.overrideArea = true;
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1 << 4;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Modifier_WhenSurfaceBuiltOnAwake_OverridesArea()
|
||||
{
|
||||
m_Modifier.gameObject.SetActive(false);
|
||||
m_BuildOnAwake = m_Modifier.gameObject.AddComponent<NavMeshSurfaceBuildFromAwake>();
|
||||
m_BuildOnAwake.surface = m_Surface;
|
||||
m_Modifier.area = 4;
|
||||
m_Modifier.overrideArea = true;
|
||||
|
||||
// Enable the components to build the NavMesh on Awake
|
||||
m_Modifier.gameObject.SetActive(true);
|
||||
|
||||
NavMesh.SamplePosition(Vector3.zero, out var hit, 0.1f, NavMesh.AllAreas);
|
||||
Assume.That(hit.hit, Is.True, "There should be a NavMesh at position (0,0,0).");
|
||||
Assert.That(hit.mask, Is.EqualTo(1 << m_Modifier.area),
|
||||
"The NavMesh should have the Modifier area mask at position (0,0,0).");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierOverrideAreaAffectsChild()
|
||||
{
|
||||
m_Modifier.area = 4;
|
||||
m_Modifier.overrideArea = true;
|
||||
m_Modifier.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
var childPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
childPlane.transform.SetParent(m_Modifier.transform);
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1 << 4;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
Object.DestroyImmediate(childPlane);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModifierOverrideAreaDoesNotAffectSibling()
|
||||
{
|
||||
m_Modifier.area = 4;
|
||||
m_Modifier.overrideArea = true;
|
||||
m_Modifier.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
var siblingPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
|
||||
m_Surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
Object.DestroyImmediate(siblingPlane);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9fe5cff05af44c0fb71a8dcc44efc41
|
||||
timeCreated: 1490606318
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class NavMeshSurfaceModifierVolumeTests
|
||||
{
|
||||
NavMeshSurface surface;
|
||||
NavMeshModifierVolume modifier;
|
||||
|
||||
[SetUp]
|
||||
public void CreatePlaneAndModifierVolume()
|
||||
{
|
||||
var go = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
surface = go.AddComponent<NavMeshSurface>();
|
||||
|
||||
modifier = new GameObject().AddComponent<NavMeshModifierVolume>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void DestroyPlaneAndModifierVolume()
|
||||
{
|
||||
GameObject.DestroyImmediate(surface.gameObject);
|
||||
GameObject.DestroyImmediate(modifier.gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AreaAffectsNavMeshOverlapping()
|
||||
{
|
||||
modifier.center = Vector3.zero;
|
||||
modifier.size = Vector3.one;
|
||||
modifier.area = 4;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1 << 4;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AreaDoesNotAffectsNavMeshWhenNotOverlapping()
|
||||
{
|
||||
modifier.center = 1.1f * Vector3.right;
|
||||
modifier.size = Vector3.one;
|
||||
modifier.area = 4;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildUsesOnlyIncludedModifierVolume()
|
||||
{
|
||||
modifier.center = Vector3.zero;
|
||||
modifier.size = Vector3.one;
|
||||
modifier.area = 4;
|
||||
modifier.gameObject.layer = 7;
|
||||
|
||||
surface.layerMask = ~(1 << 7);
|
||||
surface.BuildNavMesh();
|
||||
|
||||
var expectedAreaMask = 1;
|
||||
Assert.IsTrue(NavMeshSurfaceTests.HasNavMeshAtOrigin(expectedAreaMask));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5d873c779b014234ba92f3cb7476da6
|
||||
timeCreated: 1490606318
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,267 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
class NavMeshSurfaceTests
|
||||
{
|
||||
GameObject plane;
|
||||
NavMeshSurface surface;
|
||||
|
||||
[SetUp]
|
||||
public void CreatePlaneWithSurface()
|
||||
{
|
||||
plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
surface = new GameObject().AddComponent<NavMeshSurface>();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void DestroyPlaneWithSurface()
|
||||
{
|
||||
GameObject.DestroyImmediate(plane);
|
||||
GameObject.DestroyImmediate(surface.gameObject);
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NavMeshIsAvailableAfterBuild()
|
||||
{
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NavMeshCanBeRemovedAndAdded()
|
||||
{
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
|
||||
surface.RemoveData();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
surface.AddData();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NavMeshIsNotAvailableWhenDisabled()
|
||||
{
|
||||
surface.BuildNavMesh();
|
||||
|
||||
surface.enabled = false;
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
surface.enabled = true;
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanBuildWithCustomArea()
|
||||
{
|
||||
surface.defaultArea = 4;
|
||||
var expectedAreaMask = 1 << 4;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin(expectedAreaMask));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanBuildWithCustomAgentTypeID()
|
||||
{
|
||||
surface.agentTypeID = 1234;
|
||||
surface.BuildNavMesh();
|
||||
|
||||
Assert.IsTrue(HasNavMeshAtOrigin(NavMesh.AllAreas, 1234));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanBuildCollidersAndIgnoreRenderMeshes()
|
||||
{
|
||||
plane.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
surface.useGeometry = NavMeshCollectGeometry.PhysicsColliders;
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
|
||||
surface.useGeometry = NavMeshCollectGeometry.RenderMeshes;
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
#if !NMC_CAN_ACCESS_PHYSICS
|
||||
[Ignore("This test requires the com.unity.modules.physics package in order to run. Make sure to reference it in the project.")]
|
||||
#endif
|
||||
public void CanBuildRenderMeshesAndIgnoreColliders()
|
||||
{
|
||||
#if NMC_CAN_ACCESS_PHYSICS
|
||||
plane.GetComponent<Collider>().enabled = false;
|
||||
surface.useGeometry = NavMeshCollectGeometry.PhysicsColliders;
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
surface.useGeometry = NavMeshCollectGeometry.RenderMeshes;
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
#endif
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildIgnoresGeometryOutsideBounds()
|
||||
{
|
||||
surface.collectObjects = CollectObjects.Volume;
|
||||
surface.center = new Vector3(20, 0, 0);
|
||||
surface.size = new Vector3(10, 10, 10);
|
||||
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildIgnoresGeometrySiblings()
|
||||
{
|
||||
surface.collectObjects = CollectObjects.Children;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildDoesntCullAreaBiggerThanMinRegionArea()
|
||||
{
|
||||
// Move plane away from NavMesh tile's boundaries
|
||||
plane.transform.localScale = new Vector3(0.25f, 0, 0.25f);
|
||||
plane.transform.position = new Vector3(2.5f, 0, 7.5f);
|
||||
|
||||
surface.minRegionArea = 1f;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
Assert.IsTrue(HasNavMeshAtPosition(plane.transform.position));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildCullsAreaSmallerThanMinRegionArea()
|
||||
{
|
||||
// Move plane away from NavMesh tile's boundaries
|
||||
plane.transform.localScale = new Vector3(0.25f, 0, 0.25f);
|
||||
plane.transform.position = new Vector3(2.5f, 0, 7.5f);
|
||||
|
||||
surface.minRegionArea = 5;
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
Assert.IsFalse(HasNavMeshAtPosition(plane.transform.position));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildUsesOnlyIncludedLayers()
|
||||
{
|
||||
plane.layer = 4;
|
||||
surface.layerMask = ~(1 << 4);
|
||||
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultSettingsMatchBuiltinSettings()
|
||||
{
|
||||
var bs = surface.GetBuildSettings();
|
||||
Assert.AreEqual(NavMesh.GetSettingsByIndex(0), bs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ActiveSurfacesContainsOnlyActiveAndEnabledSurface()
|
||||
{
|
||||
Assert.IsTrue(NavMeshSurface.activeSurfaces.Contains(surface));
|
||||
Assert.AreEqual(1, NavMeshSurface.activeSurfaces.Count);
|
||||
|
||||
surface.enabled = false;
|
||||
Assert.IsFalse(NavMeshSurface.activeSurfaces.Contains(surface));
|
||||
Assert.AreEqual(0, NavMeshSurface.activeSurfaces.Count);
|
||||
|
||||
surface.enabled = true;
|
||||
surface.gameObject.SetActive(false);
|
||||
Assert.IsFalse(NavMeshSurface.activeSurfaces.Contains(surface));
|
||||
Assert.AreEqual(0, NavMeshSurface.activeSurfaces.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NavMeshMovesToSurfacePositionNextFrame()
|
||||
{
|
||||
plane.transform.position = new Vector3(100, 0, 0);
|
||||
surface.transform.position = new Vector3(100, 0, 0);
|
||||
surface.BuildNavMesh();
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
surface.transform.position = Vector3.zero;
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UpdatingAndAddingNavMesh()
|
||||
{
|
||||
var navMeshData = new NavMeshData();
|
||||
var oper = surface.UpdateNavMesh(navMeshData);
|
||||
Assert.IsFalse(HasNavMeshAtOrigin());
|
||||
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
} while (!oper.isDone);
|
||||
|
||||
surface.RemoveData();
|
||||
surface.navMeshData = navMeshData;
|
||||
surface.AddData();
|
||||
|
||||
Assert.IsTrue(HasNavMeshAtOrigin());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildTakesIntoAccountAdjacentWalkableSurfacesOutsideBounds()
|
||||
{
|
||||
surface.collectObjects = CollectObjects.Volume;
|
||||
surface.center = new Vector3(0, 0, 0);
|
||||
surface.size = new Vector3(10, 10, 10);
|
||||
|
||||
var adjacentPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||||
adjacentPlane.transform.position = new Vector3(10f, 0, 0);
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
try
|
||||
{
|
||||
Assert.IsTrue(HasNavMeshAtPosition(new Vector3(surface.size.x / 2f, 0, 0)),
|
||||
"A NavMesh should exists at the desired position.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.DestroyImmediate(adjacentPlane);
|
||||
}
|
||||
}
|
||||
|
||||
static bool HasNavMeshAtPosition(Vector3 position, int areaMask = NavMesh.AllAreas, int agentTypeID = 0)
|
||||
{
|
||||
var filter = new NavMeshQueryFilter {areaMask = areaMask, agentTypeID = agentTypeID};
|
||||
return NavMesh.SamplePosition(position, out _, 0.1f, filter);
|
||||
}
|
||||
|
||||
public static bool HasNavMeshAtOrigin(int areaMask = NavMesh.AllAreas, int agentTypeID = 0)
|
||||
{
|
||||
return HasNavMeshAtPosition(Vector3.zero, areaMask, agentTypeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 925111c157b314873b97f89e0f03d570
|
||||
timeCreated: 1490606318
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c10f4966eb108848acf7461aaf6057e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
class AddDynamicOffMeshLinkWorks : OffMeshLinkTestBase
|
||||
{
|
||||
const string k_SceneName = "OffMeshLinkTwoPlanesScene";
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXServer, RuntimePlatform.WindowsServer, RuntimePlatform.LinuxServer })] //MTT-4133 Fails on Dedicated Server
|
||||
public IEnumerator OffMeshLink_WhenAddedToGameObject_BecomesUsableImmediately()
|
||||
{
|
||||
CreateBiDirectionalLink(true);
|
||||
m_Agent.SetDestination(m_PlaneEnd.position);
|
||||
yield return null;
|
||||
|
||||
Assert.That(m_Agent.pathStatus, Is.EqualTo(NavMeshPathStatus.PathComplete), "DynamicOffMeshLink has not been created.");
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f48814e34f5bd94eb57d5a64f7d6d5f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Category("RegressionTest")]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
class AgentCustomLinkMovement : OffMeshLinkTestBase
|
||||
{
|
||||
const string k_SceneName = "OffMeshLinkTwoPlanesScene";
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXServer, RuntimePlatform.WindowsServer, RuntimePlatform.LinuxServer })] //MTT-4133 Fails on Dedicated Server
|
||||
public IEnumerator Agent_WithoutAutoTraverseOnOffMeshLink_DoesNotMoveByItself()
|
||||
{
|
||||
var link = CreateBiDirectionalLink(true);
|
||||
|
||||
m_Agent.autoTraverseOffMeshLink = false;
|
||||
m_Agent.baseOffset = 1.0f;
|
||||
m_Agent.transform.position = link.startTransform.position;
|
||||
var hasDestination = m_Agent.SetDestination(link.endTransform.position);
|
||||
|
||||
Assert.That(hasDestination, Is.True, "NavMeshAgent destination has not been set.");
|
||||
yield return null;
|
||||
|
||||
Assert.That(m_Agent.isOnOffMeshLink, Is.True, "NavMeshAgent is currently not positioned on NavMeshLink.");
|
||||
|
||||
// Move to gap between the NavMeshes connected by the NavMeshLink
|
||||
var midAirPosition = new Vector3(17.71f, 3.92f, -6.66f);
|
||||
m_Agent.transform.position = midAirPosition;
|
||||
yield return null;
|
||||
|
||||
// Ensure the agent stays at this position - as 'autoTraverseOffMeshLink' is false
|
||||
Assert.That(m_Agent.transform.position, Is.EqualTo(midAirPosition).Using(new Vector3EqualityComparer(0.01f)), "NavMeshAgent should be at midAirPosition.");
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca27eb55b0331d042a94fe7f8899234c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Category("RegressionTest")]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
class AgentVelocityTestAfterOffMeshLink : OffMeshLinkTestBase
|
||||
{
|
||||
readonly string k_SceneName = "OffMeshLinkTwoPlanesScene";
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXServer, RuntimePlatform.WindowsServer, RuntimePlatform.LinuxServer })]
|
||||
public IEnumerator Agent_AfterTraversingOffMeshLink_HasVelocityAlignedWithTheLink()
|
||||
{
|
||||
var link = CreateBiDirectionalLink(true);
|
||||
m_Agent.transform.position = link.startTransform.position + new Vector3(3, 0, 3);
|
||||
m_Agent.SetDestination(link.endTransform.position + new Vector3(-3, 0, 3));
|
||||
yield return null;
|
||||
|
||||
while (!m_Agent.isOnOffMeshLink)
|
||||
yield return null;
|
||||
|
||||
while (m_Agent.isOnOffMeshLink)
|
||||
yield return null;
|
||||
|
||||
yield return 0;
|
||||
|
||||
var agentMoveDir = m_Agent.velocity;
|
||||
agentMoveDir.y = 0;
|
||||
agentMoveDir = agentMoveDir.normalized;
|
||||
|
||||
var linkDir = link.endTransform.position - link.startTransform.position;
|
||||
linkDir.y = 0;
|
||||
linkDir = linkDir.normalized;
|
||||
|
||||
// Get the angle in degrees between the direction vectors.
|
||||
var angle = Vector3.Angle(linkDir, agentMoveDir);
|
||||
|
||||
Assert.That(angle, Is.LessThan(5.0f), "Agent Velocity is not aligned with the off-mesh link.");
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ebd8eb82fbc3924e92211a0c85dfa02
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(CurrentNextOffMeshLinkDataSetUp))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(CurrentNextOffMeshLinkDataSetUp))]
|
||||
class CurrentNextOffMeshLinkData
|
||||
{
|
||||
const string k_SceneName = "OffMeshLinkTest";
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Explicit("Unstable test")]
|
||||
public IEnumerator Agent_TraversingOffMeshLink_ReportsCorrectCurrentAndNextLink()
|
||||
{
|
||||
var agent = GameObject.Find("Agent").GetComponent<NavMeshAgent>();
|
||||
var offMeshLink = GameObject.Find("Plane1").GetComponent<NavMeshLink>();
|
||||
var target = GameObject.Find("Plane2").transform;
|
||||
|
||||
Assert.That(offMeshLink, Is.Not.Null, "Didn't find Off-mesh link");
|
||||
Assert.That(agent, Is.Not.Null, "Didn't find NavMeshAgent");
|
||||
|
||||
var destinationSet = agent.SetDestination(target.position);
|
||||
agent.speed *= 10;
|
||||
Assert.That(destinationSet, Is.True, "NavMeshAgent's destination position is not set");
|
||||
|
||||
// Wait for path calculation
|
||||
yield return null;
|
||||
|
||||
// Before link
|
||||
while (!agent.isOnOffMeshLink)
|
||||
{
|
||||
Assert.That(agent.currentOffMeshLinkData.valid, Is.False, "Before link : agent.currentOffMeshLinkData is valid");
|
||||
|
||||
AssertValidOffMeshLinkData(agent.nextOffMeshLinkData, offMeshLink);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// On link
|
||||
while (agent.isOnOffMeshLink)
|
||||
{
|
||||
Assert.That(agent.nextOffMeshLinkData.valid, Is.False, "On link : agent.nextOffMeshLinkData is valid");
|
||||
|
||||
AssertValidOffMeshLinkData(agent.currentOffMeshLinkData, offMeshLink);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// After link
|
||||
Assert.That(agent.currentOffMeshLinkData.valid, Is.False, "After link : agent.currentOffMeshLinkData is valid");
|
||||
Assert.That(agent.nextOffMeshLinkData.valid, Is.False, "After link : agent.nextOffMeshLinkData is valid");
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
|
||||
static void AssertValidOffMeshLinkData(OffMeshLinkData offMeshLinkData, NavMeshLink offMeshLink)
|
||||
{
|
||||
// Double check to avoid spamming success in log-file (decreasing tests performance)
|
||||
Assert.That(offMeshLinkData.valid, Is.True, "OffMeshLinkData should be valid.");
|
||||
Assert.That(offMeshLinkData.activated, Is.True, "OffMeshLinkData should be activated.");
|
||||
Assert.That(offMeshLinkData.linkType, Is.EqualTo(OffMeshLinkType.LinkTypeManual), "OffMeshLinkData's linkType should be Manual.");
|
||||
Assert.That(offMeshLinkData.owner, Is.EqualTo(offMeshLink), "OffMeshLinkData should reference the NavMeshLink in the scene as the owner object.");
|
||||
#pragma warning disable CS0618
|
||||
Assert.That(offMeshLinkData.offMeshLink, Is.Null, "OffMeshLinkData should not reference any legacy OffMeshLink in the scene.");
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 940906a00341424438da6b0e6ef377de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
class OffMeshLinkGetSetNavMeshArea : OffMeshLinkTestBase
|
||||
{
|
||||
int m_AreaMask;
|
||||
NavMeshLink m_Link;
|
||||
readonly string k_SceneName = "OffMeshLinkTwoPlanesScene";
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXServer, RuntimePlatform.WindowsServer, RuntimePlatform.LinuxServer })]
|
||||
public IEnumerator OffMeshLink_WithCustomArea_AllowsThroughOnlyPathsWithMatchingMasks()
|
||||
{
|
||||
m_Link = CreateBiDirectionalLink(true);
|
||||
yield return null;
|
||||
|
||||
var defaultArea = NavMesh.GetAreaFromName("Walkable");
|
||||
var jumpArea = NavMesh.GetAreaFromName("Jump");
|
||||
|
||||
Assume.That(m_Link.area, Is.EqualTo(defaultArea), "Unexpected NavMesh area for NavMeshLink");
|
||||
|
||||
// Check we can pass 'default' with 'default' mask
|
||||
m_AreaMask = 1 << defaultArea;
|
||||
VerifyAreaPassing(true);
|
||||
|
||||
// Change oml area to 'jump'
|
||||
m_Link.area = jumpArea;
|
||||
Assume.That(m_Link.area, Is.EqualTo(jumpArea), "Unexpected NavMesh area for NavMeshLink");
|
||||
|
||||
// Check we cannot pass 'jump' with 'default' mask
|
||||
VerifyAreaPassing(false);
|
||||
|
||||
// Check we can pass 'jump' with 'default' + 'jump' mask
|
||||
m_AreaMask |= 1 << jumpArea;
|
||||
VerifyAreaPassing(true);
|
||||
}
|
||||
|
||||
void VerifyAreaPassing(bool expectToPass)
|
||||
{
|
||||
var path = new NavMeshPath();
|
||||
NavMesh.CalculatePath(m_PlaneStart.position, m_PlaneEnd.position, m_AreaMask, path);
|
||||
if (expectToPass)
|
||||
Assert.That(path.status, Is.EqualTo(NavMeshPathStatus.PathComplete),
|
||||
"Expected complete path; with NavMesh area mask " + m_AreaMask + " when NavMeshLink area is " + m_Link.area);
|
||||
else
|
||||
Assert.That(path.status, Is.EqualTo(NavMeshPathStatus.PathPartial),
|
||||
"Expected partial path; with NavMesh area mask " + m_AreaMask + " when NavMeshLink area is " + m_Link.area);
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8e30eff1e26b3b428d7ae3ce3158107
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[PrebuildSetup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
[PostBuildCleanup("Unity.AI.Navigation.Tests." + nameof(SimpleScene2PlanesNavigationSetup))]
|
||||
class OffMeshLinkMultipleAddComponent
|
||||
{
|
||||
const string k_SceneName = "OffMeshLinkTwoPlanesScene";
|
||||
GameObject m_LinkGO;
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator UnitySetUp()
|
||||
{
|
||||
yield return SceneManager.LoadSceneAsync(k_SceneName, LoadSceneMode.Additive);
|
||||
yield return null;
|
||||
|
||||
SceneManager.SetActiveScene(SceneManager.GetSceneByName(k_SceneName));
|
||||
m_LinkGO = new GameObject("OffMeshLinkMultipleAddComponent");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXServer, RuntimePlatform.WindowsServer, RuntimePlatform.LinuxServer })]
|
||||
public void OffMeshLink_WhenMultipleAddedToGameObject_AreAllUsable()
|
||||
{
|
||||
var a = GameObject.Find("plane1").GetComponent<Transform>();
|
||||
var b = GameObject.Find("plane2").GetComponent<Transform>();
|
||||
|
||||
Assert.That(a, Is.Not.Null, "Plane1 is missing.");
|
||||
Assert.That(b, Is.Not.Null, "Plane2 is missing.");
|
||||
|
||||
var pathAB = new NavMeshPath();
|
||||
var pathBA = new NavMeshPath();
|
||||
|
||||
var foundAB = NavMesh.CalculatePath(a.position, b.position, -1, pathAB);
|
||||
var foundBA = NavMesh.CalculatePath(b.position, a.position, -1, pathBA);
|
||||
Assert.That(foundAB, Is.True, "Found unexpected path A->B.");
|
||||
Assert.That(foundBA, Is.True, "Found unexpected path B->A.");
|
||||
|
||||
// Create setup where one GO has two OffMeshLinks with 'Bi Directional' set to false
|
||||
AddOneWayLink(a, b);
|
||||
AddOneWayLink(b, a);
|
||||
|
||||
// Tests that path a->b and b->a are valid and have same end-points (mirrored).
|
||||
foundAB = NavMesh.CalculatePath(a.position, b.position, -1, pathAB);
|
||||
foundBA = NavMesh.CalculatePath(b.position, a.position, -1, pathBA);
|
||||
Assert.That(foundAB, Is.True, "No path from A->B");
|
||||
Assert.That(foundBA, Is.True, "No path from B->A");
|
||||
|
||||
var d1 = Vector3.Distance(pathAB.corners[0], pathBA.corners[pathBA.corners.Length - 1]);
|
||||
var d2 = Vector3.Distance(pathAB.corners[pathAB.corners.Length - 1], pathBA.corners[0]);
|
||||
|
||||
Assert.That(d1, Is.EqualTo(0.0f).Within(1e-5f), "Endpoint mismatch: A start -> B end.");
|
||||
Assert.That(d2, Is.EqualTo(0.0f).Within(1e-5f), "Endpoint mismatch: B start -> A end.");
|
||||
}
|
||||
|
||||
void AddOneWayLink(Transform start, Transform end)
|
||||
{
|
||||
var offMeshLink = m_LinkGO.AddComponent<NavMeshLink>();
|
||||
Assert.That(offMeshLink, Is.Not.Null, "Failed to create NavMeshLink.");
|
||||
offMeshLink.bidirectional = false;
|
||||
offMeshLink.startTransform = start;
|
||||
offMeshLink.endTransform = end;
|
||||
|
||||
// we modified the endpoint references above - now explicitly update positions.
|
||||
offMeshLink.UpdateLink();
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public IEnumerator UnityTearDown()
|
||||
{
|
||||
Object.DestroyImmediate(m_LinkGO);
|
||||
yield return SceneManager.UnloadSceneAsync(k_SceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9956f614ad36a614788c97144e44730f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
class OffMeshLinkTestBase
|
||||
{
|
||||
protected Transform m_PlaneStart;
|
||||
protected Transform m_PlaneEnd;
|
||||
protected NavMeshAgent m_Agent;
|
||||
|
||||
public NavMeshLink CreateBiDirectionalLink(bool autoUpdatePositions)
|
||||
{
|
||||
var planeStartGO = GameObject.Find("plane1");
|
||||
Assert.That(planeStartGO, Is.Not.Null, "Didn't find gameobject plane1");
|
||||
m_PlaneStart = planeStartGO.transform;
|
||||
var planeEndGO = GameObject.Find("plane2");
|
||||
Assert.That(planeEndGO, Is.Not.Null, "Didn't find gameobject plane2");
|
||||
m_PlaneEnd = planeEndGO.transform;
|
||||
var agentGo = GameObject.Find("Agent");
|
||||
Assert.That(agentGo, Is.Not.Null, "Didn't find gameobject Agent");
|
||||
m_Agent = agentGo.GetComponent<NavMeshAgent>();
|
||||
Assert.That(m_Agent, Is.Not.Null, "Didn't find component NavMeshAgent in gameobject Agent");
|
||||
|
||||
m_Agent.speed *= 10.0f;
|
||||
m_Agent.acceleration *= 10.0f;
|
||||
|
||||
var linkGO = new GameObject("link");
|
||||
var link = linkGO.AddComponent<NavMeshLink>();
|
||||
Assert.That(link, Is.Not.Null, "Unable to add NavMeshLink component.");
|
||||
link.startTransform = m_PlaneStart;
|
||||
link.endTransform = m_PlaneEnd;
|
||||
link.autoUpdate = autoUpdatePositions;
|
||||
return link;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6066975671f8b09468b3412d411861c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 028144d6018e97b4eabdb685c9fc01a0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Utils = UnityEngine.TestTools.Utils.Utils;
|
||||
#pragma warning disable CS0618 // UnityEditor.AI.NavMeshBuilder is necessary in this implementation
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
class CurrentNextOffMeshLinkDataSetUp : PrebuiltSceneSetup
|
||||
{
|
||||
protected override string GetSceneFile()
|
||||
{
|
||||
return "OffMeshLinkTest.unity";
|
||||
}
|
||||
|
||||
protected override void SceneSetup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var myScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
|
||||
SceneManager.SetActiveScene(myScene);
|
||||
|
||||
var plane1 = Utils.CreatePrimitive(PrimitiveType.Plane);
|
||||
GameObjectUtility.SetStaticEditorFlags(plane1, StaticEditorFlags.NavigationStatic);
|
||||
plane1.name = "Plane1";
|
||||
plane1.transform.position = Vector3.zero;
|
||||
|
||||
var plane2 = Utils.CreatePrimitive(PrimitiveType.Plane);
|
||||
GameObjectUtility.SetStaticEditorFlags(plane2, StaticEditorFlags.NavigationStatic);
|
||||
plane2.name = "Plane2";
|
||||
plane2.transform.position = new Vector3(0, 0, 15);
|
||||
|
||||
var offMeshLink = plane1.AddComponent<NavMeshLink>();
|
||||
offMeshLink.startTransform = plane1.transform;
|
||||
offMeshLink.endTransform = plane2.transform;
|
||||
|
||||
var cube = Utils.CreatePrimitive(PrimitiveType.Cube);
|
||||
cube.transform.position = new Vector3(0, 0, -4);
|
||||
cube.name = "Agent";
|
||||
cube.AddComponent<NavMeshAgent>();
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), pathToTestScene);
|
||||
UnityEditor.AI.NavMeshBuilder.BuildNavMesh();
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), pathToTestScene);
|
||||
|
||||
EditorSceneManager.CloseScene(myScene, true);
|
||||
UnityEditor.AI.NavMeshBuilder.ClearAllNavMeshes();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a0a2560470c5b542813d7c93f1b3261
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
abstract class PrebuiltSceneSetup : IPrebuildSetup, IPostBuildCleanup
|
||||
{
|
||||
const string k_RootDir = "Assets";
|
||||
const string k_TestDir = "TmpScenes";
|
||||
string testDirectory { get; set; } = "";
|
||||
protected string pathToTestScene { get; private set; } = "";
|
||||
|
||||
protected abstract string GetSceneFile();
|
||||
protected abstract void SceneSetup();
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
testDirectory = Path.Combine(k_RootDir, k_TestDir);
|
||||
pathToTestScene = Path.Combine(testDirectory, GetSceneFile());
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
if (!AssetDatabase.IsValidFolder(testDirectory))
|
||||
testDirectory = AssetDatabase.GUIDToAssetPath(AssetDatabase.CreateFolder(k_RootDir, k_TestDir));
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
SceneSetup();
|
||||
|
||||
var editorBuildSettingsScenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes)
|
||||
{
|
||||
new EditorBuildSettingsScene(pathToTestScene, true)
|
||||
};
|
||||
EditorBuildSettings.scenes = editorBuildSettingsScenes.ToArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
AssetDatabase.Refresh();
|
||||
testDirectory = Path.Combine(k_RootDir, k_TestDir);
|
||||
pathToTestScene = Path.Combine(testDirectory, GetSceneFile());
|
||||
var baseSceneGuidTxt = AssetDatabase.AssetPathToGUID(pathToTestScene);
|
||||
|
||||
if (AssetDatabase.IsValidFolder(testDirectory))
|
||||
AssetDatabase.DeleteAsset(testDirectory);
|
||||
|
||||
if (GUID.TryParse(baseSceneGuidTxt, out var sceneGuid))
|
||||
EditorBuildSettings.scenes = EditorBuildSettings.scenes.Where(scene => scene.guid != sceneGuid).ToArray();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57568e502950ef142a879100dfa67153
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
#pragma warning disable CS0618 // UnityEditor.AI.NavMeshBuilder is necessary in this implementation
|
||||
|
||||
namespace Unity.AI.Navigation.Tests
|
||||
{
|
||||
class SimpleScene2PlanesNavigationSetup : PrebuiltSceneSetup
|
||||
{
|
||||
protected override string GetSceneFile()
|
||||
{
|
||||
return "OffMeshLinkTwoPlanesScene.unity";
|
||||
}
|
||||
|
||||
protected override void SceneSetup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var myScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
|
||||
SceneManager.SetActiveScene(myScene);
|
||||
|
||||
var plane1 = Utils.CreatePrimitive(PrimitiveType.Plane);
|
||||
plane1.transform.position = new Vector3(10f, 0f, 0f);
|
||||
plane1.name = "plane1";
|
||||
GameObjectUtility.SetStaticEditorFlags(plane1, StaticEditorFlags.NavigationStatic);
|
||||
|
||||
var plane2 = Utils.CreatePrimitive(PrimitiveType.Plane);
|
||||
plane2.transform.position = new Vector3(25f, 0f, 0f);
|
||||
plane2.name = "plane2";
|
||||
GameObjectUtility.SetStaticEditorFlags(plane2, StaticEditorFlags.NavigationStatic);
|
||||
|
||||
var capsule = Utils.CreatePrimitive(PrimitiveType.Capsule);
|
||||
capsule.name = "Agent";
|
||||
capsule.transform.position = new Vector3(6, 0, 0);
|
||||
capsule.AddComponent<NavMeshAgent>();
|
||||
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), pathToTestScene);
|
||||
UnityEditor.AI.NavMeshBuilder.BuildNavMesh();
|
||||
EditorSceneManager.SaveScene(SceneManager.GetActiveScene(), pathToTestScene);
|
||||
|
||||
EditorSceneManager.CloseScene(myScene, true);
|
||||
UnityEditor.AI.NavMeshBuilder.ClearAllNavMeshes();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5110d4284121dd4481bffe2647ad892
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Unity.AI.Navigation.LegacyOffMeshLink.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:8c4dd21966739024fbd72155091d199e",
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68d7ff144262c9148888e665efa8692c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "Unity.AI.Navigation.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a",
|
||||
"GUID:0acc523941302664db1f4e527237feb3",
|
||||
"GUID:8c4dd21966739024fbd72155091d199e"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.modules.physics",
|
||||
"expression": "1.0.0",
|
||||
"define": "NMC_CAN_ACCESS_PHYSICS"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 455cd750f394b1c41b963b3335eae29c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48fe869bd7a418849ba6d20ca02072c7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace Unity.AI.Navigation.Editor.Tests.InPlaymode
|
||||
{
|
||||
[TestFixture]
|
||||
[Explicit]
|
||||
[UnityPlatform(include = new[] { RuntimePlatform.LinuxEditor, RuntimePlatform.OSXEditor, RuntimePlatform.WindowsEditor })]
|
||||
[Description("These tests run on demand and only in the editor playmode")]
|
||||
public class NavMeshLinkEditorTestsInPlaymode : NavMeshLinkEditorTests { }
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce274f071db6b3648a84436c61037cb6
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "Unity.AI.Navigation.Tests.EditorInPlaymode",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"Unity.AI.Navigation",
|
||||
"Unity.AI.Navigation.Editor",
|
||||
"Unity.AI.Navigation.Editor.Tests"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.modules.physics",
|
||||
"expression": "1.0.0",
|
||||
"define": "NMC_CAN_ACCESS_PHYSICS"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 100055fbb0e2acd4a835038b0f7cd2f5
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user