/// <summary>
        /// Call this to add a System that was manually constructed; normally these
        /// Systems are marked with [DisableAutoCreation]
        /// </summary>
        public static void AddSystem(World world, ComponentSystemBase[] systems)
        {
            foreach (ComponentSystemBase system in systems)
            {
                if (world.GetExistingSystem(system.GetType()) != null)
                {
                    throw new ArgumentException("AddAndSortSystem: Error to add a duplicate system.");
                }

                world.AddSystem(system);

                var groups = TypeManager.GetSystemAttributes(system.GetType(), typeof(UpdateInGroupAttribute));
                if (groups.Length == 0)
                {
                    var simulationSystemGroup = world.GetExistingSystem <SimulationSystemGroup>();
                    simulationSystemGroup.AddSystemToUpdateList(system);
                }

                for (int g = 0; g < groups.Length; ++g)
                {
                    var groupType   = groups[g] as UpdateInGroupAttribute;
                    var groupSystem = world.GetExistingSystem(groupType.GroupType) as ComponentSystemGroup;
                    if (groupSystem == null)
                    {
                        throw new Exception("AddAndSortSystem failed to find existing SystemGroup.");
                    }

                    groupSystem.AddSystemToUpdateList(system);
                }
            }
        }
        internal virtual void OnBeforeCreateInternal(World world)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            m_SystemID = World.AllocateSystemID();
#endif
            m_World             = world;
            m_EntityManager     = world.EntityManager;
            m_DependencyManager = m_EntityManager.DependencyManager;

            m_JobDependencyForReadingSystems = new UnsafeIntList(0, Allocator.Persistent);
            m_JobDependencyForWritingSystems = new UnsafeIntList(0, Allocator.Persistent);

            m_EntityQueries = new EntityQuery[0];
#if !NET_DOTS
            m_AlwaysUpdateSystem = GetType().GetCustomAttributes(typeof(AlwaysUpdateSystemAttribute), true).Length != 0;
#else
            m_AlwaysUpdateSystem = false;
            var attrs = TypeManager.GetSystemAttributes(GetType());
            foreach (var attr in attrs)
            {
                if (attr.GetType() == typeof(AlwaysUpdateSystemAttribute))
                {
                    m_AlwaysUpdateSystem = true;
                }
            }
#endif
        }
        internal static void FindConstraints(Type parentType, SystemElement[] sysElems)
        {
            lookupDictionary = null;

            for (int i = 0; i < sysElems.Length; ++i)
            {
                var systemType = sysElems[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 (CheckBeforeConstraints(parentType, dep, systemType))
                    {
                        continue;
                    }

                    int depIndex = LookupSystemElement(dep.SystemType, sysElems);
                    if (depIndex < 0)
                    {
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateBefore] attribute on {SysName(systemType)} targeting {SysName(dep.SystemType)}.\n"
                            + $"This attribute can only order systems that are members of the same {nameof(ComponentSystemGroup)} instance.\n"
                            + $"Make sure that both systems are in the same system group with [UpdateInGroup(typeof({SysName(parentType)})],\n"
                            + $"or by manually adding both systems to the same group's update list.");
                        continue;
                    }

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

                foreach (var attr in after)
                {
                    var dep = attr as UpdateAfterAttribute;

                    if (CheckAfterConstraints(parentType, dep, systemType))
                    {
                        continue;
                    }

                    int depIndex = LookupSystemElement(dep.SystemType, sysElems);
                    if (depIndex < 0)
                    {
                        Debug.LogWarning(
                            $"Ignoring invalid [UpdateAfter] attribute on {SysName(systemType)} targeting {SysName(dep.SystemType)}.\n"
                            + $"This attribute can only order systems that are members of the same {nameof(ComponentSystemGroup)} instance.\n"
                            + $"Make sure that both systems are in the same system group with [UpdateInGroup(typeof({SysName(parentType)})],\n"
                            + $"or by manually adding both systems to the same group's update list.");
                        continue;
                    }

                    sysElems[depIndex].updateBefore.Add(systemType);
                    sysElems[i].nAfter++;
                }
            }
        }
        /// <summary>
        /// Initialize the ComponentSystems. See <see cref="Initialize"/> for use.
        /// </summary>
        public static void InitializeSystems(World world)
        {
            var allSystemTypes = TypeManager.GetSystems();
            var allSystemNames = TypeManager.SystemNames;

            if (allSystemTypes.Length == 0)
            {
                throw new InvalidOperationException("DefaultTinyWorldInitialization: No Systems found.");
            }

            // Create top level presentation system and simulation systems.
            InitializationSystemGroup initializationSystemGroup = new InitializationSystemGroup();

            world.AddSystem(initializationSystemGroup);

            SimulationSystemGroup simulationSystemGroup = new SimulationSystemGroup();

            world.AddSystem(simulationSystemGroup);

            PresentationSystemGroup presentationSystemGroup = new PresentationSystemGroup();

            world.AddSystem(presentationSystemGroup);

            // Create the working set of systems.
#if WRITE_LOG
            Console.WriteLine("--- Adding systems:");
#endif

            for (int i = 0; i < allSystemTypes.Length; i++)
            {
                if (TypeManager.GetSystemAttributes(allSystemTypes[i], typeof(DisableAutoCreationAttribute)).Length > 0)
                {
                    continue;
                }
                if (allSystemTypes[i] == initializationSystemGroup.GetType() ||
                    allSystemTypes[i] == simulationSystemGroup.GetType() ||
                    allSystemTypes[i] == presentationSystemGroup.GetType())
                {
                    continue;
                }

                // Subtle issue. If the System was created by GetOrCreateSystem at the "right" time
                // before its own initialization, then it will exist. GetExistingSystem will return a valid
                // object. BUT, that object will not have been put into a SystemGroup.
                var sys = world.GetExistingSystem(allSystemTypes[i]);
                if (sys != null)
                {
                    AddSystemToGroup(world, sys);
                    continue;
                }

#if WRITE_LOG
                Console.WriteLine(allSystemNames[i]);
#endif
                AddSystem(world, TypeManager.ConstructSystem(allSystemTypes[i]));
            }
        }
        private static void FindConstraints(Type parentType, SysAndDep[] sysAndDep)
        {
            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 (CheckBeforeConstraints(parentType, dep, systemType))
                    {
                        continue;
                    }

                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
                        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.");
                        continue;
                    }

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

                foreach (var attr in after)
                {
                    var dep = attr as UpdateAfterAttribute;

                    if (CheckAfterConstraints(parentType, dep, systemType))
                    {
                        continue;
                    }

                    int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
                    if (depIndex < 0)
                    {
                        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.");
                        continue;
                    }

                    sysAndDep[depIndex].updateBefore.Add(systemType);
                    sysAndDep[i].nAfter++;
                }
            }
        }
        public static void InitializeSystems(World world)
        {
            var allSystemTypes = TypeManager.GetSystems();
            var allSystemNames = TypeManager.SystemNames;

            if (allSystemTypes.Length == 0)
            {
                throw new InvalidOperationException("DefaultTinyWorldInitialization: No Systems found.");
            }

            // Create top level presentation system and simulation systems.
            InitializationSystemGroup initializationSystemGroup = new InitializationSystemGroup();

            world.AddSystem(initializationSystemGroup);

            SimulationSystemGroup simulationSystemGroup = new SimulationSystemGroup();

            world.AddSystem(simulationSystemGroup);

            PresentationSystemGroup presentationSystemGroup = new PresentationSystemGroup();

            world.AddSystem(presentationSystemGroup);

            // Create the working set of systems.
#if WRITE_LOG
            Console.WriteLine("--- Adding systems:");
#endif

            for (int i = 0; i < allSystemTypes.Length; i++)
            {
                if (TypeManager.GetSystemAttributes(allSystemTypes[i], typeof(DisableAutoCreationAttribute)).Length > 0)
                {
                    continue;
                }
                if (allSystemTypes[i] == initializationSystemGroup.GetType() ||
                    allSystemTypes[i] == simulationSystemGroup.GetType() ||
                    allSystemTypes[i] == presentationSystemGroup.GetType())
                {
                    continue;
                }

                if (world.GetExistingSystem(allSystemTypes[i]) != null)
                {
                    continue;
                }

#if WRITE_LOG
                Console.WriteLine(allSystemNames[i]);
#endif
                AddSystem(world, TypeManager.ConstructSystem(allSystemTypes[i]));
            }
        }
        private static void AddSystemToGroup(World world, ComponentSystemBase system)
        {
            var groups = TypeManager.GetSystemAttributes(system.GetType(), typeof(UpdateInGroupAttribute));

            if (groups.Length == 0)
            {
                var simulationSystemGroup = world.GetExistingSystem <SimulationSystemGroup>();
                simulationSystemGroup.AddSystemToUpdateList(system);
            }

            for (int g = 0; g < groups.Length; ++g)
            {
                var groupType   = groups[g] as UpdateInGroupAttribute;
                var groupSystem = world.GetExistingSystem(groupType.GroupType) as ComponentSystemGroup;
                if (groupSystem == null)
                {
                    throw new Exception("AddSystem failed to find existing SystemGroup.");
                }

                groupSystem.AddSystemToUpdateList(system);
            }
        }
Beispiel #8
0
        static void IterateAllAutoSystems(World world, Action <World, Type> Action)
        {
            InitializationSystemGroup initializationSystemGroup = world.GetExistingSystem <InitializationSystemGroup>();
            SimulationSystemGroup     simulationSystemGroup     = world.GetExistingSystem <SimulationSystemGroup>();
            PresentationSystemGroup   presentationSystemGroup   = world.GetExistingSystem <PresentationSystemGroup>();

            foreach (var systemType in TypeManager.GetSystems())
            {
                if (TypeManager.GetSystemAttributes(systemType, typeof(DisableAutoCreationAttribute)).Length > 0)
                {
                    continue;
                }
                if (systemType == initializationSystemGroup.GetType() ||
                    systemType == simulationSystemGroup.GetType() ||
                    systemType == presentationSystemGroup.GetType())
                {
                    continue;
                }

                Action(world, systemType);
            }
        }
        private static int ComputeSystemOrdering(Type sysType, Type ourType)
        {
            foreach (var uga in TypeManager.GetSystemAttributes(sysType, typeof(UpdateInGroupAttribute)))
            {
                var updateInGroupAttribute = (UpdateInGroupAttribute)uga;

                if (updateInGroupAttribute.GroupType.IsAssignableFrom(ourType))
                {
                    if (updateInGroupAttribute.OrderFirst)
                    {
                        return(0);
                    }

                    if (updateInGroupAttribute.OrderLast)
                    {
                        return(2);
                    }
                }
            }

            return(1);
        }
        private static ComponentSystemGroup FindGroup(World world, Type systemType, Attribute attr)
        {
            var uga = attr as UpdateInGroupAttribute;

            if (uga == null)
            {
                return(null);
            }

            if (!TypeManager.IsSystemAGroup(uga.GroupType))
            {
                throw new InvalidOperationException($"Invalid [UpdateInGroup] attribute for {systemType}: {uga.GroupType} must be derived from ComponentSystemGroup.");
            }
            if (uga.OrderFirst && uga.OrderLast)
            {
                throw new InvalidOperationException($"The system {systemType} can not specify both OrderFirst=true and OrderLast=true in its [UpdateInGroup] attribute.");
            }

            var groupSys = world.GetExistingSystem(uga.GroupType);

            if (groupSys == null)
            {
                // Warn against unexpected behaviour combining DisableAutoCreation and UpdateInGroup
                var parentDisableAutoCreation = TypeManager.GetSystemAttributes(uga.GroupType, typeof(DisableAutoCreationAttribute)).Length > 0;
                if (parentDisableAutoCreation)
                {
                    Debug.LogWarning($"A system {systemType} wants to execute in {uga.GroupType} but this group has [DisableAutoCreation] and {systemType} does not. The system will not be added to any group and thus not update.");
                }
                else
                {
                    Debug.LogWarning(
                        $"A system {systemType} could not be added to group {uga.GroupType}, because the group was not created. Fix these errors before continuing. The system will not be added to any group and thus not update.");
                }
            }

            return(groupSys as ComponentSystemGroup);
        }
Beispiel #11
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
                }
            }
        }
        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
                }
            }
        }
        private static void AddSystemToRootLevelSystemGroupsInternal(World world, IEnumerable <Type> systemTypesOrig, int managedTypesCountOrig)
        {
            var initializationSystemGroup = world.GetOrCreateSystem <InitializationSystemGroup>();
            var simulationSystemGroup     = world.GetOrCreateSystem <SimulationSystemGroup>();
            var presentationSystemGroup   = world.GetOrCreateSystem <PresentationSystemGroup>();

            var managedTypes   = new List <Type>();
            var unmanagedTypes = new List <Type>();

            foreach (var stype in systemTypesOrig)
            {
                if (typeof(ComponentSystemBase).IsAssignableFrom(stype))
                {
                    managedTypes.Add(stype);
                }
                else if (typeof(ISystemBase).IsAssignableFrom(stype))
                {
                    unmanagedTypes.Add(stype);
                }
                else
                {
                    throw new InvalidOperationException("Bad type");
                }
            }

            var systems = world.GetOrCreateSystemsAndLogException(managedTypes, managedTypes.Count);

            // Add systems to their groups, based on the [UpdateInGroup] attribute.
            foreach (var system in systems)
            {
                if (system == null)
                {
                    continue;
                }

                // Skip the built-in root-level system groups
                var type = system.GetType();
                if (type == typeof(InitializationSystemGroup) ||
                    type == typeof(SimulationSystemGroup) ||
                    type == typeof(PresentationSystemGroup))
                {
                    continue;
                }

                var updateInGroupAttributes = TypeManager.GetSystemAttributes(system.GetType(), typeof(UpdateInGroupAttribute));
                if (updateInGroupAttributes.Length == 0)
                {
                    simulationSystemGroup.AddSystemToUpdateList(system);
                }

                foreach (var attr in updateInGroupAttributes)
                {
                    var group = FindGroup(world, type, attr);
                    if (group != null)
                    {
                        group.AddSystemToUpdateList(system);
                    }
                }
            }

#if !UNITY_DOTSRUNTIME
            // Add unmanaged systems
            foreach (var type in unmanagedTypes)
            {
                SystemHandleUntyped sysHandle = world.Unmanaged.CreateUnmanagedSystem(world, type);

                // Add systems to their groups, based on the [UpdateInGroup] attribute.

                var updateInGroupAttributes = TypeManager.GetSystemAttributes(type, typeof(UpdateInGroupAttribute));
                if (updateInGroupAttributes.Length == 0)
                {
                    simulationSystemGroup.AddUnmanagedSystemToUpdateList(sysHandle);
                }

                foreach (var attr in updateInGroupAttributes)
                {
                    ComponentSystemGroup groupSys = FindGroup(world, type, attr);

                    if (groupSys != null)
                    {
                        groupSys.AddUnmanagedSystemToUpdateList(sysHandle);
                    }
                }
            }
#endif


            // Update player loop
            initializationSystemGroup.SortSystems();
            simulationSystemGroup.SortSystems();
            presentationSystemGroup.SortSystems();
        }
        /// <summary>
        /// Adds the collection of systems to the world by injecting them into the root level system groups
        /// (InitializationSystemGroup, SimulationSystemGroup and PresentationSystemGroup)
        /// </summary>
        public static void AddSystemsToRootLevelSystemGroups(World world, params Type[] systemTypes)
        {
            var initializationSystemGroup = world.GetOrCreateSystem <InitializationSystemGroup>();
            var simulationSystemGroup     = world.GetOrCreateSystem <SimulationSystemGroup>();
            var presentationSystemGroup   = world.GetOrCreateSystem <PresentationSystemGroup>();

            var systems = world.GetOrCreateSystemsAndLogException(systemTypes.ToArray());

            // Add systems to their groups, based on the [UpdateInGroup] attribute.
            foreach (var system in systems)
            {
                if (system == null)
                {
                    continue;
                }

                // Skip the built-in root-level system groups
                var type = system.GetType();
                if (type == typeof(InitializationSystemGroup) ||
                    type == typeof(SimulationSystemGroup) ||
                    type == typeof(PresentationSystemGroup))
                {
                    continue;
                }

                var groups = TypeManager.GetSystemAttributes(system.GetType(), typeof(UpdateInGroupAttribute));
                if (groups.Length == 0)
                {
                    simulationSystemGroup.AddSystemToUpdateList(system);
                }

                foreach (var g in groups)
                {
                    var group = g as UpdateInGroupAttribute;
                    if (group == null)
                    {
                        continue;
                    }

                    if (!TypeManager.IsSystemAGroup(group.GroupType))
                    {
                        Debug.LogError($"Invalid [UpdateInGroup] attribute for {type}: {group.GroupType} must be derived from ComponentSystemGroup.");
                        continue;
                    }

                    var groupMgr = world.GetExistingSystem(group.GroupType);
                    if (groupMgr == null)
                    {
                        // Warn against unexpected behaviour combining DisableAutoCreation and UpdateInGroup
                        var parentDisableAutoCreation = TypeManager.GetSystemAttributes(group.GroupType, typeof(DisableAutoCreationAttribute)).Length > 0;
                        if (parentDisableAutoCreation)
                        {
                            Debug.LogWarning($"A system {type} wants to execute in {group.GroupType} but this group has [DisableAutoCreation] and {type} does not. The system will not be added to any group and thus not update.");
                        }
                        else
                        {
                            Debug.LogWarning(
                                $"A system {type} could not be added to group {group.GroupType}, because the group was not created. Fix these errors before continuing. The system will not be added to any group and thus not update.");
                        }
                        continue;
                    }

                    var groupSys = groupMgr as ComponentSystemGroup;
                    if (groupSys != null)
                    {
                        groupSys.AddSystemToUpdateList(system);
                    }
                }
            }

            // Update player loop
            initializationSystemGroup.SortSystems();
            simulationSystemGroup.SortSystems();
            presentationSystemGroup.SortSystems();
        }
Beispiel #15
0
        public static void InitializeSystems(World world)
        {
            var allSystemTypes = TypeManager.GetSystems();
            var allSystemNames = TypeManager.SystemNames;

            if (allSystemTypes.Length == 0)
            {
                throw new InvalidOperationException("DefaultTinyWorldInitialization: No Systems found.");
            }

            // Create top level presentation system and simulation systems.
            InitializationSystemGroup initializationSystemGroup = new InitializationSystemGroup();

            world.AddManager(initializationSystemGroup);

            SimulationSystemGroup simulationSystemGroup = new SimulationSystemGroup();

            world.AddManager(simulationSystemGroup);

            PresentationSystemGroup presentationSystemGroup = new PresentationSystemGroup();

            world.AddManager(presentationSystemGroup);

            // Create the working set of systems.
            int nSystems = 0;

            Type[]            systemTypes = new Type[allSystemTypes.Length];
            ComponentSystem[] systems     = new ComponentSystem[allSystemTypes.Length];

#if WRITE_LOG
            Console.WriteLine("--- Adding systems:");
#endif

            for (int i = 0; i < allSystemTypes.Length; i++)
            {
                if (TypeManager.GetSystemAttributes(allSystemTypes[i], typeof(DisableAutoCreationAttribute)).Length > 0)
                {
                    continue;
                }
                if (allSystemTypes[i] == initializationSystemGroup.GetType() ||
                    allSystemTypes[i] == simulationSystemGroup.GetType() ||
                    allSystemTypes[i] == presentationSystemGroup.GetType())
                {
                    continue;
                }

                if (world.GetExistingManager(allSystemTypes[i]) != null)
                {
                    continue;
                }
#if WRITE_LOG
                Console.WriteLine(allSystemNames[i]);
#endif
                systemTypes[nSystems] = allSystemTypes[i];
                systems[nSystems]     = TypeManager.ConstructSystem(allSystemTypes[i]);
                world.AddManager(systems[nSystems]);
                nSystems++;
            }
#if WRITE_LOG
            Console.WriteLine("--- Adding systems Done.");
#endif

            for (int i = 0; i < nSystems; ++i)
            {
                var sysType = systemTypes[i];
                var system  = systems[i];

                var groups = TypeManager.GetSystemAttributes(sysType, typeof(UpdateInGroupAttribute));
                if (groups.Length == 0)
                {
                    simulationSystemGroup.AddSystemToUpdateList(system);
                }

                for (int g = 0; g < groups.Length; ++g)
                {
                    var groupType   = groups[g] as UpdateInGroupAttribute;
                    var groupSystem = world.GetExistingManager(groupType.GroupType) as ComponentSystemGroup;
                    if (groupSystem == null)
                    {
                        throw new Exception("DefaultTinyWorldInitialization failed to find existing SystemGroup.");
                    }

                    groupSystem.AddSystemToUpdateList(system);
                }
            }
        }