Started make greybox for main location
This commit is contained in:
@@ -1,54 +1,218 @@
|
||||
using System;
|
||||
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.Lobbies;
|
||||
using Unity.Services.Lobbies.Models;
|
||||
using Unity.Services.Relay;
|
||||
using Unity.Services.Relay.Models;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
[RequireComponent(typeof(NetworkManager), typeof(UnityTransport))]
|
||||
public sealed class NetworkSessionController : MonoBehaviour
|
||||
{
|
||||
private const string PlayerNamePreferenceKey = "player_name";
|
||||
private const string RelayCodeDataKey = "relay_code";
|
||||
|
||||
public static NetworkSessionController Instance { get; private set; }
|
||||
|
||||
[SerializeField] private NetworkObject playerPrefab;
|
||||
[SerializeField] private string menuSceneName = "MainMenu";
|
||||
[SerializeField] private string gameplaySceneName = "Factory";
|
||||
public string Status { get; private set; } = "Ready.";
|
||||
[SerializeField, Min(1)] private int maxClientCount = 3;
|
||||
[SerializeField] private bool useSecureRelay = false;
|
||||
|
||||
public string Status { get; private set; } = "Relay is not initialized.";
|
||||
public string JoinCode { get; private set; } = string.Empty;
|
||||
public string LocalPlayerName { get; private set; }
|
||||
public bool IsBusy { get; private set; }
|
||||
public bool IsOnline => NetworkManager.Singleton != null && NetworkManager.Singleton.IsListening;
|
||||
public bool IsHost => networkManager != null && networkManager.IsHost;
|
||||
public IReadOnlyList<Lobby> PublicLobbies => publicLobbies;
|
||||
|
||||
private readonly List<Lobby> publicLobbies = new();
|
||||
private NetworkManager networkManager;
|
||||
private UnityTransport transport;
|
||||
private bool loadFactoryAfterServerStart;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null) { Destroy(gameObject); return; }
|
||||
Instance = this; DontDestroyOnLoad(gameObject);
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
LocalPlayerName = PlayerPrefs.GetString(PlayerNamePreferenceKey, "Worker");
|
||||
|
||||
networkManager = GetComponent<NetworkManager>();
|
||||
transport = GetComponent<UnityTransport>();
|
||||
networkManager.NetworkConfig.NetworkTransport = transport;
|
||||
networkManager.NetworkConfig.PlayerPrefab = playerPrefab.gameObject;
|
||||
networkManager.NetworkConfig.EnableSceneManagement = true;
|
||||
networkManager.OnServerStarted += LoadGameplayScene;
|
||||
networkManager.OnServerStarted += HandleServerStarted;
|
||||
networkManager.OnClientConnectedCallback += HandleClientConnected;
|
||||
}
|
||||
|
||||
private void Start() => SceneManager.LoadScene(menuSceneName);
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (networkManager != null) networkManager.OnServerStarted -= LoadGameplayScene;
|
||||
if (networkManager != null) networkManager.OnServerStarted -= HandleServerStarted;
|
||||
if (networkManager != null) networkManager.OnClientConnectedCallback -= HandleClientConnected;
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
public bool StartHost(ushort port)
|
||||
|
||||
public void SetLocalPlayerName(string playerName)
|
||||
{
|
||||
transport.SetConnectionData("0.0.0.0", port, "0.0.0.0");
|
||||
bool started = networkManager.StartHost();
|
||||
Status = started ? $"Host started on {port}." : "Host failed to start.";
|
||||
return started;
|
||||
string sanitizedName = string.IsNullOrWhiteSpace(playerName) ? "Worker" : playerName.Trim();
|
||||
LocalPlayerName = sanitizedName.Length > 24 ? sanitizedName[..24] : sanitizedName;
|
||||
PlayerPrefs.SetString(PlayerNamePreferenceKey, LocalPlayerName);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
public bool StartClient(string address, ushort port)
|
||||
|
||||
public async Task StartHostAsync()
|
||||
{
|
||||
transport.SetConnectionData(address.Trim(), port);
|
||||
bool started = networkManager.StartClient();
|
||||
Status = started ? $"Connecting to {address}:{port}..." : "Client failed to start.";
|
||||
return started;
|
||||
if (IsBusy || IsOnline) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
Status = "Creating Relay allocation...";
|
||||
Allocation allocation = await RelayService.Instance.CreateAllocationAsync(maxClientCount);
|
||||
transport.SetHostRelayData(allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port,
|
||||
allocation.AllocationIdBytes, allocation.Key, allocation.ConnectionData, useSecureRelay);
|
||||
JoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
|
||||
await PublishLobbyAsync();
|
||||
loadFactoryAfterServerStart = true;
|
||||
if (!networkManager.StartHost()) throw new InvalidOperationException("Netcode host could not start.");
|
||||
Status = "Host started.";
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Status = $"Relay host error: {exception.Message}";
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
|
||||
public async Task StartClientAsync(string joinCode)
|
||||
{
|
||||
if (IsBusy || IsOnline || string.IsNullOrWhiteSpace(joinCode)) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
Status = "Joining Relay allocation...";
|
||||
JoinAllocation allocation = await RelayService.Instance.JoinAllocationAsync(joinCode.Trim().ToUpperInvariant());
|
||||
transport.SetClientRelayData(allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port,
|
||||
allocation.AllocationIdBytes, allocation.Key, allocation.ConnectionData, allocation.HostConnectionData, useSecureRelay);
|
||||
if (!networkManager.StartClient()) throw new InvalidOperationException("Netcode client could not start.");
|
||||
Status = "Connecting to host...";
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Status = $"Relay join error: {exception.Message}";
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
|
||||
public async Task RefreshPublicLobbiesAsync()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
QueryResponse response = await LobbyService.Instance.QueryLobbiesAsync(new QueryLobbiesOptions { Count = 20 });
|
||||
publicLobbies.Clear();
|
||||
publicLobbies.AddRange(response.Results);
|
||||
Status = $"{publicLobbies.Count} open lobby/lobbies found.";
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Status = $"Lobby query error: {exception.Message}";
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
|
||||
public async Task JoinPublicLobbyAsync(string lobbyId)
|
||||
{
|
||||
if (IsBusy || IsOnline || string.IsNullOrWhiteSpace(lobbyId)) return;
|
||||
string relayCode = null;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await InitializeServicesAsync();
|
||||
Lobby lobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
|
||||
if (lobby.Data.TryGetValue(RelayCodeDataKey, out DataObject relayCodeData))
|
||||
relayCode = relayCodeData.Value;
|
||||
else
|
||||
throw new InvalidOperationException("The lobby has no Relay join code.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Status = $"Lobby join error: {exception.Message}";
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
finally { IsBusy = false; }
|
||||
|
||||
if (!string.IsNullOrEmpty(relayCode))
|
||||
await StartClientAsync(relayCode);
|
||||
}
|
||||
|
||||
private async Task PublishLobbyAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = new CreateLobbyOptions
|
||||
{
|
||||
IsPrivate = false,
|
||||
Data = new Dictionary<string, DataObject>
|
||||
{
|
||||
{ RelayCodeDataKey, new DataObject(DataObject.VisibilityOptions.Public, JoinCode) }
|
||||
}
|
||||
};
|
||||
await LobbyService.Instance.CreateLobbyAsync($"{LocalPlayerName}'s Factory", maxClientCount + 1, options);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogWarning($"Lobby publishing failed. Join code still works. {exception.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task InitializeServicesAsync()
|
||||
{
|
||||
if (UnityServices.State == ServicesInitializationState.Uninitialized)
|
||||
await UnityServices.InitializeAsync();
|
||||
if (!AuthenticationService.Instance.IsSignedIn)
|
||||
await AuthenticationService.Instance.SignInAnonymouslyAsync();
|
||||
}
|
||||
|
||||
private void HandleServerStarted()
|
||||
{
|
||||
if (!loadFactoryAfterServerStart) return;
|
||||
loadFactoryAfterServerStart = false;
|
||||
LoadGameplayScene();
|
||||
}
|
||||
|
||||
private void HandleClientConnected(ulong clientId)
|
||||
{
|
||||
if (!networkManager.IsHost && clientId == networkManager.LocalClientId)
|
||||
{
|
||||
Status = "Connected. Loading Factory...";
|
||||
if (SceneManager.GetActiveScene().name != gameplaySceneName)
|
||||
SceneManager.LoadScene(gameplaySceneName);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadGameplayScene()
|
||||
{
|
||||
Status = "Loading factory...";
|
||||
if (!IsHost) return;
|
||||
Status = "Loading Factory...";
|
||||
networkManager.SceneManager.LoadScene(gameplaySceneName, LoadSceneMode.Single);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user