using Barotrauma.Items.Components; using Lidgren.Network; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Text; namespace Barotrauma.Networking { class VoipServer { private NetServer netServer; private List queues; private Dictionary lastSendTime; public VoipServer(NetServer server) { this.netServer = server; queues = new List(); lastSendTime = new Dictionary(); } public void RegisterQueue(VoipQueue queue) { if (!queues.Contains(queue)) queues.Add(queue); } public void UnregisterQueue(VoipQueue queue) { if (queues.Contains(queue)) queues.Remove(queue); } public void SendToClients(List clients) { foreach (VoipQueue queue in queues) { if (queue.LastReadTime < DateTime.Now - VoipConfig.SEND_INTERVAL) { continue; } if (lastSendTime.ContainsKey(queue)) { if ((lastSendTime[queue] + VoipConfig.SEND_INTERVAL) > DateTime.Now) { continue; } lastSendTime[queue] = DateTime.Now; } else { lastSendTime.Add(queue, DateTime.Now); } Client sender = clients.Find(c => c.VoipQueue == queue); foreach (Client recipient in clients) { if (recipient == sender) { continue; } if (!CanReceive(sender, recipient)) { continue; } NetOutgoingMessage msg = netServer.CreateMessage(); msg.Write((byte)ServerPacketHeader.VOICE); msg.Write((byte)queue.QueueID); queue.Write(msg); GameMain.Server.CompressOutgoingMessage(msg); netServer.SendMessage(msg, recipient.Connection, NetDeliveryMethod.Unreliable); } } } private bool CanReceive(Client sender, Client recipient) { if (Screen.Selected != GameMain.GameScreen) { return true; } //no-one can hear muted players if (sender.Muted) { return false; } bool recipientSpectating = recipient.Character == null || recipient.Character.IsDead; bool senderSpectating = sender.Character == null || sender.Character.IsDead; //spectators cannot speak with in-game players or vice versa //TODO: allow spectators to hear the voice chat if close enough to the speaker? if (recipientSpectating != senderSpectating) { return false; } //both spectating, no need to do radio/distance checks if (recipientSpectating && senderSpectating) { return true; } //sender can't speak if (sender.Character != null && sender.Character.SpeechImpediment >= 100.0f) { return false; } //check if the message can be sent via radio if (ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) && ChatMessage.CanUseRadio(recipient.Character, out WifiComponent recipientRadio)) { if (recipientRadio.CanReceive(senderRadio)) { return true; } } //otherwise do a distance check return ChatMessage.GetGarbleAmount(recipient.Character, sender.Character, ChatMessage.SpeakRange) < 1.0f; } } }