//* Usado para enviar os dados para o servidor. //* Client->Server protected void Send(NeutronStream stream, Protocol protocol = Protocol.Tcp) { try { if (IsServer) { throw new NeutronException("To use this packet on the server side it is necessary to assign the \"Player\" parameter."); } #if !UNITY_SERVER || UNITY_EDITOR if (This.IsConnected) { NeutronStream.IWriter wHeader = stream.hWriter; NeutronStream.IWriter wPacket = stream.Writer; byte[] pBuffer = wPacket.ToArray().Compress(); //! Otimizado para evitar alocações, bom isso depende de como você usa o Neutron :p switch (protocol) { //* ValueTask ainda não funciona na Unity, isso mesmo, em 2021 com .net 6 e standard 2.1, e a unity atrasada com essa merda de Mono, vê se pode? case Protocol.Tcp: { if (wHeader.GetPosition() == 0) { wHeader.WriteByteArrayWithAutoSize(pBuffer); //* Pre-fixa o tamanho da mensagem no cabeçalho, um inteiro/short/byte(4/2/1 bytes), e a mensagem. byte[] hBuffer = wHeader.ToArray(); wHeader.Write(); NetworkStream networkStream = TcpClient.GetStream(); switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: networkStream.Write(hBuffer, 0, hBuffer.Length); //* Envia os dados pro servidor de modo síncrono, esta opção é melhor, não aloca e tem performance de CPU. break; default: if (Helper.GetConstants().SendAsyncPattern == AsynchronousType.APM) { networkStream.Write(hBuffer, 0, hBuffer.Length); //* Envia os dados pro servidor de modo assíncrono, mentira, envia da mesma forma de "SendType.Synchronous", preguiça mesmo. :p, porque BeginReceive e Endreceive é chato de fazer pro TCP :D } else { SocketHelper.SendTcpAsync(networkStream, hBuffer, TokenSource.Token); //* Envia os dados pro servidor de forma assíncrona., faz alocações pra caralho, no tcp não tanto, mas no UDP..... é foda. e usa muita cpu, evite, se souber como resolver, sinta-se a vontade para contribuir. } break; } //* Adiciona no profiler a quantidade de dados de saída(Outgoing). NeutronStatistics.ClientTCP.AddOutgoing(hBuffer.Length); } else { throw new Exception($"Send(Tcp): Invalid position, is not zero! Pos -> {wHeader.GetPosition()} Capacity -> {wHeader.GetCapacity()}. You called Finish() ?"); } } break; case Protocol.Udp: { if (UdpEndPoint == null) { LogHelper.Error("Unauthenticated!"); } else { StateObject.SendDatagram = pBuffer; switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: SocketHelper.SendBytes(UdpClient, pBuffer, UdpEndPoint); //* envia de modo síncrono, evita alocações e performance boa. break; default: { switch (Helper.GetConstants().SendAsyncPattern) { case AsynchronousType.APM: { //* aloca, mas não tanto, boa performance. SocketHelper.BeginSendBytes(UdpClient, pBuffer, UdpEndPoint, (ar) => { SocketHelper.EndSendBytes(UdpClient, ar); }); break; } default: SocketHelper.SendUdpAsync(UdpClient, StateObject, UdpEndPoint); //* se foder, aloca pra caralho e usa cpu como a unreal engine, ValueTask poderia resolver, mas...... break; } break; } } //* Adiciona no profiler a quantidade de dados de saída(Outgoing). NeutronStatistics.ClientUDP.AddOutgoing(pBuffer.Length); } } break; } } else { LogHelper.Error("Non-connected socket, sending failed!"); } #else throw new Exception("To use this packet on the server side it is necessary to assign the \"Player\" parameter."); #endif } catch (ObjectDisposedException) { } catch (SocketException) { } catch (Exception ex) { LogHelper.Stacktrace(ex); } }
//* Aqui os dados são enviados aos seus clientes. public void OnSendingData(NeutronPlayer player, NeutronPacket neutronPacket) { try { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var playerId = (short)neutronPacket.Sender.Id; //* Get the player id. byte[] pBuffer = neutronPacket.Buffer.Compress(); //* Compress the packet. switch (neutronPacket.Protocol) { case Protocol.Tcp: { NeutronStream.IWriter wHeader = stream.Writer; wHeader.WriteByteArrayWithAutoSize(pBuffer); //* Write the packet and its size. wHeader.Write(playerId); //* Write the player id in header. byte[] hBuffer = wHeader.ToArray(); //* Get the header buffer. wHeader.Write(); //* End the header. NetworkStream networkStream = player.TcpClient.GetStream(); //* Get the network stream. switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: networkStream.Write(hBuffer, 0, hBuffer.Length); //* Send the header. break; default: if (Helper.GetConstants().SendAsyncPattern == AsynchronousType.APM) { networkStream.Write(hBuffer, 0, hBuffer.Length); //* Send the header. } else { SocketHelper.SendTcpAsync(networkStream, hBuffer, player.TokenSource.Token); //* Send the header. } break; } NeutronStatistics.ServerTCP.AddOutgoing(hBuffer.Length); //* Add the outgoing bytes to the statistics. } break; case Protocol.Udp: { NeutronStream.IWriter wHeader = stream.Writer; wHeader.Write(playerId); //* Write the player id in header. wHeader.WriteNext(pBuffer); //* Write the packet and its size. byte[] hBuffer = wHeader.ToArray(); //* Get the header buffer. wHeader.Write(); //* End the header. player.StateObject.SendDatagram = hBuffer; //* Set the datagram to send. if (player.StateObject.UdpIsReady()) //* Check if the player is ready to send. { NonAllocEndPoint remoteEp = (NonAllocEndPoint)player.StateObject.NonAllocEndPoint; //* Get the remote end point, prevent GC pressure/allocations. switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: SocketHelper.SendBytes(player.UdpClient, hBuffer, remoteEp); //* Send the datagram. break; default: { switch (Helper.GetConstants().SendAsyncPattern) { case AsynchronousType.APM: { SocketHelper.BeginSendBytes(player.UdpClient, hBuffer, remoteEp, (ar) => { SocketHelper.EndSendBytes(player.UdpClient, ar); //* End the send. }); //* Begin the send. break; } default: SocketHelper.SendUdpAsync(player.UdpClient, player.StateObject, remoteEp); //* Send the datagram. break; } break; } } NeutronStatistics.ServerUDP.AddOutgoing(hBuffer.Length); //* Add the outgoing bytes to the statistics. } else { LogHelper.Error($"{player.StateObject.TcpRemoteEndPoint} Cannot receive UDP data. trying... if you are running on WSL2, change the ip from \"localhost\" to the IP address of WSL2 on the client."); } } break; } } } catch (ThreadAbortException) { } catch (SocketException) { } catch (ObjectDisposedException) { } catch (OperationCanceledException) { } catch (Exception) { } }