您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
170 行
6.7 KiB
170 行
6.7 KiB
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Unity.Netcode;
|
|
using Unity.Netcode.Transports.UTP;
|
|
using Unity.Networking.Transport;
|
|
using Unity.Services.Relay;
|
|
using Unity.Services.Relay.Models;
|
|
using UnityEngine;
|
|
|
|
namespace LobbyRelaySample.ngo
|
|
{
|
|
/// <summary>
|
|
/// Once the local localPlayer is in a localLobby and that localLobby has entered the In-Game state, this will load in whatever is necessary to actually run the game part.
|
|
/// This will exist in the game scene so that it can hold references to scene objects that spawned prefab instances will need.
|
|
/// </summary>
|
|
public class SetupInGame : MonoBehaviour
|
|
{
|
|
[SerializeField]
|
|
GameObject m_IngameRunnerPrefab = default;
|
|
[SerializeField]
|
|
private GameObject[] m_disableWhileInGame = default;
|
|
|
|
private InGameRunner m_inGameRunner;
|
|
|
|
private bool m_doesNeedCleanup = false;
|
|
private bool m_hasConnectedViaNGO = false;
|
|
|
|
private LocalLobby m_lobby;
|
|
|
|
private void SetMenuVisibility(bool areVisible)
|
|
{
|
|
foreach (GameObject go in m_disableWhileInGame)
|
|
go.SetActive(areVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The prefab with the NetworkManager contains all of the assets and logic needed to set up the NGO minigame.
|
|
/// The UnityTransport needs to also be set up with a new Allocation from Relay.
|
|
/// </summary>
|
|
async Task CreateNetworkManager(LocalLobby localLobby, LocalPlayer localPlayer)
|
|
{
|
|
m_lobby = localLobby;
|
|
m_inGameRunner = Instantiate(m_IngameRunnerPrefab).GetComponentInChildren<InGameRunner>();
|
|
m_inGameRunner.Initialize(OnConnectionVerified, m_lobby.PlayerCount, OnGameBegin, OnGameEnd,
|
|
localPlayer);
|
|
if (localPlayer.IsHost.Value)
|
|
{
|
|
await SetRelayHostData();
|
|
NetworkManager.Singleton.StartHost();
|
|
}
|
|
else
|
|
{
|
|
await AwaitRelayCode(localLobby);
|
|
await SetRelayClientData();
|
|
NetworkManager.Singleton.StartClient();
|
|
}
|
|
}
|
|
|
|
async Task AwaitRelayCode(LocalLobby lobby)
|
|
{
|
|
string relayCode = lobby.RelayCode.Value;
|
|
lobby.RelayCode.onChanged += (code) => relayCode = code;
|
|
while (string.IsNullOrEmpty(relayCode))
|
|
{
|
|
await Task.Delay(100);
|
|
}
|
|
}
|
|
|
|
async Task SetRelayHostData()
|
|
{
|
|
UnityTransport transport = NetworkManager.Singleton.GetComponentInChildren<UnityTransport>();
|
|
|
|
var allocation = await Relay.Instance.CreateAllocationAsync(m_lobby.MaxPlayerCount.Value);
|
|
var joincode = await Relay.Instance.GetJoinCodeAsync(allocation.AllocationId);
|
|
GameManager.Instance.HostSetRelayCode(joincode);
|
|
|
|
bool isSecure = false;
|
|
var endpoint = GetEndpointForAllocation(allocation.ServerEndpoints,
|
|
allocation.RelayServer.IpV4, allocation.RelayServer.Port, out isSecure);
|
|
|
|
transport.SetHostRelayData(AddressFromEndpoint(endpoint), endpoint.Port,
|
|
allocation.AllocationIdBytes, allocation.Key, allocation.ConnectionData, isSecure);
|
|
}
|
|
|
|
async Task SetRelayClientData()
|
|
{
|
|
UnityTransport transport = NetworkManager.Singleton.GetComponentInChildren<UnityTransport>();
|
|
|
|
var joinAllocation = await Relay.Instance.JoinAllocationAsync(m_lobby.RelayCode.Value);
|
|
bool isSecure = false;
|
|
var endpoint = GetEndpointForAllocation(joinAllocation.ServerEndpoints,
|
|
joinAllocation.RelayServer.IpV4, joinAllocation.RelayServer.Port, out isSecure);
|
|
|
|
transport.SetClientRelayData(AddressFromEndpoint(endpoint), endpoint.Port,
|
|
joinAllocation.AllocationIdBytes, joinAllocation.Key,
|
|
joinAllocation.ConnectionData, joinAllocation.HostConnectionData, isSecure);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the server endpoint for connecting to the Relay server, for either an Allocation or a JoinAllocation.
|
|
/// If DTLS encryption is available, and there's a secure server endpoint available, use that as a secure connection. Otherwise, just connect to the Relay IP unsecured.
|
|
/// </summary>
|
|
NetworkEndPoint GetEndpointForAllocation(
|
|
List<RelayServerEndpoint> endpoints,
|
|
string ip,
|
|
int port,
|
|
out bool isSecure)
|
|
{
|
|
#if ENABLE_MANAGED_UNITYTLS
|
|
foreach (RelayServerEndpoint endpoint in endpoints)
|
|
{
|
|
if (endpoint.Secure && endpoint.Network == RelayServerEndpoint.NetworkOptions.Udp)
|
|
{
|
|
isSecure = true;
|
|
return NetworkEndPoint.Parse(endpoint.Host, (ushort)endpoint.Port);
|
|
}
|
|
}
|
|
#endif
|
|
isSecure = false;
|
|
return NetworkEndPoint.Parse(ip, (ushort)port);
|
|
}
|
|
|
|
string AddressFromEndpoint(NetworkEndPoint endpoint)
|
|
{
|
|
return endpoint.Address.Split(':')[0];
|
|
}
|
|
|
|
void OnConnectionVerified()
|
|
{
|
|
m_hasConnectedViaNGO = true;
|
|
}
|
|
|
|
public void StartNetworkedGame(LocalLobby localLobby, LocalPlayer localPlayer)
|
|
{
|
|
m_doesNeedCleanup = true;
|
|
SetMenuVisibility(false);
|
|
#pragma warning disable 4014
|
|
CreateNetworkManager(localLobby, localPlayer);
|
|
#pragma warning restore 4014
|
|
}
|
|
|
|
public void OnGameBegin()
|
|
{
|
|
if (!m_hasConnectedViaNGO)
|
|
{
|
|
// If this localPlayer hasn't successfully connected via NGO, forcibly exit the minigame.
|
|
LogHandlerSettings.Instance.SpawnErrorPopup("Failed to join the game.");
|
|
OnGameEnd();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return to the localLobby after the game, whether due to the game ending or due to a failed connection.
|
|
/// </summary>
|
|
public void OnGameEnd()
|
|
{
|
|
if (m_doesNeedCleanup)
|
|
{
|
|
NetworkManager.Singleton.Shutdown(true);
|
|
Destroy(m_inGameRunner
|
|
.transform.parent
|
|
.gameObject); // Since this destroys the NetworkManager, that will kick off cleaning up networked objects.
|
|
SetMenuVisibility(true);
|
|
m_lobby.RelayCode.Value = "";
|
|
GameManager.Instance.EndGame();
|
|
m_doesNeedCleanup = false;
|
|
}
|
|
}
|
|
}
|
|
}
|