using AOT; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Networking.Transport.Utilities; namespace Unity.Networking.Transport { [BurstCompile] public unsafe struct UnreliableSequencedPipelineStage : INetworkPipelineStage { static TransportFunctionPointer ReceiveFunctionPointer = new TransportFunctionPointer(Receive); static TransportFunctionPointer SendFunctionPointer = new TransportFunctionPointer(Send); static TransportFunctionPointer InitializeConnectionFunctionPointer = new TransportFunctionPointer(InitializeConnection); public NetworkPipelineStage StaticInitialize(byte* staticInstanceBuffer, int staticInstanceBufferLength, INetworkParameter[] netParams) { return new NetworkPipelineStage( Receive: ReceiveFunctionPointer, Send: SendFunctionPointer, InitializeConnection: InitializeConnectionFunctionPointer, ReceiveCapacity: UnsafeUtility.SizeOf(), SendCapacity: UnsafeUtility.SizeOf(), HeaderCapacity: UnsafeUtility.SizeOf(), SharedStateCapacity: 0 ); } public int StaticSize => 0; [BurstCompile(DisableDirectCall = true)] [MonoPInvokeCallback(typeof(NetworkPipelineStage.ReceiveDelegate))] private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests) { var inboundArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(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); var oldSequenceId = (int*) ctx.internalProcessBuffer; ushort sequenceId = reader.ReadUShort(); if (SequenceHelpers.GreaterThan16(sequenceId, (ushort)*oldSequenceId)) { *oldSequenceId = sequenceId; // Skip over the part of the buffer which contains the header inboundBuffer = inboundBuffer.Slice(sizeof(ushort)); return; } inboundBuffer = default; } [BurstCompile(DisableDirectCall = true)] [MonoPInvokeCallback(typeof(NetworkPipelineStage.SendDelegate))] private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests) { var sequenceId = (int*) ctx.internalProcessBuffer; ctx.header.WriteUShort((ushort)*sequenceId); *sequenceId = (ushort)(*sequenceId + 1); return (int)Error.StatusCode.Success; } [BurstCompile(DisableDirectCall = true)] [MonoPInvokeCallback(typeof(NetworkPipelineStage.InitializeConnectionDelegate))] private static void InitializeConnection(byte* staticInstanceBuffer, int staticInstanceBufferLength, byte* sendProcessBuffer, int sendProcessBufferLength, byte* recvProcessBuffer, int recvProcessBufferLength, byte* sharedProcessBuffer, int sharedProcessBufferLength) { if (recvProcessBufferLength > 0) { // The receive processing buffer contains the current sequence ID, initialize it to -1 as it will be incremented when used. *(int*) recvProcessBuffer = -1; } } } }