Files
BABA_YAGA/Assets/Third Parties/D.A. Assets/DA-Shared/Runtime/Extensions/MonoBehaviourExtensions.cs
2026-05-17 15:12:16 +07:00

346 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
#pragma warning disable CS0162
namespace DA_Assets.Extensions
{
public static class MonoBehExtensions
{
public static void DestroyChilds(this GameObject parent)
{
if (parent == null)
return;
int childCount = parent.transform.childCount;
for (int i = childCount - 1; i >= 0; i--)
{
GameObject go = parent.transform.GetChild(i).gameObject;
go.Destroy();
}
Debug.Log("log_current_canvas_childs_destroy " + childCount);
}
public static bool TryGetComponentSafe<T>(this GameObject gameObject, out T component)
{
component = default;
if (gameObject == null)
return false;
return gameObject.TryGetComponent(out component);
}
public static T[] GetChilds<T>(this GameObject gameObject)
{
T[] childs = gameObject.GetComponentsInChildren<T>(true).Skip(1).ToArray();
return childs;
}
/// <summary>
/// Removes the RectTransform component from a GameObject by creating a new GameObject
/// with the same components (excluding RectTransform), children, and parent.
/// </summary>
/// <param name="gameObject">The GameObject from which to remove the RectTransform.</param>
public static GameObject RemoveRectTransform(this GameObject gameObject)
{
// Create a new GameObject
GameObject newGameObject = CreateEmptyGameObject();
newGameObject.name = gameObject.name;
// Save the siblingIndex of the old GameObject
int siblingIndex = gameObject.transform.GetSiblingIndex();
// Assign the parent object
newGameObject.transform.SetParent(gameObject.transform.parent);
newGameObject.transform.localPosition = gameObject.transform.localPosition;
newGameObject.transform.localRotation = gameObject.transform.localRotation;
newGameObject.transform.localScale = gameObject.transform.localScale;
// Set siblingIndex for the new GameObject
newGameObject.transform.SetSiblingIndex(siblingIndex);
// Transfer all child objects
for (int i = gameObject.transform.childCount - 1; i >= 0; i--)
{
Transform child = gameObject.transform.GetChild(i);
// Save the siblingIndex for child objects
int childSiblingIndex = child.GetSiblingIndex();
child.SetParent(newGameObject.transform);
child.SetSiblingIndex(childSiblingIndex);
}
// Copy all components
Component[] components = gameObject.GetComponents<Component>();
foreach (Component component in components)
{
if (!(component is Transform))
{
Component newComponent = newGameObject.AddComponent(component.GetType());
component.CopySerializedFields(newComponent);
}
}
// Destroy the old GameObject
gameObject.Destroy();
return newGameObject;
}
public static List<T> GetComponentsInReverseOrder<T>(this GameObject parent) where T : Component
{
List<T> results = new List<T>();
AddComponentsInReverseOrder(parent.transform);
return results;
void AddComponentsInReverseOrder(Transform current)
{
for (int i = current.childCount - 1; i >= 0; i--)
{
AddComponentsInReverseOrder(current.GetChild(i));
}
T component = current.GetComponent<T>();
if (component != null/* && !results.Contains(component)*/)
{
results.Add(component);
}
}
}
/// <summary>
/// Saves the GameObject as a prefab asset at the specified local path and tries to get the component of type T from the prefab.
/// </summary>
/// <typeparam name="T">The type of the MonoBehaviour to retrieve from the prefab.</typeparam>
/// <param name="gameObject">The GameObject to be saved as a prefab.</param>
/// <param name="localPath">The local path within the project where the prefab should be saved.</param>
/// <param name="savedPrefab">The component of type T retrieved from the prefab, or null if the operation failed.</param>
/// <param name="ex">Any exceptions that occurred during the process.</param>
/// <returns>True if the prefab was saved and the component of type T was successfully retrieved, otherwise false.</returns>
public static bool SaveAsPrefabAsset<T>(this GameObject gameObject, string localPath, out T savedPrefab, out Exception ex) where T : MonoBehaviour
{
// Check for null GameObject
if (gameObject == null)
{
ex = new NullReferenceException("GameObject is null.");
savedPrefab = null;
return false;
}
#if UNITY_EDITOR
// Save the GameObject as a prefab asset in Editor mode.
GameObject prefabGo = null;
try
{
prefabGo = UnityEditor.PrefabUtility.SaveAsPrefabAsset(gameObject, localPath, out bool success);
}
catch (Exception ex1)
{
ex = ex1;
}
if (prefabGo == null)
{
ex = new NullReferenceException("Prefab is null.");
savedPrefab = null;
return false;
}
// Attempt to get the component of type T from the saved prefab.
if (prefabGo.TryGetComponent<T>(out T prefabComponent))
{
ex = null;
savedPrefab = prefabComponent;
return true;
}
else
{
// Handle the case where the component of type T can't be found on the prefab.
ex = new Exception($"Can't get Type '{typeof(T).Name}' from GameObject '{prefabGo.name}'.");
savedPrefab = null;
return false;
}
#endif
// Handle cases outside of Editor mode.
ex = new Exception("Unsupported in not-Editor mode.");
savedPrefab = null;
return false;
}
/// <summary>
/// Checks if the provided UnityEngine.Object is part of any prefab.
/// </summary>
/// <param name="gameObject">The UnityEngine.Object to check.</param>
/// <returns>True if the object is part of a prefab, otherwise false.</returns>
public static bool IsPartOfAnyPrefab(this UnityEngine.Object gameObject)
{
if (gameObject == null)
return false;
#if UNITY_EDITOR
return UnityEditor.PrefabUtility.IsPartOfAnyPrefab(gameObject);
#endif
return false;
}
/// <summary>
/// Checks if any instance of the provided MonoBehaviour type exists on the scene.
/// </summary>
/// <typeparam name="T">Type of MonoBehaviour to check for.</typeparam>
/// <returns>True if at least one instance of T exists on the scene, otherwise false.</returns>
public static bool IsExistsOnScene<T>() where T : MonoBehaviour
{
int count = MonoBehaviour.FindObjectsOfType<T>().Length;
return count != 0;
}
/// <summary>
/// Destroying Unity GameObject, but as an extension.
/// <para>Works in Editor and Playmode.</para>
/// </summary>
/// <summary>
public static bool Destroy(this UnityEngine.Object @object)
{
if (@object == null)
return false;
try
{
if (@object != null)
{
//Debug.LogError($"Destroy | {unityObject.name}");
}
#if UNITY_EDITOR
UnityEngine.Object.DestroyImmediate(@object);
#else
UnityEngine.Object.Destroy(@object);
#endif
return true;
}
catch
{
return false;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="gameObject"></param>
/// <param name="component"></param>
/// <returns>Returns whether a component of the input type has been added.</returns>
public static bool TryAddComponent<T>(this GameObject gameObject, out T component, bool supportMultiInstance = false) where T : UnityEngine.Component
{
if (gameObject.TryGetComponent(out component) && !supportMultiInstance)
{
return true;
}
else
{
component = gameObject.AddComponent<T>();
return false;
}
}
public static bool TryGetComponent<T>(this GameObject gameObject, out T component) where T : UnityEngine.Component
{
try
{
component = gameObject.GetComponent<T>();
string _ = component.name;
return true;
}
catch
{
component = default;
return false;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="gameObject"></param>
/// <param name="graphic">Found or added graphic component.</param>
/// <returns>Returns whether a component of the input type has been added.</returns>
public static bool TryAddGraphic<T>(this GameObject gameObject, out T graphic) where T : Graphic
{
if (gameObject.TryGetComponent(out graphic))
{
return false;
}
else if (gameObject.TryGetComponent(out Graphic _graphic))
{
return false;
}
else
{
graphic = gameObject.AddComponent<T>();
return true;
}
}
public static bool TryDestroyComponent<T>(this GameObject gameObject) where T : UnityEngine.Component
{
if (gameObject.TryGetComponent(out T component))
{
component.Destroy();
return true;
}
else
{
return false;
}
}
/// <summary>
/// Marks target object as dirty, but as an extension.
/// </summary>
/// <param name="object">The object to mark as dirty.</param>
public static void SetDirtyExt(this UnityEngine.Object @object)
{
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(@object);
#endif
}
public static void MakeGameObjectSelectedInHierarchy(this GameObject activeGameObject)
{
#if UNITY_EDITOR
UnityEditor.Selection.activeGameObject = activeGameObject;
#endif
}
public static GameObject CreateEmptyGameObject(string name = null, Transform parent = null)
{
GameObject tempGO = new GameObject();
GameObject emptyGO;
if (parent == null)
{
emptyGO = UnityEngine.Object.Instantiate(tempGO);
}
else
{
emptyGO = UnityEngine.Object.Instantiate(tempGO, parent);
}
if (name != null)
{
tempGO.name = name;
}
tempGO.Destroy();
return emptyGO;
}
}
}