public void Execute() { UnsafeList.Destroy(vertices); UnsafeList.Destroy(chainedIndices); UnsafeUtility.Free(hashTable, allocator); }
public unsafe void Execute(int i) { float3 currentPos = Positions[i].Value; float3 currentDir = VehicleData[i].Forward; #region SpeedVariation float prevDistanceAhead = VehicleData[i].HitDistAhead; float newDistanceAhead = HitResult[i].FrontHitDistance; float distAheadDiff = prevDistanceAhead - newDistanceAhead; int hitResult = HitResult[i].HitResultPacked; float maxSpeed = RoadSegments[VehicleData[i].SegId].MaxSpeed; float newSpeed = VehicleData[i].Speed; if (hitResult == 0 && newSpeed < maxSpeed) { newSpeed += 0.5f; } else if ((hitResult & 0x1) == 1 && (distAheadDiff > 0)) { newSpeed -= (distAheadDiff / 2.0f); } if (newDistanceAhead < 5.0f) { newSpeed -= 0.2f; } newSpeed = newSpeed > maxSpeed ? maxSpeed : newSpeed; newSpeed = newSpeed < 0 ? 0 : newSpeed; #endregion float stepLength = newSpeed * DeltaTime; float segLength = RoadSegments[VehicleData[i].SegId].Length; float stepPerc = stepLength / segLength; float nextPosPerc = VehicleData[i].CurrentSegPos + stepPerc * VehicleData[i].Direction; Unity.Mathematics.Random rdGen = new Unity.Mathematics.Random(); rdGen.InitState(FrameSeed + RandSeed[i]); #region switchLane int laneCount = RoadSegments[VehicleData[i].SegId].LaneNumber; int currentLane = VehicleData[i].Lane; int laneSwitch = rdGen.NextInt(-10, 10); laneSwitch = laneSwitch / 10; if (currentLane == 0 && laneSwitch == -1) { laneSwitch = 0; } if (currentLane == (laneCount - 1) && laneSwitch == 1) { laneSwitch = 0; } int nextLane = VehicleData[i].Lane + laneSwitch; #endregion //great, still in this seg if (nextPosPerc < 1.0f && nextPosPerc > 0.0f) { //step forward float3 nextPos = currentPos + currentDir * stepLength; //offset lane nextPos += laneSwitch * VehicleData[i].Direction * RoadSegments[VehicleData[i].SegId].LaneWidth * RoadSegments[VehicleData[i].SegId].RightDirection; VehicleData[i] = new VehicleData( VehicleData[i].Id, VehicleData[i].SegId, newSpeed, VehicleData[i].Forward, nextPosPerc, VehicleData[i].Direction, nextPos, nextLane, newDistanceAhead ); AABB newAABB = AABB[i]; newAABB.Max += currentDir * stepLength; newAABB.Min += currentDir * stepLength; AABB[i] = newAABB; Positions[i] = new Position() { Value = nextPos }; } //reach end node, find next seg else { int currentSeg = VehicleData[i].SegId; int reachedNode = VehicleData[i].Direction > 0.0f ? RoadSegments[currentSeg].EndNodeId : RoadSegments[currentSeg].StartNodeId; //find next available segment int *_availableSeg = (int *)UnsafeUtility.Malloc( 5 * sizeof(int), sizeof(int), Allocator.Temp); int availableSegCount = 0; for (int k = 0; k < 3; k++) { int seg1 = RoadNodes[reachedNode].ConnectionSegIds[k].x; int seg2 = RoadNodes[reachedNode].ConnectionSegIds[k].y; if (seg1 != -1 && seg1 != currentSeg && //not current seg, and next seg not one-way !(RoadSegments[seg1].EndNodeId == reachedNode && RoadSegments[seg1].IsOneWay == 1)) { _availableSeg[availableSegCount++] = seg1; } if (seg2 != -1 && seg2 != currentSeg && //not current seg, and next seg not one-way !(RoadSegments[seg2].EndNodeId == reachedNode && RoadSegments[seg2].IsOneWay == 1)) { _availableSeg[availableSegCount++] = seg2; } } int nextSeg = currentSeg; float dir = 1.0f; if (availableSegCount > 0)//luckily we can proceed { int selectSegId = rdGen.NextInt(0, availableSegCount); nextSeg = _availableSeg[selectSegId]; dir = RoadSegments[nextSeg].StartNodeId == reachedNode ? 1.0f : -1.0f; } else//to the end, spawn a new pos { nextSeg = rdGen.NextInt(0, RoadSegments.Length); } float3 nextForward = RoadSegments[nextSeg].Direction * dir; quaternion newRot = quaternion.LookRotation(nextForward, new float3() { x = 0, y = 1, z = 0 }); laneCount = RoadSegments[nextSeg].LaneNumber; nextLane = nextLane < laneCount ? nextLane : laneCount - 1; float laneOffset = (nextLane + 0.5f) * RoadSegments[nextSeg].LaneWidth; if (RoadSegments[nextSeg].IsOneWay == 1) { laneOffset -= (laneCount / 2.0f) * RoadSegments[nextSeg].LaneWidth; } float nextPerct = dir > 0.0f ? (nextPosPerc > 0.0f ? nextPosPerc - 1.0f : -nextPosPerc) : (nextPosPerc > 0.0f ? 2.0f - nextPosPerc : nextPosPerc + 1.0f); float3 nextPos = (1.0f - nextPerct) * RoadNodes[RoadSegments[nextSeg].StartNodeId].Position + (nextPerct) * RoadNodes[RoadSegments[nextSeg].EndNodeId].Position; nextPos += laneOffset * dir * RoadSegments[nextSeg].RightDirection; VehicleData[i] = new VehicleData( VehicleData[i].Id, nextSeg, newSpeed, nextForward, nextPerct, dir, nextPos, nextLane, newDistanceAhead ); AABB newAABB = AABB[i]; newAABB.Max += (nextPos - currentPos); newAABB.Min += (nextPos - currentPos); AABB[i] = newAABB; Positions[i] = new Position() { Value = nextPos }; Rotations[i] = new Rotation() { Value = newRot }; UnsafeUtility.Free(_availableSeg, Allocator.Temp); _availableSeg = null; } }
public void DestroyEntities(Entity *entities, int count) { var entityIndex = 0; var additionalDestroyList = new UnsafeList(Allocator.Persistent); int minDestroyStride = int.MaxValue; int maxDestroyStride = 0; while (entityIndex != count) { var entityBatchInChunk = GetFirstEntityBatchInChunk(entities + entityIndex, count - entityIndex); var chunk = entityBatchInChunk.Chunk; var batchCount = entityBatchInChunk.Count; var indexInChunk = entityBatchInChunk.StartIndex; if (chunk == null) { entityIndex += batchCount; continue; } AddToDestroyList(chunk, indexInChunk, batchCount, count, ref additionalDestroyList, ref minDestroyStride, ref maxDestroyStride); DestroyBatch(entities + entityIndex, chunk, indexInChunk, batchCount); entityIndex += batchCount; } // Apply additional destroys from any LinkedEntityGroup if (additionalDestroyList.Ptr != null) { var additionalDestroyPtr = (Entity *)additionalDestroyList.Ptr; // Optimal for destruction speed is if entities with same archetype/chunk are followed one after another. // So we lay out the to be destroyed objects assuming that the destroyed entities are "similar": // Reorder destruction by index in entityGroupArray... //@TODO: This is a very specialized fastpath that is likely only going to give benefits in the stress test. /// Figure out how to make this more general purpose. if (minDestroyStride == maxDestroyStride) { var reordered = (Entity *)UnsafeUtility.Malloc(additionalDestroyList.Length * sizeof(Entity), 16, Allocator.TempJob); int batchCount = additionalDestroyList.Length / minDestroyStride; for (int i = 0; i != batchCount; i++) { for (int j = 0; j != minDestroyStride; j++) { reordered[j * batchCount + i] = additionalDestroyPtr[i * minDestroyStride + j]; } } DestroyEntities(reordered, additionalDestroyList.Length); UnsafeUtility.Free(reordered, Allocator.TempJob); } else { DestroyEntities(additionalDestroyPtr, additionalDestroyList.Length); } UnsafeUtility.Free(additionalDestroyPtr, Allocator.Persistent); } }
public void Dispose() { UnsafeUtility.Free(s, Allocator.Temp); }
public static unsafe void SerializeWorld(EntityManager entityManager, BinaryWriter writer, out int[] sharedComponentsToSerialize) { writer.Write(CurrentFileFormatVersion); var archetypeManager = entityManager.ArchetypeManager; GetAllArchetypes(archetypeManager, out var archetypeToIndex, out var archetypeArray); var typeindices = new HashSet <int>(); foreach (var archetype in archetypeArray) { for (int iType = 0; iType < archetype.Archetype->TypesCount; ++iType) { typeindices.Add(archetype.Archetype->Types[iType].TypeIndex); } } var typeArray = typeindices.Select(index => { var type = TypeManager.GetType(index); var name = TypeManager.GetType(index).AssemblyQualifiedName; var hash = TypeManager.GetTypeInfo(index).FastEqualityTypeInfo.Hash; return(new { index, type, name, hash, asciiName = Encoding.ASCII.GetBytes(name) }); }).OrderBy(t => t.name).ToArray(); int typeNameBufferSize = typeArray.Sum(t => t.asciiName.Length + 1); writer.Write(typeArray.Length); foreach (var n in typeArray) { writer.Write(n.hash); } writer.Write(typeNameBufferSize); foreach (var n in typeArray) { writer.Write(n.asciiName); writer.Write((byte)0); } var typeIndexMap = new Dictionary <int, int>(); for (int i = 0; i < typeArray.Length; ++i) { typeIndexMap[typeArray[i].index] = i; } WriteArchetypes(writer, archetypeArray, typeIndexMap); //TODO: ensure chunks are defragged? NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos; var bufferPatches = new NativeList <BufferPatchRecord>(128, Allocator.Temp); var totalChunkCount = GenerateRemapInfo(entityManager, archetypeArray, out entityRemapInfos); writer.Write(totalChunkCount); var tempChunk = (Chunk *)UnsafeUtility.Malloc(Chunk.kChunkSize, 16, Allocator.Temp); var sharedIndexToSerialize = new Dictionary <int, int>(); for (int archetypeIndex = 0; archetypeIndex < archetypeArray.Length; ++archetypeIndex) { var archetype = archetypeArray[archetypeIndex].Archetype; for (var c = (Chunk *)archetype->ChunkList.Begin; c != archetype->ChunkList.End; c = (Chunk *)c->ChunkListNode.Next) { bufferPatches.Clear(); UnsafeUtility.MemCpy(tempChunk, c, Chunk.kChunkSize); tempChunk->SharedComponentValueArray = (int *)((byte *)(tempChunk) + Chunk.GetSharedComponentOffset(archetype->NumSharedComponents)); byte *tempChunkBuffer = tempChunk->Buffer; // Find all buffer pointer locations and work out how much memory the deserializer must allocate on load. for (int ti = 0; ti < archetype->TypesCount; ++ti) { int index = archetype->TypeMemoryOrder[ti]; if (!archetype->Types[index].IsBuffer) { continue; } int subArrayOffset = archetype->Offsets[index]; BufferHeader *header = (BufferHeader *)OffsetFromPointer(tempChunkBuffer, subArrayOffset); int stride = archetype->SizeOfs[index]; int count = c->Count; var ct = TypeManager.GetTypeInfo(archetype->Types[index].TypeIndex); for (int bi = 0; bi < count; ++bi) { if (header->Pointer != null) { header->Pointer = null; bufferPatches.Add(new BufferPatchRecord { ChunkOffset = (int)(((byte *)header) - (byte *)tempChunkBuffer), AllocSizeBytes = ct.ElementSize * header->Capacity, }); } header = (BufferHeader *)OffsetFromPointer(header, stride); } } EntityRemapUtility.PatchEntities(archetype->ScalarEntityPatches, archetype->ScalarEntityPatchCount, archetype->BufferEntityPatches, archetype->BufferEntityPatchCount, tempChunkBuffer, tempChunk->Count, ref entityRemapInfos); ClearUnusedChunkData(tempChunk); tempChunk->ChunkListNode.Next = null; tempChunk->ChunkListNode.Prev = null; tempChunk->ChunkListWithEmptySlotsNode.Next = null; tempChunk->ChunkListWithEmptySlotsNode.Prev = null; tempChunk->Archetype = (Archetype *)archetypeIndex; if (archetype->NumManagedArrays != 0) { throw new ArgumentException("Serialization of GameObject components is not supported for pure entity scenes"); } for (int i = 0; i != archetype->NumSharedComponents; i++) { int sharedComponentIndex = tempChunk->SharedComponentValueArray[i]; int newIndex; if (tempChunk->SharedComponentValueArray[i] != 0) { if (sharedIndexToSerialize.TryGetValue(sharedComponentIndex, out newIndex)) { tempChunk->SharedComponentValueArray[i] = newIndex; } else { // 0 is reserved for null types in shared components newIndex = sharedIndexToSerialize.Count + 1; sharedIndexToSerialize[sharedComponentIndex] = newIndex; tempChunk->SharedComponentValueArray[i] = newIndex; } } } writer.WriteBytes(tempChunk, Chunk.kChunkSize); writer.Write(bufferPatches.Length); if (bufferPatches.Length > 0) { writer.WriteList(bufferPatches); // Write heap backed data for each required patch. // TODO: PERF: Investigate static-only deserialization could manage one block and mark in pointers somehow that they are not indiviual for (int i = 0; i < bufferPatches.Length; ++i) { var patch = bufferPatches[i]; // NOTE that this reads the pointer from the original, unpatched chunk. // We have nulled out the pointer in the serialized data above. var header = (BufferHeader *)OffsetFromPointer(c->Buffer, patch.ChunkOffset); writer.WriteBytes(header->Pointer, patch.AllocSizeBytes); } } } } bufferPatches.Dispose(); entityRemapInfos.Dispose(); UnsafeUtility.Free(tempChunk, Allocator.Temp); sharedComponentsToSerialize = new int[sharedIndexToSerialize.Count]; foreach (var i in sharedIndexToSerialize) { sharedComponentsToSerialize[i.Value - 1] = i.Key; } }
public override void AdvanceFrame() { _sync.IncrementFrame(); _current_input.Clear(); Debug.Log($"End of frame({_sync.FrameCount})..."); if (_rollingback) { return; } int frame = _sync.FrameCount; // Hold onto the current frame in our queue of saved states. We'll need // the Checksum later to verify that our replay of the same frame got the // same results. var info = new SavedInfo { Frame = frame, Input = _last_input, Size = _sync.GetLastSavedFrame().Size, Buffer = (byte *)UnsafeUtility.Malloc(_sync.GetLastSavedFrame().Size, UnsafeUtility.AlignOf <byte>(), Allocator.Temp), Checksum = _sync.GetLastSavedFrame().Checksum, }; UnsafeUtility.MemCpy(info.Buffer, _sync.GetLastSavedFrame().Buffer, info.Size); _saved_frames.Push(info); if (frame - _last_verified == _check_distance) { // We've gone far enough ahead and should now start replaying frames. // Load the last verified frame and set the rollback flag to true. _sync.LoadFrame(_last_verified); _rollingback = true; while (!_saved_frames.IsEmpty) { _callbacks.AdvanceFrame(); // Verify that the Checksumn of this frame is the same as the one in our // list. info = _saved_frames.Peek(); _saved_frames.Pop(); if (info.Frame != _sync.FrameCount) { Debug.LogWarning($"SyncTest: Frame number {info.Frame} does not match saved frame number {frame}"); } int Checksum = _sync.GetLastSavedFrame().Checksum; if (info.Checksum != Checksum) { _callbacks.OnLogState?.Invoke($"Original f{_sync.FrameCount}:", (IntPtr)info.Buffer, info.Size); _callbacks.OnLogState?.Invoke($"Replay f{_sync.FrameCount}:", (IntPtr)_sync.GetLastSavedFrame().Buffer, _sync.GetLastSavedFrame().Size); Debug.LogWarning($"SyncTest: Checksum for frame {frame} does not match saved ({Checksum} != {Checksum})"); } else { Debug.Log($"Checksum {Checksum} for frame {info.Frame} matches."); } UnsafeUtility.Free(info.Buffer, Allocator.Temp); } _last_verified = frame; _rollingback = false; } }
public void Execute() { UnsafeUtility.Free(Container.m_Buffer, Container.m_AllocatorLabel); Container.m_Buffer = null; }
protected override unsafe void OnUpdate() { var ecb = new EntityCommandBuffer(Allocator.TempJob); Entities .WithAll <SceneData, RequestSceneLoaded>() .WithNone <SceneLoadRequest>() .ForEach((Entity e) => { var sceneData = EntityManager.GetComponentData <SceneData>(e); var sceneGuid = sceneData.Scene.SceneGuid; var path = DataRootPath + sceneGuid.Guid.ToString("N"); #if IO_ENABLE_TRACE Debug.Log($"SceneStreamingSystem: starting load for {DebugSceneGuid(sceneData)} from {path}"); #endif // Fire async reads for scene data SceneLoadRequest request = new SceneLoadRequest(); request.SceneOpHandle = IOService.RequestAsyncRead(path); ecb.AddComponent(e, request); ecb.RemoveComponent <RequestSceneLoaded>(e); sceneData.Status = SceneStatus.Loading; ecb.SetComponent(e, sceneData); }); ecb.Playback(EntityManager); ecb.Dispose(); var pendingRequests = m_PendingRequestsQuery.ToEntityArray(Allocator.TempJob); ecb = new EntityCommandBuffer(Allocator.TempJob); foreach (var requestEntity in pendingRequests) { SceneData sceneData = EntityManager.GetComponentData <SceneData>(requestEntity); SceneLoadRequest request = EntityManager.GetComponentData <SceneLoadRequest>(requestEntity); var opStatus = request.SceneOpHandle.GetStatus(); if (opStatus <= Status.InProgress) { continue; } if (opStatus == Status.Failure) { request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); Debug.Log($"SceneStreamingSystem: Failed to load {DebugSceneGuid(sceneData)}"); sceneData.Status = SceneStatus.FailedToLoad; ecb.SetComponent(requestEntity, sceneData); continue; } Assert.IsTrue(opStatus == Status.Success); request.SceneOpHandle.GetData(out var data, out var sceneDataSize); SceneHeader header = *(SceneHeader *)data; int headerSize = UnsafeUtility.SizeOf <SceneHeader>(); if (header.Version != SceneHeader.CurrentVersion) { throw new Exception($"Scene serialization version mismatch in {DebugSceneGuid(sceneData)}. Reading version '{header.Version}', expected '{SceneHeader.CurrentVersion}'"); } byte *decompressedScene = data + headerSize; if (header.Codec != Codec.Codec.None) { decompressedScene = (byte *)UnsafeUtility.Malloc(header.DecompressedSize, 16, Allocator.Temp); if (!CodecService.Decompress(header.Codec, data + headerSize, sceneDataSize - headerSize, decompressedScene, header.DecompressedSize)) { throw new Exception($"Failed to decompress compressed scene {DebugSceneGuid(sceneData)} using codec '{header.Codec}'"); } } using (var sceneReader = new MemoryBinaryReader(decompressedScene)) { var loadingEM = m_LoadingWorld.EntityManager; var transaction = loadingEM.BeginExclusiveEntityTransaction(); SerializeUtility.DeserializeWorld(transaction, sceneReader); loadingEM.EndExclusiveEntityTransaction(); } var scene = sceneData.Scene; var activeEM = EntityManager; activeEM.MoveEntitiesFrom(out var movedEntities, m_LoadingWorld.EntityManager); foreach (var e in movedEntities) { ecb.AddSharedComponent(e, scene.SceneGuid); ecb.AddSharedComponent(e, scene.SceneInstanceId); } // Fixup Entity references now that the entities have moved EntityManager.World.GetExistingSystem <EntityReferenceRemapSystem>().Update(); EntityManager.World.GetExistingSystem <RemoveRemapInformationSystem>().Update(); if (header.Codec != Codec.Codec.None) { UnsafeUtility.Free(decompressedScene, Allocator.Temp); } #if IO_ENABLE_TRACE Debug.Log($"SceneStreamingSystem: Loaded scene {DebugSceneGuid(sceneData)}"); #endif sceneData.Status = SceneStatus.Loaded; ecb.SetComponent(requestEntity, sceneData); request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); m_LoadingWorld.EntityManager.PrepareForDeserialize(); movedEntities.Dispose(); } ecb.Playback(EntityManager); ecb.Dispose(); pendingRequests.Dispose(); }
public void Execute() { var addedSharedComponentsCount = 0; var removedSharedComponentsCount = 0; var removedEntityCurrentCount = 0; var addedEntityCurrentCount = 0; for (var i = 0; i < RemovedShadowChunks.Length; i++) { var chunkSequenceNumber = RemovedShadowChunks[i]; var shadowChunk = ShadowChunksBySequenceNumber[chunkSequenceNumber]; UnsafeUtility.MemCpy((Entity *)RemovedEntities.GetUnsafePtr() + removedEntityCurrentCount, shadowChunk.EntityDataBuffer, shadowChunk.EntityCount * sizeof(Entity)); UnsafeUtility.MemCpyReplicate((int *)RemovedEntitiesMappingToComponent.GetUnsafePtr() + removedEntityCurrentCount, &removedSharedComponentsCount, sizeof(int), shadowChunk.EntityCount); removedEntityCurrentCount += shadowChunk.EntityCount; IndicesInManagedComponentStore[removedSharedComponentsCount++] = SharedComponentValueIndexByChunk[chunkSequenceNumber]; ShadowChunksBySequenceNumber.Remove(chunkSequenceNumber); SharedComponentValueIndexByChunk.Remove(chunkSequenceNumber); UnsafeUtility.Free(shadowChunk.EntityDataBuffer, Allocator.Persistent); } for (var i = 0; i < GatheredChanges.Length; i++) { var changes = GatheredChanges[i]; if (changes.RemovedEntities.Length == 0) { continue; } UnsafeUtility.MemCpy((Entity *)RemovedEntities.GetUnsafePtr() + removedEntityCurrentCount, changes.RemovedEntities.Ptr, changes.RemovedEntities.Length * sizeof(Entity)); UnsafeUtility.MemCpyReplicate((int *)RemovedEntitiesMappingToComponent.GetUnsafePtr() + removedEntityCurrentCount, &removedSharedComponentsCount, sizeof(int), changes.RemovedEntities.Length); removedEntityCurrentCount += changes.RemovedEntities.Length; IndicesInManagedComponentStore[removedSharedComponentsCount++] = SharedComponentValueIndexByChunk[changes.Chunk->SequenceNumber]; } for (var i = 0; i < GatheredChanges.Length; i++) { var changes = GatheredChanges[i]; if (changes.AddedEntities.Length == 0) { continue; } var chunkSequenceNumber = changes.Chunk->SequenceNumber; if (changes.AddedEntities.Length > 0) { var archetype = changes.Chunk->Archetype; var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex); var sharedComponentValueArray = changes.Chunk->SharedComponentValues; var sharedComponentOffset = indexInTypeArray - archetype->FirstSharedComponent; var sharedComponentDataIndex = sharedComponentValueArray[sharedComponentOffset]; SharedComponentValueIndexByChunk[chunkSequenceNumber] = sharedComponentDataIndex; UnsafeUtility.MemCpy((Entity *)AddedEntities.GetUnsafePtr() + addedEntityCurrentCount, changes.AddedEntities.Ptr, changes.AddedEntities.Length * sizeof(Entity)); var index = removedSharedComponentsCount + addedSharedComponentsCount; UnsafeUtility.MemCpyReplicate((int *)AddedEntitiesMappingToComponent.GetUnsafePtr() + addedEntityCurrentCount, &index, sizeof(int), changes.AddedEntities.Length); addedEntityCurrentCount += changes.AddedEntities.Length; IndicesInManagedComponentStore[index] = sharedComponentDataIndex; addedSharedComponentsCount++; } } }
public void Dispose() { UnsafeUtility.Free(m_Counter, m_AllocatorLabel); m_Counter = null; }
public void Dispose() { UnsafeUtility.Free(m_indices, m_allocator); }
public void Dispose() { // Free the allocated memory UnsafeUtility.Free(m_Buffer, m_AllocatorLabel); }
public void Dispose() { UnsafeUtility.Free(v1, Allocator.Persistent); UnsafeUtility.Free(v2, Allocator.Persistent); UnsafeUtility.Free(result, Allocator.Persistent); }
public void Dispose() { UnsafeUtility.Free(Data, Allocator); UnsafeUtility.Free(_control, Allocator); }
public static unsafe void SerializeWorld(EntityManager entityManager, BinaryWriter writer, out int[] sharedComponentsToSerialize, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos) { writer.Write(CurrentFileFormatVersion); var entityComponentStore = entityManager.EntityComponentStore; NativeHashMap <EntityArchetype, int> archetypeToIndex; EntityArchetype[] archetypeArray; GetAllArchetypes(entityComponentStore, out archetypeToIndex, out archetypeArray); var typeHashes = new NativeHashMap <ulong, int>(1024, Allocator.Temp); foreach (var archetype in archetypeArray) { for (int iType = 0; iType < archetype.Archetype->TypesCount; ++iType) { var typeIndex = archetype.Archetype->Types[iType].TypeIndex; var typeInfo = TypeManager.GetTypeInfo(typeIndex); var hash = typeInfo.StableTypeHash; ValidateTypeForSerialization(typeInfo); typeHashes.TryAdd(hash, 0); } } var typeHashSet = typeHashes.GetKeyArray(Allocator.Temp); writer.Write(typeHashSet.Length); foreach (ulong hash in typeHashSet) { writer.Write(hash); } var typeHashToIndexMap = new NativeHashMap <ulong, int>(typeHashSet.Length, Allocator.Temp); for (int i = 0; i < typeHashes.Length; ++i) { typeHashToIndexMap.TryAdd(typeHashSet[i], i); } WriteArchetypes(writer, archetypeArray, typeHashToIndexMap); var sharedComponentMapping = GatherSharedComponents(archetypeArray, out var sharedComponentArraysTotalCount); var sharedComponentArrays = new NativeArray <int>(sharedComponentArraysTotalCount, Allocator.Temp); FillSharedComponentArrays(sharedComponentArrays, archetypeArray, sharedComponentMapping); writer.Write(sharedComponentArrays.Length); writer.WriteArray(sharedComponentArrays); sharedComponentArrays.Dispose(); //TODO: ensure chunks are defragged? var bufferPatches = new NativeList <BufferPatchRecord>(128, Allocator.Temp); var totalChunkCount = GenerateRemapInfo(entityManager, archetypeArray, entityRemapInfos); writer.Write(totalChunkCount); GatherAllUsedBlobAssets(archetypeArray, out var blobAssetRefs, out var blobAssets); var blobAssetOffsets = new NativeArray <int>(blobAssets.Length, Allocator.Temp); int totalBlobAssetSize = 0; int Align16(int x) => (x + 15) & ~15; for (int i = 0; i < blobAssets.Length; ++i) { totalBlobAssetSize += sizeof(BlobAssetHeader); blobAssetOffsets[i] = totalBlobAssetSize; totalBlobAssetSize += Align16(blobAssets[i].header->Length); } writer.Write(totalBlobAssetSize); var zeroBytes = int4.zero; for (int i = 0; i < blobAssets.Length; ++i) { var blobAssetLength = blobAssets[i].header->Length; BlobAssetHeader header = new BlobAssetHeader { ValidationPtr = null, Allocator = Allocator.None, Length = Align16(blobAssetLength) }; writer.WriteBytes(&header, sizeof(BlobAssetHeader)); writer.WriteBytes(blobAssets[i].header + 1, blobAssetLength); writer.WriteBytes(&zeroBytes, header.Length - blobAssetLength); } var tempChunk = (Chunk *)UnsafeUtility.Malloc(Chunk.kChunkSize, 16, Allocator.Temp); for (int archetypeIndex = 0; archetypeIndex < archetypeArray.Length; ++archetypeIndex) { var archetype = archetypeArray[archetypeIndex].Archetype; for (var ci = 0; ci < archetype->Chunks.Count; ++ci) { var chunk = archetype->Chunks.p[ci]; bufferPatches.Clear(); UnsafeUtility.MemCpy(tempChunk, chunk, Chunk.kChunkSize); tempChunk->metaChunkEntity = EntityRemapUtility.RemapEntity(ref entityRemapInfos, tempChunk->metaChunkEntity); // Prevent patching from touching buffers allocated memory BufferHeader.PatchAfterCloningChunk(tempChunk); byte *tempChunkBuffer = tempChunk->Buffer; EntityRemapUtility.PatchEntities(archetype->ScalarEntityPatches, archetype->ScalarEntityPatchCount, archetype->BufferEntityPatches, archetype->BufferEntityPatchCount, tempChunkBuffer, tempChunk->Count, ref entityRemapInfos); if (archetype->ContainsBlobAssetRefs) { PatchBlobAssetsInChunkBeforeSave(tempChunk, chunk, blobAssetOffsets, blobAssetRefs); } FillPatchRecordsForChunk(chunk, bufferPatches); ClearChunkHeaderComponents(tempChunk); ChunkDataUtility.MemsetUnusedChunkData(tempChunk, 0); tempChunk->Archetype = (Archetype *)archetypeIndex; if (archetype->NumManagedArrays != 0) { throw new ArgumentException("Serialization of GameObject components is not supported for pure entity scenes"); } writer.WriteBytes(tempChunk, Chunk.kChunkSize); writer.Write(bufferPatches.Length); if (bufferPatches.Length > 0) { writer.WriteList(bufferPatches); // Write heap backed data for each required patch. // TODO: PERF: Investigate static-only deserialization could manage one block and mark in pointers somehow that they are not indiviual for (int i = 0; i < bufferPatches.Length; ++i) { var patch = bufferPatches[i]; var header = (BufferHeader *)OffsetFromPointer(tempChunk->Buffer, patch.ChunkOffset); writer.WriteBytes(header->Pointer, patch.AllocSizeBytes); BufferHeader.Destroy(header); } } } } blobAssetRefs.Dispose(); blobAssets.Dispose(); bufferPatches.Dispose(); UnsafeUtility.Free(tempChunk, Allocator.Temp); sharedComponentsToSerialize = new int[sharedComponentMapping.Length - 1]; using (var keyArray = sharedComponentMapping.GetKeyArray(Allocator.Temp)) foreach (var key in keyArray) { if (key == 0) { continue; } if (sharedComponentMapping.TryGetValue(key, out var val)) { sharedComponentsToSerialize[val - 1] = key; } } archetypeToIndex.Dispose(); typeHashes.Dispose(); typeHashSet.Dispose(); typeHashToIndexMap.Dispose(); }
protected unsafe override void Start() { float3 gravity = new float3(0, -9.81f, 0); base.init(gravity); // Make heightfield data float *heights; int2 size; float3 scale; bool simple = false; bool flat = false; bool mountain = false; if (simple) { size = new int2(2, 2); scale = new float3(1, 0.1f, 1); heights = (float *)UnsafeUtility.Malloc(size.x * size.y * sizeof(float), 4, Allocator.Temp); heights[0] = 1; heights[1] = 0; heights[2] = 0; heights[3] = 1; } else { size = new int2(SizeX, SizeZ); scale = new float3(ScaleX, ScaleY, ScaleZ); float period = 50.0f; heights = (float *)UnsafeUtility.Malloc(size.x * size.y * sizeof(float), 4, Allocator.Temp); for (int j = 0; j < size.y; j++) { for (int i = 0; i < size.x; i++) { float a = (i + j) * 2.0f * (float)math.PI / period; heights[i + j * size.x] = flat ? 0.0f : math.sin(a); if (mountain) { float fractionFromCenter = 1.0f - math.min(math.length(new float2(i - size.x / 2, j - size.y / 2)) / (math.min(size.x, size.y) / 2), 1.0f); float mountainHeight = math.smoothstep(0.0f, 1, fractionFromCenter) * 25.0f; heights[i + j * size.x] += mountainHeight; } } } } // static terrain Entity staticEntity; { BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.TerrainCollider.Create(size, scale, heights, Method); bool convertToMesh = false; if (convertToMesh) { #pragma warning disable 618 var res = Unity.Physics.Authoring.DisplayBodyColliders.DrawComponent.BuildDebugDisplayMesh((Unity.Physics.Collider *)collider.GetUnsafePtr()); #pragma warning restore 618 Vector3[] v = res[0].Mesh.vertices; float3[] vertices = new float3[v.Length]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = v[i]; } collider = Unity.Physics.MeshCollider.Create(vertices, res[0].Mesh.triangles); } bool compound = false; if (compound) { var instances = new NativeArray <CompoundCollider.ColliderBlobInstance>(4, Allocator.Temp); for (int i = 0; i < 4; i++) { instances[i] = new CompoundCollider.ColliderBlobInstance { Collider = collider, CompoundFromChild = new RigidTransform { pos = new float3((i % 2) * scale.x * (size.x - 1), 0.0f, (i / 2) * scale.z * (size.y - 1)), rot = quaternion.identity } }; } collider = Unity.Physics.CompoundCollider.Create(instances); instances.Dispose(); } float3 position = new float3(size.x - 1, 0.0f, size.y - 1) * scale * -0.5f; staticEntity = CreateStaticBody(position, quaternion.identity, collider); } UnsafeUtility.Free(heights, Allocator.Temp); }
public unsafe void Execute(ref HitResult thisHitResult, ref Translation translation, ref Rotation rotation, ref VehicleData vehicleData, ref BVHAABB bvhAabb) { var threadRandom = RdGens[threadId]; float3 currentPos = translation.Value; float3 currentDir = vehicleData.Forward; int laneCount, nextLane; //spawn new pos if (!BoundingBox.Contains(currentPos)) { int nextSeg = threadRandom.NextInt(0, RoadSegments.Length); float3 nextForward = RoadSegments[nextSeg].Direction; quaternion newRot = quaternion.LookRotation(nextForward, new float3() { x = 0, y = 1, z = 0 }); laneCount = RoadSegments[nextSeg].LaneNumber; nextLane = 0; float laneOffset = (nextLane + 0.5f) * RoadSegments[nextSeg].LaneWidth; if (RoadSegments[nextSeg].IsOneWay == 1) { laneOffset -= (laneCount / 2.0f) * RoadSegments[nextSeg].LaneWidth; } float nextPerct = 0; float3 nextPos = (1.0f - nextPerct) * RoadNodes[RoadSegments[nextSeg].StartNodeId].Position + (nextPerct) * RoadNodes[RoadSegments[nextSeg].EndNodeId].Position; nextPos += laneOffset * RoadSegments[nextSeg].RightDirection; vehicleData = new VehicleData( vehicleData.Id, nextSeg, vehicleData.Speed, nextForward, nextPerct, 1.0f, nextPos, nextLane, 50.0f ); BVHAABB newAABB = bvhAabb; newAABB.Max += (nextPos - currentPos); newAABB.Min += (nextPos - currentPos); bvhAabb = newAABB; translation = new Translation() { Value = nextPos }; rotation = new Rotation() { Value = newRot }; return; } #region Redlight infront int currentSeg = vehicleData.SegId; int nextCrossing = vehicleData.Direction > 0.0f ? RoadSegments[currentSeg].EndNodeId : RoadSegments[currentSeg].StartNodeId; float3 nextCrossingPos = RoadNodes[nextCrossing].Position; float distanceToCrossing = math.distance(currentPos, nextCrossingPos); int2 nextCrossingGreenlightConnect = RoadNodes[nextCrossing].ConnectionSegIds[RoadNodes[nextCrossing].ActiveConnection]; if (currentSeg != nextCrossingGreenlightConnect.x && currentSeg != nextCrossingGreenlightConnect.y && distanceToCrossing < 20.0f) { return; } #endregion #region SpeedVariation float prevDistanceAhead = vehicleData.HitDistAhead; float newDistanceAhead = thisHitResult.FrontHitDistance; float distAheadDiff = prevDistanceAhead - newDistanceAhead; int hitResult = thisHitResult.HitResultPacked; float maxSpeed = RoadSegments[vehicleData.SegId].MaxSpeed; float newSpeed = vehicleData.Speed; if (hitResult == 0 && newSpeed < maxSpeed) { newSpeed += 0.5f; } else if ((hitResult & 0x1) == 1 && (distAheadDiff > 0)) { newSpeed -= ((distAheadDiff) / 20.0f); } if (newDistanceAhead < 5.0f) { newSpeed = 0.0f; } newSpeed = newSpeed > maxSpeed ? maxSpeed : newSpeed; newSpeed = newSpeed < 0 ? 0 : newSpeed; #endregion float stepLength = newSpeed * DeltaTime; float segLength = RoadSegments[vehicleData.SegId].Length; float stepPerc = stepLength / segLength; float nextPosPerc = vehicleData.CurrentSegPos + stepPerc * vehicleData.Direction; #region switchLane laneCount = RoadSegments[vehicleData.SegId].LaneNumber; int currentLane = vehicleData.Lane; int laneSwitch = threadRandom.NextInt(-10, 10); laneSwitch = laneSwitch / 10; if (currentLane == 0 && laneSwitch == -1) { laneSwitch = 0; } if (currentLane == (laneCount - 1) && laneSwitch == 1) { laneSwitch = 0; } nextLane = vehicleData.Lane + laneSwitch; #endregion //great, still in this seg if (nextPosPerc < 1.0f && nextPosPerc > 0.0f) { //step forward float3 nextPos = currentPos + currentDir * stepLength; //offset lane nextPos += laneSwitch * vehicleData.Direction * RoadSegments[vehicleData.SegId].LaneWidth * RoadSegments[vehicleData.SegId].RightDirection; vehicleData = new VehicleData( vehicleData.Id, vehicleData.SegId, newSpeed, vehicleData.Forward, nextPosPerc, vehicleData.Direction, nextPos, nextLane, newDistanceAhead ); BVHAABB newAABB = bvhAabb; newAABB.Max += currentDir * stepLength; newAABB.Min += currentDir * stepLength; bvhAabb = newAABB; translation = new Translation() { Value = nextPos }; } //reach end node, find next seg else { //find next available segment int *_availableSeg = (int *)UnsafeUtility.Malloc( 5 * sizeof(int), sizeof(int), Allocator.Temp); int availableSegCount = 0; for (int k = 0; k < 3; k++) { int seg1 = RoadNodes[nextCrossing].ConnectionSegIds[k].x; int seg2 = RoadNodes[nextCrossing].ConnectionSegIds[k].y; if (seg1 != -1 && seg1 != currentSeg && //not current seg, and next seg not one-way !(RoadSegments[seg1].EndNodeId == nextCrossing && RoadSegments[seg1].IsOneWay == 1)) { _availableSeg[availableSegCount++] = seg1; } if (seg2 != -1 && seg2 != currentSeg && //not current seg, and next seg not one-way !(RoadSegments[seg2].EndNodeId == nextCrossing && RoadSegments[seg2].IsOneWay == 1)) { _availableSeg[availableSegCount++] = seg2; } } int nextSeg = currentSeg; float dir = 1.0f; if (availableSegCount > 0)//luckily we can proceed { int selectSegId = threadRandom.NextInt(0, availableSegCount); nextSeg = _availableSeg[selectSegId]; dir = RoadSegments[nextSeg].StartNodeId == nextCrossing ? 1.0f : -1.0f; } else//to the end, spawn a new pos { nextSeg = threadRandom.NextInt(0, RoadSegments.Length); } float3 nextForward = RoadSegments[nextSeg].Direction * dir; quaternion newRot = quaternion.LookRotation(nextForward, new float3() { x = 0, y = 1, z = 0 }); laneCount = RoadSegments[nextSeg].LaneNumber; nextLane = nextLane < laneCount ? nextLane : laneCount - 1; float laneOffset = (nextLane + 0.5f) * RoadSegments[nextSeg].LaneWidth; if (RoadSegments[nextSeg].IsOneWay == 1) { laneOffset -= (laneCount / 2.0f) * RoadSegments[nextSeg].LaneWidth; } float nextPerct = dir > 0.0f ? (nextPosPerc > 0.0f ? nextPosPerc - 1.0f : -nextPosPerc) : (nextPosPerc > 0.0f ? 2.0f - nextPosPerc : nextPosPerc + 1.0f); float3 nextPos = (1.0f - nextPerct) * RoadNodes[RoadSegments[nextSeg].StartNodeId].Position + (nextPerct) * RoadNodes[RoadSegments[nextSeg].EndNodeId].Position; nextPos += laneOffset * dir * RoadSegments[nextSeg].RightDirection; vehicleData = new VehicleData( vehicleData.Id, nextSeg, newSpeed, nextForward, nextPerct, dir, nextPos, nextLane, newDistanceAhead ); BVHAABB newAABB = bvhAabb; newAABB.Max += (nextPos - currentPos); newAABB.Min += (nextPos - currentPos); bvhAabb = newAABB; translation = new Translation() { Value = nextPos }; rotation = new Rotation() { Value = newRot }; UnsafeUtility.Free(_availableSeg, Allocator.Temp); RdGens[threadId] = threadRandom; _availableSeg = null; } }
public void Dispose() { m_Blocks->Dispose(); UnsafeUtility.Free(m_Blocks, Allocator.Persistent); }
public void Dispose() { UnsafeUtility.Free(v, Allocator.Persistent); UnsafeUtility.Free(gradient, Allocator.Persistent); }
public void Dispose() { UnsafeUtility.Free(q, Allocator.Persistent); UnsafeUtility.Free(rt, Allocator.Persistent); UnsafeUtility.Free(pos, Allocator.Persistent); }
public void Execute() { UnsafeUtility.Free(Ptr, Allocator); }
public void Dispose() { UnsafeUtility.Free(f4, Allocator.Persistent); UnsafeUtility.Free(u4, Allocator.Persistent); }
public void Dispose() { UnsafeUtility.Free(m_RootPtr, Allocator.Persistent); }
public unsafe void Execute() { *m_Ptr = 0; UnsafeUtility.Free(m_Ptr, m_Allocator); }
public void Execute() { OutputStreamContext->End(); UnsafeUtility.Free(OutputStreamContext, Allocator.TempJob); }
// Create a compound collider containing an array of other colliders. // The source colliders are copied into the compound, so that it becomes one blob. public static unsafe BlobAssetReference <Collider> Create(NativeArray <ColliderBlobInstance> children) { SafetyChecks.CheckNotEmptyAndThrow(children, nameof(children)); // Get the total required memory size for the compound plus all its children, // and the combined filter of all children // TODO: Verify that the size is enough int totalSize = Math.NextMultipleOf16(UnsafeUtility.SizeOf <CompoundCollider>()); CollisionFilter filter = children[0].Collider.Value.Filter; var srcToDestInstanceAddrs = new NativeHashMap <long, long>(children.Length, Allocator.Temp); for (var childIndex = 0; childIndex < children.Length; childIndex++) { var child = children[childIndex]; var instanceKey = (long)child.Collider.GetUnsafePtr(); if (srcToDestInstanceAddrs.ContainsKey(instanceKey)) { continue; } totalSize += Math.NextMultipleOf16(child.Collider.Value.MemorySize); filter = CollisionFilter.CreateUnion(filter, child.Collider.Value.Filter); srcToDestInstanceAddrs.Add(instanceKey, 0L); } totalSize += (children.Length + BoundingVolumeHierarchy.Constants.MaxNumTreeBranches) * UnsafeUtility.SizeOf <BoundingVolumeHierarchy.Node>(); // Allocate the collider var compoundCollider = (CompoundCollider *)UnsafeUtility.Malloc(totalSize, 16, Allocator.Temp); UnsafeUtility.MemClear(compoundCollider, totalSize); compoundCollider->m_Header.Type = ColliderType.Compound; compoundCollider->m_Header.CollisionType = CollisionType.Composite; compoundCollider->m_Header.Version = 1; compoundCollider->m_Header.Magic = 0xff; compoundCollider->m_Header.Filter = filter; // Initialize children array Child *childrenPtr = (Child *)((byte *)compoundCollider + UnsafeUtility.SizeOf <CompoundCollider>()); compoundCollider->m_ChildrenBlob.Offset = (int)((byte *)childrenPtr - (byte *)(&compoundCollider->m_ChildrenBlob.Offset)); compoundCollider->m_ChildrenBlob.Length = children.Length; byte *end = (byte *)childrenPtr + UnsafeUtility.SizeOf <Child>() * children.Length; end = (byte *)Math.NextMultipleOf16((ulong)end); uint maxTotalNumColliderKeyBits = 0; // Copy children for (int i = 0; i < children.Length; i++) { Collider *collider = (Collider *)children[i].Collider.GetUnsafePtr(); var srcInstanceKey = (long)collider; var dstAddr = srcToDestInstanceAddrs[srcInstanceKey]; if (dstAddr == 0L) { dstAddr = (long)end; srcToDestInstanceAddrs[srcInstanceKey] = dstAddr; UnsafeUtility.MemCpy(end, collider, collider->MemorySize); end += Math.NextMultipleOf16(collider->MemorySize); } childrenPtr[i].m_ColliderOffset = (int)((byte *)dstAddr - (byte *)(&childrenPtr[i].m_ColliderOffset)); childrenPtr[i].CompoundFromChild = children[i].CompoundFromChild; maxTotalNumColliderKeyBits = math.max(maxTotalNumColliderKeyBits, collider->TotalNumColliderKeyBits); } // Build mass properties compoundCollider->MassProperties = compoundCollider->BuildMassProperties(); // Build bounding volume int numNodes = compoundCollider->BuildBoundingVolume(out NativeArray <BoundingVolumeHierarchy.Node> nodes); int bvhSize = numNodes * UnsafeUtility.SizeOf <BoundingVolumeHierarchy.Node>(); compoundCollider->m_BvhNodesBlob.Offset = (int)(end - (byte *)(&compoundCollider->m_BvhNodesBlob.Offset)); compoundCollider->m_BvhNodesBlob.Length = numNodes; UnsafeUtility.MemCpy(end, nodes.GetUnsafeReadOnlyPtr(), bvhSize); compoundCollider->UpdateCachedBoundingRadius(); end += bvhSize; // Validate nesting level of composite colliders. compoundCollider->TotalNumColliderKeyBits = maxTotalNumColliderKeyBits + compoundCollider->NumColliderKeyBits; // If TotalNumColliderKeyBits is greater than 32, it means maximum nesting level of composite colliders has been breached. // ColliderKey has 32 bits so it can't handle infinite nesting of composite colliders. if (compoundCollider->TotalNumColliderKeyBits > 32) { SafetyChecks.ThrowArgumentException(nameof(children), "Composite collider exceeded maximum level of nesting!"); } // Copy to blob asset int usedSize = (int)(end - (byte *)compoundCollider); UnityEngine.Assertions.Assert.IsTrue(usedSize < totalSize); compoundCollider->MemorySize = usedSize; var blob = BlobAssetReference <Collider> .Create(compoundCollider, usedSize); UnsafeUtility.Free(compoundCollider, Allocator.Temp); return(blob); }
public void Dispose() { ReleaseAllUploadBuffers(); UnsafeUtility.Free(m_ThreadData, Allocator.Persistent); }
public void Dispose() { UnsafeUtility.Free((void *)data->arrayPtr, Allocator.Persistent); UnsafeUtility.Free(data, Allocator.Persistent); }
void InstantiateEntitiesGroup(Entity *srcEntities, int srcEntityCount, Entity *outputRootEntities, int instanceCount) { int totalCount = srcEntityCount * instanceCount; var tempAllocSize = sizeof(EntityRemapUtility.SparseEntityRemapInfo) * totalCount + sizeof(InstantiateRemapChunk) * totalCount + sizeof(Entity) * instanceCount; byte * allocation; const int kMaxStackAllocSize = 16 * 1024; if (tempAllocSize > kMaxStackAllocSize) { allocation = (byte *)UnsafeUtility.Malloc(tempAllocSize, 16, Allocator.Temp); } else { var temp = stackalloc byte[tempAllocSize]; allocation = temp; } var entityRemap = (EntityRemapUtility.SparseEntityRemapInfo *)allocation; var remapChunks = (InstantiateRemapChunk *)(entityRemap + totalCount); var outputEntities = (Entity *)(remapChunks + totalCount); var remapChunksCount = 0; for (int i = 0; i != srcEntityCount; i++) { var srcEntity = srcEntities[i]; remapChunksCount = InstantiateEntitiesOne(srcEntity, outputEntities, instanceCount, remapChunks, remapChunksCount); for (int r = 0; r != instanceCount; r++) { var ptr = entityRemap + (r * srcEntityCount + i); ptr->Src = srcEntity; ptr->Target = outputEntities[r]; } if (i == 0) { for (int r = 0; r != instanceCount; r++) { outputRootEntities[r] = outputEntities[r]; } } } for (int i = 0; i != remapChunksCount; i++) { var chunk = remapChunks[i].Chunk; var dstArchetype = chunk->Archetype; var allocatedCount = remapChunks[i].AllocatedCount; var indexInChunk = remapChunks[i].IndexInChunk; var instanceBeginIndex = remapChunks[i].InstanceBeginIndex; var localRemap = entityRemap + instanceBeginIndex * srcEntityCount; EntityRemapUtility.PatchEntitiesForPrefab(dstArchetype->ScalarEntityPatches + 1, dstArchetype->ScalarEntityPatchCount - 1, dstArchetype->BufferEntityPatches, dstArchetype->BufferEntityPatchCount, chunk->Buffer, indexInChunk, allocatedCount, localRemap, srcEntityCount); ManagedChangesTracker.PatchEntitiesForPrefab(dstArchetype, chunk, indexInChunk, allocatedCount, localRemap, srcEntityCount, Allocator.Temp); } if (tempAllocSize > kMaxStackAllocSize) { UnsafeUtility.Free(allocation, Allocator.Temp); } }
/// <summary> /// Reallocate to grow the capacity of the set /// </summary> /// /// <param name="newCapacity"> /// Capacity to grow to. Must be larger than the current capacity. /// </param> private void Reallocate(int newCapacity) { int newBucketCapacity = newCapacity * 2; newBucketCapacity = NextHigherPowerOfTwo(newBucketCapacity); // No change in capacity if (m_State->ItemCapacity == newCapacity && m_State->BucketCapacityMask + 1 == newBucketCapacity) { return; } // Can't shrink if (newCapacity < m_State->ItemCapacity) { throw new Exception("NativeHashSet<T> can't shrink"); } // Allocate new data int nextOffset; int bucketOffset; int totalSize = CalculateDataLayout( newCapacity, newBucketCapacity, out nextOffset, out bucketOffset); byte *newData = (byte *)UnsafeUtility.Malloc( totalSize, JobsUtility.CacheLineSize, m_Allocator); byte *newItems = newData; byte *newNext = newData + nextOffset; byte *newBuckets = newData + bucketOffset; // The items are taken from a free-list and might not be tightly // packed, copy all of the old capacity UnsafeUtility.MemCpy( newItems, m_State->Items, m_State->ItemCapacity * UnsafeUtility.SizeOf <T>()); UnsafeUtility.MemCpy( newNext, m_State->Next, m_State->ItemCapacity * UnsafeUtility.SizeOf <int>()); for ( int emptyNext = m_State->ItemCapacity; emptyNext < newCapacity; ++emptyNext) { ((int *)newNext)[emptyNext] = -1; } // Re-hash the buckets, first clear the new bucket list, then insert // all values from the old list for (int bucket = 0; bucket < newBucketCapacity; ++bucket) { ((int *)newBuckets)[bucket] = -1; } for (int bucket = 0; bucket <= m_State->BucketCapacityMask; ++bucket) { int *buckets = (int *)m_State->Buckets; int *nextPtrs = (int *)newNext; while (buckets[bucket] >= 0) { int curEntry = buckets[bucket]; buckets[bucket] = nextPtrs[curEntry]; int newBucket = UnsafeUtility.ReadArrayElement <T>( m_State->Items, curEntry).GetHashCode() & (newBucketCapacity - 1); nextPtrs[curEntry] = ((int *)newBuckets)[newBucket]; ((int *)newBuckets)[newBucket] = curEntry; } } // Free the old state contents UnsafeUtility.Free(m_State->Items, m_Allocator); // Set the new state contents if (m_State->AllocatedIndexLength > m_State->ItemCapacity) { m_State->AllocatedIndexLength = m_State->ItemCapacity; } m_State->Items = newData; m_State->Next = newNext; m_State->Buckets = newBuckets; m_State->ItemCapacity = newCapacity; m_State->BucketCapacityMask = newBucketCapacity - 1; }