Files
2025-11-30 08:35:03 +02:00

138 lines
3.4 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Needle.Engine.Utils
{
public static class ObjectUtils
{
public static T GetComponentInParent<T>(GameObject go)
{
if (!go) return default;
if (go.TryGetComponent<T>(out var t))
{
return t;
}
var parent = go.transform?.parent;
if (parent) return GetComponentInParent<T>(parent.gameObject);
return default;
}
public static void FindObjectsOfType<T>(List<T> results) where T : class
{
var gos = SceneManager.GetActiveScene().GetRootGameObjects();
foreach (var go in gos) Traverse(go);
void Traverse(GameObject go)
{
if (go.gameObject.TryGetComponent<T>(out var res))
{
results.Add(res);
}
var t = go.transform;
for (var i = 0; i < t.childCount; i++)
{
var ch = t.GetChild(i);
Traverse(ch.gameObject);
}
}
}
public static T FindObjectOfType<T>(bool activeOnly = true) where T : class
{
var active = SceneManager.GetActiveScene();
for (var i = 0; i < SceneManager.sceneCount; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (activeOnly && scene != active) continue;
var gos = scene.GetRootGameObjects();
foreach (var go in gos)
{
var res = Traverse(go);
if (res != null) return res;
}
T Traverse(GameObject go)
{
if (go.gameObject.TryGetComponent<T>(out var res))
return res;
var t = go.transform;
for (var i = 0; i < t.childCount; i++)
{
var ch = t.GetChild(i);
res = Traverse(ch.gameObject);
if (res != null) return res;
}
return default;
}
}
return default;
}
public static void SafeDestroy(this Object obj)
{
if (!obj) return;
if (!Application.isPlaying) Object.DestroyImmediate(obj);
else Object.Destroy(obj);
}
public static string GetId(this Object obj)
{
if (obj == null) return null;
var original = obj;
// always use guid from transform
// threejs knows no difference between gameobject and transform
// this is merely to avoid having multiple guids pointing to the same object
if (obj is GameObject go) obj = go.transform;
#if UNITY_EDITOR
var identifier = GlobalObjectId.GetGlobalObjectIdSlow(obj);
var id = identifier.targetObjectId.ToString();
// id can be zero with hideflags set to e.g. DontSaveInEditor
if (id == "0")
{
switch (obj)
{
default:
id = obj.GetInstanceID().ToString();
break;
case Texture tex:
return tex.imageContentsHash.ToString();
}
}
if (obj)
{
if (EditorUtility.IsPersistent(obj))
id += "_" + identifier.assetGUID;
if (PrefabUtility.IsPartOfAnyPrefab(obj))
id += "_" + identifier.targetPrefabId;
}
// fallback to random id
if (id == "0")
{
id = "r_" + Mathf.FloorToInt(Random.Range(1_000_000, 9_999_999)).ToString();
}
// HACK: since we serialize rect transforms since 71699dff7b948bb1931517720135cf1fb6659381 to allow putting UI in gltf files we need to differentiate between transforms and rect transform components.
if (original is RectTransform) id += "_1";
return id;
#else
return obj.GetInstanceID().ToString();
#endif
}
public static string GetIdShort(this Object obj)
{
#if UNITY_EDITOR
var identifier = GlobalObjectId.GetGlobalObjectIdSlow(obj);
var id = identifier.targetObjectId.ToString();
return id;
#else
return obj.GetInstanceID().ToString();
#endif
}
}
}