Example #1
0
    unsafe public void ReadWriteBoxedWithStringArrayWithOneElement()
    {
        var srcData = new ComponentWithStringArray()
        {
            StringArray = new string[] { "One" }
        };

        // Write to stream
        var buffer = new UnsafeAppendBuffer(0, 16, Allocator.Persistent);
        var writer = new PropertiesBinaryWriter(&buffer);

        var boxedSrcData = (object)srcData;

        BoxedProperties.WriteBoxedType(boxedSrcData, writer);

        var objectTable = writer.GetObjectTable();

        // Read from stream
        var readStream = writer.Buffer.AsReader();
        var reader     = new PropertiesBinaryReader(&readStream, objectTable);

        var boxedRead = BoxedProperties.ReadBoxedClass(typeof(ComponentWithStringArray), reader);

        // Check same
        ComponentWithStringArray.AreEqual(srcData, (ComponentWithStringArray)boxedRead);

        buffer.Dispose();
    }
Example #2
0
    unsafe public void ReadWriteBoxed()
    {
        var srcData = ConfigureStruct();

        // Write to stream
        var buffer = new UnsafeAppendBuffer(0, 16, Allocator.Persistent);
        var writer = new PropertiesBinaryWriter(&buffer);

        var boxedSrcData = (object)srcData;

        BoxedProperties.WriteBoxedType(boxedSrcData, writer);

        var objectTable = writer.GetObjectTable();

        // Read from stream
        var readStream = writer.Buffer.AsReader();
        var reader     = new PropertiesBinaryReader(&readStream, objectTable);

        var boxedRead = BoxedProperties.ReadBoxedStruct(typeof(TestStruct), reader);

        // Check same
        TestStruct.AreEqual(srcData, (TestStruct)boxedRead);

        buffer.Dispose();
    }
Example #3
0
        static object CloneManagedComponent(object obj)
        {
            if (obj == null)
            {
                return(null);
            }
            else
            {
#if !NET_DOTS
                var type   = obj.GetType();
                var buffer = new UnsafeAppendBuffer(16, 16, Allocator.Temp);
                var writer = new PropertiesBinaryWriter(&buffer);
                BoxedProperties.WriteBoxedType(obj, writer);

                var    readBuffer = buffer.AsReader();
                var    r2         = new PropertiesBinaryReader(&readBuffer, writer.GetObjectTable());
                object newObj     = BoxedProperties.ReadBoxedClass(type, r2);
                buffer.Dispose();
                return(newObj);
#else
                // Until DOTS Runtime supports Properties just reuse the same instance
                return(obj);
#endif
            }
        }
        public static EntityChangeSet Deserialize(UnsafeAppendBuffer.Reader *bufferReader, NativeArray <RuntimeGlobalObjectId> globalObjectIDs, GlobalAssetObjectResolver resolver)
        {
            bufferReader->ReadNext <ComponentTypeHash>(out var typeHashes, Allocator.Persistent);

            for (int i = 0; i != typeHashes.Length; i++)
            {
                var stableTypeHash = typeHashes[i].StableTypeHash;
                var typeIndex      = TypeManager.GetTypeIndexFromStableTypeHash(stableTypeHash);
                if (typeIndex == -1)
                {
                    typeHashes.Dispose();
                    throw new ArgumentException("The LiveLink Patch Type Layout doesn't match the Data Layout of the Components. Please Rebuild the Player.");
                }
            }

            var createdEntityCount   = bufferReader->ReadNext <int>();
            var destroyedEntityCount = bufferReader->ReadNext <int>();

            bufferReader->ReadNext <EntityGuid>(out var entities, Allocator.Persistent);
            bufferReader->ReadNext <NativeString64>(out var names, Allocator.Persistent);
            bufferReader->ReadNext <PackedComponent>(out var addComponents, Allocator.Persistent);
            bufferReader->ReadNext <PackedComponent>(out var removeComponents, Allocator.Persistent);
            bufferReader->ReadNext <PackedComponentDataChange>(out var setComponents, Allocator.Persistent);
            bufferReader->ReadNext <byte>(out var componentData, Allocator.Persistent);
            bufferReader->ReadNext <EntityReferenceChange>(out var entityReferenceChanges, Allocator.Persistent);
            bufferReader->ReadNext <BlobAssetReferenceChange>(out var blobAssetReferenceChanges, Allocator.Persistent);
            bufferReader->ReadNext <LinkedEntityGroupChange>(out var linkedEntityGroupAdditions, Allocator.Persistent);
            bufferReader->ReadNext <LinkedEntityGroupChange>(out var linkedEntityGroupRemovals, Allocator.Persistent);
            bufferReader->ReadNext <BlobAssetChange>(out var createdBlobAssets, Allocator.Persistent);
            bufferReader->ReadNext <ulong>(out var destroyedBlobAssets, Allocator.Persistent);
            bufferReader->ReadNext <byte>(out var blobAssetData, Allocator.Persistent);
            bufferReader->ReadNext <PackedComponent>(out var setSharedComponentPackedComponents, Allocator.Persistent);


            var resolvedObjects = new UnityEngine.Object[globalObjectIDs.Length];

            resolver.ResolveObjects(globalObjectIDs, resolvedObjects);
            var reader = new PropertiesBinaryReader(bufferReader, resolvedObjects);
            var setSharedComponents = new PackedSharedComponentDataChange[setSharedComponentPackedComponents.Length];

            for (int i = 0; i < setSharedComponentPackedComponents.Length; i++)
            {
                object componentValue;
                if (bufferReader->ReadNext <int>() == 1)
                {
                    var packedTypeIndex = setSharedComponentPackedComponents[i].PackedTypeIndex;
                    var stableTypeHash  = typeHashes[packedTypeIndex].StableTypeHash;
                    var typeIndex       = TypeManager.GetTypeIndexFromStableTypeHash(stableTypeHash);
                    var type            = TypeManager.GetType(typeIndex);
                    componentValue = BoxedProperties.ReadBoxedStruct(type, reader);
                }
Example #5
0
        //@TODO: Encode type in hashcode...

#if !NET_DOTS
        public static unsafe int ManagedGetHashCode(object lhs, TypeInfo typeInfo)
        {
            var fn = (TypeInfo.ManagedGetHashCodeDelegate)typeInfo.GetHashFn;

            if (fn != null)
            {
                return(fn(lhs));
            }

            int hash = 0;

            using (var buffer = new UnsafeAppendBuffer(16, 16, Allocator.Temp))
            {
                var writer = new PropertiesBinaryWriter(&buffer);
                BoxedProperties.WriteBoxedType(lhs, writer);

                var remainder   = buffer.Length & (sizeof(int) - 1);
                var alignedSize = buffer.Length - remainder;
                var bufferPtrAtEndOfAlignedData = buffer.Ptr + alignedSize;
                for (int i = 0; i < alignedSize; i += sizeof(int))
                {
                    hash *= FNV_32_PRIME;
                    hash ^= *(int *)(buffer.Ptr + i);
                }
                for (var i = 0; i < remainder; i++)
                {
                    hash *= FNV_32_PRIME;
                    hash ^= *(byte *)(bufferPtrAtEndOfAlignedData + i);
                }
                foreach (var obj in writer.GetObjectTable())
                {
                    hash *= FNV_32_PRIME;
                    hash ^= obj.GetHashCode();
                }
            }

            return(hash);
        }
Example #6
0
        public static unsafe bool ManagedEquals(object lhs, object rhs, TypeInfo typeInfo)
        {
            var fn = (TypeInfo.ManagedCompareEqualDelegate)typeInfo.EqualFn;

            if (fn != null)
            {
                return(fn(lhs, rhs));
            }

            using (var bufferLHS = new UnsafeAppendBuffer(512, 16, Allocator.Temp))
                using (var bufferRHS = new UnsafeAppendBuffer(512, 16, Allocator.Temp))
                {
                    var writerLHS = new PropertiesBinaryWriter(&bufferLHS);
                    BoxedProperties.WriteBoxedType(lhs, writerLHS);
                    var writerRHS = new PropertiesBinaryWriter(&bufferRHS);
                    BoxedProperties.WriteBoxedType(rhs, writerRHS);

                    if (UnsafeUtility.MemCmp(bufferLHS.Ptr, bufferRHS.Ptr, bufferLHS.Length) != 0)
                    {
                        return(false);
                    }

                    var objectTableLHS = writerLHS.GetObjectTable();
                    var objectTableRHS = writerRHS.GetObjectTable();
                    Assertions.Assert.AreEqual(objectTableLHS.Length, objectTableRHS.Length);

                    for (int i = 0; i < objectTableLHS.Length; ++i)
                    {
                        if (!objectTableLHS[i].Equals(objectTableRHS[i]))
                        {
                            return(false);
                        }
                    }
                }

            return(true);
        }
        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;
                }
            }
        }