Example #1
0
            public unsafe void Execute(DynamicComponentTypeHandle *ghostChunkComponentTypesPtr,
                                       int ghostChunkComponentTypesLength)
            {
                var writer = NetDriver.BeginSend(UnreliablePipeline, ConnectionFromEntity[ConnectionEntity].Value,
                                                 GlobalConstants.TargetPacketSize);

                WriteHeader(ref writer, AckFromEntity[ConnectionEntity]);

                var lenWriter = writer;

                writer.WriteUInt(0);
                writer.WriteUInt(0);

                // 销毁的entity
                uint despawnLen = 0;
                uint updateLen  = 0;

                despawnLen = SerializeDespawnEntities(ref writer, DespawnChunks);

                if (writer.HasFailedWrites)
                {
                    NetDriver.AbortSend(writer);
                    throw new InvalidOperationException("单个快照中无法包含所有需要销毁的GhostId!");
                }

                updateLen = SerializeEntities(ref writer, GhostChunks, default, ghostChunkComponentTypesPtr,
Example #2
0
            internal unsafe int ProcessPipelineSend(NetworkDriver.Concurrent driver, int startStage, NetworkPipeline pipeline, NetworkConnection connection,
                                                    NetworkInterfaceSendHandle sendHandle, int headerSize, NativeList <UpdatePipeline> currentUpdates)
            {
                int retval = sendHandle.size;
                NetworkPipelineContext ctx = default(NetworkPipelineContext);

                ctx.timestamp = m_timestamp[0];
                var p            = m_Pipelines[pipeline.Id - 1];
                var connectionId = connection.m_NetworkId;

                var resumeQ      = new NativeList <int>(16, Allocator.Temp);
                int resumeQStart = 0;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                if (headerSize != p.headerCapacity + UnsafeUtility.SizeOf <UdpCHeader>() + 1 && sendHandle.data != IntPtr.Zero)
                {
                    throw new InvalidOperationException("Invalid header size.");
                }
#endif
                var inboundBuffer = default(InboundSendBuffer);
                if (sendHandle.data != IntPtr.Zero)
                {
                    inboundBuffer.bufferWithHeaders       = (byte *)sendHandle.data + UnsafeUtility.SizeOf <UdpCHeader>() + 1;
                    inboundBuffer.bufferWithHeadersLength = sendHandle.size - UnsafeUtility.SizeOf <UdpCHeader>() - 1;
                    inboundBuffer.buffer       = inboundBuffer.bufferWithHeaders + p.headerCapacity;
                    inboundBuffer.bufferLength = inboundBuffer.bufferWithHeadersLength - p.headerCapacity;
                }

                while (true)
                {
                    headerSize = p.headerCapacity;

                    int internalBufferOffset       = p.sendBufferOffset + sizePerConnection[SendSizeOffset] * connectionId;
                    int internalSharedBufferOffset = p.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connectionId;

                    bool needsUpdate = false;
                    // If this is not the first stage we need to fast forward the buffer offset to the correct place
                    if (startStage > 0)
                    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (inboundBuffer.bufferWithHeadersLength > 0)
                        {
                            throw new InvalidOperationException("Can't start from a stage with a buffer");
                        }
#endif
                        for (int i = 0; i < startStage; ++i)
                        {
                            internalBufferOffset       += (m_StageCollection[m_StageList[p.FirstStageIndex + i]].SendCapacity + AlignmentMinusOne) & (~AlignmentMinusOne);
                            internalSharedBufferOffset += (m_StageCollection[m_StageList[p.FirstStageIndex + i]].SharedStateCapacity + AlignmentMinusOne) & (~AlignmentMinusOne);
                            headerSize -= m_StageCollection[m_StageList[p.FirstStageIndex + i]].HeaderCapacity;
                        }
                    }

                    for (int i = startStage; i < p.NumStages; ++i)
                    {
                        int stageHeaderCapacity = m_StageCollection[m_StageList[p.FirstStageIndex + i]].HeaderCapacity;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (stageHeaderCapacity > headerSize)
                        {
                            throw new InvalidOperationException("Not enough header space");
                        }
#endif
                        inboundBuffer.headerPadding = headerSize;
                        headerSize -= stageHeaderCapacity;
                        if (stageHeaderCapacity > 0 && inboundBuffer.bufferWithHeadersLength > 0)
                        {
                            var headerArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(inboundBuffer.bufferWithHeaders + headerSize, stageHeaderCapacity, Allocator.Invalid);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref headerArray, AtomicSafetyHandle.GetTempMemoryHandle());
#endif
                            ctx.header = new DataStreamWriter(headerArray);
                        }
                        else
                        {
                            ctx.header = new DataStreamWriter(stageHeaderCapacity, Allocator.Temp);
                        }
                        var prevInbound = inboundBuffer;
                        ProcessSendStage(i, internalBufferOffset, internalSharedBufferOffset, p, ref resumeQ, ref ctx, ref inboundBuffer, ref needsUpdate);

                        if (needsUpdate)
                        {
                            AddSendUpdate(connection, i, pipeline, currentUpdates);
                        }
                        if (inboundBuffer.bufferWithHeadersLength == 0)
                        {
                            break;
                        }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (inboundBuffer.headerPadding != prevInbound.headerPadding)
                        {
                            throw new InvalidOperationException("Changing the header padding in a pipeline is not supported");
                        }
#endif
                        if (inboundBuffer.buffer != prevInbound.buffer)
                        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            if (inboundBuffer.buffer != inboundBuffer.bufferWithHeaders + inboundBuffer.headerPadding ||
                                inboundBuffer.bufferLength + inboundBuffer.headerPadding > inboundBuffer.bufferWithHeadersLength)
                            {
                                throw new InvalidOperationException("When creating an internal buffer in piplines the buffer must be a subset of the buffer width headers");
                            }
#endif

                            // Copy header to new buffer so it is part of the payload
                            UnsafeUtility.MemCpy(inboundBuffer.bufferWithHeaders + headerSize, ctx.header.AsNativeArray().GetUnsafeReadOnlyPtr(), ctx.header.Length);
                        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        else
                        {
                            if (inboundBuffer.bufferWithHeaders != prevInbound.bufferWithHeaders)
                            {
                                throw new InvalidOperationException("Changing the send buffer with headers without changing the buffer is not supported");
                            }
                        }
#endif
                        if (ctx.header.Length < stageHeaderCapacity)
                        {
                            int wastedSpace = stageHeaderCapacity - ctx.header.Length;
                            // Remove wasted space in the header
                            UnsafeUtility.MemMove(inboundBuffer.buffer - wastedSpace, inboundBuffer.buffer, inboundBuffer.bufferLength);
                        }

                        // Update the inbound buffer for next iteration
                        inboundBuffer.buffer       = inboundBuffer.bufferWithHeaders + headerSize;
                        inboundBuffer.bufferLength = ctx.header.Length + inboundBuffer.bufferLength;


                        needsUpdate = false;

                        internalBufferOffset       += (ctx.internalProcessBufferLength + AlignmentMinusOne) & (~AlignmentMinusOne);
                        internalSharedBufferOffset += (ctx.internalSharedProcessBufferLength + AlignmentMinusOne) & (~AlignmentMinusOne);
                    }

                    if (inboundBuffer.bufferLength != 0)
                    {
                        if (sendHandle.data != IntPtr.Zero && inboundBuffer.bufferWithHeaders == (byte *)sendHandle.data + UnsafeUtility.SizeOf <UdpCHeader>() + 1)
                        {
                            // Actually send the data - after collapsing it again
                            if (inboundBuffer.buffer != inboundBuffer.bufferWithHeaders)
                            {
                                UnsafeUtility.MemMove(inboundBuffer.bufferWithHeaders, inboundBuffer.buffer, inboundBuffer.bufferLength);
                                inboundBuffer.buffer = inboundBuffer.bufferWithHeaders;
                            }
                            ((byte *)sendHandle.data)[UnsafeUtility.SizeOf <UdpCHeader>()] = (byte)pipeline.Id;
                            int sendSize = UnsafeUtility.SizeOf <UdpCHeader>() + 1 + inboundBuffer.bufferLength;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            if (sendSize > sendHandle.size)
                            {
                                throw new InvalidOperationException("Pipeline increased the data in the buffer, this is not allowed");
                            }
#endif
                            sendHandle.size = sendSize;
                            retval          = driver.CompleteSend(connection, sendHandle);
                            sendHandle      = default;
                        }
                        else
                        {
                            // Sending without pipeline, the correct pipeline will be added by the default flags when this is called
                            var writer = driver.BeginSend(connection);
                            writer.WriteByte((byte)pipeline.Id);
                            writer.WriteBytes(inboundBuffer.buffer, inboundBuffer.bufferLength);
                            if (writer.HasFailedWrites)
                            {
                                driver.AbortSend(writer);
                            }
                            else
                            {
                                driver.EndSend(writer);
                            }
                        }
                    }

                    if (resumeQStart >= resumeQ.Length)
                    {
                        break;
                    }

                    startStage = resumeQ[resumeQStart++];

                    inboundBuffer = default(InboundSendBuffer);
                }
                if (sendHandle.data != IntPtr.Zero)
                {
                    driver.AbortSend(sendHandle);
                }
                return(retval);
            }