-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove timeline dll, add nav stuff to tools
- Loading branch information
1 parent
71f6bf3
commit 19bca74
Showing
33 changed files
with
2,436 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,4 +20,4 @@ | |
"extends": "../package.json" | ||
}, | ||
"hideInEditor": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
334 changes: 334 additions & 0 deletions
334
MapStation.Tools/Runtime/NavMeshComponents/Editor/NavMeshAssetManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using UnityEditor.Experimental.SceneManagement; | ||
using UnityEditor.SceneManagement; | ||
using UnityEngine.AI; | ||
using UnityEngine; | ||
|
||
namespace UnityEditor.AI | ||
{ | ||
public class NavMeshAssetManager : ScriptableSingleton<NavMeshAssetManager> | ||
{ | ||
internal struct AsyncBakeOperation | ||
{ | ||
public NavMeshSurface surface; | ||
public NavMeshData bakeData; | ||
public AsyncOperation bakeOperation; | ||
} | ||
|
||
List<AsyncBakeOperation> m_BakeOperations = new List<AsyncBakeOperation>(); | ||
internal List<AsyncBakeOperation> GetBakeOperations() { return m_BakeOperations; } | ||
|
||
struct SavedPrefabNavMeshData | ||
{ | ||
public NavMeshSurface surface; | ||
public NavMeshData navMeshData; | ||
} | ||
|
||
List<SavedPrefabNavMeshData> m_PrefabNavMeshDataAssets = new List<SavedPrefabNavMeshData>(); | ||
|
||
static string GetAndEnsureTargetPath(NavMeshSurface 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) | ||
{ | ||
#if UNITY_2020_1_OR_NEWER | ||
var assetPath = prefabStage.assetPath; | ||
#else | ||
var assetPath = prefabStage.prefabAssetPath; | ||
#endif | ||
if (!string.IsNullOrEmpty(assetPath)) | ||
{ | ||
var prefabDirectoryName = Path.GetDirectoryName(assetPath); | ||
if (!string.IsNullOrEmpty(prefabDirectoryName)) | ||
targetPath = prefabDirectoryName; | ||
} | ||
} | ||
} | ||
if (!Directory.Exists(targetPath)) | ||
Directory.CreateDirectory(targetPath); | ||
return targetPath; | ||
} | ||
|
||
static void CreateNavMeshAsset(NavMeshSurface 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(NavMeshSurface 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 NavMeshSurface; | ||
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(NavMeshSurface 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 (NavMeshSurface 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(NavMeshSurface 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(NavMeshSurface 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 (NavMeshSurface s in surfaces) | ||
ClearSurface(s); | ||
} | ||
|
||
static void SetNavMeshData(NavMeshSurface navSurface, NavMeshData navMeshData) | ||
{ | ||
var so = new SerializedObject(navSurface); | ||
var navMeshDataProperty = so.FindProperty("m_NavMeshData"); | ||
navMeshDataProperty.objectReferenceValue = navMeshData; | ||
so.ApplyModifiedPropertiesWithoutUndo(); | ||
} | ||
|
||
void StoreNavMeshDataIfInPrefab(NavMeshSurface 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 NavMeshSurface; | ||
isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData; | ||
} | ||
m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { surface = surfaceToStore, navMeshData = isDataOwner ? surfaceToStore.navMeshData : null }); | ||
} | ||
|
||
bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface 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<NavMeshSurface>(true); | ||
foreach (var surface in surfaces) | ||
DeleteStoredPrefabNavMeshDataAsset(surface); | ||
} | ||
|
||
void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface 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<NavMeshSurface>(true); | ||
NavMeshSurface 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 NavMeshSurface; | ||
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; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.