166 lines
6.3 KiB
C#
166 lines
6.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace Unity.AI.Navigation.Updater
|
|
{
|
|
internal static class NavMeshUpdaterUtility
|
|
{
|
|
const string k_NavMeshSettingsPropertyPath = "NavMeshSettings";
|
|
const string k_NavMeshDataPropertyPath = "m_NavMeshData";
|
|
const string k_EmptyFileIdSerialization = "{fileID: 0}";
|
|
|
|
const string k_DefaultNavMeshSurfaceName = "Navigation";
|
|
|
|
const int k_WalkableAreaId = 0;
|
|
|
|
public static bool ConvertScene(string path)
|
|
{
|
|
Scene previousActiveScene = SceneManager.GetActiveScene();
|
|
|
|
OpenAndSetActiveScene(path, out Scene convertedScene, out bool alreadyOpened);
|
|
|
|
// Retrieve the legacy NavMesh data from the active scene
|
|
#pragma warning disable CS0618 // UnityEditor.AI.NavMeshBuilder is necessary in this implementation
|
|
var settingObject = new SerializedObject(UnityEditor.AI.NavMeshBuilder.navMeshSettingsObject);
|
|
#pragma warning restore CS0618
|
|
var navMeshDataProperty = settingObject.FindProperty(k_NavMeshDataPropertyPath);
|
|
var navMeshData = navMeshDataProperty.objectReferenceValue as NavMeshData;
|
|
|
|
if (navMeshData == null)
|
|
{
|
|
Debug.LogWarning("The NavMesh asset referenced in the scene is missing or corrupted.");
|
|
return false;
|
|
}
|
|
|
|
// Convert static Navigation Flags with a NavMeshModifier
|
|
GameObject[] rootObjects = convertedScene.GetRootGameObjects();
|
|
var sceneObjects = SceneModeUtility.GetObjects(rootObjects, true);
|
|
foreach (GameObject go in sceneObjects)
|
|
ConvertStaticValues(go);
|
|
|
|
// Create a global NavMeshSurface and copy legacy NavMesh settings
|
|
var surfaceObject = new GameObject(k_DefaultNavMeshSurfaceName, typeof(NavMeshSurface));
|
|
var navMeshSurface = surfaceObject.GetComponent<NavMeshSurface>();
|
|
|
|
navMeshSurface.navMeshData = navMeshData;
|
|
|
|
NavMeshBuildSettings settings = navMeshData.buildSettings;
|
|
navMeshSurface.collectObjects = CollectObjects.MarkedWithModifier;
|
|
navMeshSurface.useGeometry = NavMeshCollectGeometry.RenderMeshes;
|
|
navMeshSurface.overrideVoxelSize = settings.overrideVoxelSize;
|
|
navMeshSurface.voxelSize = settings.voxelSize;
|
|
navMeshSurface.overrideTileSize = settings.overrideTileSize;
|
|
navMeshSurface.tileSize = settings.tileSize;
|
|
navMeshSurface.minRegionArea = settings.minRegionArea;
|
|
navMeshSurface.buildHeightMesh = settings.buildHeightMesh;
|
|
|
|
// Remove NavMeshData reference from the scene
|
|
navMeshDataProperty.objectReferenceValue = null;
|
|
settingObject.ApplyModifiedProperties();
|
|
|
|
// Rename NavMesh asset
|
|
var assetPath = AssetDatabase.GetAssetPath(navMeshData);
|
|
AssetDatabase.RenameAsset(assetPath, "NavMesh-" + navMeshSurface.name + ".asset");
|
|
AssetDatabase.Refresh();
|
|
|
|
EditorSceneManager.SaveScene(convertedScene);
|
|
|
|
navMeshSurface.AddData();
|
|
|
|
if (!alreadyOpened)
|
|
EditorSceneManager.CloseScene(convertedScene, true);
|
|
|
|
SceneManager.SetActiveScene(previousActiveScene);
|
|
|
|
return true;
|
|
}
|
|
|
|
private static void OpenAndSetActiveScene(string path, out Scene scene, out bool alreadyOpened)
|
|
{
|
|
for (int i = 0; i < SceneManager.sceneCount; i++)
|
|
{
|
|
scene = SceneManager.GetSceneAt(i);
|
|
if (!scene.isLoaded)
|
|
continue;
|
|
|
|
if (path == scene.path)
|
|
{
|
|
if (SceneManager.GetActiveScene() != scene)
|
|
SceneManager.SetActiveScene(scene);
|
|
|
|
alreadyOpened = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
|
|
SceneManager.SetActiveScene(scene);
|
|
alreadyOpened = false;
|
|
}
|
|
|
|
private static void ConvertStaticValues(GameObject go)
|
|
{
|
|
// Disable CS0618 warning about StaticEditorFlags.NavigationStatic and StaticEditorFlags.OffMeshLinkGeneration being deprecated
|
|
#pragma warning disable 618
|
|
var staticFlags = GameObjectUtility.GetStaticEditorFlags(go);
|
|
if ((staticFlags & StaticEditorFlags.NavigationStatic) != 0)
|
|
{
|
|
NavMeshModifier modifier = go.AddComponent<NavMeshModifier>();
|
|
modifier.area = GameObjectUtility.GetNavMeshArea(go);
|
|
if (modifier.area != k_WalkableAreaId)
|
|
modifier.overrideArea = true;
|
|
|
|
if ((staticFlags & StaticEditorFlags.OffMeshLinkGeneration) != 0)
|
|
{
|
|
modifier.overrideGenerateLinks = true;
|
|
modifier.generateLinks = true;
|
|
}
|
|
|
|
staticFlags &= ~StaticEditorFlags.NavigationStatic;
|
|
GameObjectUtility.SetStaticEditorFlags(go, staticFlags);
|
|
}
|
|
#pragma warning restore 618
|
|
}
|
|
|
|
internal static bool IsSceneReferencingLegacyNavMesh(string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path))
|
|
throw new ArgumentNullException(nameof(path));
|
|
|
|
if (path.StartsWith("Packages"))
|
|
return false;
|
|
|
|
if (!path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase))
|
|
return false;
|
|
|
|
using (StreamReader file = File.OpenText(path))
|
|
{
|
|
string line;
|
|
bool skipUntilSettings = true;
|
|
while ((line = file.ReadLine()) != null)
|
|
{
|
|
if (skipUntilSettings)
|
|
{
|
|
if (line.Contains($"{k_NavMeshSettingsPropertyPath}:"))
|
|
skipUntilSettings = false;
|
|
}
|
|
else
|
|
{
|
|
if (line.Contains($"{k_NavMeshDataPropertyPath}:"))
|
|
{
|
|
return !line.Contains(k_EmptyFileIdSerialization);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|