public NetworkPipelineStage StaticInitialize(byte *staticInstanceBuffer, int staticInstanceBufferLength, INetworkParameter[] netParams)
 {
     ReliableUtility.Parameters param = default;
     foreach (var netParam in netParams)
     {
         if (netParam.GetType() == typeof(ReliableUtility.Parameters))
         {
             param = (ReliableUtility.Parameters)netParam;
         }
     }
     if (param.WindowSize == 0)
     {
         param = new ReliableUtility.Parameters {
             WindowSize = ReliableUtility.ParameterConstants.WindowSize
         }
     }
     ;
     if (param.WindowSize <= 0 || param.WindowSize > 32)
     {
         throw new System.ArgumentOutOfRangeException("The reliability pipeline does not support negative WindowSize nor WindowSizes larger than 32");
     }
     UnsafeUtility.MemCpy(staticInstanceBuffer, &param, UnsafeUtility.SizeOf <ReliableUtility.Parameters>());
     return(new NetworkPipelineStage(
                Receive: ReceiveFunctionPointer,
                Send: SendFunctionPointer,
                InitializeConnection: InitializeConnectionFunctionPointer,
                ReceiveCapacity: ReliableUtility.ProcessCapacityNeeded(param),
                SendCapacity: ReliableUtility.ProcessCapacityNeeded(param),
                HeaderCapacity: UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>(),
                SharedStateCapacity: ReliableUtility.SharedCapacityNeeded(param),
                NetworkParameterConstants.MTU
                ));
 }
Exemple #2
0
    static unsafe void GatherExtraStats(NativeArray <byte> sendBuffer, NativeArray <byte> sharedBuffer, long timestamp, ref int usedCount, ref int oldestAge, ref int maxRtt, ref int maxProcessingTime)
    {
        var ptr    = (byte *)sendBuffer.GetUnsafePtr();
        var ctx    = (ReliableUtility.Context *)ptr;
        var shared = (ReliableUtility.SharedContext *)sharedBuffer.GetUnsafePtr();

        for (int i = 0; i < shared->WindowSize; i++)
        {
            var seqId = (int *)(ptr + ctx->IndexPtrOffset + i * ctx->IndexStride);
            if (*seqId != -1)
            {
                usedCount++;
                var packetInfo = ReliableUtility.GetPacketInformation((byte *)sendBuffer.GetUnsafeReadOnlyPtr(), *seqId);
                oldestAge = Math.Max(oldestAge, (int)(timestamp - packetInfo->SendTime));
            }

            var timingData = ReliableUtility.GetLocalPacketTimer((byte *)sharedBuffer.GetUnsafeReadOnlyPtr(), (ushort)i);
            if (timingData->SentTime > 0 && timingData->ReceiveTime > 0)
            {
                maxRtt = Math.Max(maxRtt, (int)(timingData->ReceiveTime - timingData->SentTime - timingData->ProcessingTime));
            }

            maxProcessingTime = Math.Max(maxProcessingTime, timingData->ProcessingTime);
        }
    }
Exemple #3
0
 public NetworkPipelineStage StaticInitialize(byte *staticInstanceBuffer, int staticInstanceBufferLength, INetworkParameter[] netParams)
 {
     ReliableUtility.Parameters param = default;
     foreach (var netParam in netParams)
     {
         if (netParam.GetType() == typeof(ReliableUtility.Parameters))
         {
             param = (ReliableUtility.Parameters)netParam;
         }
     }
     if (param.WindowSize == 0)
     {
         param = new ReliableUtility.Parameters {
             WindowSize = ReliableUtility.ParameterConstants.WindowSize
         }
     }
     ;
     UnsafeUtility.MemCpy(staticInstanceBuffer, &param, UnsafeUtility.SizeOf <ReliableUtility.Parameters>());
     return(new NetworkPipelineStage(
                Receive: ReceiveFunctionPointer,
                Send: SendFunctionPointer,
                InitializeConnection: InitializeConnectionFunctionPointer,
                ReceiveCapacity: ReliableUtility.ProcessCapacityNeeded(param),
                SendCapacity: ReliableUtility.ProcessCapacityNeeded(param),
                HeaderCapacity: UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>(),
                SharedStateCapacity: ReliableUtility.SharedCapacityNeeded(param)
                ));
 }
Exemple #4
0
        private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            // Request an update to see if a queued packet needs to be resent later or if an ack packet should be sent
            requests = NetworkPipelineStage.Requests.Update;
            bool needsResume = false;

            var header   = new ReliableUtility.PacketHeader();
            var reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer;

            needsResume = ReliableUtility.ReleaseOrResumePackets(ctx);
            if (needsResume)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }

            if (inboundBuffer.bufferLength > 0)
            {
                reliable->LastSentTime = ctx.timestamp;

                ReliableUtility.Write(ctx, inboundBuffer, ref header);
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                if (reliable->Resume != ReliableUtility.NullEntry)
                {
                    requests |= NetworkPipelineStage.Requests.Resume;
                }

                reliable->PreviousTimestamp = ctx.timestamp;
                return;
            }

            if (reliable->Resume != ReliableUtility.NullEntry)
            {
                reliable->LastSentTime = ctx.timestamp;
                inboundBuffer          = ReliableUtility.ResumeSend(ctx, out header, ref needsResume);
                if (needsResume)
                {
                    requests |= NetworkPipelineStage.Requests.Resume;
                }
                ctx.header.Clear();
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                reliable->PreviousTimestamp = ctx.timestamp;
                return;
            }

            if (ReliableUtility.ShouldSendAck(ctx))
            {
                reliable->LastSentTime = ctx.timestamp;

                ReliableUtility.WriteAckPacket(ctx, ref header);
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                reliable->PreviousTimestamp = ctx.timestamp;

                // TODO: Sending dummy byte over since the pipeline won't send an empty payload (ignored on receive)
                inboundBuffer.bufferWithHeadersLength = inboundBuffer.headerPadding + 1;
                inboundBuffer.bufferWithHeaders       = (byte *)UnsafeUtility.Malloc(inboundBuffer.bufferWithHeadersLength, 8, Allocator.Temp);
                inboundBuffer.SetBufferFrombufferWithHeaders();
                return;
            }
            reliable->PreviousTimestamp = ctx.timestamp;
        }
 public void InitializeConnection(NativeSlice <byte> sendProcessBuffer, NativeSlice <byte> recvProcessBuffer,
                                  NativeSlice <byte> sharedProcessBuffer)
 {
     if (sharedProcessBuffer.Length >= ReliableUtility.SharedCapacityNeeded(m_ReliableParams) &&
         (sendProcessBuffer.Length + recvProcessBuffer.Length) >= ReliableUtility.ProcessCapacityNeeded(m_ReliableParams) * 2)
     {
         ReliableUtility.InitializeContext(sharedProcessBuffer, sendProcessBuffer, recvProcessBuffer, m_ReliableParams);
     }
 }
        public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
        {
            // Request an update to see if a queued packet needs to be resent later or if an ack packet should be sent
            needsUpdate = true;

            var header = new ReliableUtility.PacketHeader();

            unsafe
            {
                var reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer.GetUnsafePtr();

                needsResume = ReliableUtility.ReleaseOrResumePackets(ctx);

                if (inboundBuffer.buffer1.Length > 0)
                {
                    reliable->LastSentTime = ctx.timestamp;

                    ReliableUtility.Write(ctx, inboundBuffer, ref header);
                    ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                    if (reliable->Resume != ReliableUtility.NullEntry)
                    {
                        needsResume = true;
                    }

                    reliable->PreviousTimestamp = ctx.timestamp;
                    return(inboundBuffer);
                }

                if (reliable->Resume != ReliableUtility.NullEntry)
                {
                    reliable->LastSentTime = ctx.timestamp;
                    var slice = ReliableUtility.ResumeSend(ctx, out header, ref needsResume);
                    ctx.header.Clear();
                    ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                    inboundBuffer.buffer1       = slice;
                    inboundBuffer.buffer2       = default(NativeSlice <byte>);
                    reliable->PreviousTimestamp = ctx.timestamp;
                    return(inboundBuffer);
                }

                if (ReliableUtility.ShouldSendAck(ctx))
                {
                    reliable->LastSentTime = ctx.timestamp;

                    ReliableUtility.WriteAckPacket(ctx, ref header);
                    ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                    reliable->PreviousTimestamp = ctx.timestamp;

                    // TODO: Sending dummy byte over since the pipeline won't send an empty payload (ignored on receive)
                    inboundBuffer.buffer1 = new NativeSlice <byte>(ctx.internalProcessBuffer, 0, 1);
                    return(inboundBuffer);
                }
                reliable->PreviousTimestamp = ctx.timestamp;
                return(inboundBuffer);
            }
        }
 private static void InitializeConnection(byte *staticInstanceBuffer, int staticInstanceBufferLength,
                                          byte *sendProcessBuffer, int sendProcessBufferLength, byte *recvProcessBuffer, int recvProcessBufferLength,
                                          byte *sharedProcessBuffer, int sharedProcessBufferLength)
 {
     ReliableUtility.Parameters param;
     UnsafeUtility.MemCpy(&param, staticInstanceBuffer, UnsafeUtility.SizeOf <ReliableUtility.Parameters>());
     if (sharedProcessBufferLength >= ReliableUtility.SharedCapacityNeeded(param) &&
         (sendProcessBufferLength + recvProcessBufferLength) >= ReliableUtility.ProcessCapacityNeeded(param) * 2)
     {
         ReliableUtility.InitializeContext(sharedProcessBuffer, sharedProcessBufferLength, sendProcessBuffer, sendProcessBufferLength, recvProcessBuffer, recvProcessBufferLength, param);
     }
 }
        public NativeSlice <byte> Receive(NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            needsResume = false;
            // Request a send update to see if a queued packet needs to be resent later or if an ack packet should be sent
            needsSendUpdate = true;

            var context = default(DataStreamReader.Context);
            var header  = default(ReliableUtility.PacketHeader);
            var slice   = default(NativeSlice <byte>);

            unsafe
            {
                ReliableUtility.Context *      reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer.GetUnsafePtr();
                ReliableUtility.SharedContext *shared   = (ReliableUtility.SharedContext *)ctx.internalSharedProcessBuffer.GetUnsafePtr();
                shared->errorCode = 0;
                if (reliable->Resume == ReliableUtility.NullEntry)
                {
                    if (inboundBuffer.Length <= 0)
                    {
                        return(slice);
                    }
                    var reader = new DataStreamReader(inboundBuffer);
                    reader.ReadBytes(ref context, (byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                    if (header.Type == (ushort)ReliableUtility.PacketType.Ack)
                    {
                        ReliableUtility.ReadAckPacket(ctx, header);
                        inboundBuffer = new NativeSlice <byte>();
                        return(inboundBuffer);
                    }

                    var result = ReliableUtility.Read(ctx, header);

                    if (result >= 0)
                    {
                        var nextExpectedSequenceId = (ushort)(reliable->Delivered + 1);
                        if (result == nextExpectedSequenceId)
                        {
                            reliable->Delivered = result;
                            slice = inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                            if (needsResume = SequenceHelpers.GreaterThan16((ushort)shared->ReceivedPackets.Sequence,
                                                                            (ushort)result))
                            {
                                reliable->Resume = (ushort)(result + 1);
                            }
                        }
                        else
                        {
                            ReliableUtility.SetPacket(ctx.internalProcessBuffer, result, inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>()));
                            slice = ReliableUtility.ResumeReceive(ctx, reliable->Delivered + 1, ref needsResume);
                        }
                    }
                }
                else
                {
                    slice = ReliableUtility.ResumeReceive(ctx, reliable->Resume, ref needsResume);
                }
            }
            return(slice);
        }
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            // Request a send update to see if a queued packet needs to be resent later or if an ack packet should be sent
            requests = NetworkPipelineStage.Requests.SendUpdate;
            bool needsResume = false;

            var header = default(ReliableUtility.PacketHeader);
            var slice  = default(InboundRecvBuffer);

            ReliableUtility.Context *      reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer;
            ReliableUtility.SharedContext *shared   = (ReliableUtility.SharedContext *)ctx.internalSharedProcessBuffer;
            shared->errorCode = 0;
            if (reliable->Resume == ReliableUtility.NullEntry)
            {
                if (inboundBuffer.bufferLength <= 0)
                {
                    inboundBuffer = slice;
                    return;
                }
                var inboundArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(inboundBuffer.buffer, inboundBuffer.bufferLength, Allocator.Invalid);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                var safetyHandle = AtomicSafetyHandle.GetTempMemoryHandle();
                NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref inboundArray, safetyHandle);
#endif
                var reader = new DataStreamReader(inboundArray);
                reader.ReadBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                if (header.Type == (ushort)ReliableUtility.PacketType.Ack)
                {
                    ReliableUtility.ReadAckPacket(ctx, header);
                    inboundBuffer = default;
                    return;
                }

                var result = ReliableUtility.Read(ctx, header);

                if (result >= 0)
                {
                    var nextExpectedSequenceId = (ushort)(reliable->Delivered + 1);
                    if (result == nextExpectedSequenceId)
                    {
                        reliable->Delivered = result;
                        slice = inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                        if (needsResume = SequenceHelpers.GreaterThan16((ushort)shared->ReceivedPackets.Sequence,
                                                                        (ushort)result))
                        {
                            reliable->Resume = (ushort)(result + 1);
                        }
                    }
                    else
                    {
                        ReliableUtility.SetPacket(ctx.internalProcessBuffer, result, inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>()));
                        slice = ReliableUtility.ResumeReceive(ctx, reliable->Delivered + 1, ref needsResume);
                    }
                }
            }
            else
            {
                slice = ReliableUtility.ResumeReceive(ctx, reliable->Resume, ref needsResume);
            }
            if (needsResume)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }
            inboundBuffer = slice;
        }