UnityGame/Library/PackageCache/com.unity.ai.navigation/Editor/Updater/NavMeshUpdaterUtility.cs

166 lines
6.3 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
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;
}
}
}