diff options
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/NavmeshPrefabEditor.cs')
-rw-r--r-- | Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/NavmeshPrefabEditor.cs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/NavmeshPrefabEditor.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/NavmeshPrefabEditor.cs new file mode 100644 index 0000000..3f5b717 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/NavmeshPrefabEditor.cs @@ -0,0 +1,168 @@ +using UnityEditor; +using UnityEngine; +using System.Linq; + +namespace Pathfinding { + using Pathfinding.Util; + + /// <summary>Editor for the <see cref="NavmeshPrefab"/> component</summary> + [CustomEditor(typeof(NavmeshPrefab), true)] + [CanEditMultipleObjects] + public class NavmeshPrefabEditor : EditorBase { + protected override void OnEnable () { + base.OnEnable(); + AstarPathEditor.LoadStyles(); + EditorApplication.update += OnUpdate; + } + + protected override void OnDisable () { + base.OnDisable(); + EditorApplication.update -= OnUpdate; + } + + void OnUpdate () { + } + + static int pendingScanProgressId; + + static int PendingScan (Promise<NavmeshPrefab.SerializedOutput>[] pendingScanProgress, NavmeshPrefab[] pendingScanTargets) { + var progressId = UnityEditor.Progress.Start("Scanning Navmesh Prefab", "Scanning Navmesh Prefab", UnityEditor.Progress.Options.None, -1); + EditorApplication.CallbackFunction cb = null; + cb = () => { + if (UnityEditor.Progress.Exists(progressId)) { + bool allDone = true; + var avg = 0.0f; + for (int i = 0; i < pendingScanProgress.Length; i++) { + if (pendingScanTargets[i] == null) { + avg += 1.0f; + } else { + avg += pendingScanProgress[i].Progress; + + if (pendingScanProgress[i].IsCompleted) { + var data = pendingScanProgress[i].Complete().data; + // Data can be null if some exception has been thrown during the scan + if (data != null) { + pendingScanTargets[i].SaveToFile(data); + } + pendingScanProgress[i].Dispose(); + pendingScanTargets[i] = null; + pendingScanProgress[i] = default; + } else { + allDone = false; + } + } + } + avg /= pendingScanProgress.Length; + UnityEditor.Progress.Report(progressId, avg); + + if (allDone) { + UnityEditor.Progress.Finish(progressId); + } + } else { + EditorApplication.update -= cb; + } + }; + EditorApplication.update += cb; + return progressId; + } + + protected override void Inspector () { + AstarPath.FindAstarPath(); + Section("Shape"); + BoundsField("bounds"); + + bool needsRounding = false; + RecastGraph graph = null; + if (AstarPath.active != null && AstarPath.active.data.recastGraph != null) { + graph = AstarPath.active.data.recastGraph; + } + bool isPrefab = EditorUtility.IsPersistent(this.target); + + if (graph != null && !isPrefab) { + if (!graph.useTiles) { + EditorGUILayout.HelpBox("The recast graph in the scene doesn't use tiles. It needs to use tiles to be used with this component.", MessageType.Warning); + if (GUILayout.Button("Enable tiling on recast graph")) { + graph.useTiles = true; + } + } + + var roundedTiles = this.targets.Cast<NavmeshPrefab>().Select(target => { + var navmeshPrefab = target as NavmeshPrefab; + var bounds = navmeshPrefab.bounds; + var desiredBounds = NavmeshPrefab.SnapSizeToClosestTileMultiple(graph, bounds); + return new { + needsRounding = !Mathf.Approximately(bounds.extents.x, desiredBounds.extents.x) || !Mathf.Approximately(bounds.extents.z, desiredBounds.extents.z), + desiredBounds = desiredBounds + }; + }).ToArray(); + needsRounding = roundedTiles.Any(x => x.needsRounding); + + if (needsRounding) { + EditorGUILayout.HelpBox("Bounds size is not a multiple of the recast graph's tile size (" + (graph.editorTileSize * graph.cellSize).ToString("0.0") + ").\nThe tile size is cell size * tile size in voxels (set in recast graph settings)", MessageType.Warning); + if (GUILayout.Button("Round to nearest multiple")) { + UnityEditor.Undo.RecordObjects(targets, "Snap to nearest tile multiple"); + for (int i = 0; i < targets.Length; i++) { + (targets[i] as NavmeshPrefab).bounds = roundedTiles[i].desiredBounds; + EditorUtility.SetDirty(targets[i]); + } + } + } + + if (GUILayout.Button("Snap position to nearest tile")) { + for (int i = 0; i < targets.Length; i++) { + var navmeshPrefab = targets[i] as NavmeshPrefab; + navmeshPrefab.SnapToClosestTileAlignment(); + } + } + } + Section("Settings"); + PropertyField("applyOnStart"); + PropertyField("removeTilesWhenDisabled"); + Section("Serialized Data"); + EditorGUILayout.BeginHorizontal(); + PropertyField("serializedNavmesh"); + +#if UNITY_2021_3_OR_NEWER + EditorGUI.showMixedValue = targets.Length > 1; + var target = this.target as NavmeshPrefab; + GUILayout.Label(EditorUtility.FormatBytes(target.serializedNavmesh != null ? target.serializedNavmesh.dataSize : 0), GUILayout.ExpandWidth(false)); + EditorGUI.showMixedValue = false; +#endif + EditorGUILayout.EndHorizontal(); + + if (UnityEditor.Progress.Exists(pendingScanProgressId)) { + var r = EditorGUILayout.GetControlRect(); + EditorGUI.ProgressBar(r, UnityEditor.Progress.GetProgress(pendingScanProgressId), "Scanning..."); + Repaint(); + } else { + EditorGUI.BeginDisabledGroup(needsRounding || isPrefab || graph == null); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Scan & Save")) { + var pendingScanProgress = new Promise<NavmeshPrefab.SerializedOutput>[targets.Length]; + var pendingScanTargets = new NavmeshPrefab[targets.Length]; + for (int i = 0; i < targets.Length; i++) { + var navmeshPrefab = targets[i] as NavmeshPrefab; + pendingScanProgress[i] = navmeshPrefab.ScanAsync(graph); + // this.pendingScanProgress[i].Complete(); + pendingScanTargets[i] = navmeshPrefab; + } + + pendingScanProgressId = PendingScan(pendingScanProgress, pendingScanTargets); + } + EditorGUI.EndDisabledGroup(); + EditorGUI.BeginDisabledGroup(isPrefab || graph == null); + if (GUILayout.Button("Edit graph", GUILayout.ExpandWidth(false))) { + Selection.activeGameObject = AstarPath.active.gameObject; + AstarPath.active.showGraphs = true; + } + EditorGUI.EndDisabledGroup(); + EditorGUILayout.EndHorizontal(); + if (isPrefab) { + EditorGUILayout.HelpBox("Open the prefab or add it to a scene to scan it.", MessageType.Info); + } else if (graph == null) { + EditorGUILayout.HelpBox("No recast graph was found in the scene. Add one if you want to scan this navmesh prefab.", MessageType.Info); + } + } + } + } +} |