using System.Collections.Generic;
using UnityEngine;
using Unity.Services.Core;
using Unity.Services.Authentication;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport.Relay;
using UnityEngine.SceneManagement;
using TMPro;
// --- EXPLICIT REFERENCES ---
// This tells the script exactly which "Lobby" to use
using Unity.Services.Lobby;
using Unity.Services.Lobby.Models;
public class LobbyManager : MonoBehaviour
{
[Header("UI References")]
public GameObject lobbyPanel;
public Transform serverListContent;
public GameObject serverEntryPrefab;
public TMP_InputField serverNameInput;
public string gameplaySceneName = "mpfreeroam";
private Lobby joinedLobby;
private float heartbeatTimer;
private float listRefreshTimer;
private async void Start()
{
await UnityServices.InitializeAsync();
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
Debug.Log("Lobby System Ready.");
}
private void Update()
{
HandleLobbyHeartbeat();
HandleLobbyPoll();
}
public async void CreatePublicLobby()
{
try
{
string lobbyName = serverNameInput.text;
if (string.IsNullOrEmpty(lobbyName)) lobbyName = "Racer " + Random.Range(10, 99);
// 1. Create Relay
Allocation allocation = await RelayService.Instance.CreateAllocationAsync(10);
string relayJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
// 2. Create Lobby Options
CreateLobbyOptions options = new CreateLobbyOptions
{
IsPrivate = false,
Data = new Dictionary<string, DataObject>
{
{ "RelayCode", new DataObject(DataObject.VisibilityOptions.Member, relayJoinCode) }
}
};
// 3. Create Lobby
joinedLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, 10, options);
Debug.Log("Lobby Created: " + joinedLobby.Name);
// 4. Start Host
RelayServerData relayData = new RelayServerData(allocation, "dtls");
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayData);
NetworkManager.Singleton.StartHost();
NetworkManager.Singleton.SceneManager.LoadScene(gameplaySceneName, LoadSceneMode.Single);
}
catch (System.Exception e)
{
Debug.LogError(e.Message);
}
}
public async void RefreshServerList()
{
try
{
foreach (Transform child in serverListContent) Destroy(child.gameObject);
// Query Options
QueryLobbiesOptions options = new QueryLobbiesOptions
{
Count = 20,
Filters = new List<QueryFilter>
{
new QueryFilter(QueryFilter.FieldOptions.AvailableSlots, "0", QueryFilter.OpOptions.GT)
}
};
// Query Lobbies
QueryResponse response = await LobbyService.Instance.QueryLobbiesAsync(options);
foreach (Lobby lobby in response.Results)
{
GameObject buttonObj = Instantiate(serverEntryPrefab, serverListContent);
var buttonText = buttonObj.GetComponentInChildren<TextMeshProUGUI>();
if (buttonText) buttonText.text = $"{lobby.Name} ({lobby.Players.Count}/{lobby.MaxPlayers})";
string id = lobby.Id;
buttonObj.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => JoinLobby(id));
}
}
catch (System.Exception e)
{
Debug.LogError(e.Message);
}
}
public async void JoinLobby(string lobbyId)
{
try
{
joinedLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
string relayCode = joinedLobby.Data["RelayCode"].Value;
JoinAllocation allocation = await RelayService.Instance.JoinAllocationAsync(relayCode);
RelayServerData relayData = new RelayServerData(allocation, "dtls");
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayData);
NetworkManager.Singleton.StartClient();
}
catch (System.Exception e)
{
Debug.LogError(e.Message);
}
}
private void HandleLobbyHeartbeat()
{
if (joinedLobby != null && IsHost())
{
heartbeatTimer -= Time.deltaTime;
if (heartbeatTimer <= 0f)
{
heartbeatTimer = 15f;
LobbyService.Instance.SendHeartbeatPingAsync(joinedLobby.Id);
}
}
}
private void HandleLobbyPoll()
{
if (joinedLobby == null && lobbyPanel.activeSelf)
{
listRefreshTimer -= Time.deltaTime;
if (listRefreshTimer <= 0f)
{
listRefreshTimer = 3f;
RefreshServerList();
}
}
}
private bool IsHost()
{
if (joinedLobby == null) return false;
return joinedLobby.HostId == AuthenticationService.Instance.PlayerId;
}
}