您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

147 行
5.8 KiB

using System;
using System.Threading.Tasks;
using LobbyRelaySample.relay;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services.Relay;
using UnityEngine;
using UnityEngine.SocialPlatforms;
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, IReceiveMessages
{
[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;
public void Start()
{
Locator.Get.Messenger.Subscribe(this);
}
public void OnDestroy()
{
Locator.Get.Messenger.Unsubscribe(this);
}
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, OnGameEnd, localPlayer);
if (localPlayer.IsHost.Value)
{
await SetRelayHostData();
NetworkManager.Singleton.StartHost();
}
else
{
await SetRelayClientData();
NetworkManager.Singleton.StartClient();
}
}
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);
m_lobby.RelayNGOCode.Value = joincode;
bool isSecure = false;
var endpoint = RelayUtpSetup.GetEndpointForAllocation(allocation.ServerEndpoints,
allocation.RelayServer.IpV4, allocation.RelayServer.Port, out isSecure);
transport.SetHostRelayData(RelayUtpSetup.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 = RelayUtpSetup.GetEndpointForAllocation(joinAllocation.ServerEndpoints,
joinAllocation.RelayServer.IpV4, joinAllocation.RelayServer.Port, out isSecure);
transport.SetClientRelayData(RelayUtpSetup.AddressFromEndpoint(endpoint), endpoint.Port,
joinAllocation.AllocationIdBytes, joinAllocation.Key,
joinAllocation.ConnectionData, joinAllocation.HostConnectionData, isSecure);
}
private 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 OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.ConfirmInGameState) { }
else if (type == MessageType.MinigameBeginning)
{
if (!m_hasConnectedViaNGO)
{
// If this localPlayer hasn't successfully connected via NGO, forcibly exit the minigame.
Locator.Get.Messenger.OnReceiveMessage(MessageType.DisplayErrorPopup, "Failed to join the game.");
OnGameEnd();
}
}
else if (type == MessageType.ChangeMenuState)
{
// Once we're in-game, any state change reflects the localPlayer leaving the game, so we should clean up.
OnGameEnd();
}
}
/// <summary>
/// Return to the localLobby after the game, whether due to the game ending or due to a failed connection.
/// </summary>
private void OnGameEnd()
{
if (m_doesNeedCleanup)
{
NetworkManager.Singleton.Shutdown();
Destroy(m_inGameRunner
.gameObject); // Since this destroys the NetworkManager, that will kick off cleaning up networked objects.
SetMenuVisibility(true);
m_lobby.RelayNGOCode = null;
m_doesNeedCleanup = false;
}
}
}
}