unity/EditorPlugin/FindUsages/ShowUtil.cs (159 lines of code) (raw):
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using UnityEditor;
using UnityEditor.Animations;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace JetBrains.Rider.Unity.Editor.FindUsages
{
internal static class ShowUtil
{
public static void ShowFileUsage(string filePath)
{
var prefab = AssetDatabase.LoadAssetAtPath(filePath, typeof(Object));
ShowObjectUsage(prefab);
}
public static void ShowObjectUsage(Object prefab)
{
Selection.activeObject = prefab;
EditorGUIUtility.PingObject(prefab);
}
public static void ShowUsageOnScene(string filePath, string sceneName, string[] path, int[] rootIndices)
{
var sceneCount = SceneManager.sceneCount;
bool wasFound = false;
for (int i = 0; i < sceneCount; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (!scene.isLoaded)
continue;
if (scene.name.Equals(sceneName))
{
wasFound = true;
SelectUsageOnScene(scene, path, rootIndices);
break;
}
}
if (!wasFound)
{
var result = EditorUtility.DisplayDialogComplex("Find usages",
$"Do you want to close the current scene and open scene \"{sceneName}.unity\"?",
"Open Scene",
"Cancel",
"Open Scene Additive");
switch (result)
{
case 0:
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
var scene = EditorSceneManager.OpenScene(filePath, OpenSceneMode.Single);
SelectUsageOnScene(scene, path, rootIndices, true);
break;
case 1:
return;
case 2:
var sceneAdditive = EditorSceneManager.OpenScene(filePath, OpenSceneMode.Additive);
SelectUsageOnScene(sceneAdditive, path, rootIndices, true);
break;
}
}
}
private static void SelectUsageOnScene(Scene scene, string[] path, int[] rootIndices, bool doNotMoveCamera = false)
{
if (rootIndices.Length == 0)
return;
var rootObjects = scene.GetRootGameObjects();
if (rootIndices[0] >= rootObjects.Length)
return;
GameObject toSelect = rootObjects[rootIndices[0]];
if (!toSelect.name.Equals(path[0]))
return;
for (int i = 1; i < rootIndices.Length; i++)
{
var transform = toSelect.transform;
if (rootIndices[i] >= transform.childCount || rootIndices[i] < 0)
return;
toSelect = transform.GetChild(rootIndices[i]).gameObject;
if (!toSelect.name.Equals(path[i])) // check that object is same (with false-positives, but we warn user if scene is dirty)
return;
}
// Bring scene hierarchy and scene view to front
EditorGUIUtility.PingObject(toSelect);
Selection.activeObject = toSelect;
if (!doNotMoveCamera) // When scene is loaded, each GO has default transform
SceneView.lastActiveSceneView.FrameSelected();
}
public static void ShowAnimatorUsage([NotNull] string[] pathElements, [NotNull] string controllerFilePath)
{
var parent = FindParentForElementToSelect(pathElements, controllerFilePath);
if (parent is null) return;
var lastName = pathElements.Last();
if (lastName is null) return;
var elementToSelect = pathElements.Length != 1 ? FindChildElementToSelect(parent, lastName) : parent;
EditorGUIUtility.PingObject(elementToSelect);
Selection.activeObject = elementToSelect;
}
public static void ShowAnimationEventUsage([NotNull] string animFilePath)
{
var asset = AssetDatabase.LoadAssetAtPath(animFilePath, typeof(Object));
if (!(asset is AnimationClip clip)) return;
EditorGUIUtility.PingObject(clip);
Selection.activeObject = clip;
}
[CanBeNull]
private static AnimatorStateMachine FindParentForElementToSelect([NotNull] IList<string> pathElements,
[NotNull] string controllerFilePath)
{
var asset = AssetDatabase.LoadAssetAtPath(controllerFilePath, typeof(Object));
if (!(asset is AnimatorController controller)) return null;
var currentStateMachine = FindLayerStateMachine(pathElements, controller);
if (currentStateMachine is null) return null;
for (int i = 1, parentElementsCount = pathElements.Count - 1; i < parentElementsCount; i++)
{
var name = pathElements[i];
if (name is null) return null;
currentStateMachine = FindChildStateMachine(currentStateMachine, name);
if (currentStateMachine is null) return null;
}
return currentStateMachine;
}
[CanBeNull]
private static AnimatorStateMachine FindLayerStateMachine([NotNull] IList<string> pathElements,
[NotNull] AnimatorController controller)
{
var layers = controller.layers;
if (layers is null) return null;
var layerName = pathElements[0];
if (layerName is null) return null;
var animatorControllerLayer = layers
.Where(l => l != null && layerName.Equals(l.name))
.Select(layer => layer)
.FirstOrDefault();
return animatorControllerLayer?.stateMachine;
}
private static Object FindChildElementToSelect([NotNull] AnimatorStateMachine currentStateMachine,
[NotNull] string name)
{
Object toSelect;
var childStateMachine = FindChildStateMachine(currentStateMachine, name);
if (!(childStateMachine is null)) toSelect = childStateMachine;
else toSelect = FindChildState(currentStateMachine, name);
return toSelect;
}
[CanBeNull]
private static AnimatorStateMachine FindChildStateMachine([NotNull] AnimatorStateMachine animatorStateMachine,
[NotNull] string name)
{
return animatorStateMachine.stateMachines?
.Select(stateMachine => stateMachine.stateMachine)
.FirstOrDefault(stateMachine => stateMachine != null && name.Equals(stateMachine.name));
}
[CanBeNull]
private static AnimatorState FindChildState([NotNull] AnimatorStateMachine stateMachine, [NotNull] string name)
{
return stateMachine.states?
.Select(state => state.state)
.FirstOrDefault(state => state != null && name.Equals(state.name));
}
}
}