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, ¶m, 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 )); }
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); } }
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, ¶m, 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) )); }
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(¶m, 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; }