static void ApplyBlobAssetChanges( EntityManager entityManager, NativeArray <EntityGuid> packedEntityGuids, NativeMultiHashMap <int, Entity> packedEntities, NativeArray <ComponentType> packedTypes, NativeArray <BlobAssetChange> createdBlobAssets, NativeArray <byte> createdBlobAssetData, NativeArray <ulong> destroyedBlobAssets, NativeArray <BlobAssetReferenceChange> blobAssetReferenceChanges) { if (createdBlobAssets.Length == 0 && blobAssetReferenceChanges.Length == 0) { return; } var patcherBlobAssetSystem = entityManager.World.GetOrCreateSystem <EntityPatcherBlobAssetSystem>(); var blobAssetDataPtr = (byte *)createdBlobAssetData.GetUnsafePtr(); for (var i = 0; i < createdBlobAssets.Length; i++) { if (!patcherBlobAssetSystem.TryGetBlobAsset(createdBlobAssets[i].Hash, out _)) { patcherBlobAssetSystem.AllocateBlobAsset(blobAssetDataPtr, createdBlobAssets[i].Length, createdBlobAssets[i].Hash); } blobAssetDataPtr += createdBlobAssets[i].Length; } for (var i = 0; i < destroyedBlobAssets.Length; i++) { patcherBlobAssetSystem.ReleaseBlobAsset(destroyedBlobAssets[i]); } for (var i = 0; i < blobAssetReferenceChanges.Length; i++) { var packedComponent = blobAssetReferenceChanges[i].Component; var component = packedTypes[packedComponent.PackedTypeIndex]; var targetOffset = blobAssetReferenceChanges[i].Offset; BlobAssetReferenceData targetBlobAssetReferenceData; if (patcherBlobAssetSystem.TryGetBlobAsset(blobAssetReferenceChanges[i].Value, out var blobAssetPtr)) { targetBlobAssetReferenceData = new BlobAssetReferenceData { m_Ptr = (byte *)blobAssetPtr.Data }; } if (packedEntities.TryGetFirstValue(packedComponent.PackedEntityIndex, out var entity, out var iterator)) { do { if (!entityManager.Exists(entity)) { Debug.LogWarning($"ApplyBlobAssetReferencePatches<{component}>({packedEntityGuids[packedComponent.PackedEntityIndex]}) but entity to patch does not exist."); } else if (!entityManager.HasComponent(entity, component)) { Debug.LogWarning($"ApplyBlobAssetReferencePatches<{component}>({packedEntityGuids[packedComponent.PackedEntityIndex]}) but component in entity to patch does not exist."); } else { if (component.IsBuffer) { var pointer = (byte *)entityManager.GetBufferRawRW(entity, component.TypeIndex); UnsafeUtility.MemCpy(pointer + targetOffset, &targetBlobAssetReferenceData, sizeof(BlobAssetReferenceData)); } #if !NET_DOTS else if (component.IsManagedComponent) { var obj = entityManager.GetManagedComponentDataAsObject(entity, component); var pointer = (byte *)UnsafeUtility.PinGCObjectAndGetAddress(obj, out ulong handle); pointer += TypeManager.ObjectOffset; UnsafeUtility.MemCpy(pointer + targetOffset, &targetBlobAssetReferenceData, sizeof(BlobAssetReferenceData)); UnsafeUtility.ReleaseGCObject(handle); } #endif else { var pointer = (byte *)entityManager.GetComponentDataRawRW(entity, component.TypeIndex); UnsafeUtility.MemCpy(pointer + targetOffset, &targetBlobAssetReferenceData, sizeof(BlobAssetReferenceData)); } } }while (packedEntities.TryGetNextValue(out entity, ref iterator)); } } // Workaround to catch some special cases where the memory is never released. (e.g. reloading a scene, toggling live-link on/off). patcherBlobAssetSystem.ReleaseUnusedBlobAssets(); }
/// <summary> /// Construct a BlobAssetReference from the blob data /// </summary> /// <param name="blobData">The blob data to attach to the returned object</param> /// <returns>The created BlobAssetReference</returns> internal static BlobAssetReference <T> Create(BlobAssetReferenceData blobData) { return(new BlobAssetReference <T> { m_data = blobData }); }
static void ApplyBlobAssetChanges( EntityManager entityManager, NativeArray <EntityGuid> packedEntityGuids, NativeMultiHashMap <int, Entity> packedEntities, NativeArray <ComponentType> packedTypes, NativeArray <BlobAssetChange> createdBlobAssets, NativeArray <byte> createdBlobAssetData, NativeArray <ulong> destroyedBlobAssets, NativeArray <BlobAssetReferenceChange> blobAssetReferenceChanges) { if (createdBlobAssets.Length == 0 && blobAssetReferenceChanges.Length == 0) { return; } s_ApplyBlobAssetChangesProfilerMarker.Begin(); var managedObjectBlobAssetReferencePatches = new NativeMultiHashMap <EntityComponentPair, ManagedObjectBlobAssetReferencePatch>(blobAssetReferenceChanges.Length, Allocator.Temp); var patcherBlobAssetSystem = entityManager.World.GetOrCreateSystem <EntityPatcherBlobAssetSystem>(); var blobAssetDataPtr = (byte *)createdBlobAssetData.GetUnsafePtr(); for (var i = 0; i < createdBlobAssets.Length; i++) { if (!patcherBlobAssetSystem.TryGetBlobAsset(createdBlobAssets[i].Hash, out _)) { patcherBlobAssetSystem.AllocateBlobAsset(blobAssetDataPtr, createdBlobAssets[i].Length, createdBlobAssets[i].Hash); } blobAssetDataPtr += createdBlobAssets[i].Length; } for (var i = 0; i < destroyedBlobAssets.Length; i++) { patcherBlobAssetSystem.ReleaseBlobAsset(entityManager, destroyedBlobAssets[i]); } for (var i = 0; i < blobAssetReferenceChanges.Length; i++) { var packedComponent = blobAssetReferenceChanges[i].Component; var component = packedTypes[packedComponent.PackedTypeIndex]; var targetOffset = blobAssetReferenceChanges[i].Offset; BlobAssetReferenceData targetBlobAssetReferenceData; if (patcherBlobAssetSystem.TryGetBlobAsset(blobAssetReferenceChanges[i].Value, out var blobAssetPtr)) { targetBlobAssetReferenceData = new BlobAssetReferenceData { m_Ptr = (byte *)blobAssetPtr.Data }; } if (packedEntities.TryGetFirstValue(packedComponent.PackedEntityIndex, out var entity, out var iterator)) { do { if (!entityManager.Exists(entity)) { Debug.LogWarning($"ApplyBlobAssetReferencePatches<{component}>({packedEntityGuids[packedComponent.PackedEntityIndex]}) but entity to patch does not exist."); } else if (!entityManager.HasComponent(entity, component)) { Debug.LogWarning($"ApplyBlobAssetReferencePatches<{component}>({packedEntityGuids[packedComponent.PackedEntityIndex]}) but component in entity to patch does not exist."); } else { if (component.IsBuffer) { var pointer = (byte *)entityManager.GetBufferRawRW(entity, component.TypeIndex); UnsafeUtility.MemCpy(pointer + targetOffset, &targetBlobAssetReferenceData, sizeof(BlobAssetReferenceData)); } else if (component.IsManagedComponent || component.IsSharedComponent) { managedObjectBlobAssetReferencePatches.Add( new EntityComponentPair { Entity = entity, Component = component }, new ManagedObjectBlobAssetReferencePatch { Id = targetOffset, Target = blobAssetReferenceChanges[i].Value }); } else { var pointer = (byte *)entityManager.GetComponentDataRawRW(entity, component.TypeIndex); UnsafeUtility.MemCpy(pointer + targetOffset, &targetBlobAssetReferenceData, sizeof(BlobAssetReferenceData)); } } }while (packedEntities.TryGetNextValue(out entity, ref iterator)); } } s_ApplyBlobAssetChangesProfilerMarker.End(); #if !UNITY_DOTSRUNTIME var managedObjectPatcher = new ManagedObjectBlobAssetReferencePatcher(patcherBlobAssetSystem); // Apply all managed entity patches using (var keys = managedObjectBlobAssetReferencePatches.GetKeyArray(Allocator.Temp)) { keys.Sort(); var uniqueCount = keys.Unique(); for (var i = 0; i < uniqueCount; i++) { var pair = keys[i]; var patches = managedObjectBlobAssetReferencePatches.GetValuesForKey(pair); if (pair.Component.IsManagedComponent) { var obj = entityManager.GetComponentObject <object>(pair.Entity, pair.Component); managedObjectPatcher.ApplyPatches(ref obj, patches); } else if (pair.Component.IsSharedComponent) { var obj = entityManager.GetSharedComponentData(pair.Entity, pair.Component.TypeIndex); managedObjectPatcher.ApplyPatches(ref obj, patches); entityManager.SetSharedComponentDataBoxedDefaultMustBeNull(pair.Entity, pair.Component.TypeIndex, obj); } patches.Dispose(); } } #endif managedObjectBlobAssetReferencePatches.Dispose(); // Workaround to catch some special cases where the memory is never released. (e.g. reloading a scene, toggling live-link on/off). patcherBlobAssetSystem.ReleaseUnusedBlobAssets(); }