Multiplayer working between editor and build but not build to build

I’m trying to set up a lobby system for a unity game and it mostly works.

But i have run into an issue where for some reason the lobbies are not working for a build connecting to a build but it works with the editor connecting to the build or the build connecting to the editor.

I have no idea why this is happening.

This is the lobby code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using UnityEngine.UI;
using TMPro;
using System;

public class SimpleLobby : MonoBehaviour
{
private Lobby _connectedLobby;
private QueryResponse _lobbies;
private UnityTransport _transport;
private const string JoinCodeKey = “j”;
public string playerName;
private string _playerId;
private string lobbyCode;
[SerializeField] private TextMeshProUGUI lobbyCodeText;

[SerializeField] private Button playButton;
[SerializeField] private TMP_InputField nameInputField;
[SerializeField] private TMP_InputField codeInputField;
[SerializeField] private GameObject lobbyUI;

private void Awake() => _transport = FindObjectOfType();

public async void CreateOrJoinLobby()
{
playerName = nameInputField.text;

await Authenticate(playerName);

_connectedLobby = await QuickJoinLobby() ?? await CreateLobby();

if (_connectedLobby != null) lobbyUI.SetActive(false);
}

public async void JoinByCode()
{
playerName = nameInputField.text;

await Authenticate(playerName);

_connectedLobby = await GetLobbyByCode();

if (_connectedLobby != null) lobbyUI.SetActive(false);
}

private async Task GetLobbyByCode()
{
try
{
// Attempt to join a lobby in progress
var lobby = await Lobbies.Instance.JoinLobbyByCodeAsync(codeInputField.text);

// If we found one, grab the relay allocation details
var a = await RelayService.Instance.JoinAllocationAsync(lobby.Data[JoinCodeKey].Value);

// Set the details to the transform
SetTransformAsClient(a);

// Join the game room as a client
NetworkManager.Singleton.StartClient();
return lobby;
}
catch (LobbyServiceException e)
{
Debug.Log($“No lobbies available via quick join”);
return null;
}
}

public async Task Authenticate(string playerName)
{
//this.playerName = playerName;
InitializationOptions initializationOptions = new InitializationOptions();
initializationOptions.SetProfile(playerName);

await UnityServices.InitializeAsync(initializationOptions);

AuthenticationService.Instance.SignedIn += () =>
{
_playerId = AuthenticationService.Instance.PlayerId;
Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
};
}

private async Task QuickJoinLobby()
{
try
{
// Attempt to join a lobby in progress
var lobby = await Lobbies.Instance.QuickJoinLobbyAsync();

// If we found one, grab the relay allocation details
var a = await RelayService.Instance.JoinAllocationAsync(lobby.Data[JoinCodeKey].Value);

// Set the details to the transform
SetTransformAsClient(a);

// Join the game room as a client
NetworkManager.Singleton.StartClient();
return lobby;
}
catch(LobbyServiceException e)
{
Debug.Log($“No lobbies available via quick join”);
return null;
}
}

private async Task CreateLobby()
{
try
{
const int maxPlayers = 10;

// Create a relay allocation and generate a join code to share with the lobby
var a = await RelayService.Instance.CreateAllocationAsync(maxPlayers);
var joinCode = await RelayService.Instance.GetJoinCodeAsync(a.AllocationId);
lobbyCode = joinCode;
lobbyCodeText.text = "Server code: " + joinCode;

// Create a lobby, adding the relay join code to the lobby data
var options = new CreateLobbyOptions
{
Data = new Dictionary<string, DataObject> { { JoinCodeKey, new DataObject(DataObject.VisibilityOptions.Public, joinCode) } }
};
var lobby = await Lobbies.Instance.CreateLobbyAsync(“Useless Lobby Name”, maxPlayers, options);

// Send a heartbeat every 15 seconds to keep the room alive
StartCoroutine(HeartbeatLobby(lobby.Id, 15));

// Set the game room to use the relay allocation
_transport.SetHostRelayData(a.RelayServer.IpV4, (ushort)a.RelayServer.Port, a.AllocationIdBytes, a.Key, a.ConnectionData);

// Start the game. i’m doing this immediately, but maybe you want to wait for the lobby to fill up
NetworkManager.Singleton.StartHost();
return lobby;
}
catch(Exception e)
{
Debug.LogFormat("Failed creating a lobby " + e);
return null;
}
}

private void SetTransformAsClient(JoinAllocation a)
{
_transport.SetClientRelayData(a.RelayServer.IpV4, (ushort)a.RelayServer.Port, a.AllocationIdBytes, a.Key, a.ConnectionData, a.HostConnectionData);
}

private static IEnumerator HeartbeatLobby(string lobbyId, float waitTimeSeconds)
{
var delay = new WaitForSecondsRealtime(waitTimeSeconds);
while (true)
{
Lobbies.Instance.SendHeartbeatPingAsync(lobbyId);
yield return delay;
}
}

private void OnDestroy()
{
try
{
StopAllCoroutines();
// todo: Add a check to see if you’re host
if(_connectedLobby != null)
{
if (_connectedLobby.HostId == _playerId) Lobbies.Instance.DeleteLobbyAsync(_connectedLobby.Id);
else Lobbies.Instance.RemovePlayerAsync(_connectedLobby.Id, _playerId);
}
}
catch (LobbyServiceException e)
{
Debug.Log($“Error shutting down lobby: {e}”);
}
}
}

Apparently its because this isn’t working and is not creating the profile based on the name of the player
public async Task Authenticate(string playerName)
{
InitializationOptions initializationOptions = new InitializationOptions();
initializationOptions.SetProfile(playerName);

await UnityServices.InitializeAsync(initializationOptions);

AuthenticationService.Instance.SignedIn += () =>
{
_playerId = AuthenticationService.Instance.PlayerId;
Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
};
}

Hi Mellenbull,
Thank you for providing your code !

I would like to ask for a few more details: What do you mean by “not working” ? Do you have any error/exception or stacktrace ?

Mellenbull How you solve this issue?

When you try to test lobby using two opened editors, just to simulate two different users. But
AuthenticationService auth this two fake users as same one, so in result both of then received the same updates from LobbyService