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(); }
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(); }
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); }
//@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); }
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; } } }