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

115 行
4.9 KiB

using System;
using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Once the local player is in a lobby and that lobby 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] private GameObject m_prefabNetworkManager = default;
[SerializeField] private GameObject[] m_disableWhileInGame = default;
private GameObject m_inGameManagerObj;
private NetworkManager m_networkManager;
private InGameRunner m_inGameRunner;
private bool m_isHost;
private bool m_doesNeedCleanup = false;
private bool m_hasConnectedViaNGO = false;
private Action<UnityTransport> m_initializeTransport;
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);
}
private void CreateNetworkManager()
{
m_inGameManagerObj = GameObject.Instantiate(m_prefabNetworkManager);
m_networkManager = m_inGameManagerObj.GetComponentInChildren<NetworkManager>();
m_inGameRunner = m_inGameManagerObj.GetComponentInChildren<InGameRunner>();
m_inGameRunner.Initialize(OnConnectionVerified, m_lobby.PlayerCount, OnGameEnd);
UnityTransport transport = m_inGameManagerObj.GetComponentInChildren<UnityTransport>();
if (m_isHost)
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupHost>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartHost(); });
else
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupClient>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartClient(); });
}
private void OnConnectionVerified()
{ m_hasConnectedViaNGO = true;
}
// These are public for use in the Inspector.
public void OnLobbyChange(LocalLobby lobby)
{ m_lobby = lobby; // Most of the time this is redundant, but we need to get multiple members of the lobby to the Relay setup components, so might as well just hold onto the whole thing.
}
public void OnLocalUserChange(LobbyUser user)
{ m_isHost = user.IsHost;
}
public void SetRelayServerData(string address, int port, byte[] allocationBytes, byte[] key, byte[] connectionData, byte[] hostConnectionData, bool isSecure)
{
m_initializeTransport = (transport) => { transport.SetRelayServerData(address, (ushort)port, allocationBytes, key, connectionData, hostConnectionData, isSecure); };
}
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.ConfirmInGameState)
{
m_doesNeedCleanup = true;
SetMenuVisibility(false);
CreateNetworkManager();
}
else if (type == MessageType.GameBeginning)
{
if (!m_hasConnectedViaNGO)
{
// If this player hasn't successfully connected via NGO, get booted.
Locator.Get.Messenger.OnReceiveMessage(MessageType.DisplayErrorPopup, "Failed to join the game.");
// TODO: Need to handle both failing to connect and connecting but failing to initialize.
// I.e. cleaning up networked objects *might* be necessary.
OnGameEnd();
}
}
else if (type == MessageType.ChangeGameState)
{
// Once we're in-game, any state change reflects the player leaving the game, so we should clean up.
OnGameEnd();
}
}
/// <summary>
/// Return to the lobby after the game, whether due to the game ending or due to a failed connection.
/// </summary>
private void OnGameEnd()
{
if (m_doesNeedCleanup)
{
GameObject.Destroy(m_inGameManagerObj); // Since this destroys the NetworkManager, that will kick off cleaning up networked objects.
SetMenuVisibility(true);
m_lobby.RelayNGOCode = null;
m_doesNeedCleanup = false;
}
}
}
}