/// <summary> /// Store the packet for possible later resends, and fill in the header we'll use to send it (populate with /// sequence ID, last acknowledged ID from remote with ackmask. /// </summary> /// <param name="context">Pipeline context, the reliability shared state is used here.</param> /// <param name="inboundBuffer">Buffer with packet data.</param> /// <param name="header">Packet header which will be populated.</param> /// <returns>Sequence ID assigned to this packet.</returns> public static unsafe int Write(NetworkPipelineContext context, InboundBufferVec inboundBuffer, ref PacketHeader header) { SharedContext *reliable = (SharedContext *)context.internalSharedProcessBuffer.GetUnsafePtr(); var sequence = (ushort)reliable->SentPackets.Sequence; if (!TryAquire(context.internalProcessBuffer, sequence)) { reliable->errorCode = ErrorCodes.OutgoingQueueIsFull; return((int)ErrorCodes.OutgoingQueueIsFull); } reliable->stats.PacketsSent++; header.SequenceId = sequence; header.AckedSequenceId = (ushort)reliable->ReceivedPackets.Sequence; header.AckMask = reliable->ReceivedPackets.AckMask; reliable->ReceivedPackets.Acked = reliable->ReceivedPackets.Sequence; // Attach our processing time of the packet we're acknowledging (time between receiving it and sending this ack) header.ProcessingTime = CalculateProcessingTime(context.internalSharedProcessBuffer, header.AckedSequenceId, context.timestamp); reliable->SentPackets.Sequence = (ushort)(reliable->SentPackets.Sequence + 1); SetHeaderAndPacket(context.internalProcessBuffer, sequence, header, inboundBuffer, context.timestamp); StoreTimestamp(context.internalSharedProcessBuffer, sequence, context.timestamp); return(sequence); }
public unsafe bool DelayPacket(ref NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsUpdate, long timestamp) { // Find empty slot in bookkeeping data space to track this packet int packetPayloadOffset = 0; int packetDataOffset = 0; var processBufferPtr = (byte*) ctx.internalProcessBuffer.GetUnsafePtr(); bool foundSlot = GetEmptyDataSlot(processBufferPtr, ref packetPayloadOffset, ref packetDataOffset); if (!foundSlot) { //UnityEngine.Debug.LogWarning("No space left for delaying packet (" + m_PacketCount + " packets in queue)"); return false; } NativeSlice<byte> packetPayload = new NativeSlice<byte>(ctx.internalProcessBuffer, packetPayloadOffset, inboundBuffer.buffer1.Length + inboundBuffer.buffer2.Length); StorePacketPayload(packetPayload, inboundBuffer.buffer1, inboundBuffer.buffer2); // Add tracking for this packet so we can resurrect later DelayedPacket packet; packet.delayUntil = timestamp + m_PacketDelayMs; packet.processBufferOffset = packetPayloadOffset; packet.packetSize = inboundBuffer.buffer1.Length + inboundBuffer.buffer2.Length; byte* packetPtr = (byte*) &packet; UnsafeUtility.MemCpy(processBufferPtr + packetDataOffset, packetPtr, UnsafeUtility.SizeOf<DelayedPacket>()); // Schedule an update call so packet can be resurrected later needsUpdate = true; return true; }
public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate) { var len1 = inboundBuffer.buffer1.Length; var len2 = inboundBuffer.buffer2.Length; for (int i = 0; i < len1; ++i) { ctx.internalProcessBuffer[i] = (byte)(inboundBuffer.buffer1[i] ^ 0xff); } for (int i = 0; i < len2; ++i) { ctx.internalProcessBuffer[len1 + i] = (byte)(inboundBuffer.buffer2[i] ^ 0xff); } var nextInbound = default(InboundBufferVec); nextInbound.buffer1 = new NativeSlice <byte>(ctx.internalProcessBuffer, 0, len1 + len2); return(nextInbound); }
public unsafe InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate) { var sendData = (int *)ctx.internalProcessBuffer.GetUnsafePtr(); for (int i = 1; i <= 3; ++i) { Assert.AreEqual(*sendData, i * 10); sendData++; } var sharedData = (int *)ctx.internalSharedProcessBuffer.GetUnsafePtr(); for (int i = 7; i <= 8; ++i) { Assert.AreEqual(*sharedData, i * 10); sharedData++; } return(inboundBuffer); }
public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate) { ctx.header.Write((int)2); return(inboundBuffer); }
public InboundBufferVec InvokeSend(int pipelineStageId, NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate) { switch (pipelineStageId) { case 0: return(testPipelineStageWithHeader.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 1: return(testEncryptPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 2: return(testEncryptInPlacePipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 3: return(testInvertPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 4: return(testDelayedReadPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 5: return(testDelayedSendPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 6: return(testUnreliableSequencedPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 7: return(testPipelineStageWithHeaderTwo.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 8: return(testPipelineWithInitializers.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); case 9: return(testPipelineWithInitializersTwo.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate)); } return(inboundBuffer); }
/// <summary> /// Write packet, packet header and tracking information to the given buffer space. This buffer /// should contain the reliability Context at the front, that contains the capacity of the buffer /// and pointer offsets needed to find the slots we can copy the packet to. /// </summary> /// <param name="self">Buffer space where we can store packets.</param> /// <param name="sequence">The sequence ID of the packet, this is used to find a slot inside the buffer.</param> /// <param name="header">The packet header which we'll store with the packet payload.</param> /// <param name="data">The packet data which we're storing.</param> /// <exception cref="OverflowException"></exception> public static unsafe void SetHeaderAndPacket(NativeSlice <byte> self, int sequence, PacketHeader header, InboundBufferVec data, long timestamp) { byte * ptr = (byte *)self.GetUnsafePtr(); Context *ctx = (Context *)ptr; int totalSize = data.buffer1.Length + data.buffer2.Length; if (totalSize > ctx->DataStride) #if ENABLE_UNITY_COLLECTIONS_CHECKS { throw new OverflowException(); } #else { return; } #endif var index = sequence % ctx->Capacity; PacketInformation *info = GetPacketInformation(self, sequence); info->SequenceId = sequence; info->Size = totalSize; info->SendTime = timestamp; Packet *packet = GetPacket(self, sequence); packet->Header = header; var offset = (ctx->DataPtrOffset + (index * ctx->DataStride)) + UnsafeUtility.SizeOf <PacketHeader>(); void *dataPtr = (ptr + offset); if (data.buffer1.Length > 0) { UnsafeUtility.MemCpy(dataPtr, data.buffer1.GetUnsafeReadOnlyPtr(), data.buffer1.Length); } if (data.buffer2.Length > 0) { UnsafeUtility.MemCpy(&dataPtr + data.buffer1.Length, data.buffer2.GetUnsafeReadOnlyPtr(), data.buffer2.Length); } }