/// <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); } }
/// <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(byte *self, int sequence, PacketHeader header, InboundSendBuffer data, long timestamp) { Context *ctx = (Context *)self; int totalSize = data.bufferLength + data.headerPadding; if (totalSize + UnsafeUtility.SizeOf <PacketHeader>() > 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 = (ushort)totalSize; info->HeaderPadding = (ushort)data.headerPadding; info->SendTime = timestamp; Packet *packet = GetPacket(self, sequence); packet->Header = header; var offset = (ctx->DataPtrOffset + (index * ctx->DataStride)) + UnsafeUtility.SizeOf <PacketHeader>(); void *dataPtr = (self + offset); if (data.bufferLength > 0) { UnsafeUtility.MemCpy((byte *)dataPtr + data.headerPadding, data.buffer, data.bufferLength); } }
/// <summary> /// Resend a packet which we have not received an acknowledgement for in time. Pipeline resume /// will be enabled if there are more packets which we need to resend. The send reliability context /// will then also be updated to track the next packet we need to resume. /// </summary> /// <param name="context">Pipeline context, we'll use both the shared reliability context and send context.</param> /// <param name="header">Packet header for the packet payload we're resending.</param> /// <param name="needsResume">Indicates if a pipeline resume is needed again.</param> /// <returns>Buffer slice to packet payload.</returns> /// <exception cref="ApplicationException"></exception> public static unsafe NativeSlice <byte> ResumeSend(NetworkPipelineContext context, out PacketHeader header, ref bool needsResume) { SharedContext *reliable = (SharedContext *)context.internalSharedProcessBuffer.GetUnsafePtr(); Context * ctx = (Context *)context.internalProcessBuffer.GetUnsafePtr(); #if ENABLE_UNITY_COLLECTIONS_CHECKS if (ctx->Resume == NullEntry) { throw new ApplicationException("This function should not be called unless there is data in resume"); } #endif var sequence = (ushort)ctx->Resume; PacketInformation *information; information = GetPacketInformation(context.internalProcessBuffer, sequence); // Reset the resend timer information->SendTime = context.timestamp; Packet *packet = GetPacket(context.internalProcessBuffer, sequence); header = packet->Header; // Update acked/ackmask to latest values header.AckedSequenceId = (ushort)reliable->ReceivedPackets.Sequence; header.AckMask = reliable->ReceivedPackets.AckMask; var offset = (ctx->DataPtrOffset + ((sequence % ctx->Capacity) * ctx->DataStride)) + UnsafeUtility.SizeOf <PacketHeader>(); NativeSlice <byte> slice = new NativeSlice <byte>(context.internalProcessBuffer, offset, information->Size); reliable->stats.PacketsResent++; needsResume = false; ctx->Resume = -1; // Check if another packet needs to be resent right after this one for (int i = sequence + 1; i < reliable->ReceivedPackets.Sequence + 1; i++) { var timeToResend = CurrentResendTime(context.internalSharedProcessBuffer); information = GetPacketInformation(context.internalProcessBuffer, i); if (information->SequenceId >= 0 && information->SendTime + timeToResend > context.timestamp) { needsResume = true; ctx->Resume = i; } } return(slice); }
public static extern void Broadcast(Host *host, byte channelID, Packet *packet);
public static extern int SendPeer(Peer *peer, byte channelID, Packet *packet);
public static extern int ResizePacket(Packet *packet, IntPtr dataLength);
public static extern void DestroyPacket(Packet *packet);