unity – Any way to guarantee the order of objects returned by FindObjectsOfType?

You want a hierarchical sort using Comparer<Transform> with GetSiblingIndex:

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using JetBrains.Annotations;
using UnityEngine;

namespace xyz
{
    /// <summary>
    ///     Hierarchical comparisons utility.
    /// </summary>
    public static class HierarchyComparer
    {
        /// <summary>
        ///     Gets an instance that compares a hierarchy of <see cref="UnityEngine.Component" />.
        /// </summary>
        (PublicAPI)
        public static System.Collections.Generic.Comparer<Component> Component { get; } = new Comparer<Component>(Compare);

        /// <summary>
        ///     Gets an instance that compares a hierarchy of <see cref="UnityEngine.GameObject" />.
        /// </summary>
        (PublicAPI)
        public static System.Collections.Generic.Comparer<GameObject> GameObject { get; } = new Comparer<GameObject>(Compare);

        /// <summary>
        ///     Gets an instance that compares a hierarchy of <see cref="UnityEngine.Transform" />.
        /// </summary>
        (PublicAPI)
        public static System.Collections.Generic.Comparer<Transform> Transform { get; } = new Comparer<Transform>(Compare);

        private static int Compare((CanBeNull) Component x, (CanBeNull) Component y)
        {
#pragma warning disable IDE0031 // Null check can be simplified
            return Compare(x != null ? x.transform : null, y != null ? y.transform : null);
#pragma warning restore IDE0031
        }

        private static int Compare((CanBeNull) GameObject x, (CanBeNull) GameObject y)
        {
#pragma warning disable IDE0031 // Null check can be simplified
            return Compare(x != null ? x.transform : null, y != null ? y.transform : null);
#pragma warning restore IDE0031
        }

        private static int Compare((CanBeNull) Transform x, (CanBeNull) Transform y)
        {
            if (x == null && y == null)
                return 0;

            if (x == null)
                return -1;

            if (y == null)
                return +1;

            var hierarchy1 = GetHierarchy(x);
            var hierarchy2 = GetHierarchy(y);

            while (true)
            {
                if (!hierarchy1.Any())
                    return -1;

                var pop1 = hierarchy1.Pop();

                if (!hierarchy2.Any())
                    return +1;

                var pop2 = hierarchy2.Pop();

                var index1 = pop1.Index;
                var index2 = pop2.Index;

                if (index1 == index2)
                    continue;

                var compare = index1.CompareTo(index2);

                return compare;
            }
        }

        private static Stack<Hierarchy> GetHierarchy((NotNull) Transform transform)
        {
            if (transform == null)
                throw new ArgumentNullException(nameof(transform));

            var stack = new Stack<Hierarchy>();

            var current = transform;

            while (current != null)
            {
                var index = current.GetSiblingIndex();

                stack.Push(new Hierarchy(index, current));

                current = current.parent;
            }

            return stack;
        }

        /// <summary>
        ///     Hierarchically sort an array of components.
        /// </summary>
        /// <param name="components"></param>
        /// <returns></returns>
        (PublicAPI)
        public static Component() HierarchicalSort((NotNull) this Component() components)
        {
            if (components == null)
                throw new ArgumentNullException(nameof(components));

            Array.Sort(components, Component);

            return components;
        }

        /// <summary>
        ///     Hierarchically sort an array of game objects.
        /// </summary>
        /// <param name="gameObjects"></param>
        /// <returns></returns>
        (PublicAPI)
        public static GameObject() HierarchicalSort((NotNull) this GameObject() gameObjects)
        {
            if (gameObjects == null)
                throw new ArgumentNullException(nameof(gameObjects));

            Array.Sort(gameObjects, GameObject);

            return gameObjects;
        }

        /// <summary>
        ///     Hierarchically sort an array of transforms.
        /// </summary>
        /// <param name="transforms"></param>
        /// <returns></returns>
        (PublicAPI)
        public static Transform() HierarchicalSort((NotNull) this Transform() transforms)
        {
            if (transforms == null)
                throw new ArgumentNullException(nameof(transforms));

            Array.Sort(transforms, Transform);

            return transforms;
        }

        #region Nested type: Comparer

        private sealed class Comparer<T> : System.Collections.Generic.Comparer<T>
        {
            public Comparer((NotNull) Func<T, T, int> func)
            {
                Func = func ?? throw new ArgumentNullException(nameof(func));
            }

            private Func<T, T, int> Func { get; }

            public override int Compare(T x, T y)
            {
                return Func(x, y);
            }
        }

        #endregion

        #region Nested type: Hierarchy

        private struct Hierarchy
        {
            public int Index { get; }

            (SuppressMessage("ReSharper", "MemberCanBePrivate.Local", Justification = "debugging"))
            public Transform Target { get; }

            public Hierarchy(int index, (NotNull) Transform transform)
            {
                if (index < 0)
                    throw new ArgumentOutOfRangeException(nameof(index));

#pragma warning disable IDE0016 // Null check can be simplified
                if (transform == null)
                    throw new ArgumentNullException(nameof(transform));
#pragma warning restore IDE0016

                Index = index;
                Target = transform;
            }

            public override string ToString()
            {
                return $"{nameof(Index)}: {Index}, {nameof(Target)}: {Target}";
            }
        }

        #endregion
    }
}

Throw that to an array of transforms, they will always be sorted in hierarchy order.

Edit:

Refined version, minor adjustments, supports any Component, less code but functionally identical:

using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using UnityEngine;

namespace xyz
{
    public static class HierarchicalSorting
    {
        private static int Compare((CanBeNull) Component x, (CanBeNull) Component y)
        {
            return Compare(x != null ? x.transform : null, y != null ? y.transform : null);
        }

        private static int Compare((CanBeNull) GameObject x, (CanBeNull) GameObject y)
        {
            return Compare(x != null ? x.transform : null, y != null ? y.transform : null);
        }

        private static int Compare((CanBeNull) Transform x, (CanBeNull) Transform y)
        {
            if (x == null && y == null)
                return 0;

            if (x == null)
                return -1;

            if (y == null)
                return +1;

            var hierarchy1 = GetHierarchy(x);
            var hierarchy2 = GetHierarchy(y);

            while (true)
            {
                if (!hierarchy1.Any())
                    return -1;

                var pop1 = hierarchy1.Pop();

                if (!hierarchy2.Any())
                    return +1;

                var pop2 = hierarchy2.Pop();

                var compare = pop1.CompareTo(pop2);

                if (compare == 0)
                    continue;

                return compare;
            }
        }

        (NotNull)
        private static Stack<int> GetHierarchy((NotNull) Transform transform)
        {
            if (transform == null)
                throw new ArgumentNullException(nameof(transform));

            var stack = new Stack<int>();

            var current = transform;

            while (current != null)
            {
                var index = current.GetSiblingIndex();

                stack.Push(index);

                current = current.parent;
            }

            return stack;
        }

        (PublicAPI)
        (NotNull)
        (ItemNotNull)
        public static T() Sort<T>((NotNull) (ItemNotNull) T() components) where T : Component
        {
            if (components == null)
                throw new ArgumentNullException(nameof(components));

            Array.Sort(components, new RelayComparer<T>(Compare));

            return components;
        }

        (PublicAPI)
        (NotNull)
        (ItemNotNull)
        public static GameObject() Sort((NotNull) (ItemNotNull) GameObject() gameObjects)
        {
            if (gameObjects == null)
                throw new ArgumentNullException(nameof(gameObjects));

            Array.Sort(gameObjects, new RelayComparer<GameObject>(Compare));

            return gameObjects;
        }

        (PublicAPI)
        (NotNull)
        (ItemNotNull)
        public static Transform() Sort((NotNull) (ItemNotNull) Transform() transforms)
        {
            if (transforms == null)
                throw new ArgumentNullException(nameof(transforms));

            Array.Sort(transforms, new RelayComparer<Transform>(Compare));

            return transforms;
        }

        private sealed class RelayComparer<T> : Comparer<T>
        {
            public RelayComparer((NotNull) Func<T, T, int> func)
            {
                Func = func ?? throw new ArgumentNullException(nameof(func));
            }

            (NotNull)
            private Func<T, T, int> Func { get; }

            public override int Compare(T x, T y)
            {
                return Func(x, y);
            }
        }
    }
}