Skip to content

Instantly share code, notes, and snippets.

@WhiteOlivierus
Created July 10, 2024 08:16
Show Gist options
  • Select an option

  • Save WhiteOlivierus/d94b7d88b27250f171865cee06a1bac6 to your computer and use it in GitHub Desktop.

Select an option

Save WhiteOlivierus/d94b7d88b27250f171865cee06a1bac6 to your computer and use it in GitHub Desktop.
A way for monitoring changes in the unity editor hierarchy
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using Object = UnityEngine.Object;
[InitializeOnLoad]
public static class HierarchyMonitor
{
private static readonly Dictionary<GameObject, string> _previousNames = new();
private static readonly Dictionary<GameObject, Transform> _previousParents = new();
public delegate void GameObjectEventHandler(GameObject gameObject);
public delegate void GameObjectRenamedEventHandler(GameObject editedObject);
public delegate void GameObjectParentChangedEventHandler(GameObject gameObject, Transform oldParent, Transform newParent);
public static event GameObjectEventHandler GameObjectAdded;
public static event GameObjectEventHandler GameObjectRemoved;
public static event GameObjectRenamedEventHandler GameObjectRenamed;
public static event GameObjectParentChangedEventHandler GameObjectParentChanged;
static HierarchyMonitor()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
RefreshPreviousState();
}
private static void RefreshPreviousState()
{
_previousNames.Clear();
_previousParents.Clear();
GameObject[] gameObjects = Object.FindObjectsOfType<GameObject>();
foreach (GameObject gameObject in gameObjects)
{
if (gameObject.hideFlags != HideFlags.None ||
_previousNames.ContainsKey(gameObject))
{
continue;
}
_previousNames.Add(gameObject, gameObject.name);
_previousParents.Add(gameObject, gameObject.transform.parent);
}
}
private static void OnHierarchyChanged()
{
GameObject[] currentGameObjects = Object.FindObjectsOfType<GameObject>();
foreach (GameObject gameObject in currentGameObjects)
{
HandleGameObjectAdded(gameObject);
HandleGameObjectRenamed(gameObject);
HandleGameObjectParentChanged(gameObject);
}
ICollection<GameObject> keys = _previousNames.Keys.ToList();
foreach (GameObject previousGameObject in keys)
{
HandleGameObjectDeleted(currentGameObjects, previousGameObject);
}
RefreshPreviousState();
}
private static void HandleGameObjectDeleted(GameObject[] currentGameObjects, GameObject previousGameObject)
{
if (Array.Exists(currentGameObjects, obj => obj == previousGameObject))
{
return;
}
Debug.Log($"GameObject removed: {_previousNames[previousGameObject]}");
GameObjectRemoved?.Invoke(previousGameObject);
_previousNames.Remove(previousGameObject);
}
private static void HandleGameObjectRenamed(GameObject gameObject)
{
if (!_previousNames.ContainsKey(gameObject) ||
gameObject.name == _previousNames[gameObject])
{
return;
}
Debug.Log($"GameObject renamed from: {_previousNames[gameObject]} to: {gameObject.name}");
GameObjectRenamed?.Invoke(gameObject);
_previousNames[gameObject] = gameObject.name;
}
private static void HandleGameObjectAdded(GameObject gameObject)
{
if (_previousNames.ContainsKey(gameObject))
{
return;
}
Debug.Log($"GameObject added: {gameObject.name}");
GameObjectAdded?.Invoke(gameObject);
_previousNames.Add(gameObject, gameObject.name);
_previousParents.Add(gameObject, gameObject.transform.parent);
}
private static void HandleGameObjectParentChanged(GameObject gameObject)
{
Transform currentParent = gameObject.transform.parent;
if (!_previousParents.ContainsKey(gameObject) ||
currentParent == _previousParents[gameObject])
{
return;
}
Debug.Log($"GameObject parent changed: {gameObject.name}");
GameObjectParentChanged?.Invoke(gameObject, _previousParents[gameObject], currentParent);
_previousParents[gameObject] = currentParent;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment