mirror of
				https://github.com/DerTyp7/grow-ai-unity.git
				synced 2025-10-30 21:07:09 +01:00 
			
		
		
		
	init
This commit is contained in:
		| @@ -0,0 +1,325 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using UnityEditor.Experimental.SceneManagement; | ||||
| using UnityEditor.SceneManagement; | ||||
| using UnityEngine.AI; | ||||
| using UnityEngine; | ||||
|  | ||||
| namespace UnityEditor.AI | ||||
| { | ||||
|     public class NavMeshAssetManager2d : ScriptableSingleton<NavMeshAssetManager2d> | ||||
|     { | ||||
|         internal struct AsyncBakeOperation | ||||
|         { | ||||
|             public NavMeshSurface2d surface; | ||||
|             public NavMeshData bakeData; | ||||
|             public AsyncOperation bakeOperation; | ||||
|         } | ||||
|  | ||||
|         List<AsyncBakeOperation> m_BakeOperations = new List<AsyncBakeOperation>(); | ||||
|         internal List<AsyncBakeOperation> GetBakeOperations() { return m_BakeOperations; } | ||||
|  | ||||
|         struct SavedPrefabNavMeshData | ||||
|         { | ||||
|             public NavMeshSurface2d surface; | ||||
|             public NavMeshData navMeshData; | ||||
|         } | ||||
|  | ||||
|         List<SavedPrefabNavMeshData> m_PrefabNavMeshDataAssets = new List<SavedPrefabNavMeshData>(); | ||||
|  | ||||
|         static string GetAndEnsureTargetPath(NavMeshSurface2d surface) | ||||
|         { | ||||
|             // Create directory for the asset if it does not exist yet. | ||||
|             var activeScenePath = surface.gameObject.scene.path; | ||||
|  | ||||
|             var targetPath = "Assets"; | ||||
|             if (!string.IsNullOrEmpty(activeScenePath)) | ||||
|             { | ||||
|                 targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var prefabStage = PrefabStageUtility.GetPrefabStage(surface.gameObject); | ||||
|                 var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surface.gameObject); | ||||
|                 if (isPartOfPrefab && !string.IsNullOrEmpty(prefabStage.prefabAssetPath)) | ||||
|                 { | ||||
|                     var prefabDirectoryName = Path.GetDirectoryName(prefabStage.prefabAssetPath); | ||||
|                     if (!string.IsNullOrEmpty(prefabDirectoryName)) | ||||
|                         targetPath = prefabDirectoryName; | ||||
|                 } | ||||
|             } | ||||
|             if (!Directory.Exists(targetPath)) | ||||
|                 Directory.CreateDirectory(targetPath); | ||||
|             return targetPath; | ||||
|         } | ||||
|  | ||||
|         static void CreateNavMeshAsset(NavMeshSurface2d surface) | ||||
|         { | ||||
|             var targetPath = GetAndEnsureTargetPath(surface); | ||||
|  | ||||
|             var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset"); | ||||
|             combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath); | ||||
|             AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath); | ||||
|         } | ||||
|  | ||||
|         NavMeshData GetNavMeshAssetToDelete(NavMeshSurface2d navSurface) | ||||
|         { | ||||
|             if (PrefabUtility.IsPartOfPrefabInstance(navSurface) && !PrefabUtility.IsPartOfModelPrefab(navSurface)) | ||||
|             { | ||||
|                 // Don't allow deleting the asset belonging to the prefab parent | ||||
|                 var parentSurface = PrefabUtility.GetCorrespondingObjectFromSource(navSurface) as NavMeshSurface2d; | ||||
|                 if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData) | ||||
|                     return null; | ||||
|             } | ||||
|  | ||||
|             // Do not delete the NavMeshData asset referenced from a prefab until the prefab is saved | ||||
|             var prefabStage = PrefabStageUtility.GetPrefabStage(navSurface.gameObject); | ||||
|             var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(navSurface.gameObject); | ||||
|             if (isPartOfPrefab && IsCurrentPrefabNavMeshDataStored(navSurface)) | ||||
|                 return null; | ||||
|  | ||||
|             return navSurface.navMeshData; | ||||
|         } | ||||
|  | ||||
|         void ClearSurface(NavMeshSurface2d navSurface) | ||||
|         { | ||||
|             var hasNavMeshData = navSurface.navMeshData != null; | ||||
|             StoreNavMeshDataIfInPrefab(navSurface); | ||||
|  | ||||
|             var assetToDelete = GetNavMeshAssetToDelete(navSurface); | ||||
|             navSurface.RemoveData(); | ||||
|  | ||||
|             if (hasNavMeshData) | ||||
|             { | ||||
|                 SetNavMeshData(navSurface, null); | ||||
|                 EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene); | ||||
|             } | ||||
|  | ||||
|             if (assetToDelete) | ||||
|                 AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete)); | ||||
|         } | ||||
|  | ||||
|         public void StartBakingSurfaces(UnityEngine.Object[] surfaces) | ||||
|         { | ||||
|             // Remove first to avoid double registration of the callback | ||||
|             EditorApplication.update -= UpdateAsyncBuildOperations; | ||||
|             EditorApplication.update += UpdateAsyncBuildOperations; | ||||
|  | ||||
|             foreach (NavMeshSurface2d surf in surfaces) | ||||
|             { | ||||
|                 StoreNavMeshDataIfInPrefab(surf); | ||||
|  | ||||
|                 var oper = new AsyncBakeOperation(); | ||||
|  | ||||
|                 oper.bakeData = InitializeBakeData(surf); | ||||
|                 oper.bakeOperation = surf.UpdateNavMesh(oper.bakeData); | ||||
|                 oper.surface = surf; | ||||
|  | ||||
|                 m_BakeOperations.Add(oper); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         static NavMeshData InitializeBakeData(NavMeshSurface2d surface) | ||||
|         { | ||||
|             var emptySources = new List<NavMeshBuildSource>(); | ||||
|             var emptyBounds = new Bounds(); | ||||
|             return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds | ||||
|                 , surface.transform.position, surface.transform.rotation); | ||||
|         } | ||||
|  | ||||
|         void UpdateAsyncBuildOperations() | ||||
|         { | ||||
|             foreach (var oper in m_BakeOperations) | ||||
|             { | ||||
|                 if (oper.surface == null || oper.bakeOperation == null) | ||||
|                     continue; | ||||
|  | ||||
|                 if (oper.bakeOperation.isDone) | ||||
|                 { | ||||
|                     var surface = oper.surface; | ||||
|                     var delete = GetNavMeshAssetToDelete(surface); | ||||
|                     if (delete != null) | ||||
|                         AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete)); | ||||
|  | ||||
|                     surface.RemoveData(); | ||||
|                     SetNavMeshData(surface, oper.bakeData); | ||||
|  | ||||
|                     if (surface.isActiveAndEnabled) | ||||
|                         surface.AddData(); | ||||
|                     CreateNavMeshAsset(surface); | ||||
|                     EditorSceneManager.MarkSceneDirty(surface.gameObject.scene); | ||||
|                 } | ||||
|             } | ||||
|             m_BakeOperations.RemoveAll(o => o.bakeOperation == null || o.bakeOperation.isDone); | ||||
|             if (m_BakeOperations.Count == 0) | ||||
|                 EditorApplication.update -= UpdateAsyncBuildOperations; | ||||
|         } | ||||
|  | ||||
|         public bool IsSurfaceBaking(NavMeshSurface2d surface) | ||||
|         { | ||||
|             if (surface == null) | ||||
|                 return false; | ||||
|  | ||||
|             foreach (var oper in m_BakeOperations) | ||||
|             { | ||||
|                 if (oper.surface == null || oper.bakeOperation == null) | ||||
|                     continue; | ||||
|  | ||||
|                 if (oper.surface == surface) | ||||
|                     return true; | ||||
|             } | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         public void ClearSurfaces(UnityEngine.Object[] surfaces) | ||||
|         { | ||||
|             foreach (NavMeshSurface2d s in surfaces) | ||||
|                 ClearSurface(s); | ||||
|         } | ||||
|  | ||||
|         static void SetNavMeshData(NavMeshSurface2d navSurface, NavMeshData navMeshData) | ||||
|         { | ||||
|             var so = new SerializedObject(navSurface); | ||||
|             var navMeshDataProperty = so.FindProperty("m_NavMeshData"); | ||||
|             navMeshDataProperty.objectReferenceValue = navMeshData; | ||||
|             so.ApplyModifiedPropertiesWithoutUndo(); | ||||
|         } | ||||
|  | ||||
|         void StoreNavMeshDataIfInPrefab(NavMeshSurface2d surfaceToStore) | ||||
|         { | ||||
|             var prefabStage = PrefabStageUtility.GetPrefabStage(surfaceToStore.gameObject); | ||||
|             var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surfaceToStore.gameObject); | ||||
|             if (!isPartOfPrefab) | ||||
|                 return; | ||||
|  | ||||
|             // check if data has already been stored for this surface | ||||
|             foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets) | ||||
|                 if (storedAssetInfo.surface == surfaceToStore) | ||||
|                     return; | ||||
|  | ||||
|             if (m_PrefabNavMeshDataAssets.Count == 0) | ||||
|             { | ||||
|                 PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; | ||||
|                 PrefabStage.prefabSaving += DeleteStoredNavMeshDataAssetsForOwnedSurfaces; | ||||
|  | ||||
|                 PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; | ||||
|                 PrefabStage.prefabStageClosing += ForgetUnsavedNavMeshDataChanges; | ||||
|             } | ||||
|  | ||||
|             var isDataOwner = true; | ||||
|             if (PrefabUtility.IsPartOfPrefabInstance(surfaceToStore) && !PrefabUtility.IsPartOfModelPrefab(surfaceToStore)) | ||||
|             { | ||||
|                 var basePrefabSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceToStore) as NavMeshSurface2d; | ||||
|                 isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData; | ||||
|             } | ||||
|             m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { surface = surfaceToStore, navMeshData = isDataOwner ? surfaceToStore.navMeshData : null }); | ||||
|         } | ||||
|  | ||||
|         bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface2d surface) | ||||
|         { | ||||
|             if (surface == null) | ||||
|                 return false; | ||||
|  | ||||
|             foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets) | ||||
|             { | ||||
|                 if (storedAssetInfo.surface == surface) | ||||
|                     return storedAssetInfo.navMeshData == surface.navMeshData; | ||||
|             } | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         void DeleteStoredNavMeshDataAssetsForOwnedSurfaces(GameObject gameObjectInPrefab) | ||||
|         { | ||||
|             // Debug.LogFormat("DeleteStoredNavMeshDataAsset() when saving prefab {0}", gameObjectInPrefab.name); | ||||
|  | ||||
|             var surfaces = gameObjectInPrefab.GetComponentsInChildren<NavMeshSurface2d>(true); | ||||
|             foreach (var surface in surfaces) | ||||
|                 DeleteStoredPrefabNavMeshDataAsset(surface); | ||||
|         } | ||||
|  | ||||
|         void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface2d surface) | ||||
|         { | ||||
|             for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--) | ||||
|             { | ||||
|                 var storedAssetInfo = m_PrefabNavMeshDataAssets[i]; | ||||
|                 if (storedAssetInfo.surface == surface) | ||||
|                 { | ||||
|                     var storedNavMeshData = storedAssetInfo.navMeshData; | ||||
|                     if (storedNavMeshData != null && storedNavMeshData != surface.navMeshData) | ||||
|                     { | ||||
|                         var assetPath = AssetDatabase.GetAssetPath(storedNavMeshData); | ||||
|                         AssetDatabase.DeleteAsset(assetPath); | ||||
|                     } | ||||
|  | ||||
|                     m_PrefabNavMeshDataAssets.RemoveAt(i); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (m_PrefabNavMeshDataAssets.Count == 0) | ||||
|             { | ||||
|                 PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; | ||||
|                 PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void ForgetUnsavedNavMeshDataChanges(PrefabStage prefabStage) | ||||
|         { | ||||
|             // Debug.Log("On prefab closing - forget about this object's surfaces and stop caring about prefab saving"); | ||||
|  | ||||
|             if (prefabStage == null) | ||||
|                 return; | ||||
|  | ||||
|             var allSurfacesInPrefab = prefabStage.prefabContentsRoot.GetComponentsInChildren<NavMeshSurface2d>(true); | ||||
|             NavMeshSurface2d surfaceInPrefab = null; | ||||
|             var index = 0; | ||||
|             do | ||||
|             { | ||||
|                 if (allSurfacesInPrefab.Length > 0) | ||||
|                     surfaceInPrefab = allSurfacesInPrefab[index]; | ||||
|  | ||||
|                 for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--) | ||||
|                 { | ||||
|                     var storedPrefabInfo = m_PrefabNavMeshDataAssets[i]; | ||||
|                     if (storedPrefabInfo.surface == null) | ||||
|                     { | ||||
|                         // Debug.LogFormat("A surface from the prefab got deleted after it has baked a new NavMesh but it hasn't saved it. Now the unsaved asset gets deleted. ({0})", storedPrefabInfo.navMeshData); | ||||
|  | ||||
|                         // surface got deleted, thus delete its initial NavMeshData asset | ||||
|                         if (storedPrefabInfo.navMeshData != null) | ||||
|                         { | ||||
|                             var assetPath = AssetDatabase.GetAssetPath(storedPrefabInfo.navMeshData); | ||||
|                             AssetDatabase.DeleteAsset(assetPath); | ||||
|                         } | ||||
|  | ||||
|                         m_PrefabNavMeshDataAssets.RemoveAt(i); | ||||
|                     } | ||||
|                     else if (surfaceInPrefab != null && storedPrefabInfo.surface == surfaceInPrefab) | ||||
|                     { | ||||
|                         //Debug.LogFormat("The surface {0} from the prefab was storing the original navmesh data and now will be forgotten", surfaceInPrefab); | ||||
|  | ||||
|                         var baseSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceInPrefab) as NavMeshSurface2d; | ||||
|                         if (baseSurface == null || surfaceInPrefab.navMeshData != baseSurface.navMeshData) | ||||
|                         { | ||||
|                             var assetPath = AssetDatabase.GetAssetPath(surfaceInPrefab.navMeshData); | ||||
|                             AssetDatabase.DeleteAsset(assetPath); | ||||
|  | ||||
|                             //Debug.LogFormat("The surface {0} from the prefab has baked new NavMeshData but did not save this change so the asset has been now deleted. ({1})", | ||||
|                             //    surfaceInPrefab, assetPath); | ||||
|                         } | ||||
|  | ||||
|                         m_PrefabNavMeshDataAssets.RemoveAt(i); | ||||
|                     } | ||||
|                 } | ||||
|             } while (++index < allSurfacesInPrefab.Length); | ||||
|  | ||||
|             if (m_PrefabNavMeshDataAssets.Count == 0) | ||||
|             { | ||||
|                 PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces; | ||||
|                 PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 j.mei7
					j.mei7