// ----------------------------------------------------------------------------------------------------------
        // PUBLIC
        // ----------------------------------------------------------------------------------------------------------

        public static Archetype *GetOrCreateArchetype(ComponentTypeInArchetype *inTypesSorted, int count,
                                                      EntityComponentStore *entityComponentStore)
        {
            var srcArchetype = entityComponentStore->GetExistingArchetype(inTypesSorted, count);

            if (srcArchetype != null)
            {
                return(srcArchetype);
            }

            srcArchetype = entityComponentStore->CreateArchetype(inTypesSorted, count);
            var types = stackalloc ComponentTypeInArchetype[count + 1];

            // Setup Instantiable archetype
            {
                UnsafeUtility.MemCpy(types, inTypesSorted, sizeof(ComponentTypeInArchetype) * count);

                var hasCleanup       = false;
                var removedTypes     = 0;
                var prefabTypeIndex  = TypeManager.GetTypeIndex <Prefab>();
                var cleanupTypeIndex = TypeManager.GetTypeIndex <CleanupEntity>();
                for (var t = 0; t < srcArchetype->TypesCount; ++t)
                {
                    var type = srcArchetype->Types[t];

                    hasCleanup |= type.TypeIndex == cleanupTypeIndex;

                    var skip = type.IsSystemStateComponent || type.TypeIndex == prefabTypeIndex;
                    if (skip)
                    {
                        ++removedTypes;
                    }
                    else
                    {
                        types[t - removedTypes] = srcArchetype->Types[t];
                    }
                }

                // Entity has already been destroyed, so it shouldn't be instantiated anymore
                if (hasCleanup)
                {
                    srcArchetype->InstantiableArchetype = null;
                }
                else if (removedTypes > 0)
                {
                    var instantiableArchetype = GetOrCreateArchetype(types, count - removedTypes, entityComponentStore);

                    srcArchetype->InstantiableArchetype = instantiableArchetype;
                    Assert.IsTrue(instantiableArchetype->InstantiableArchetype == instantiableArchetype);
                    Assert.IsTrue(instantiableArchetype->SystemStateResidueArchetype == null);
                }
                else
                {
                    srcArchetype->InstantiableArchetype = srcArchetype;
                }
            }


            // Setup System state cleanup archetype
            if (srcArchetype->SystemStateCleanupNeeded)
            {
                var  cleanupEntityType = new ComponentTypeInArchetype(ComponentType.ReadWrite <CleanupEntity>());
                bool cleanupAdded      = false;

                types[0] = inTypesSorted[0];
                var newTypeCount = 1;

                for (var t = 1; t < srcArchetype->TypesCount; ++t)
                {
                    var type = srcArchetype->Types[t];

                    if (type.IsSystemStateComponent)
                    {
                        if (!cleanupAdded && (cleanupEntityType < srcArchetype->Types[t]))
                        {
                            types[newTypeCount++] = cleanupEntityType;
                            cleanupAdded          = true;
                        }

                        types[newTypeCount++] = srcArchetype->Types[t];
                    }
                }

                if (!cleanupAdded)
                {
                    types[newTypeCount++] = cleanupEntityType;
                }

                var systemStateResidueArchetype = GetOrCreateArchetype(types, newTypeCount, entityComponentStore);
                srcArchetype->SystemStateResidueArchetype = systemStateResidueArchetype;

                Assert.IsTrue(systemStateResidueArchetype->SystemStateResidueArchetype == systemStateResidueArchetype);
                Assert.IsTrue(systemStateResidueArchetype->InstantiableArchetype == null);
            }

            // Setup meta chunk archetype
            if (count > 1)
            {
                types[0] = new ComponentTypeInArchetype(typeof(Entity));
                int metaArchetypeTypeCount = 1;
                for (int i = 1; i < count; ++i)
                {
                    var           t = inTypesSorted[i];
                    ComponentType typeToInsert;
                    if (inTypesSorted[i].IsChunkComponent)
                    {
                        typeToInsert = new ComponentType
                        {
                            TypeIndex = TypeManager.ChunkComponentToNormalTypeIndex(t.TypeIndex)
                        };
                        SortingUtilities.InsertSorted(types, metaArchetypeTypeCount++, typeToInsert);
                    }
                }

                if (metaArchetypeTypeCount > 1)
                {
                    SortingUtilities.InsertSorted(types, metaArchetypeTypeCount++, new ComponentType(typeof(ChunkHeader)));
                    srcArchetype->MetaChunkArchetype = GetOrCreateArchetype(types, metaArchetypeTypeCount, entityComponentStore);
                }
            }

            return(srcArchetype);
        }