public static void CopyManagedObjects(
            ManagedComponentStore srcStore, Archetype *srcArch, int srcManagedArrayIndex, int srcChunkCapacity, int srcStartIndex,
            ManagedComponentStore dstStore, Archetype *dstArch, int dstManagedArrayIndex, int dstChunkCapacity, int dstStartIndex, int count)
        {
            var srcI = 0;
            var dstI = 0;

            while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
            {
                if (srcArch->Types[srcI] < dstArch->Types[dstI])
                {
                    ++srcI;
                }
                else if (srcArch->Types[srcI] > dstArch->Types[dstI])
                {
                    ++dstI;
                }
                else
                {
                    if (srcArch->ManagedArrayOffset[srcI] >= 0)
                    {
                        for (var i = 0; i < count; ++i)
                        {
                            var obj = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);
                            dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, obj);
                        }
                    }

                    ++srcI;
                    ++dstI;
                }
            }
        }
예제 #2
0
        public static void CopyManagedObjects(
            ManagedComponentStore srcStore, Archetype *srcArch, int srcManagedArrayIndex, int srcChunkCapacity, int srcStartIndex,
            ManagedComponentStore dstStore, Archetype *dstArch, int dstManagedArrayIndex, int dstChunkCapacity, int dstStartIndex, int count)
        {
            var srcI = 0;
            var dstI = 0;

            while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
            {
                if (srcArch->Types[srcI] < dstArch->Types[dstI])
                {
                    ++srcI;
                }
                else if (srcArch->Types[srcI] > dstArch->Types[dstI])
                {
                    ++dstI;
                }
                else
                {
                    if (srcArch->IsManaged(srcI))
                    {
                        var componentType = srcArch->Types[srcI];
                        var typeInfo      = TypeManager.GetTypeInfo(componentType.TypeIndex);
                        if (typeInfo.Category == TypeManager.TypeCategory.Class)
                        {
                            // If we are dealing with a Class/GameObject types just perform a shallow copy
                            for (var i = 0; i < count; ++i)
                            {
                                var obj = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, obj);
                            }
                        }
                        else
                        {
                            for (var i = 0; i < count; ++i)
                            {
                                var obj = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, obj);
                            }
                        }
                    }

                    ++srcI;
                    ++dstI;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// This method will handle the cloning of Hybrid Components (if any) during the batched instantiation of an Entity
        /// </summary>
        /// <param name="obj">The Hybrid Component. We don't know for sure it's a component to clone or to reference, this method is also about detecting this use case and the return value will give us the info</param>
        /// <param name="srcStore">Source Managed Store of the entity to instantiate</param>
        /// <param name="dstArch">Destination archetype of the entity to instantiate</param>
        /// <param name="dstStore">Destination Managed Store that will own the instances we create</param>
        /// <param name="dstManagedArrayIndex">Index of the Hybrid Component associated with <paramref name="obj"/></param>
        /// <param name="dstChunkCapacity">Chunk capacity</param>
        /// <param name="srcEntity">Entity to instantiate</param>
        /// <param name="dstEntities">Array containing all the entities instantiated</param>
        /// <param name="dstTypeIndex">Destination type index</param>
        /// <param name="dstBaseIndex">Destination base index</param>
        /// <param name="gameObjectInstances">An array that will contain all the cloned Game Object companion. This method will fill this array at the first call for a Hybrid Component to clone and will be used for subsequent ones</param>
        /// <returns><c>true</c> if the <paramref name="obj"/> was meant to be cloned, <c>false</c> if it is meant to be referenced</returns>
        static bool InstantiateHybridComponentDelegate(object obj, ManagedComponentStore srcStore,
                                                       Archetype *dstArch, ManagedComponentStore dstStore, int dstManagedArrayIndex, int dstChunkCapacity,
                                                       Entity srcEntity, NativeArray <Entity> dstEntities, int dstTypeIndex, int dstBaseIndex, ref object[] gameObjectInstances)
        {
            // For now, it only makes sense to support a conversion that happens in the same world
            // If whenever that changes, this assert will warn us it's not supported
            Assert.AreEqual(srcStore, dstStore, "Companion GameObject instancing assumes the src and dst EntityManager are the same, are you instancing across worlds?");

            // This method is only about cloning Hybrid Components: if it's not a component we have nothing to do
            var unityComponent = obj as UnityEngine.Component;

            if (unityComponent == null)
            {
                return(false);
            }

            // This method is only about cloning Hybrid Components: if there's no Companion Link it means there's nothing to clone
            // This can still be a valid use case, the entity might be storing references to external Hybrid Components (e.g. first stage of conversion)
            var companionLink = unityComponent.gameObject.GetComponent <CompanionLink>();

            if (companionLink == null)
            {
                return(false);
            }

            // The instantiation works in two phases:
            //  1) The first call on this method will clone the GameObject that owns the Hybrid Components for each instance we have to create and make it a Companion Game Object by attaching a CompanionLink component to it
            //  2) The first and all other calls will add the Hybrid Managed Component we cloned to the entity

            // 1) We know it's the first call if the array is null, it means we have to clone the GameObject for dstEntities.Length times and make it a Companion Game Object by adding a CompanionLink to it
            //    Cloning the Game Object will also clone its components, which is exactly what we're looking for.
            //    Note that we are relaxed with the content of the Game Object we clone: it may contains more than we need regarding the association with the Entity, but that's what we want,
            //      if the user adds Components to the Game Object that are not used by the entity: so be it, the user will still have these components in the instantiated Game Objects
            if (gameObjectInstances == null)
            {
                gameObjectInstances = new object[dstEntities.Length];

                for (int i = 0; i < dstEntities.Length; ++i)
                {
                    var instance = GameObject.Instantiate(unityComponent.gameObject);
                    instance.name = CompanionLink.GenerateCompanionName(dstEntities[i]);

                    gameObjectInstances[i] = instance;
                    instance.hideFlags    |= HideFlags.HideInHierarchy;
                }
            }

            // For each instance we create, we add the cloned Hybrid Component to the entity
            for (int i = 0; i < dstEntities.Length; i++)
            {
                var componentInInstance = ((GameObject)gameObjectInstances[i]).GetComponent(obj.GetType());
                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstTypeIndex, dstBaseIndex + i, componentInInstance);
            }

            return(true);
        }
예제 #4
0
        internal void SetComponentObject(Entity entity, ComponentType componentType, object componentObject)
        {
            EntityComponentStore->AssertEntityHasComponent(entity, componentType.TypeIndex);

            Chunk *chunk;
            int    chunkIndex;

            EntityComponentStore->GetChunk(entity, out chunk, out chunkIndex);
            ManagedComponentStore.SetManagedObject(chunk, componentType, chunkIndex, componentObject);
        }
        public static void ReplicateManagedObjects(
            ManagedComponentStore srcStore, Archetype *srcArch, int srcManagedArrayIndex, int srcChunkCapacity, int srcIndex,
            ManagedComponentStore dstStore, Archetype *dstArch, int dstManagedArrayIndex, int dstChunkCapacity, int dstBaseIndex, int count, Entity srcEntity, NativeArray <Entity> dstEntities)
        {
            object[] companionGameObjectInstances = null;

            var srcI = 0;
            var dstI = 0;

            while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
            {
                if (srcArch->Types[srcI] < dstArch->Types[dstI])
                {
                    ++srcI;
                }
                else if (srcArch->Types[srcI] > dstArch->Types[dstI])
                {
                    ++dstI;
                }
                else
                {
                    if (srcArch->IsManaged(srcI))
                    {
                        var componentType = srcArch->Types[srcI];
                        var typeInfo      = TypeManager.GetTypeInfo(componentType.TypeIndex);
                        var obj           = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcIndex);

                        if (typeInfo.Category == TypeManager.TypeCategory.Class)
                        {
                            // If we're dealing with a class based type, we will defer the execution to InstantiateHybridComponent (if dependency injection was made), this method will
                            // - Determine if the object should be cloned (true is returned) or referenced (false is returned)
                            // - Clone the GameObject and its components (as many times as we have in 'count'), and make it a Companion Game Object by adding a CompanionLink component to it
                            // - Add the Cloned Hybrid Component to the instantiated entities (again 'count' times)
                            if (InstantiateHybridComponent == null || !InstantiateHybridComponent(obj, srcStore, dstArch, dstStore, dstManagedArrayIndex, dstChunkCapacity, srcEntity, dstEntities, dstI, dstBaseIndex, ref companionGameObjectInstances))
                            {
                                // We end up here if we have to reference the object and not cloning it
                                for (var i = 0; i < count; ++i)
                                {
                                    dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstBaseIndex + i, obj);
                                }
                            }
                        }
                        else
                        {
#if NET_DOTS
                            for (var i = 0; i < count; ++i)
                            {
                                // Until DOTS Runtime supports Properties just perform a simple shallow copy
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstBaseIndex + i, obj);
                            }
#else
                            if (obj == null)
                            {
                                // If we are dealing with a Class/GameObject types just perform a shallow copy
                                for (var i = 0; i < count; ++i)
                                {
                                    dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstBaseIndex + i, obj);
                                }
                            }
                            else
                            {
                                // Unless we want to enforce managed components to implement an IDeepClonable interface
                                // we instead generate a binary stream of an object and then use that to instantiate our new deep copy
                                var type   = TypeManager.GetType(componentType.TypeIndex);
                                var buffer = new UnsafeAppendBuffer(16, 16, Allocator.Temp);
                                var writer = new PropertiesBinaryWriter(&buffer);
                                BoxedProperties.WriteBoxedType(obj, writer);

                                for (var i = 0; i < count; ++i)
                                {
                                    var    readBuffer = buffer.AsReader();
                                    var    reader     = new PropertiesBinaryReader(&readBuffer, writer.GetObjectTable());
                                    object newObj     = BoxedProperties.ReadBoxedClass(type, reader);

                                    dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstBaseIndex + i, newObj);
                                }
                                buffer.Dispose();
                            }
#endif
                        }
                    }

                    ++srcI;
                    ++dstI;
                }
            }
        }
        public static void CopyManagedObjects(
            ManagedComponentStore srcStore, Archetype *srcArch, int srcManagedArrayIndex, int srcChunkCapacity, int srcStartIndex,
            ManagedComponentStore dstStore, Archetype *dstArch, int dstManagedArrayIndex, int dstChunkCapacity, int dstStartIndex, int count)
        {
            var srcI = 0;
            var dstI = 0;

            while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
            {
                if (srcArch->Types[srcI] < dstArch->Types[dstI])
                {
                    ++srcI;
                }
                else if (srcArch->Types[srcI] > dstArch->Types[dstI])
                {
                    ++dstI;
                }
                else
                {
                    if (srcArch->IsManaged(srcI))
                    {
                        var componentType = srcArch->Types[srcI];
                        var typeInfo      = TypeManager.GetTypeInfo(componentType.TypeIndex);
                        if (typeInfo.Category == TypeManager.TypeCategory.Class)
                        {
                            // If we are dealing with a Class/GameObject types just perform a shallow copy
                            for (var i = 0; i < count; ++i)
                            {
                                var obj = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, obj);
                            }
                        }
                        else
                        {
#if NET_DOTS
                            for (var i = 0; i < count; ++i)
                            {
                                var obj = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);
                                // Until DOTS Runtime supports Properties just perform a simple shallow copy
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, obj);
                            }
#else
                            var buffer = new UnsafeAppendBuffer(16, 16, Allocator.Temp);
                            for (var i = 0; i < count; ++i)
                            {
                                object newObj = null;
                                var    obj    = srcStore.GetManagedObject(srcArch, srcManagedArrayIndex, srcChunkCapacity, srcI, srcStartIndex + i);

                                if (obj != null)
                                {
                                    // Unless we want to enforce managed components to implement an IDeepClonable interface
                                    // we instead generate a binary stream of an object and then use that to instantiate our new deep copy
                                    var writer = new PropertiesBinaryWriter(&buffer);
                                    BoxedProperties.WriteBoxedType(obj, writer);

                                    var readBuffer = buffer.AsReader();
                                    var reader     = new PropertiesBinaryReader(&readBuffer, writer.GetObjectTable());
                                    var type       = TypeManager.GetType(componentType.TypeIndex);
                                    newObj = BoxedProperties.ReadBoxedClass(type, reader);

                                    buffer.Reset();
                                }
                                dstStore.SetManagedObject(dstArch, dstManagedArrayIndex, dstChunkCapacity, dstI, dstStartIndex + i, newObj);
                            }
                            buffer.Dispose();
#endif
                        }
                    }

                    ++srcI;
                    ++dstI;
                }
            }
        }