From 23740065374f9858c99c1f1149653e93ab49a3fe Mon Sep 17 00:00:00 2001 From: Joao Victor Oliveira Date: Sun, 19 Oct 2025 01:39:21 -0300 Subject: [PATCH] Add RiptideNetworkingNetProvider implementation Introduces RiptideNetProvider, an INetProvider implementation for MetaVoiceChat using Riptide networking. Handles voice data relay between clients and server, manages singleton instance, and integrates with MetaVc component. --- .../RiptideNetworkingNetProvider.cs | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 NetProviders/RiptideNetworking/RiptideNetworkingNetProvider.cs diff --git a/NetProviders/RiptideNetworking/RiptideNetworkingNetProvider.cs b/NetProviders/RiptideNetworking/RiptideNetworkingNetProvider.cs new file mode 100644 index 0000000..7d8d365 --- /dev/null +++ b/NetProviders/RiptideNetworking/RiptideNetworkingNetProvider.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using MetaVoiceChat.Utils; +using UnityEngine; +using Riptide; + +namespace MetaVoiceChat.NetProviders.Riptide +{ + [RequireComponent(typeof(MetaVc))] + public class RiptideNetProvider : MonoBehaviour, INetProvider + { + private static RiptideNetProvider _singleton; + public static RiptideNetProvider Singleton + { + get { return _singleton; } + set + { + if (_singleton == null) + { + _singleton = value; + } + + else if (_singleton != value) + { + Debug.Log($"{nameof(RiptideNetProvider)} instance already exists, destroying duplicate"); + Destroy(value); + } + } + } + + static int GetMaxDataBytesPerPacket() + { + int bytes = MaxVoiceBytes; + bytes -= sizeof(int); // Index + bytes -= sizeof(double); // Timestamp + bytes -= sizeof(byte); // Additional latency + bytes -= sizeof(ushort); // Array length + return bytes; + } + + bool INetProvider.IsLocalPlayerDeafened => Singleton.MetaVc.isDeafened; + + public MetaVc MetaVc { get; private set; } + + static int MaxVoiceBytes = 1100; + [Header("Components")] + [SerializeField] private Player player; + + private void Start() + { + if (player.IsLocal) Singleton = this; + + MetaVc = GetComponent(); + MetaVc.StartClient(this, player.IsLocal, GetMaxDataBytesPerPacket()); + } + + private void OnDestroy() + { + if (player.IsLocal) Singleton = null; + + MetaVc.StopClient(); + } + + public void RelayFrame(int index, double timestamp, ReadOnlySpan data) + { + // Debug.Log($"[RiptideNetProvider - RelayFrame] Relaying voice frame for player '{player.username}' (Index: {index}, Timestamp: {timestamp}, Data Length: {data.Length} bytes)"); + byte[] array = FixedLengthArrayPool.Rent(data.Length); + data.CopyTo(array); + + float additionalLatency = Time.deltaTime; + + if (NetworkManager.Singleton.Server.IsRunning) ServerSendVoice(player.Id, index, timestamp, additionalLatency, array); + else ClientSendVoice(index, timestamp, additionalLatency, array); + } + + #region ServerToClientSenders + private void ServerSendVoice(ushort playerId, int index, double timestamp, float additionalLatency, byte[] array) + { + if (!Player.List.TryGetValue(playerId, out Player player)) + { + // Debug.LogWarning($"[RiptideNetProvider - ServerSendVoice] Could not find player with ID {playerId} to send voice frame!"); + return; + } + // Debug.Log($"[RiptideNetProvider - ServerSendVoice] Sending voice from server for player '{player.username}'" + + // $" (Index: {index}, Timestamp: {timestamp}, Latency: {additionalLatency}s, DatLength: {array.Length} bytes)"); + + Message message = Message.Create(MessageSendMode.Unreliable, ServerToClientId.voiceChat); + message.AddUShort(player.Id); + message.AddInt(index); + message.AddDouble(timestamp); + message.AddFloat(additionalLatency); + message.AddBytes(array); + NetworkManager.Singleton.Server.SendToAll(message); + } + #endregion + + #region ClientToServerSenders + private void ClientSendVoice(int index, double timestamp, float additionalLatency, byte[] array) + { + // Debug.Log($"[RiptideNetProvider - ClientSendVoice] Sending voice from client for player '{player.username}' (Index: {index}, Timestamp: {timestamp}," + + // $" Latency: {additionalLatency}s, Data Length: {array.Length} bytes)"); + Message message = Message.Create(MessageSendMode.Unreliable, ClientToServerId.voiceChat); + message.AddInt(index); + message.AddDouble(timestamp); + message.AddFloat(additionalLatency); + message.AddBytes(array); + NetworkManager.Singleton.Client.Send(message); + } + #endregion + + #region ServerToClientHandlers + [MessageHandler((ushort)ServerToClientId.voiceChat)] + private static void ReceiveServerVoice(Message message) + { + if (NetworkManager.Singleton.Server.IsRunning) return; + ushort playerId = message.GetUShort(); + if (Player.List.TryGetValue(playerId, out Player player)) + { + if (player.IsLocal) return; + // Debug.Log($"[RiptideNetProvider - ReceiveServerVoice] Received voice from server (Player ID: {playerId})"); + player.metaVc.ReceiveFrame(message.GetInt(), message.GetDouble(), message.GetFloat(), message.GetBytes()); + } + } + #endregion + + #region ClientToServerHandlers + [MessageHandler((ushort)ClientToServerId.voiceChat)] + private static void ReceiveClientVoice(ushort fromClientId, Message message) + { + if (Player.List.TryGetValue(fromClientId, out Player player)) + { + int index = message.GetInt(); + double timestamp = message.GetDouble(); + float additionalLatency = message.GetFloat(); + byte[] data = message.GetBytes(); + + // Debug.Log($"[RiptideNetProvider - ReceiveClientVoice] Received voice from player {player.username}"); + player.metaVc.ReceiveFrame(index, timestamp, additionalLatency, data); + Singleton.ServerSendVoice(fromClientId, index, timestamp, additionalLatency, data); + } + } + #endregion + } +}