refactored VRExperimentController to utilize SharedUDPListener for packet handling

This commit is contained in:
tom.hempel
2025-10-25 15:58:28 +02:00
parent f3b4a4ddb0
commit 868180e3ec
4 changed files with 25 additions and 102 deletions

View File

@ -93,6 +93,7 @@ namespace Convai.Scripts.Runtime.Multiplayer
ConvaiLogger.Info($" - Voice Audio: 0xC0A1", ConvaiLogger.LogCategory.Character);
ConvaiLogger.Info($" - NPC Speech: 0xC0A3", ConvaiLogger.LogCategory.Character);
ConvaiLogger.Info($" - Avatar Sync: 0xC0A0", ConvaiLogger.LogCategory.Character);
ConvaiLogger.Info($" - Experiment Control: JSON (text-based)", ConvaiLogger.LogCategory.Character);
// Start listening for all packets
_ = ListenForPackets(_cancellationTokenSource.Token);

View File

@ -2,9 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using Newtonsoft.Json;
@ -34,8 +32,6 @@ public class VRExperimentController : MonoBehaviour
[SerializeField] private bool enableDebugLogging = true;
// Network components
private UdpClient udpClient;
private Thread udpListenerThread;
private bool isListening = false;
private int udpPort;
@ -197,70 +193,40 @@ public class VRExperimentController : MonoBehaviour
{
try
{
if (allowPortSharing)
// Wait for shared listener to be ready
if (Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance == null)
{
// Create UDP client with port reuse for local testing
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, udpPort));
}
else
{
// Standard UDP client binding
udpClient = new UdpClient(udpPort);
LogError("SharedUDPListener not found! Make sure it's in the scene.");
return;
}
udpListenerThread = new Thread(new ThreadStart(UDPListenerLoop));
udpListenerThread.IsBackground = true;
// Subscribe to shared listener
Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance.OnPacketReceived += HandlePacketReceived;
isListening = true;
udpListenerThread.Start();
LogMessage($"UDP Experiment Control Listener started on port {udpPort} (filtering JSON messages only, Port sharing: {allowPortSharing})");
LogMessage($"UDP Experiment Control Listener subscribed to shared listener on port {udpPort} (filtering JSON messages only)");
}
catch (Exception e)
{
if (allowPortSharing)
{
LogError($"Failed to start UDP listener with port sharing: {e.Message}");
LogMessage("Trying with different port...");
TryAlternativePort();
}
else
{
LogError($"Failed to start UDP listener: {e.Message}");
}
LogError($"Failed to subscribe to shared UDP listener: {e.Message}");
}
}
/// <summary>
/// Try alternative ports for local testing
/// Handle packet received from shared listener
/// </summary>
private void TryAlternativePort()
private void HandlePacketReceived(byte[] data, IPEndPoint senderEndPoint)
{
// Try a few alternative ports for local testing
int[] alternativePorts = { 1222, 1223, 1224, 1225, 1226 };
// Check if this is an experiment control message (JSON)
if (!IsExperimentControlMessage(data)) return;
foreach (int port in alternativePorts)
string message = Encoding.UTF8.GetString(data);
// Add message to queue for main thread processing
lock (queueLock)
{
try
{
udpClient = new UdpClient(port);
udpListenerThread = new Thread(new ThreadStart(UDPListenerLoop));
udpListenerThread.IsBackground = true;
isListening = true;
udpListenerThread.Start();
LogMessage($"UDP Experiment Control Listener started on alternative port {port}");
return;
}
catch (Exception)
{
// Try next port
continue;
}
messageQueue.Enqueue(message);
}
LogError("Failed to start UDP listener on any available port");
}
/// <summary>
@ -270,59 +236,15 @@ public class VRExperimentController : MonoBehaviour
{
isListening = false;
if (udpClient != null)
// Unsubscribe from shared listener
if (Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance != null)
{
udpClient.Close();
udpClient = null;
}
if (udpListenerThread != null && udpListenerThread.IsAlive)
{
udpListenerThread.Join(1000); // Wait up to 1 second
if (udpListenerThread.IsAlive)
{
udpListenerThread.Abort();
}
udpListenerThread = null;
Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance.OnPacketReceived -= HandlePacketReceived;
}
LogMessage("UDP Listener stopped");
}
/// <summary>
/// UDP listener loop (runs in separate thread)
/// </summary>
private void UDPListenerLoop()
{
while (isListening)
{
try
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, udpPort);
byte[] data = udpClient.Receive(ref remoteEndPoint);
// Check if this looks like a JSON experiment control message
if (IsExperimentControlMessage(data))
{
string message = Encoding.UTF8.GetString(data);
// Add message to queue for main thread processing
lock (queueLock)
{
messageQueue.Enqueue(message);
}
}
// If it's not an experiment control message (likely avatar data), ignore it
}
catch (Exception e)
{
if (isListening) // Only log if we're still supposed to be listening
{
LogError($"UDP Listener error: {e.Message}");
}
}
}
}
/// <summary>
/// Check if the received data is an experiment control message (JSON) vs avatar data (binary)
@ -684,9 +606,9 @@ public class VRExperimentController : MonoBehaviour
/// </summary>
private int GetActualListenPort()
{
if (udpClient?.Client?.LocalEndPoint != null)
if (Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance != null)
{
return ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
return Convai.Scripts.Runtime.Multiplayer.SharedUDPListener.Instance.ListenPort;
}
return udpPort;
}

Binary file not shown.

Binary file not shown.