internal static void Sort <T>(List <T> items, GetSystemType <T> getType, Type parentType)
        {
#if !NET_DOTS
            lookupDictionary = null;
#endif
            // Populate dictionary mapping systemType to system-and-before/after-types.
            // This is clunky - it is easier to understand, and cleaner code, to
            // just use a Dictionary<Type, SysAndDep>. However, Tiny doesn't currently have
            // the ability to use Type as a key to a NativeHash, so we're stuck until that gets addressed.
            //
            // Likewise, this is important shared code. It can be done cleaner with 2 versions, but then...
            // 2 sets of bugs and slightly different behavior will creep in.
            //
            var sysAndDep = new SysAndDep <T> [items.Count];

            for (int i = 0; i < items.Count; ++i)
            {
                var sys = items[i];

                sysAndDep[i] = new SysAndDep <T>
                {
                    item         = sys,
                    type         = getType(sys),
                    updateBefore = new List <Type>(),
                    nAfter       = 0,
                };
            }

            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                var systemType = sysAndDep[i].type;

                var before = TypeManager.GetSystemAttributes(systemType, typeof(UpdateBeforeAttribute));
                var after  = TypeManager.GetSystemAttributes(systemType, typeof(UpdateAfterAttribute));
                foreach (var attr in before)
                {
                    var dep = attr as UpdateBeforeAttribute;
                    if (!typeof(ComponentSystemBase).IsAssignableFrom(dep.SystemType))
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateBefore] attribute on {systemType} because {dep.SystemType} is not a subclass of {nameof(ComponentSystemBase)}.\n"
                            + $"Set the target parameter of [UpdateBefore] to a system class in the same {nameof(ComponentSystemGroup)} as {systemType}.");
#else
                        Debug.LogWarning($"WARNING: invalid [UpdateBefore] attribute:");
                        Debug.LogWarning(TypeManager.GetSystemName(dep.SystemType));
                        Debug.LogWarning(" is not derived from ComponentSystemBase. Set the target parameter of [UpdateBefore] to a system class in the same ComponentSystemGroup.");
#endif
                        continue;
                    }

                    if (dep.SystemType == systemType)
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateBefore] attribute on {systemType} because a system cannot be updated before itself.\n"
                            + $"Set the target parameter of [UpdateBefore] to a different system class in the same {nameof(ComponentSystemGroup)} as {systemType}.");
#else
                        Debug.LogWarning($"WARNING: invalid [UpdateBefore] attribute:");
                        Debug.LogWarning(TypeManager.GetSystemName(systemType));
                        Debug.LogWarning("  depends on itself. Set the target parameter of [UpdateBefore] to a system class in the same ComponentSystemGroup.");
#endif
                        continue;
                    }

                    if (parentType == typeof(InitializationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginInitializationEntityCommandBufferSystem))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateBefore] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be first.");
#else
                            throw new ArgumentException($"Invalid [UpdateBefore] BeginInitializationEntityCommandBufferSystem, because that system is already restricted to be first.");
#endif
                        }

                        if (dep.SystemType == typeof(EndInitializationEntityCommandBufferSystem))
                        {
                            WarningForBeforeCheck(systemType, dep.SystemType);
                            continue;
                        }
                    }

                    if (parentType == typeof(SimulationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginSimulationEntityCommandBufferSystem))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateBefore] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be first.");
#else
                            throw new ArgumentException($"Invalid [UpdateBefore] BeginSimulationEntityCommandBufferSystem, because that system is already restricted to be first.");
#endif
                        }

                        if (dep.SystemType == typeof(LateSimulationSystemGroup))
                        {
                            WarningForBeforeCheck(systemType, dep.SystemType);
                            continue;
                        }

                        if (dep.SystemType == typeof(EndSimulationEntityCommandBufferSystem))
                        {
                            WarningForBeforeCheck(systemType, dep.SystemType);
                            continue;
                        }
                    }

                    if (parentType == typeof(PresentationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginPresentationEntityCommandBufferSystem))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateBefore] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be first.");
#else
                            throw new ArgumentException($"Invalid [UpdateBefore] BeginPreesntationEntityCommandBufferSystem, because that system is already restricted to be first.");
#endif
                        }
                    }

                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateBefore] attribute on {systemType} because {dep.SystemType} belongs to a different {nameof(ComponentSystemGroup)}.\n"
                            + $"This attribute can only order systems that are children of the same {nameof(ComponentSystemGroup)}.\n"
                            + $"Make sure that both systems are in the same parent group with [UpdateInGroup(typeof({parentType})].\n"
                            + $"You can also change the relative order of groups when appropriate, by using [UpdateBefore] and [UpdateAfter] attributes at the group level.");
#else
                        Debug.LogWarning("WARNING: invalid [UpdateBefore] dependency:");
                        Debug.LogWarning(TypeManager.GetSystemName(systemType));
                        Debug.LogWarning("  depends on a non-sibling system: ");
                        Debug.LogWarning(TypeManager.GetSystemName(dep.SystemType));
#endif
                        continue;
                    }

                    sysAndDep[i].updateBefore.Add(dep.SystemType);
                    sysAndDep[depIndex].nAfter++;
                }

                foreach (var attr in after)
                {
                    var dep = attr as UpdateAfterAttribute;
                    if (!typeof(ComponentSystemBase).IsAssignableFrom(dep.SystemType))
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateAfter] attribute on {systemType} because {dep.SystemType} is not a subclass of {nameof(ComponentSystemBase)}.\n"
                            + $"Set the target parameter of [UpdateAfter] to a system class in the same {nameof(ComponentSystemGroup)} as {systemType}.");
#else
                        Debug.LogWarning($"WARNING: invalid [UpdateAfter] attribute:");
                        Debug.LogWarning(TypeManager.GetSystemName(dep.SystemType));
                        Debug.LogWarning(" is not derived from ComponentSystemBase. Set the target parameter of [UpdateAfter] to a system class in the same ComponentSystemGroup.");
#endif
                        continue;
                    }

                    if (dep.SystemType == systemType)
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateAfter] attribute on {systemType} because a system cannot be updated after itself.\n"
                            + $"Set the target parameter of [UpdateAfter] to a different system class in the same {nameof(ComponentSystemGroup)} as {systemType}.");
#else
                        Debug.LogWarning($"WARNING: invalid [UpdateAfter] attribute:");
                        Debug.LogWarning(TypeManager.GetSystemName(systemType));
                        Debug.LogWarning("  depends on itself. Set the target parameter of [UpdateAfter] to a system class in the same ComponentSystemGroup.");
#endif
                        continue;
                    }

                    if (parentType == typeof(InitializationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginInitializationEntityCommandBufferSystem))
                        {
                            WarningForAfterCheck(systemType, dep.SystemType);
                            continue;
                        }

                        if (dep.SystemType == typeof(EndInitializationEntityCommandBufferSystem))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateAfter] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be last.");
#else
                            throw new ArgumentException($"Invalid [UpdateAfter] EndInitializationEntityCommandBufferSystem, because that system is already restricted to be last.");
#endif
                        }
                    }

                    if (parentType == typeof(SimulationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginSimulationEntityCommandBufferSystem))
                        {
                            WarningForAfterCheck(systemType, dep.SystemType);
                            continue;
                        }

                        if (dep.SystemType == typeof(LateSimulationSystemGroup))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateAfter] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be last.");
#else
                            throw new ArgumentException($"Invalid [UpdateAfter] EndLateSimulationEntityCommandBufferSystem, because that system is already restricted to be last.");
#endif
                        }

                        if (dep.SystemType == typeof(EndSimulationEntityCommandBufferSystem))
                        {
#if !NET_DOTS
                            throw new ArgumentException(
                                      $"Invalid [UpdateAfter] {dep.SystemType} attribute on {systemType}, because that system is already restricted to be last.");
#else
                            throw new ArgumentException($"Invalid [UpdateAfter] EndSimulationEntityCommandBufferSystem, because that system is already restricted to be last.");
#endif
                        }
                    }

                    if (parentType == typeof(PresentationSystemGroup))
                    {
                        if (dep.SystemType == typeof(BeginPresentationEntityCommandBufferSystem))
                        {
                            WarningForAfterCheck(systemType, dep.SystemType);
                            continue;
                        }
                    }

                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
#if !NET_DOTS
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateAfter] attribute on {systemType} because {dep.SystemType} belongs to a different {nameof(ComponentSystemGroup)}.\n"
                            + $"This attribute can only order systems that are children of the same {nameof(ComponentSystemGroup)}.\n"
                            + $"Make sure that both systems are in the same parent group with [UpdateInGroup(typeof({parentType})].\n"
                            + $"You can also change the relative order of groups when appropriate, by using [UpdateBefore] and [UpdateAfter] attributes at the group level.");
#else
                        Debug.LogWarning("WARNING: invalid [UpdateAfter] dependency:");
                        Debug.LogWarning(TypeManager.GetSystemName(systemType));
                        Debug.LogWarning("  depends on a non-sibling system: ");
                        Debug.LogWarning(TypeManager.GetSystemName(dep.SystemType));
#endif
                        continue;
                    }

                    sysAndDep[depIndex].updateBefore.Add(systemType);
                    sysAndDep[i].nAfter++;
                }
            }

            // Clear the systems list and rebuild it in sorted order from the lookup table
            var readySystems = new Heap <TypeHeapElement>(items.Count);
            items.Clear();
            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].nAfter == 0)
                {
                    readySystems.Insert(new TypeHeapElement(i, sysAndDep[i].type));
                }
            }

            while (!readySystems.Empty)
            {
                var sysIndex = readySystems.Extract().unsortedIndex;
                var sd       = sysAndDep[sysIndex];

                sysAndDep[sysIndex] = new SysAndDep <T>(); // "Remove()"
                items.Add(sd.item);
                foreach (var beforeType in sd.updateBefore)
                {
                    int beforeIndex = LookupSysAndDep(beforeType, sysAndDep);
                    if (beforeIndex < 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), beforeIndex < 0");
                    }
                    if (sysAndDep[beforeIndex].nAfter <= 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), nAfter <= 0");
                    }

                    sysAndDep[beforeIndex].nAfter--;
                    if (sysAndDep[beforeIndex].nAfter == 0)
                    {
                        readySystems.Insert(new TypeHeapElement(beforeIndex, sysAndDep[beforeIndex].type));
                    }
                }
            }

            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].item != null)
                {
                    // Since no System in the circular dependency would have ever been added
                    // to the heap, we should have values for everything in sysAndDep. Check,
                    // just in case.
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var visitedSystems = new List <Type>();
                    var startIndex     = i;
                    var currentIndex   = i;
                    while (true)
                    {
                        if (sysAndDep[currentIndex].item != null)
                        {
                            visitedSystems.Add(sysAndDep[currentIndex].type);
                        }

                        currentIndex = LookupSysAndDep(sysAndDep[currentIndex].updateBefore[0], sysAndDep);
                        if (currentIndex < 0 || currentIndex == startIndex || sysAndDep[currentIndex].item == null)
                        {
                            throw new CircularSystemDependencyException(visitedSystems);
                        }
                    }
#else
                    sysAndDep[i] = new SysAndDep <T>();
#endif
                }
            }
        }
Ejemplo n.º 2
0
        public virtual void SortSystemUpdateList()
        {
            if (!m_systemSortDirty)
            {
                return;
            }
            m_systemSortDirty = false;
#if !NET_DOTS
            lookupDictionary = null;
#endif
            // Populate dictionary mapping systemType to system-and-before/after-types.
            // This is clunky - it is easier to understand, and cleaner code, to
            // just use a Dictionary<Type, SysAndDep>. However, Tiny doesn't currently have
            // the ability to use Type as a key to a NativeHash, so we're stuck until that gets addressed.
            //
            // Likewise, this is important shared code. It can be done cleaner with 2 versions, but then...
            // 2 sets of bugs and slightly different behavior will creep in.
            //
            var sysAndDep = new SysAndDep[m_systemsToUpdate.Count];

            for (int i = 0; i < m_systemsToUpdate.Count; ++i)
            {
                var sys = m_systemsToUpdate[i];
                if (TypeManager.IsSystemAGroup(sys.GetType()))
                {
                    (sys as ComponentSystemGroup).SortSystemUpdateList();
                }
                sysAndDep[i] = new SysAndDep
                {
                    system       = sys,
                    updateBefore = new List <Type>(),
                    nAfter       = 0,
                };
            }
            for (int i = 0; i < m_systemsToUpdate.Count; ++i)
            {
                var sys    = m_systemsToUpdate[i];
                var before = TypeManager.GetSystemAttributes(sys.GetType(), typeof(UpdateBeforeAttribute));
                var after  = TypeManager.GetSystemAttributes(sys.GetType(), typeof(UpdateAfterAttribute));
                foreach (var attr in before)
                {
                    var dep      = attr as UpdateBeforeAttribute;
                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
#if !NET_DOTS
                        Debug.LogWarning("Ignoring invalid [UpdateBefore] dependency for " + sys.GetType() + ": " + dep.SystemType + " must be a member of the same ComponentSystemGroup.");
#else
                        Debug.LogWarning("WARNING: invalid [UpdateBefore] dependency:");
                        Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
                        Debug.LogWarning("  depends on a non-sibling or non-ComponentSystem.");
#endif
                        continue;
                    }

                    sysAndDep[i].updateBefore.Add(dep.SystemType);
                    sysAndDep[depIndex].nAfter++;
                }
                foreach (var attr in after)
                {
                    var dep      = attr as UpdateAfterAttribute;
                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
#if !NET_DOTS
                        Debug.LogWarning("Ignoring invalid [UpdateAfter] dependency for " + sys.GetType() + ": " + dep.SystemType + " must be a member of the same ComponentSystemGroup.");
#else
                        Debug.LogWarning("WARNING: invalid [UpdateAfter] dependency:");
                        Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
                        Debug.LogWarning("  depends on a non-sibling or non-ComponentSystem.");
#endif
                        continue;
                    }
                    sysAndDep[depIndex].updateBefore.Add(sys.GetType());
                    sysAndDep[i].nAfter++;
                }
            }

            // Clear the systems list and rebuild it in sorted order from the lookup table
            var readySystems = new Heap <TypeHeapElement>(m_systemsToUpdate.Count);
            m_systemsToUpdate.Clear();
            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].nAfter == 0)
                {
                    readySystems.Insert(new TypeHeapElement(i, sysAndDep[i].system.GetType()));
                }
            }
            while (!readySystems.Empty)
            {
                int       sysIndex = readySystems.Extract().unsortedIndex;
                SysAndDep sd       = sysAndDep[sysIndex];
                Type      sysType  = sd.system.GetType();

                sysAndDep[sysIndex] = new SysAndDep();  // "Remove()"
                m_systemsToUpdate.Add(sd.system);
                foreach (var beforeType in sd.updateBefore)
                {
                    int beforeIndex = LookupSysAndDep(beforeType, sysAndDep);
                    if (beforeIndex < 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), beforeIndex < 0");
                    }
                    if (sysAndDep[beforeIndex].nAfter <= 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), nAfter <= 0");
                    }

                    sysAndDep[beforeIndex].nAfter--;
                    if (sysAndDep[beforeIndex].nAfter == 0)
                    {
                        readySystems.Insert(new TypeHeapElement(beforeIndex, sysAndDep[beforeIndex].system.GetType()));
                    }
                }
            }

            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].system != null)
                {
                    // Since no System in the circular dependency would have ever been added
                    // to the heap, we should have values for everything in sysAndDep. Check,
                    // just in case.
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var visitedSystems = new List <ComponentSystemBase>();
                    var startIndex     = i;
                    var currentIndex   = i;
                    while (true)
                    {
                        if (sysAndDep[currentIndex].system != null)
                        {
                            visitedSystems.Add(sysAndDep[currentIndex].system);
                        }

                        currentIndex = LookupSysAndDep(sysAndDep[currentIndex].updateBefore[0], sysAndDep);
                        if (currentIndex < 0 || currentIndex == startIndex || sysAndDep[currentIndex].system == null)
                        {
                            throw new CircularSystemDependencyException(visitedSystems);
                        }
                    }
#else
                    sysAndDep[i] = new SysAndDep();
#endif
                }
            }
        }
Ejemplo n.º 3
0
        internal static void Sort(List <SystemElement> elements, Type parentType)
        {
#if !NET_DOTS
            lookupDictionary = null;
#endif
            // Populate dictionary mapping systemType to system-and-before/after-types.
            // This is clunky - it is easier to understand, and cleaner code, to
            // just use a Dictionary<Type, SysAndDep>. However, Tiny doesn't currently have
            // the ability to use Type as a key to a NativeHash, so we're stuck until that gets addressed.
            //
            // Likewise, this is important shared code. It can be done cleaner with 2 versions, but then...
            // 2 sets of bugs and slightly different behavior will creep in.
            //
            var sysAndDep = new SysAndDep[elements.Count];

            for (int i = 0; i < elements.Count; ++i)
            {
                var elem = elements[i];

                sysAndDep[i] = new SysAndDep
                {
                    type          = elem.Type,
                    externalIndex = elem.Index,
                    updateBefore  = new List <Type>(),
                    nAfter        = 0,
                };
            }

            FindConstraints(parentType, sysAndDep);

            // Clear the systems list and rebuild it in sorted order from the lookup table
            elements.Clear();

            var readySystems = new Heap(sysAndDep.Length);
            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].nAfter == 0)
                {
                    readySystems.Insert(new TypeHeapElement(i, sysAndDep[i].type));
                }
            }

            while (!readySystems.Empty)
            {
                var sysIndex = readySystems.Extract().unsortedIndex;
                var sd       = sysAndDep[sysIndex];

                sysAndDep[sysIndex] = default; // "Remove()"
                elements.Add(new SystemElement {
                    Type = sd.type, Index = sd.externalIndex
                });
                foreach (var beforeType in sd.updateBefore)
                {
                    int beforeIndex = LookupSysAndDep(beforeType, sysAndDep);
                    if (beforeIndex < 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), beforeIndex < 0");
                    }
                    if (sysAndDep[beforeIndex].nAfter <= 0)
                    {
                        throw new Exception("Bug in SortSystemUpdateList(), nAfter <= 0");
                    }

                    sysAndDep[beforeIndex].nAfter--;
                    if (sysAndDep[beforeIndex].nAfter == 0)
                    {
                        readySystems.Insert(new TypeHeapElement(beforeIndex, sysAndDep[beforeIndex].type));
                    }
                }
            }

            for (int i = 0; i < sysAndDep.Length; ++i)
            {
                if (sysAndDep[i].type != null)
                {
                    // Since no System in the circular dependency would have ever been added
                    // to the heap, we should have values for everything in sysAndDep. Check,
                    // just in case.
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var visitedSystems = new List <Type>();
                    var startIndex     = i;
                    var currentIndex   = i;
                    while (true)
                    {
                        if (sysAndDep[currentIndex].type != null)
                        {
                            visitedSystems.Add(sysAndDep[currentIndex].type);
                        }

                        currentIndex = LookupSysAndDep(sysAndDep[currentIndex].updateBefore[0], sysAndDep);
                        if (currentIndex < 0 || currentIndex == startIndex || sysAndDep[currentIndex].type == null)
                        {
                            throw new CircularSystemDependencyException(visitedSystems);
                        }
                    }
#else
                    sysAndDep[i] = default;
#endif
                }
            }
        }