Last active
April 7, 2025 13:35
-
-
Save SugoiDev/33f21b96b34f85edaf8e2d0ea88bc179 to your computer and use it in GitHub Desktop.
Returns the full path of a GameObject. Includes, optionally, the Scence name and a component name
This file contains hidden or 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
//#undef UNITY_EDITOR | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System.Text; | |
using JetBrains.Annotations; | |
using UnityEditor.Experimental.SceneManagement; | |
using UnityEngine; | |
using UnityObject = UnityEngine.Object; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
#endif | |
public static class UnityObjectExtensions { | |
private static readonly Stack<StringBuilder> | |
_SbPool = new Stack<StringBuilder>(); | |
/// <summary> | |
/// Will return a string in the form [A]ObjectGrandParentName/ObjectParentName/ObjectName/SomeComponentName | |
/// Where [A] can be [SceneName] or [Prefab], and SomeComponent is only shown if <see cref="component"/> is not null, and [SceneName] is only shown if <see cref="includeScene"/> is true. | |
/// </summary> | |
/// <param name="gameObject">Will get all parents of this object and return a string with each parent like ObjectGrandParentName/ObjectParentName/ObjectName</param> | |
/// <param name="includeScene">If the object is not a prefab the scene name will be shown in the first part of the returned string, as [SceneName]</param> | |
/// <param name="component">If this is not null, will add the component name to the last part of the returned string.</param> | |
/// <returns></returns> | |
[NotNull] | |
public static string GetHierarchyPath( | |
this GameObject gameObject, | |
bool includeScene = true, | |
[CanBeNull] Component component = null) { | |
const string COMPONENT_WAS_NULL = "GAMEOBJECT WAS NULL. NO HIERARCHY PATH!"; | |
//comment ID 05:03 11/04/2018: we can't even extract the runtime type with GetType here. It is really null. | |
if (gameObject != null) { | |
return COMPONENT_WAS_NULL; | |
} | |
StringBuilder sb; | |
if (_SbPool.Count > 0) { | |
sb = _SbPool.Pop(); | |
sb.Clear(); | |
} else { | |
sb = new StringBuilder(200); | |
} | |
try { | |
#if UNITY_EDITOR | |
bool isPrefab; | |
#if UNITY_2018_3_OR_NEWER | |
isPrefab = UnityEditor.PrefabUtility.GetPrefabAssetType(gameObject.gameObject) != UnityEditor.PrefabAssetType.NotAPrefab; | |
#else | |
isPrefab = UnityEditor.PrefabUtility.GetPrefabType(o) == UnityEditor.PrefabType.Prefab; | |
#endif | |
var assetPath = string.Empty; | |
if (isPrefab) { | |
#if UNITY_2018_3_OR_NEWER | |
assetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(gameObject); | |
#else | |
assetPath = AssetDatabase.GetAssetPath(gameObject); | |
#endif | |
sb.Append("[PREFAB]/["); | |
} else { | |
#endif | |
if (includeScene) { | |
var sceneName = gameObject.scene.name; | |
if (sceneName == string.Empty) { | |
#if UNITY_2018_3_OR_NEWER | |
var prefabStage = PrefabStageUtility.GetPrefabStage(gameObject); | |
if (prefabStage != null) { | |
sceneName = "Prefab Stage"; | |
} else { | |
#endif | |
sceneName = "Unsaved Scene"; | |
#if UNITY_2018_3_OR_NEWER | |
} | |
#endif | |
} | |
sb.Append("["); | |
sb.Append(sceneName); | |
sb.Append("]/"); | |
//will be like [SceneName]/ so far | |
} | |
#if UNITY_EDITOR | |
} | |
#endif | |
sb.Append(gameObject.name); | |
//will be like [SceneName]/RootGameObjectName | |
//[SceneName]/ will not be there if includeScene = false | |
var componentTypeName = string.Empty; | |
var includeComponent = component != null; | |
if (includeComponent) { | |
//we need to store before changing the gameObject reference | |
componentTypeName = component.GetType().GetTypeInfo().Name; | |
} | |
while (gameObject && gameObject.transform.parent) { | |
gameObject = gameObject.transform.parent.gameObject; | |
sb.Append("/"); | |
sb.Append(gameObject.GetType().GetTypeInfo().Name); | |
} | |
//will be like [SceneName]/RootGameObjectName/ChildObjectName/GrandChildObjectName | |
if (includeComponent) { | |
sb.Append("/"); | |
sb.Append(componentTypeName); | |
//will be like [SceneName]/RootGameObjectName/ChildObjectName/GrandChildObjectName/ComponentName | |
//[SceneName]/ will not be there if includeScene = false | |
} | |
#if UNITY_EDITOR | |
//finish putting rest of prefab | |
//should be something like this | |
//[PREFAB]/[RootObj/ChildObj/MaybeSomeComponent | |
//will then be like this (2 lines) | |
//[PREFAB]/[RootObj/ChildObj/MaybeSomeComponent] | |
//(Path on disk: ASSET_PATH_ON_DISK) | |
if (isPrefab) { | |
sb.Append("]\n(Path on disk: "); | |
sb.Append(assetPath); | |
sb.Append(")"); | |
} | |
#endif | |
var path = sb.ToString(); | |
sb.Clear(); | |
return path; | |
} | |
finally { | |
_SbPool.Push(sb); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment