I’ve created a script to naturally sort gameobjects by their name in the hierarchy, and I cannot seem to figure out how to use the built-in Undo system when root objects have SetSiblingIndex called on them.
Here’s what I’ve got so far:
using UnityEditor;
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Zapdot
{
public static class EditorTools
{
[MenuItem("Tools/Utility/Sort Hierarchy #h", false)]
public static void SortObjects()
{
List<Transform> objsToSort = new List<Transform>();
Transform rootParent = null;
int minIndex = int.MaxValue;
if (Selection.transforms.Length > 1)
{
rootParent = Selection.transforms[0].parent;
foreach (Transform t in Selection.transforms)
{
minIndex = Mathf.Min(minIndex, t.GetSiblingIndex());
objsToSort.Add(t);
}
if (rootParent != null)
Undo.RegisterCompleteObjectUndo(rootParent, "Sort Hierarchy");
else
Undo.RegisterCompleteObjectUndo(objsToSort.ToArray(), "Sort Hierarchy");
}
else if (Selection.activeTransform.childCount > 0)
{
// since we're sorting all of the children, our minIndex would be 0.
minIndex = 0;
rootParent = Selection.activeTransform;
for (int i = 0; i < rootParent.childCount; ++i)
objsToSort.Add(rootParent.GetChild(i));
Undo.RegisterCompleteObjectUndo(rootParent, "Sort Hierarchy");
}
objsToSort.Sort(new NaturalNameComparer());
for (int i = 0; i < objsToSort.Count; ++i)
objsToSort*.SetSiblingIndex(minIndex + i);*
}
[MenuItem(“Tools/Utility/Sort Hierarchy #h”, true)]
public static bool SortObjectsValidate()
{
return Selection.transforms.Length > 1 || (Selection.transforms.Length == 1 && Selection.activeTransform.childCount > 1);
}
}
public class NaturalNameComparer : IComparer
{
private static readonly Regex _re = new Regex(@“(?<=\D)(?=\d)|(?<=\d)(?=\D)”);
public int Compare(Transform obj1, Transform obj2)
{
string x = obj1.name.ToLower();
string y = obj2.name.ToLower();
if (string.Compare(x, 0, y, 0, Mathf.Min(x.Length, y.Length)) == 0)
{
if (x.Length == y.Length)
return 0;
return x.Length < y.Length ? -1 : 1;
}
var a = _re.Split(x);
var b = _re.Split(y);
int i = 0;
while (true)
{
int r = PartCompare(a_, b*);
if (r != 0)
return r;
++i;
}
}*_
private static int PartCompare(string x, string y)
{
int a, b;
if (int.TryParse(x, out a) && int.TryParse(y, out b))
return a.CompareTo(b);
return x.CompareTo(y);
}
}
}
To reproduce:
* Add this editor script to an empty project
* Create two gameobjects as root objects in a scene, “b” and “a”
* Select them both
* Run the function (shift h)
* Try to undo – the objects don’t reorder themselves to their original position.