public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex, DynamicComponentTypeHandle *ghostChunkComponentTypesPtr, int ghostChunkComponentTypesLength) { 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; 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; #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; } dataSize += PredictionBackupState.GetDataSize(GhostComponentCollection[compIdx].ComponentSize, chunk.Capacity); } // Chunk does not exist in the history, or has changed ghost type in which case we need to create a new one state = (System.IntPtr)UnsafeUtility.Malloc(headerSize + entitySize + dataSize, 16, Allocator.Persistent); newPredictionState.Enqueue(new PredictionStateEntry { chunk = chunk, data = state }); (*(PredictionBackupState *)state).ghostType = ghostTypeId; (*(PredictionBackupState *)state).entityCapacity = chunk.Capacity; } else { stillUsedPredictionState.TryAdd(chunk, 1); } Entity *entities = PredictionBackupState.GetEntities(state, headerSize); 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, 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(); UnsafeUtility.MemCpy(dataPtr, compData, chunk.Count * compSize); } else { UnsafeUtility.MemClear(dataPtr, chunk.Count * compSize); } 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; 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).GetUnsafePtr(); UnsafeUtility.MemCpy(dataPtr + ent * compSize, compData + childChunk.index * compSize, compSize); } else { UnsafeUtility.MemClear(dataPtr + ent * compSize, compSize); } } 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]) { SmoothComponent(compData + compSize * ent, dataPtr + compSize * ent, GhostComponentCollection[compIdx].ComponentType); } } } 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(); SmoothComponent(compData + compSize * childChunk.index, dataPtr + compSize * ent, GhostComponentCollection[compIdx].ComponentType); } } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } } }
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, DynamicComponentTypeHandle *userTypes, int userTypesLength) { if (!predictionState.TryGetValue(chunk, out var state) || (*(PredictionBackupState *)state).entityCapacity != chunk.Capacity) { return; } 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 headerSize = PredictionBackupState.GetHeaderSize(); var entitySize = PredictionBackupState.GetEntitiesSize(chunk.Capacity, out var singleEntitySize); Entity *backupEntities = PredictionBackupState.GetEntities(state); var entities = chunk.GetNativeArray(entityType); var predictedGhostComponents = chunk.GetNativeArray(predictedGhostType); int numBaseComponents = typeData.NumComponents - typeData.NumChildComponents; int baseOffset = typeData.FirstComponent; var actions = new NativeList <SmoothingActionState>(Allocator.Temp); var childActions = new NativeList <SmoothingActionState>(Allocator.Temp); int backupOffset = headerSize + entitySize; // todo: this loop could be cached on chunk.capacity, because now we are re-calculating it everytime. for (int comp = 0; comp < typeData.NumComponents; ++comp) { int index = baseOffset + comp; int compIdx = GhostComponentIndex[index].ComponentIndex; int serializerIdx = GhostComponentIndex[index].SerializerIndex; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (compIdx >= ghostChunkComponentTypesLength) { throw new System.InvalidOperationException("Component index out of range"); } #endif if ((GhostComponentIndex[index].SendMask & requiredSendMask) == 0) { continue; } if (GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { backupOffset += PredictionBackupState.GetDataSize(GhostSystemConstants.DynamicBufferComponentSnapshotSize, chunk.Capacity); continue; } var compSize = GhostComponentCollection[serializerIdx].ComponentSize; if (smoothingActions.TryGetValue(GhostComponentCollection[serializerIdx].ComponentType, out var action)) { action.compIndex = compIdx; action.compSize = compSize; action.serializerIndex = serializerIdx; action.entityIndex = GhostComponentIndex[index].EntityIndex; action.compBackupOffset = backupOffset; if (comp < numBaseComponents) { actions.Add(action); } else { childActions.Add(action); } } backupOffset += PredictionBackupState.GetDataSize(compSize, chunk.Capacity); } foreach (var action in actions) { if (chunk.Has(ghostChunkComponentTypesPtr[action.compIndex])) { 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]) { continue; } var compData = (byte *)chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[action.compIndex], action.compSize).GetUnsafePtr(); void *usrDataPtr = null; if (action.userTypeId >= 0 && chunk.Has(userTypes[action.userTypeId])) { var usrData = (byte *)chunk.GetDynamicComponentDataArrayReinterpret <byte>(userTypes[action.userTypeId], action.userTypeSize).GetUnsafeReadOnlyPtr(); usrDataPtr = usrData + action.userTypeSize * ent; } byte *dataPtr = ((byte *)state) + action.compBackupOffset; action.action.Ptr.Invoke(compData + action.compSize * ent, dataPtr + action.compSize * ent, usrDataPtr); } } } var linkedEntityGroupAccessor = chunk.GetBufferAccessor(linkedEntityGroupType); foreach (var action in childActions) { 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[action.entityIndex].Value, out var childChunk) && childChunk.chunk.Has(ghostChunkComponentTypesPtr[action.compIndex])) { var compData = (byte *)childChunk.chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[action.compIndex], action.compSize).GetUnsafePtr(); void *usrDataPtr = null; if (action.userTypeId >= 0 && chunk.Has(userTypes[action.userTypeId])) { var usrData = (byte *)chunk.GetDynamicComponentDataArrayReinterpret <byte>(userTypes[action.userTypeId], action.userTypeSize).GetUnsafeReadOnlyPtr(); usrDataPtr = usrData + action.userTypeSize * ent; } byte *dataPtr = ((byte *)state) + action.compBackupOffset; action.action.Ptr.Invoke(compData + action.compSize * childChunk.index, dataPtr + action.compSize * ent, usrDataPtr); } } } }
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 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]; int baseOffset = typeData.FirstComponent; Entity *backupEntities = PredictionBackupState.GetEntities(state); var entities = chunk.GetNativeArray(entityType); var predictedGhostComponents = chunk.GetNativeArray(predictedGhostType); byte *dataPtr = PredictionBackupState.GetData(state); int numBaseComponents = typeData.NumComponents - typeData.NumChildComponents; 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])) { if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { 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[serializerIdx].ReportPredictionErrors.Ptr.Invoke((System.IntPtr)(compData + compSize * ent), (System.IntPtr)(dataPtr + compSize * ent), ref errors); } } } else { //FIXME Buffers need to report error for the size and an aggregate for each element in the buffer } } 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 compSize = GhostComponentCollection[serializerIdx].ComponentType.IsBuffer ? GhostSystemConstants.DynamicBufferComponentSnapshotSize : GhostComponentCollection[serializerIdx].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])) { if (!GhostComponentCollection[serializerIdx].ComponentType.IsBuffer) { var compData = (byte *)childChunk.chunk.GetDynamicComponentDataArrayReinterpret <byte>(ghostChunkComponentTypesPtr[compIdx], compSize).GetUnsafeReadOnlyPtr(); int errorIndex = GhostComponentIndex[baseOffset + comp].PredictionErrorBaseIndex; var errors = new UnsafeList <float>(((float *)predictionErrors.GetUnsafePtr()) + errorIndex + ThreadIndex * numPredictionErrors, numPredictionErrors - errorIndex); GhostComponentCollection[serializerIdx].ReportPredictionErrors.Ptr.Invoke((System.IntPtr)(compData + compSize * childChunk.index), (System.IntPtr)(dataPtr + compSize * ent), ref errors); } else { //FIXME Buffers need to report error for the size and an aggregate for each element in the buffer } } } dataPtr = PredictionBackupState.GetNextData(dataPtr, compSize, chunk.Capacity); } } }