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);
                    }
                }
            }
Example #2
0
            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);
                    }
                }
            }
Example #3
0
            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);
                    }
                }
            }
Example #4
0
            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);
                        }
                    }
                }
            }
Example #5
0
            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);
                    }
                }
            }