I’m trying to establish a WebSocket connection between a WebGL client and a Unity Services NGO game server but am encountering issues.
My Setup:
- Unity Editor (local client) connects to an NGO Linux server (WebSockets inactive).
- WebGL client connects to a local Unity Editor server (WebSockets active).
Actions Taken:
- Enabled “Use Websockets” in Unity Transport.
- Built and deployed a Linux server to NGO and a WebGL client.
Problem:
After setting up the connection, the WebGL client receives the server’s IP and port, but the connection fails. I’ve tried using WebSocketNetworkInterface
as suggested in the Unity Transport 2.1 documentation, but it results in an error indicating the interface cannot be found.
Request for Advice:
- Is there a specific WebSocket API or external library I should use for the WebGL client to connect with the server via Transport WebSocket?
- Are there additional WebSocket configurations required for this setup in a multiplayer NGO context?
Any insights or recommendations would be highly appreciated.
Here are my current scripts. Please advise of any further info is needed.
using System.Collections;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services.Core;
#if !UNITY_WEBGL
using Unity.Services.Multiplay;
#endif
using UnityEngine;
using Unity.Networking.Transport; // Required for NetworkDriver
public class Server : MonoBehaviour
{
void Start()
{
DontDestroyOnLoad(gameObject);
#if UNITY_EDITOR
StartCoroutine(StartLocalServer());
#else
StartCoroutine(StartServer());
#if !UNITY_WEBGL
StartCoroutine(ApproveBackfillTicketEverySecond());
#endif
#endif
}
IEnumerator StartLocalServer()
{
Debug.Log("Starting local server...");
var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
#if UNITY_WEBGL
var networkDriver = NetworkDriver.Create(new WebSocketNetworkInterface());
#else
var networkDriver = NetworkDriver.Create(); // Default UDP
#endif
transport.SetConnectionData("127.0.0.1", 7777); // Localhost for testing
if (!NetworkManager.Singleton.StartServer())
{
Debug.LogError("Failed to start local server");
yield break;
}
NetworkManager.Singleton.SceneManager.LoadScene("GameLogic", LoadSceneMode.Single);
yield return null;
}
async Task StartServer()
{
await UnityServices.InitializeAsync();
#if !UNITY_WEBGL
var server = MultiplayService.Instance.ServerConfig;
var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
transport.SetConnectionData("0.0.0.0", server.Port); // Bind to server port
#endif
if (!NetworkManager.Singleton.StartServer())
{
Debug.LogError("Failed to start server");
throw new Exception("Failed to start server");
}
NetworkManager.Singleton.SceneManager.LoadScene("GameLogic", LoadSceneMode.Single);
#if !UNITY_WEBGL
var callbacks = new MultiplayEventCallbacks();
callbacks.Allocate += OnAllocate;
callbacks.Deallocate += OnDeallocate;
while (MultiplayService.Instance == null)
{
await Task.Yield();
}
var events = await MultiplayService.Instance.SubscribeToServerEventsAsync(callbacks);
await CreateBackfillTicket();
#endif
}
#if !UNITY_WEBGL
async void OnAllocate(MultiplayAllocation allocation)
{
await MultiplayService.Instance.ReadyServerForPlayersAsync();
}
async Task CreateBackfillTicket()
{
var results = await MultiplayService.Instance.GetPayloadAllocationFromJsonAs<MatchmakingResults>();
var options = new CreateBackfillTicketOptions("DedicatedServerQueue",
MultiplayService.Instance.ServerConfig.IpAddress + ":" + MultiplayService.Instance.ServerConfig.Port,
new Dictionary<string, object>(),
new BackfillTicketProperties(results.MatchProperties));
await MatchmakerService.Instance.CreateBackfillTicketAsync(options);
}
IEnumerator ApproveBackfillTicketEverySecond()
{
yield return new WaitForSeconds(4);
while (true)
{
yield return new WaitForSeconds(1f);
// Approve backfill ticket logic...
}
}
#endif
}
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Matchmaker;
using UnityEngine;
using Unity.Networking.Transport; // Required for NetworkDriver
public class Client : MonoBehaviour
{
static bool initialized;
async void Start()
{
if (!initialized)
{
await UnityServices.InitializeAsync();
await AuthenticationService.Instance.SignInAnonymouslyAsync();
initialized = true;
}
if (LoadClientButton.connectToLocalServer)
{
ConnectToLocalServer();
}
else
{
await ConnectToNGOServer();
}
}
void ConnectToLocalServer()
{
var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
#if UNITY_WEBGL
var networkDriver = NetworkDriver.Create(new WebSocketNetworkInterface());
#else
var networkDriver = NetworkDriver.Create(); // Default UDP
#endif
transport.SetConnectionData("127.0.0.1", 7777); // Localhost
if (!NetworkManager.Singleton.StartClient())
{
Debug.LogError("Failed to connect to local server");
}
}
async Task ConnectToNGOServer()
{
var players = new List<Player> { new Player(AuthenticationService.Instance.PlayerId, new Dictionary<string, object>()) };
var options = new CreateTicketOptions("DedicatedServerQueue", new Dictionary<string, object>());
while (!await FindMatch(players, options))
{
await Task.Delay(1000);
}
}
async Task<bool> FindMatch(List<Player> players, CreateTicketOptions options)
{
var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
#if UNITY_WEBGL
var networkDriver = NetworkDriver.Create(new WebSocketNetworkInterface());
#else
var networkDriver = NetworkDriver.Create(); // Default UDP
#endif
var ticketResponse = await MatchmakerService.Instance.CreateTicketAsync(players, options);
while (true)
{
await Task.Delay(1000);
var ticketStatusResponse = await MatchmakerService.Instance.GetTicketAsync(ticketResponse.Id);
if (ticketStatusResponse?.Value is MultiplayAssignment assignment)
{
if (assignment.Status == MultiplayAssignment.StatusOptions.Found && assignment.Port.HasValue)
{
transport.SetConnectionData(assignment.Ip, (ushort)assignment.Port);
return NetworkManager.Singleton.StartClient();
}
}
}
}
}