/// <summary> /// Send a message to all connected clients. /// </summary> /// <typeparam name="T">Message type</typeparam> /// <param name="msg">Message</param> /// <param name="channelId">Transport channel to use</param> public void SendToAll <T>(T msg, int channelId = Channel.Reliable) { if (logger.LogEnabled()) { logger.Log("Server.SendToAll id:" + typeof(T)); } using (var writer = NetworkWriterPool.GetWriter()) { // pack message into byte[] once MessagePacker.Pack(msg, writer); var segment = writer.ToArraySegment(); var count = 0; // using SendToMany (with IEnumerable) will cause Enumerator to be boxed and create GC/alloc // instead we can use while loop and MoveNext to avoid boxing var enumerator = _connections.Values.GetEnumerator(); while (enumerator.MoveNext()) { var player = enumerator.Current; player.Send(segment, channelId); count++; } enumerator.Dispose(); NetworkDiagnostics.OnSend(msg, segment.Count, count); } }
/// <summary> /// Sends a message, but notify when it is delivered or lost /// </summary> /// <typeparam name="T">type of message to send</typeparam> /// <param name="message">message to send</param> /// <param name="token">a arbitrary object that the sender will receive with their notification</param> public void SendNotify <T>(T message, object token, int channelId = Channel.Unreliable) { if (sendWindow.Count == WINDOW_SIZE) { NotifyLost?.Invoke(this, token); return; } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { var notifyPacket = new NotifyPacket { Sequence = (ushort)sequencer.Next(), ReceiveSequence = receiveSequence, AckMask = receiveMask }; sendWindow.Enqueue(new PacketEnvelope { Sequence = notifyPacket.Sequence, Token = token }); MessagePacker.Pack(notifyPacket, writer); MessagePacker.Pack(message, writer); NetworkDiagnostics.OnSend(message, channelId, writer.Length, 1); Send(writer.ToArraySegment(), channelId); lastNotifySentTime = Time.unscaledTime; } }
/// <summary> /// This sends a network message to the connection. /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="msg">The message to send.</param> /// <param name="channelId">The transport layer channel to send on.</param> /// <returns></returns> public void Send <T>(T message, int channelId = Channel.Reliable) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // pack message and send allocation free MessagePacker.Pack(message, writer); NetworkDiagnostics.OnSend(message, channelId, writer.Length, 1); Send(writer.ToArraySegment(), channelId); } }
/// <summary> /// This sends a network message to the connection. You can await it to check for errors /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="msg">The message to send.</param> /// <param name="channelId">The transport layer channel to send on.</param> /// <returns></returns> public virtual UniTask SendAsync <T>(T msg, int channelId = Channel.Reliable) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // pack message and send allocation free MessagePacker.Pack(msg, writer); NetworkDiagnostics.OnSend(msg, channelId, writer.Length, 1); return(SendAsync(writer.ToArraySegment(), channelId)); } }
/// <summary> /// This sends a network message to the connection. /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="msg">The message to send.</param> /// <param name="channelId">The transport layer channel to send on.</param> /// <returns></returns> public void Send <T>(T message, INotifyCallBack token) { if (isDisconnected) { return; } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { MessagePacker.Pack(message, writer); var segment = writer.ToArraySegment(); NetworkDiagnostics.OnSend(message, segment.Count, 1); connection.SendNotify(segment, token); } }
/// <summary> /// This sends a network message to the connection. /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="msg">The message to send.</param> /// <param name="channelId">The transport layer channel to send on.</param> /// <returns></returns> public void Send <T>(T message, int channelId = Channel.Reliable) { if (isDisconnected) { return; } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { MessagePacker.Pack(message, writer); var segment = writer.ToArraySegment(); NetworkDiagnostics.OnSend(message, segment.Count, 1); Send(segment, channelId); } }
/// <summary> /// Sends a message to many connections /// <para> /// Same as <see cref="SendToMany{T}(IEnumerable{INetworkPlayer}, T, int)"/> but uses for loop to avoid allocations /// </para> /// </summary> /// <remarks> /// Using list in foreach loop causes Unity's mono version to box the struct which causes allocations, <see href="https://docs.unity3d.com/2019.4/Documentation/Manual/BestPracticeUnderstandingPerformanceInUnity4-1.html">Understanding the managed heap</see> /// </remarks> public static void SendToMany <T>(IReadOnlyList <INetworkPlayer> players, T msg, int channelId = Channel.Reliable) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // pack message into byte[] once MessagePacker.Pack(msg, writer); var segment = writer.ToArraySegment(); int count = players.Count; for (int i = 0; i < count; i++) { players[i].Send(segment, channelId); } NetworkDiagnostics.OnSend(msg, segment.Count, count); } }
/// <summary> /// Sends a message to many connections /// </summary> /// <typeparam name="T"></typeparam> /// <param name="players"></param> /// <param name="msg"></param> /// <param name="channelId"></param> public static void SendToMany <T>(IEnumerable <INetworkPlayer> players, T msg, int channelId = Channel.Reliable) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // pack message into byte[] once MessagePacker.Pack(msg, writer); var segment = writer.ToArraySegment(); int count = 0; foreach (INetworkPlayer player in players) { player.Send(segment, channelId); count++; } NetworkDiagnostics.OnSend(msg, segment.Count, count); } }
public static void Send <T>(IEnumerable <INetworkConnection> connections, T msg, int channelId = Channel.Reliable) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // pack message into byte[] once MessagePacker.Pack(msg, writer); var segment = writer.ToArraySegment(); int count = 0; foreach (INetworkConnection conn in connections) { // send to all connections, but don't wait for them conn.Send(segment, channelId); count++; } NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count); } }