144 lines
5.4 KiB
C#
144 lines
5.4 KiB
C#
using Barotrauma.Items.Components;
|
|
using Microsoft.Xna.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Barotrauma.Networking
|
|
{
|
|
class VoipServer
|
|
{
|
|
private readonly ServerPeer netServer;
|
|
private readonly List<VoipQueue> queues;
|
|
private readonly Dictionary<VoipQueue,DateTime> lastSendTime;
|
|
|
|
public VoipServer(ServerPeer server)
|
|
{
|
|
netServer = server;
|
|
queues = new List<VoipQueue>();
|
|
lastSendTime = new Dictionary<VoipQueue, DateTime>();
|
|
}
|
|
|
|
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<Client> 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);
|
|
if (sender == null) { return; }
|
|
|
|
foreach (Client recipient in clients)
|
|
{
|
|
if (recipient == sender) { continue; }
|
|
|
|
if (!CanReceive(sender, recipient, out float distanceFactor)) { continue; }
|
|
|
|
IWriteMessage msg = new WriteOnlyMessage();
|
|
|
|
msg.WriteByte((byte)ServerPacketHeader.VOICE);
|
|
msg.WriteByte((byte)queue.QueueID);
|
|
msg.WriteRangedSingle(distanceFactor, 0.0f, 1.0f, 8);
|
|
queue.Write(msg);
|
|
|
|
netServer.Send(msg, recipient.Connection, DeliveryMethod.Unreliable);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool CanReceive(Client sender, Client recipient, out float distanceFactor)
|
|
{
|
|
if (Screen.Selected != GameMain.GameScreen)
|
|
{
|
|
distanceFactor = 0.0f;
|
|
return true;
|
|
}
|
|
|
|
distanceFactor = 0.0f;
|
|
|
|
//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;
|
|
|
|
//non-spectators cannot hear spectators, and spectators can always hear spectators
|
|
if (senderSpectating)
|
|
{
|
|
return recipientSpectating;
|
|
}
|
|
|
|
//sender can't speak
|
|
if (sender.Character != null && sender.Character.SpeechImpediment >= 100.0f) { return false; }
|
|
|
|
//check if the message can be sent via radio
|
|
WifiComponent recipientRadio = null;
|
|
if (!sender.VoipQueue.ForceLocal &&
|
|
ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) &&
|
|
(recipientSpectating || ChatMessage.CanUseRadio(recipient.Character, out recipientRadio)))
|
|
{
|
|
if (recipientSpectating)
|
|
{
|
|
if (recipient.SpectatePos == null) { return true; }
|
|
distanceFactor = MathHelper.Clamp(Vector2.Distance(sender.Character.WorldPosition, recipient.SpectatePos.Value) / senderRadio.Range, 0.0f, 1.0f);
|
|
return distanceFactor < 1.0f;
|
|
}
|
|
else if (recipientRadio != null && recipientRadio.CanReceive(senderRadio))
|
|
{
|
|
distanceFactor = MathHelper.Clamp(Vector2.Distance(sender.Character.WorldPosition, recipient.Character.WorldPosition) / senderRadio.Range, 0.0f, 1.0f);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (recipientSpectating)
|
|
{
|
|
if (recipient.SpectatePos == null) { return true; }
|
|
distanceFactor = MathHelper.Clamp(Vector2.Distance(sender.Character.WorldPosition, recipient.SpectatePos.Value) / ChatMessage.SpeakRangeVOIP, 0.0f, 1.0f);
|
|
return distanceFactor < 1.0f;
|
|
}
|
|
else
|
|
{
|
|
//otherwise do a distance check
|
|
float garbleAmount = ChatMessage.GetGarbleAmount(recipient.Character, sender.Character, ChatMessage.SpeakRangeVOIP);
|
|
distanceFactor = garbleAmount;
|
|
return garbleAmount < 1.0f;
|
|
}
|
|
}
|
|
|
|
public static void Read(IReadMessage inc, Client connectedClient)
|
|
{
|
|
var queue = connectedClient.VoipQueue;
|
|
if (queue.Read(inc, discardData: false))
|
|
{
|
|
connectedClient.VoipServerDecoder.OnNewVoiceReceived();
|
|
}
|
|
|
|
#if DEBUG
|
|
var msg = new WriteOnlyMessage().WithHeader(ServerPacketHeader.VOICE_AMPLITUDE_DEBUG);
|
|
msg.WriteRangedSingle(connectedClient.VoipServerDecoder.Amplitude, min: 0, max: 1, bitCount: 8);
|
|
|
|
GameMain.Server?.ServerPeer?.Send(msg, connectedClient.Connection, DeliveryMethod.Unreliable);
|
|
#endif
|
|
}
|
|
}
|
|
}
|