public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var deserializerState = new GhostDeserializerState { GhostMap = GhostMap }; var ghostEntityArray = chunk.GetNativeArray(ghostEntityType); var ghostSnapshotDataArray = chunk.GetBufferAccessor(ghostSnapshotDataType); var predictedGhostComponentArray = chunk.GetNativeArray(predictedGhostComponentType); var ghostHealthArray = chunk.GetNativeArray(ghostHealthType); var ghostPlayerUnitArray = chunk.GetNativeArray(ghostPlayerUnitType); var ghostUnitSelectionStateArray = chunk.GetNativeArray(ghostUnitSelectionStateType); var ghostLinkedEntityGroupArray = chunk.GetBufferAccessor(ghostLinkedEntityGroupType); #if UNITY_EDITOR || DEVELOPMENT_BUILD var minMaxOffset = ThreadIndex * (JobsUtility.CacheLineSize / 4); #endif for (int entityIndex = 0; entityIndex < ghostEntityArray.Length; ++entityIndex) { var snapshot = ghostSnapshotDataArray[entityIndex]; #if UNITY_EDITOR || DEVELOPMENT_BUILD var latestTick = snapshot.GetLatestTick(); if (latestTick != 0) { if (minMaxSnapshotTick[minMaxOffset] == 0 || SequenceHelpers.IsNewer(minMaxSnapshotTick[minMaxOffset], latestTick)) { minMaxSnapshotTick[minMaxOffset] = latestTick; } if (minMaxSnapshotTick[minMaxOffset + 1] == 0 || SequenceHelpers.IsNewer(latestTick, minMaxSnapshotTick[minMaxOffset + 1])) { minMaxSnapshotTick[minMaxOffset + 1] = latestTick; } } #endif ACivilianSnapshotData snapshotData; snapshot.GetDataAtTick(targetTick, out snapshotData); var predictedData = predictedGhostComponentArray[entityIndex]; var lastPredictedTickInst = lastPredictedTick; if (lastPredictedTickInst == 0 || predictedData.AppliedTick != snapshotData.Tick) { lastPredictedTickInst = snapshotData.Tick; } else if (!SequenceHelpers.IsNewer(lastPredictedTickInst, snapshotData.Tick)) { lastPredictedTickInst = snapshotData.Tick; } if (minPredictedTick[ThreadIndex] == 0 || SequenceHelpers.IsNewer(minPredictedTick[ThreadIndex], lastPredictedTickInst)) { minPredictedTick[ThreadIndex] = lastPredictedTickInst; } predictedGhostComponentArray[entityIndex] = new PredictedGhostComponent { AppliedTick = snapshotData.Tick, PredictionStartTick = lastPredictedTickInst }; if (lastPredictedTickInst != snapshotData.Tick) { continue; } var ghostHealth = ghostHealthArray[entityIndex]; var ghostPlayerUnit = ghostPlayerUnitArray[entityIndex]; var ghostUnitSelectionState = ghostUnitSelectionStateArray[entityIndex]; var ghostRotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value]; var ghostTranslation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value]; var ghostChild0Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value]; var ghostChild0Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value]; var ghostChild1Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value]; var ghostChild1Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value]; ghostHealth.Value = snapshotData.GetHealthValue(deserializerState); ghostPlayerUnit.PlayerId = snapshotData.GetPlayerUnitPlayerId(deserializerState); ghostPlayerUnit.UnitId = snapshotData.GetPlayerUnitUnitId(deserializerState); ghostUnitSelectionState.IsSelected = snapshotData.GetUnitSelectionStateIsSelected(deserializerState); ghostRotation.Value = snapshotData.GetRotationValue(deserializerState); ghostTranslation.Value = snapshotData.GetTranslationValue(deserializerState); ghostChild0Rotation.Value = snapshotData.GetChild0RotationValue(deserializerState); ghostChild0Translation.Value = snapshotData.GetChild0TranslationValue(deserializerState); ghostChild1Rotation.Value = snapshotData.GetChild1RotationValue(deserializerState); ghostChild1Translation.Value = snapshotData.GetChild1TranslationValue(deserializerState); ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value] = ghostRotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value] = ghostTranslation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value] = ghostChild0Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value] = ghostChild0Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value] = ghostChild1Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value] = ghostChild1Translation; ghostHealthArray[entityIndex] = ghostHealth; ghostPlayerUnitArray[entityIndex] = ghostPlayerUnit; ghostUnitSelectionStateArray[entityIndex] = ghostUnitSelectionState; } }
//Sum up all the dynamic buffers raw data content size. Each buffer content size is aligned to 16 bytes private int GetChunkBuffersDataSize(GhostCollectionPrefabSerializer typeData, ArchetypeChunk chunk, DynamicComponentTypeHandle *ghostChunkComponentTypesPtr, int ghostChunkComponentTypesLength, DynamicBuffer <GhostCollectionComponentIndex> GhostComponentIndex, DynamicBuffer <GhostComponentSerializer.State> GhostComponentCollection) { int numBaseComponents = typeData.NumComponents - typeData.NumChildComponents; int bufferTotalSize = 0; int baseOffset = typeData.FirstComponent; for (int comp = 0; comp < numBaseComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; int serializerIdx = GhostComponentIndex[baseOffset + comp].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[baseOffset + comp].SendMask & requiredSendMask) == 0) { continue; } if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { continue; } if (chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var bufferData = chunk.GetUntypedBufferAccessor(ref ghostChunkComponentTypesPtr[compIdx]); for (int i = 0; i < bufferData.Length; ++i) { bufferTotalSize += bufferData.GetBufferCapacity(i) * GhostComponentCollection[serializerIdx].ComponentSize; } bufferTotalSize = GhostCollectionSystem.SnapshotSizeAligned(bufferTotalSize); } } if (typeData.NumChildComponents > 0) { var linkedEntityGroupAccessor = chunk.GetBufferAccessor(linkedEntityGroupType); for (int comp = numBaseComponents; comp < typeData.NumComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; int serializerIdx = GhostComponentIndex[baseOffset + comp].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[baseOffset + comp].SendMask & requiredSendMask) == 0) { continue; } if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { continue; } for (int ent = 0; ent < chunk.Count; ++ent) { var linkedEntityGroup = linkedEntityGroupAccessor[ent]; if (childEntityLookup.TryGetValue(linkedEntityGroup[GhostComponentIndex[baseOffset + comp].EntityIndex].Value, out var childChunk) && childChunk.chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var bufferData = childChunk.chunk.GetUntypedBufferAccessor(ref ghostChunkComponentTypesPtr[compIdx]); bufferTotalSize += bufferData.GetBufferCapacity(childChunk.index) * GhostComponentCollection[serializerIdx].ComponentSize; } bufferTotalSize = GhostCollectionSystem.SnapshotSizeAligned(bufferTotalSize); } } } return(bufferTotalSize); }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex, DynamicComponentTypeHandle *ghostChunkComponentTypesPtr, int ghostChunkComponentTypesLength) { var GhostTypeCollection = GhostTypeCollectionFromEntity[GhostCollectionSingleton]; var GhostComponentIndex = GhostComponentIndexFromEntity[GhostCollectionSingleton]; var GhostComponentCollection = GhostComponentCollectionFromEntity[GhostCollectionSingleton]; var ghostComponents = chunk.GetNativeArray(ghostType); int ghostTypeId = ghostComponents.GetFirstGhostTypeId(); if (ghostTypeId < 0) { return; } var typeData = GhostTypeCollection[ghostTypeId]; var singleEntitySize = UnsafeUtility.SizeOf <Entity>(); int baseOffset = typeData.FirstComponent; if (!predictionState.TryGetValue(chunk, out var state) || (*(PredictionBackupState *)state).ghostType != ghostTypeId || (*(PredictionBackupState *)state).entityCapacity != chunk.Capacity) { int dataSize = 0; // Sum up the size of all components rounded up for (int comp = 0; comp < typeData.NumComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; int serializerIdx = GhostComponentIndex[baseOffset + comp].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[baseOffset + comp].SendMask & requiredSendMask) == 0) { continue; } //for buffers we store a a pair of uint: // uint length: the num of elements // uint backupDataOffset: the start position in the backup buffer if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { dataSize += PredictionBackupState.GetDataSize( GhostComponentCollection[serializerIdx].ComponentSize, chunk.Capacity); } else { dataSize += PredictionBackupState.GetDataSize(GhostSystemConstants.DynamicBufferComponentSnapshotSize, chunk.Capacity); } } //compute the space necessary to store the dynamic buffers data for the chunk int buffersDataCapacity = 0; if (typeData.NumBuffers > 0) { buffersDataCapacity = GetChunkBuffersDataSize(typeData, chunk, ghostChunkComponentTypesPtr, ghostChunkComponentTypesLength, GhostComponentIndex, GhostComponentCollection); } // Chunk does not exist in the history, or has changed ghost type in which case we need to create a new one state = PredictionBackupState.AllocNew(ghostTypeId, dataSize, chunk.Capacity, buffersDataCapacity); newPredictionState.Enqueue(new PredictionStateEntry { chunk = chunk, data = state }); } else { stillUsedPredictionState.TryAdd(chunk, 1); if (typeData.NumBuffers > 0) { //resize the backup state to fit the dynamic buffers contents var buffersDataCapacity = GetChunkBuffersDataSize(typeData, chunk, ghostChunkComponentTypesPtr, ghostChunkComponentTypesLength, GhostComponentIndex, GhostComponentCollection); int bufferBackupDataCapacity = PredictionBackupState.GetBufferDataCapacity(state); if (bufferBackupDataCapacity < buffersDataCapacity) { var dataSize = ((PredictionBackupState *)state)->dataSize; var newState = PredictionBackupState.AllocNew(ghostTypeId, dataSize, chunk.Capacity, buffersDataCapacity); UnsafeUtility.Free((void *)state, Allocator.Persistent); state = newState; updatedPredictionState.Enqueue(new PredictionStateEntry { chunk = chunk, data = newState }); } } } Entity *entities = PredictionBackupState.GetEntities(state); var srcEntities = chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr(); UnsafeUtility.MemCpy(entities, srcEntities, chunk.Count * singleEntitySize); if (chunk.Count < chunk.Capacity) { UnsafeUtility.MemClear(entities + chunk.Count, (chunk.Capacity - chunk.Count) * singleEntitySize); } byte *dataPtr = PredictionBackupState.GetData(state); byte *bufferBackupDataPtr = PredictionBackupState.GetBufferDataPtr(state); int numBaseComponents = typeData.NumComponents - typeData.NumChildComponents; int bufferBackupDataOffset = 0; for (int comp = 0; comp < numBaseComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; int serializerIdx = GhostComponentIndex[baseOffset + comp].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[baseOffset + comp].SendMask & requiredSendMask) == 0) { continue; } var compSize = GhostComponentCollection[serializerIdx].ComponentType.IsBuffer ? GhostSystemConstants.DynamicBufferComponentSnapshotSize : GhostComponentCollection[serializerIdx].ComponentSize; if (!chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { UnsafeUtility.MemClear(dataPtr, chunk.Count * compSize); } else if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { var compData = (byte *)chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[compIdx], compSize).GetUnsafeReadOnlyPtr(); UnsafeUtility.MemCpy(dataPtr, compData, chunk.Count * compSize); } else { var bufferData = chunk.GetUntypedBufferAccessor(ref ghostChunkComponentTypesPtr[compIdx]); var bufElemSize = GhostComponentCollection[serializerIdx].ComponentSize; //Use local variable to iterate and set the buffer offset and length. The dataptr must be //advanced "per chunk" to the next correct position var tempDataPtr = dataPtr; for (int i = 0; i < bufferData.Length; ++i) { //Retrieve an copy each buffer data. Set size and offset in the backup buffer in the component backup var bufferPtr = bufferData.GetUnsafeReadOnlyPtrAndLength(i, out var size); ((int *)tempDataPtr)[0] = size; ((int *)tempDataPtr)[1] = bufferBackupDataOffset; if (size > 0) { UnsafeUtility.MemCpy(bufferBackupDataPtr + bufferBackupDataOffset, (byte *)bufferPtr, size * bufElemSize); } bufferBackupDataOffset += size * bufElemSize; tempDataPtr += compSize; } bufferBackupDataOffset = GhostCollectionSystem.SnapshotSizeAligned(bufferBackupDataOffset); } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } if (typeData.NumChildComponents > 0) { var linkedEntityGroupAccessor = chunk.GetBufferAccessor(linkedEntityGroupType); for (int comp = numBaseComponents; comp < typeData.NumComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; int serializerIdx = GhostComponentIndex[baseOffset + comp].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[baseOffset + comp].SendMask & requiredSendMask) == 0) { continue; } var isBuffer = GhostComponentCollection[serializerIdx].ComponentType.IsBuffer; var compSize = isBuffer ? GhostSystemConstants.DynamicBufferComponentSnapshotSize : GhostComponentCollection[serializerIdx].ComponentSize; if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { //use a temporary for the iteration here. Otherwise when the dataptr is offset for the chunk, we //end up in the wrong position var tempDataPtr = dataPtr; for (int ent = 0; ent < chunk.Count; ++ent) { var linkedEntityGroup = linkedEntityGroupAccessor[ent]; if (childEntityLookup.TryGetValue(linkedEntityGroup[GhostComponentIndex[baseOffset + comp].EntityIndex].Value, out var childChunk) && childChunk.chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var compData = (byte *)childChunk.chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[compIdx], compSize).GetUnsafeReadOnlyPtr(); UnsafeUtility.MemCpy(tempDataPtr, compData + childChunk.index * compSize, compSize); } else { UnsafeUtility.MemClear(tempDataPtr, compSize); } tempDataPtr += compSize; } } else { var bufElemSize = GhostComponentCollection[serializerIdx].ComponentSize; var tempDataPtr = dataPtr; for (int ent = 0; ent < chunk.Count; ++ent) { var linkedEntityGroup = linkedEntityGroupAccessor[ent]; if (childEntityLookup.TryGetValue(linkedEntityGroup[GhostComponentIndex[baseOffset + comp].EntityIndex].Value, out var childChunk) && childChunk.chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var bufferData = childChunk.chunk.GetUntypedBufferAccessor(ref ghostChunkComponentTypesPtr[compIdx]); //Retrieve an copy each buffer data. Set size and offset in the backup buffer in the component backup var bufferPtr = bufferData.GetUnsafeReadOnlyPtrAndLength(childChunk.index, out var size); ((int *)tempDataPtr)[0] = size; ((int *)tempDataPtr)[1] = bufferBackupDataOffset; if (size > 0) { UnsafeUtility.MemCpy(bufferBackupDataPtr + bufferBackupDataOffset, (byte *)bufferPtr, size * bufElemSize); } bufferBackupDataOffset += size * bufElemSize; } else { //reset the entry to 0. Don't use memcpy in this case (is faster this way) ((long *)tempDataPtr)[0] = 0; } tempDataPtr += compSize; } bufferBackupDataOffset = GhostCollectionSystem.SnapshotSizeAligned(bufferBackupDataOffset); } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex, DynamicComponentTypeHandle *ghostChunkComponentTypesPtr, int ghostChunkComponentTypesLength) { if (!predictionState.TryGetValue(chunk, out var state) || (*(PredictionBackupState *)state).entityCapacity != chunk.Capacity) { return; } var ghostComponents = chunk.GetNativeArray(ghostType); int ghostTypeId = ghostComponents[0].ghostType; var typeData = GhostTypeCollection[ghostTypeId]; var headerSize = PredictionBackupState.GetHeaderSize(); var entitySize = PredictionBackupState.GetEntitiesSize(chunk.Capacity, out var singleEntitySize); int baseOffset = typeData.FirstComponent; Entity *backupEntities = PredictionBackupState.GetEntities(state, headerSize); var entities = chunk.GetNativeArray(entityType); var predictedGhostComponents = chunk.GetNativeArray(predictedGhostType); byte *dataPtr = PredictionBackupState.GetData(state, headerSize, entitySize); int numBaseComponents = typeData.NumComponents - typeData.NumChildComponents; for (int comp = 0; comp < numBaseComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentCollection[compIdx].SendMask & requiredSendMask) == 0) { continue; } var compSize = GhostComponentCollection[compIdx].ComponentSize; if (chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var compData = (byte *)chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[compIdx], compSize).GetUnsafeReadOnlyPtr(); for (int ent = 0; ent < entities.Length; ++ent) { // If this entity did not predict anything there was no rollback and no need to debug it if (!GhostPredictionSystemGroup.ShouldPredict(tick, predictedGhostComponents[ent])) { continue; } if (entities[ent] == backupEntities[ent]) { int errorIndex = GhostComponentIndex[baseOffset + comp].PredictionErrorBaseIndex; var errors = new UnsafeList <float>(((float *)predictionErrors.GetUnsafePtr()) + errorIndex + ThreadIndex * numPredictionErrors, numPredictionErrors - errorIndex); GhostComponentCollection[compIdx].ReportPredictionErrors.Ptr.Invoke((System.IntPtr)(compData + compSize * ent), (System.IntPtr)(dataPtr + compSize * ent), ref errors); } } } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } if (typeData.NumChildComponents > 0) { var linkedEntityGroupAccessor = chunk.GetBufferAccessor(linkedEntityGroupType); for (int comp = numBaseComponents; comp < typeData.NumComponents; ++comp) { int compIdx = GhostComponentIndex[baseOffset + comp].ComponentIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentCollection[compIdx].SendMask & requiredSendMask) == 0) { continue; } var compSize = GhostComponentCollection[compIdx].ComponentSize; var entityIdx = GhostComponentIndex[baseOffset + comp].EntityIndex; for (int ent = 0; ent < chunk.Count; ++ent) { // If this entity did not predict anything there was no rollback and no need to debug it if (!GhostPredictionSystemGroup.ShouldPredict(tick, predictedGhostComponents[ent])) { continue; } if (entities[ent] != backupEntities[ent]) { continue; } var linkedEntityGroup = linkedEntityGroupAccessor[ent]; if (childEntityLookup.TryGetValue(linkedEntityGroup[entityIdx].Value, out var childChunk) && childChunk.chunk.Has(ghostChunkComponentTypesPtr[compIdx])) { var compData = (byte *)childChunk.chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[compIdx], compSize).GetUnsafePtr(); int errorIndex = GhostComponentIndex[baseOffset + comp].PredictionErrorBaseIndex; var errors = new UnsafeList <float>(((float *)predictionErrors.GetUnsafePtr()) + errorIndex + ThreadIndex * numPredictionErrors, numPredictionErrors - errorIndex); GhostComponentCollection[compIdx].ReportPredictionErrors.Ptr.Invoke((System.IntPtr)(compData + compSize * childChunk.index), (System.IntPtr)(dataPtr + compSize * ent), ref errors); } } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var deserializerState = new GhostDeserializerState { GhostMap = GhostMap }; var ghostEntityArray = chunk.GetNativeArray(ghostEntityType); var ghostSnapshotDataArray = chunk.GetBufferAccessor(ghostSnapshotDataType); var predictedGhostComponentArray = chunk.GetNativeArray(predictedGhostComponentType); var ghostPlayerIdComponentDataArray = chunk.GetNativeArray(ghostPlayerIdComponentDataType); var ghostRotationArray = chunk.GetNativeArray(ghostRotationType); var ghostTranslationArray = chunk.GetNativeArray(ghostTranslationType); var ghostVelocityArray = chunk.GetNativeArray(ghostVelocityType); #if UNITY_EDITOR || DEVELOPMENT_BUILD var minMaxOffset = ThreadIndex * (JobsUtility.CacheLineSize / 4); #endif for (int entityIndex = 0; entityIndex < ghostEntityArray.Length; ++entityIndex) { var snapshot = ghostSnapshotDataArray[entityIndex]; #if UNITY_EDITOR || DEVELOPMENT_BUILD var latestTick = snapshot.GetLatestTick(); if (latestTick != 0) { if (minMaxSnapshotTick[minMaxOffset] == 0 || SequenceHelpers.IsNewer(minMaxSnapshotTick[minMaxOffset], latestTick)) { minMaxSnapshotTick[minMaxOffset] = latestTick; } if (minMaxSnapshotTick[minMaxOffset + 1] == 0 || SequenceHelpers.IsNewer(latestTick, minMaxSnapshotTick[minMaxOffset + 1])) { minMaxSnapshotTick[minMaxOffset + 1] = latestTick; } } #endif ShipSnapshotData snapshotData; snapshot.GetDataAtTick(targetTick, out snapshotData); var predictedData = predictedGhostComponentArray[entityIndex]; var lastPredictedTickInst = lastPredictedTick; if (lastPredictedTickInst == 0 || predictedData.AppliedTick != snapshotData.Tick) { lastPredictedTickInst = snapshotData.Tick; } else if (!SequenceHelpers.IsNewer(lastPredictedTickInst, snapshotData.Tick)) { lastPredictedTickInst = snapshotData.Tick; } if (minPredictedTick[ThreadIndex] == 0 || SequenceHelpers.IsNewer(minPredictedTick[ThreadIndex], lastPredictedTickInst)) { minPredictedTick[ThreadIndex] = lastPredictedTickInst; } predictedGhostComponentArray[entityIndex] = new PredictedGhostComponent { AppliedTick = snapshotData.Tick, PredictionStartTick = lastPredictedTickInst }; if (lastPredictedTickInst != snapshotData.Tick) { continue; } var ghostPlayerIdComponentData = ghostPlayerIdComponentDataArray[entityIndex]; var ghostRotation = ghostRotationArray[entityIndex]; var ghostTranslation = ghostTranslationArray[entityIndex]; var ghostVelocity = ghostVelocityArray[entityIndex]; ghostPlayerIdComponentData.PlayerId = snapshotData.GetPlayerIdComponentDataPlayerId(deserializerState); ghostRotation.Value = snapshotData.GetRotationValue(deserializerState); ghostTranslation.Value = snapshotData.GetTranslationValue(deserializerState); ghostVelocity.Value = snapshotData.GetVelocityValue(deserializerState); ghostPlayerIdComponentDataArray[entityIndex] = ghostPlayerIdComponentData; ghostRotationArray[entityIndex] = ghostRotation; ghostTranslationArray[entityIndex] = ghostTranslation; ghostVelocityArray[entityIndex] = ghostVelocity; } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { GhostDeserializerState deserializerState = new GhostDeserializerState { GhostMap = GhostMap }; NativeArray <Entity> ghostEntityArray = chunk.GetNativeArray(ghostEntityType); BufferAccessor <NetCodeTestGhostObjectSnapshotData> ghostSnapshotDataArray = chunk.GetBufferAccessor(ghostSnapshotDataType); NativeArray <PredictedGhostComponent> predictedGhostComponentArray = chunk.GetNativeArray(predictedGhostComponentType); NativeArray <Rotation> ghostRotationArray = chunk.GetNativeArray(ghostRotationType); NativeArray <Translation> ghostTranslationArray = chunk.GetNativeArray(ghostTranslationType); #if UNITY_EDITOR || DEVELOPMENT_BUILD int minMaxOffset = ThreadIndex * (JobsUtility.CacheLineSize / 4); #endif for (int entityIndex = 0; entityIndex < ghostEntityArray.Length; ++entityIndex) { DynamicBuffer <NetCodeTestGhostObjectSnapshotData> snapshot = ghostSnapshotDataArray[entityIndex]; #if UNITY_EDITOR || DEVELOPMENT_BUILD uint latestTick = snapshot.GetLatestTick(); if (latestTick != 0) { if (minMaxSnapshotTick[minMaxOffset] == 0 || SequenceHelpers.IsNewer(minMaxSnapshotTick[minMaxOffset], latestTick)) { minMaxSnapshotTick[minMaxOffset] = latestTick; } if (minMaxSnapshotTick[minMaxOffset + 1] == 0 || SequenceHelpers.IsNewer(latestTick, minMaxSnapshotTick[minMaxOffset + 1])) { minMaxSnapshotTick[minMaxOffset + 1] = latestTick; } } #endif NetCodeTestGhostObjectSnapshotData snapshotData; snapshot.GetDataAtTick(targetTick, out snapshotData); PredictedGhostComponent predictedData = predictedGhostComponentArray[entityIndex]; uint lastPredictedTickInst = lastPredictedTick; if (lastPredictedTickInst == 0 || predictedData.AppliedTick != snapshotData.Tick) { lastPredictedTickInst = snapshotData.Tick; } else if (!SequenceHelpers.IsNewer(lastPredictedTickInst, snapshotData.Tick)) { lastPredictedTickInst = snapshotData.Tick; } if (minPredictedTick[ThreadIndex] == 0 || SequenceHelpers.IsNewer(minPredictedTick[ThreadIndex], lastPredictedTickInst)) { minPredictedTick[ThreadIndex] = lastPredictedTickInst; } predictedGhostComponentArray[entityIndex] = new PredictedGhostComponent { AppliedTick = snapshotData.Tick, PredictionStartTick = lastPredictedTickInst }; if (lastPredictedTickInst != snapshotData.Tick) { continue; } Rotation ghostRotation = ghostRotationArray[entityIndex]; Translation ghostTranslation = ghostTranslationArray[entityIndex]; ghostRotation.Value = snapshotData.GetRotationValue(deserializerState); ghostTranslation.Value = snapshotData.GetTranslationValue(deserializerState); ghostRotationArray[entityIndex] = ghostRotation; ghostTranslationArray[entityIndex] = ghostTranslation; } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { //Writeable. NativeArray <PathFinding> pathfindingArray = chunk.GetNativeArray(pathFindingComponentHandle); BufferAccessor <PathNode> pathNodeBufferAccessor = chunk.GetBufferAccessor(pathNodeBufferHandle); //Read Only. NativeArray <CurrentTarget> currentTargetArray = chunk.GetNativeArray(currentTargetComponentHandle); NativeArray <Translation> translationArray = chunk.GetNativeArray(translationComponentHandle); NativeArray <Entity> entities = chunk.GetNativeArray(entityType); //Create a copy of the grid for this thread and chunk. NativeArray2D <MapNode> gridCopy = new NativeArray2D <MapNode>(gridRef.Length0, gridRef.Length1, Allocator.Temp, NativeArrayOptions.UninitializedMemory); UnsafeUtility.MemCpy(gridCopy.GetUnsafePtr(), gridRef.GetUnsafePtrReadOnly(), gridRef.Length * sizeof(MapNode)); for (int indexInChunk = 0; indexInChunk < chunk.Count; ++indexInChunk) { //Writable. PathFinding pathfinding = pathfindingArray[indexInChunk]; DynamicBuffer <PathNode> path = pathNodeBufferAccessor[indexInChunk]; //Read Only. Entity entity = entities[indexInChunk]; CurrentTarget currentTarget = currentTargetArray[indexInChunk]; Translation translation = translationArray[indexInChunk]; bool hasPath = chunk.Has(hasPathComponentHandle); if (!pathfinding.requestedPath) { //We only want to remove our has path component if we didn't request a new one, to avoid re-adding later in the job if we find a new path. if (pathfinding.completedPath) { pathfinding.completedPath = false; ecb.RemoveComponent <HasPathTag>(chunkIndex, entity); pathfindingArray[indexInChunk] = pathfinding; } continue; } path.Clear(); pathfinding.currentIndexOnPath = 0; pathfinding.completedPath = false; pathfinding.requestedPath = false; //Calculate the closest nodes to us and our target position. //Don't search for path if we're already at our target node. pathfinding.currentNode = MapUtils.FindNearestNode(translation.Value, gridCopy); pathfinding.targetNode = MapUtils.FindNearestNode(currentTarget.targetData.targetPos, gridCopy); if (pathfinding.targetNode.Equals(pathfinding.currentNode)) { pathfindingArray[indexInChunk] = pathfinding; continue; } CalculateGridH(gridCopy, ref pathfinding); bool pathfound = SearchForPath(pathfinding.currentNode, pathfinding.targetNode, gridCopy); if (pathfound) { ConstructPath(gridCopy, ref pathfinding, ref path); if (!hasPath) { ecb.AddComponent <HasPathTag>(chunkIndex, entity); } } else if (hasPath) { ecb.RemoveComponent <HasPathTag>(chunkIndex, entity); } pathfindingArray[indexInChunk] = pathfinding; } gridCopy.Dispose(); }
public unsafe void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { float3 up = math.up(); var chunkCCData = chunk.GetNativeArray(CharacterControllerComponentType); var chunkCCInternalData = chunk.GetNativeArray(CharacterControllerInternalType); var chunkPhysicsColliderData = chunk.GetNativeArray(PhysicsColliderType); var chunkTranslationData = chunk.GetNativeArray(TranslationType); var chunkRotationData = chunk.GetNativeArray(RotationType); var hasChunkCollisionEventBufferType = chunk.Has(CollisionEventBufferType); var hasChunkTriggerEventBufferType = chunk.Has(TriggerEventBufferType); BufferAccessor <StatefulCollisionEvent> collisionEventBuffers = default; BufferAccessor <StatefulTriggerEvent> triggerEventBuffers = default; if (hasChunkCollisionEventBufferType) { collisionEventBuffers = chunk.GetBufferAccessor(CollisionEventBufferType); } if (hasChunkTriggerEventBufferType) { triggerEventBuffers = chunk.GetBufferAccessor(TriggerEventBufferType); } DeferredImpulseWriter.BeginForEachIndex(chunkIndex); for (int i = 0; i < chunk.Count; i++) { var ccComponentData = chunkCCData[i]; var ccInternalData = chunkCCInternalData[i]; var collider = chunkPhysicsColliderData[i]; var position = chunkTranslationData[i]; var rotation = chunkRotationData[i]; DynamicBuffer <StatefulCollisionEvent> collisionEventBuffer = default; DynamicBuffer <StatefulTriggerEvent> triggerEventBuffer = default; if (hasChunkCollisionEventBufferType) { collisionEventBuffer = collisionEventBuffers[i]; } if (hasChunkTriggerEventBufferType) { triggerEventBuffer = triggerEventBuffers[i]; } // Collision filter must be valid if (!collider.IsValid || collider.Value.Value.Filter.IsEmpty) { continue; } // Character step input CharacterControllerStepInput stepInput = new CharacterControllerStepInput { World = PhysicsWorld, DeltaTime = DeltaTime, Up = math.up(), Gravity = ccComponentData.Gravity, MaxIterations = ccComponentData.MaxIterations, Tau = k_DefaultTau, Damping = k_DefaultDamping, SkinWidth = ccComponentData.SkinWidth, ContactTolerance = ccComponentData.ContactTolerance, MaxSlope = ccComponentData.MaxSlope, RigidBodyIndex = PhysicsWorld.GetRigidBodyIndex(ccInternalData.Entity), CurrentVelocity = ccInternalData.LinearVelocity, MaxMovementSpeed = ccComponentData.MaxMovementSpeed }; // Character transform RigidTransform transform = new RigidTransform { pos = position.Value, rot = rotation.Value }; NativeList <StatefulCollisionEvent> currentFrameCollisionEvents = default; NativeList <StatefulTriggerEvent> currentFrameTriggerEvents = default; if (ccComponentData.RaiseCollisionEvents != 0) { currentFrameCollisionEvents = new NativeList <StatefulCollisionEvent>(Allocator.Temp); } if (ccComponentData.RaiseTriggerEvents != 0) { currentFrameTriggerEvents = new NativeList <StatefulTriggerEvent>(Allocator.Temp); } // Check support CheckSupport(ref PhysicsWorld, ref collider, stepInput, transform, out ccInternalData.SupportedState, out float3 surfaceNormal, out float3 surfaceVelocity, currentFrameCollisionEvents); // User input float3 desiredVelocity = ccInternalData.LinearVelocity; HandleUserInput(ccComponentData, stepInput.Up, surfaceVelocity, ref ccInternalData, ref desiredVelocity); // Calculate actual velocity with respect to surface if (ccInternalData.SupportedState == CharacterSupportState.Supported) { CalculateMovement(ccInternalData.CurrentRotationAngle, stepInput.Up, ccInternalData.IsJumping, ccInternalData.LinearVelocity, desiredVelocity, surfaceNormal, surfaceVelocity, out ccInternalData.LinearVelocity); } else { ccInternalData.LinearVelocity = desiredVelocity; } // World collision + integrate CollideAndIntegrate(stepInput, ccComponentData.CharacterMass, ccComponentData.AffectsPhysicsBodies != 0, collider.ColliderPtr, ref transform, ref ccInternalData.LinearVelocity, ref DeferredImpulseWriter, currentFrameCollisionEvents, currentFrameTriggerEvents); // Update collision event status if (currentFrameCollisionEvents.IsCreated) { UpdateCollisionEvents(currentFrameCollisionEvents, collisionEventBuffer); } if (currentFrameTriggerEvents.IsCreated) { UpdateTriggerEvents(currentFrameTriggerEvents, triggerEventBuffer); } // Write back and orientation integration position.Value = transform.pos; rotation.Value = quaternion.AxisAngle(up, ccInternalData.CurrentRotationAngle); // Write back to chunk data { chunkCCInternalData[i] = ccInternalData; chunkTranslationData[i] = position; chunkRotationData[i] = rotation; } } DeferredImpulseWriter.EndForEachIndex(); }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var deserializerState = new GhostDeserializerState { GhostMap = GhostMap }; var ghostEntityArray = chunk.GetNativeArray(ghostEntityType); var ghostSnapshotDataArray = chunk.GetBufferAccessor(ghostSnapshotDataType); var ghostPilotDataArray = chunk.GetNativeArray(ghostPilotDataType); var ghostLinkedEntityGroupArray = chunk.GetBufferAccessor(ghostLinkedEntityGroupType); #if UNITY_EDITOR || DEVELOPMENT_BUILD var minMaxOffset = ThreadIndex * (JobsUtility.CacheLineSize / 4); #endif for (int entityIndex = 0; entityIndex < ghostEntityArray.Length; ++entityIndex) { var snapshot = ghostSnapshotDataArray[entityIndex]; #if UNITY_EDITOR || DEVELOPMENT_BUILD var latestTick = snapshot.GetLatestTick(); if (latestTick != 0) { if (minMaxSnapshotTick[minMaxOffset] == 0 || SequenceHelpers.IsNewer(minMaxSnapshotTick[minMaxOffset], latestTick)) { minMaxSnapshotTick[minMaxOffset] = latestTick; } if (minMaxSnapshotTick[minMaxOffset + 1] == 0 || SequenceHelpers.IsNewer(latestTick, minMaxSnapshotTick[minMaxOffset + 1])) { minMaxSnapshotTick[minMaxOffset + 1] = latestTick; } } #endif // If there is no data found don't apply anything (would be default state), required for prespawned ghosts PilotSnapshotData snapshotData; if (!snapshot.GetDataAtTick(targetTick, targetTickFraction, out snapshotData)) { return; } var ghostPilotData = ghostPilotDataArray[entityIndex]; var ghostRotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value]; var ghostTranslation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value]; var ghostChild0Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value]; var ghostChild0Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value]; var ghostChild1Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value]; var ghostChild1Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value]; var ghostChild2Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][3].Value]; var ghostChild2Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][3].Value]; var ghostChild3Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][4].Value]; var ghostChild3Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][4].Value]; var ghostChild4Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][5].Value]; var ghostChild4Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][5].Value]; var ghostChild5Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][6].Value]; var ghostChild5Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][6].Value]; var ghostChild6Rotation = ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][7].Value]; var ghostChild6Translation = ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][7].Value]; ghostPilotData.PlayerId = snapshotData.GetPilotDataPlayerId(deserializerState); ghostRotation.Value = snapshotData.GetRotationValue(deserializerState); ghostTranslation.Value = snapshotData.GetTranslationValue(deserializerState); ghostChild0Rotation.Value = snapshotData.GetChild0RotationValue(deserializerState); ghostChild0Translation.Value = snapshotData.GetChild0TranslationValue(deserializerState); ghostChild1Rotation.Value = snapshotData.GetChild1RotationValue(deserializerState); ghostChild1Translation.Value = snapshotData.GetChild1TranslationValue(deserializerState); ghostChild2Rotation.Value = snapshotData.GetChild2RotationValue(deserializerState); ghostChild2Translation.Value = snapshotData.GetChild2TranslationValue(deserializerState); ghostChild3Rotation.Value = snapshotData.GetChild3RotationValue(deserializerState); ghostChild3Translation.Value = snapshotData.GetChild3TranslationValue(deserializerState); ghostChild4Rotation.Value = snapshotData.GetChild4RotationValue(deserializerState); ghostChild4Translation.Value = snapshotData.GetChild4TranslationValue(deserializerState); ghostChild5Rotation.Value = snapshotData.GetChild5RotationValue(deserializerState); ghostChild5Translation.Value = snapshotData.GetChild5TranslationValue(deserializerState); ghostChild6Rotation.Value = snapshotData.GetChild6RotationValue(deserializerState); ghostChild6Translation.Value = snapshotData.GetChild6TranslationValue(deserializerState); ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value] = ghostRotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][0].Value] = ghostTranslation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value] = ghostChild0Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][1].Value] = ghostChild0Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value] = ghostChild1Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][2].Value] = ghostChild1Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][3].Value] = ghostChild2Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][3].Value] = ghostChild2Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][4].Value] = ghostChild3Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][4].Value] = ghostChild3Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][5].Value] = ghostChild4Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][5].Value] = ghostChild4Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][6].Value] = ghostChild5Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][6].Value] = ghostChild5Translation; ghostRotationFromEntity[ghostLinkedEntityGroupArray[entityIndex][7].Value] = ghostChild6Rotation; ghostTranslationFromEntity[ghostLinkedEntityGroupArray[entityIndex][7].Value] = ghostChild6Translation; ghostPilotDataArray[entityIndex] = ghostPilotData; } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { BuildMeshProfiler.Begin(); var dimensions = chunk.GetNativeArray(DimensionType); var vertexBuffer = chunk.GetBufferAccessor(VertexType); var triangleBuffer = chunk.GetBufferAccessor(TriangleType); var colors = chunk.GetNativeArray(ColorType); var entities = chunk.GetNativeArray(EntityType); var spriteData = chunk.GetNativeArray(SpriteDataType); var resolutions = chunk.GetNativeArray(SpriteResType); for (int i = 0; i < chunk.Count; i++) { var dimension = dimensions[i]; var indices = triangleBuffer[i]; var vertices = vertexBuffer[i]; var color = colors[i].Value.ToNormalizedFloat4(); var entity = entities[i]; var spriteInfo = spriteData[i]; var resolution = resolutions[i].Value; var spriteScale = (float2)(dimension.Value) / resolution; indices.Clear(); vertices.Clear(); var right = new float3(1, 0, 0); var extents = dimension.Extents(); var outer = spriteInfo.OuterUV; var padding = spriteInfo.Padding; var bl = -extents; var spriteW = dimension.Width(); var spriteH = dimension.Height(); var pixelAdjustments = new float4( (padding.x * spriteScale.x) / spriteW, (padding.y * spriteScale.y) / spriteH, (spriteW - padding.z * spriteScale.x) / spriteW, (spriteH - padding.w * spriteScale.y) / spriteH ); var pixelYAdjust = spriteScale.y * 1.5f; var topAdjust = spriteScale.y * (padding.w > 0 ? 1f : 0f); var bottomAdjust = spriteScale.y * (padding.y > 0 ? 1f : 0f); var v = new float4( bl.x + spriteW * pixelAdjustments.x, (bl.y + spriteH * pixelAdjustments.y) + bottomAdjust, bl.x + spriteW * pixelAdjustments.z, (bl.y + spriteH * pixelAdjustments.w) - topAdjust ); vertices.Add(new MeshVertexData { Position = new float3(v.xy, 0), Normal = right, Color = color, UV1 = outer.xy, UV2 = new float2(1) }); vertices.Add(new MeshVertexData { Position = new float3(v.xw, 0), Normal = right, Color = color, UV1 = outer.xw, UV2 = new float2(1) }); vertices.Add(new MeshVertexData { Position = new float3(v.zw, 0), Normal = right, Color = color, UV1 = outer.zw, UV2 = new float2(1) }); vertices.Add(new MeshVertexData { Position = new float3(v.zy, 0), Normal = right, Color = color, UV1 = outer.zy, UV2 = new float2(1) }); // TODO: Figure this out mathematically instead of hard coding // batched meshes need to be figured out and rebuilt... indices.Add(new TriangleIndexElement { Value = 0 }); indices.Add(new TriangleIndexElement { Value = 1 }); indices.Add(new TriangleIndexElement { Value = 2 }); indices.Add(new TriangleIndexElement { Value = 0 }); indices.Add(new TriangleIndexElement { Value = 2 }); indices.Add(new TriangleIndexElement { Value = 3 }); CmdBuffer.AddComponent <CachedMeshTag>(entity.Index, entity); } BuildMeshProfiler.End(); }