您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
236 行
9.6 KiB
236 行
9.6 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.Collections;
|
|
using Unity.Netcode;
|
|
using UnityEngine;
|
|
using VContainer;
|
|
|
|
namespace Unity.Multiplayer.Samples.BossRoom
|
|
{
|
|
public enum ConnectStatus
|
|
{
|
|
Undefined,
|
|
Success, //client successfully connected. This may also be a successful reconnect.
|
|
ServerFull, //can't join, server is already at capacity.
|
|
LoggedInAgain, //logged in on a separate client, causing this one to be kicked out.
|
|
UserRequestedDisconnect, //Intentional Disconnect triggered by the user.
|
|
GenericDisconnect, //server disconnected, but no specific reason given.
|
|
Reconnecting, //client lost connection and is attempting to reconnect.
|
|
IncompatibleBuildType, //client build type is incompatible with server.
|
|
HostEndedSession, //host intentionally ended the session.
|
|
StartHostFailed, // server failed to bind
|
|
StartClientFailed // failed to connect to server and/or invalid network endpoint
|
|
}
|
|
|
|
public struct ReconnectMessage
|
|
{
|
|
public int CurrentAttempt;
|
|
public int MaxAttempt;
|
|
|
|
public ReconnectMessage(int currentAttempt, int maxAttempt)
|
|
{
|
|
CurrentAttempt = currentAttempt;
|
|
MaxAttempt = maxAttempt;
|
|
}
|
|
}
|
|
|
|
public struct ConnectionEventMessage : INetworkSerializeByMemcpy
|
|
{
|
|
public ConnectStatus ConnectStatus;
|
|
public FixedPlayerName PlayerName;
|
|
}
|
|
|
|
[Serializable]
|
|
public class ConnectionPayload
|
|
{
|
|
public string playerId;
|
|
public string playerName;
|
|
public bool isDebug;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This state machine handles connection through the NetworkManager. It is responsible for listening to
|
|
/// NetworkManger callbacks and other outside calls and redirecting them to the current ConnectionState object.
|
|
/// </summary>
|
|
public class ConnectionManager : MonoBehaviour
|
|
{
|
|
public enum ServerType : byte
|
|
{
|
|
Undefined = 0,
|
|
DedicatedServer,
|
|
ClientHostedServer
|
|
}
|
|
|
|
ConnectionState m_CurrentState;
|
|
|
|
[SerializeField]
|
|
NetworkManager m_NetworkManager;
|
|
public NetworkManager NetworkManager => m_NetworkManager;
|
|
|
|
[SerializeField]
|
|
NetworkObject m_GameState;
|
|
public NetworkObject GameState => m_GameState;
|
|
|
|
[Inject]
|
|
IObjectResolver m_Resolver;
|
|
|
|
public int MaxConnectedPlayers = 8;
|
|
|
|
internal readonly OfflineState m_Offline = new OfflineState();
|
|
internal readonly ClientConnectingState m_ClientConnecting = new ClientConnectingState();
|
|
internal readonly ClientConnectedState m_ClientConnected = new ClientConnectedState();
|
|
internal readonly ClientReconnectingState m_ClientReconnecting = new ClientReconnectingState();
|
|
internal readonly DisconnectingWithReasonState m_DisconnectingWithReason = new DisconnectingWithReasonState();
|
|
internal readonly ServerStartingState m_ServerStarting = new ServerStartingState();
|
|
internal readonly ServerListeningState m_ServerListening = new ServerListeningState();
|
|
internal readonly HostStartingState m_HostStarting = new HostStartingState();
|
|
internal readonly HostListeningState m_HostListening = new HostListeningState();
|
|
|
|
public ServerType IsConnectedToHost { get; set; }
|
|
|
|
void Awake()
|
|
{
|
|
DontDestroyOnLoad(gameObject);
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_DisconnectingWithReason, m_HostStarting, m_HostListening, m_ServerListening, m_ServerStarting };
|
|
foreach (var connectionState in states)
|
|
{
|
|
m_Resolver.Inject(connectionState);
|
|
}
|
|
|
|
m_CurrentState = m_Offline;
|
|
|
|
NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback;
|
|
NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
|
|
NetworkManager.OnServerStarted += OnServerStarted;
|
|
NetworkManager.ConnectionApprovalCallback += ApprovalCheck;
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
NetworkManager.OnClientConnectedCallback -= OnClientConnectedCallback;
|
|
NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
|
|
NetworkManager.OnServerStarted -= OnServerStarted;
|
|
NetworkManager.ConnectionApprovalCallback -= ApprovalCheck;
|
|
}
|
|
|
|
internal void ChangeState(ConnectionState nextState)
|
|
{
|
|
Debug.Log($"Changed connection state from {m_CurrentState.GetType().Name} to {nextState.GetType().Name}.");
|
|
|
|
if (m_CurrentState != null)
|
|
{
|
|
m_CurrentState.Exit();
|
|
}
|
|
|
|
m_CurrentState = nextState;
|
|
m_CurrentState.Enter();
|
|
}
|
|
|
|
void OnClientDisconnectCallback(ulong clientId)
|
|
{
|
|
m_CurrentState.OnClientDisconnect(clientId);
|
|
}
|
|
|
|
void OnClientConnectedCallback(ulong clientId)
|
|
{
|
|
m_CurrentState.OnClientConnected(clientId);
|
|
}
|
|
|
|
void OnServerStarted()
|
|
{
|
|
m_CurrentState.OnServerStarted();
|
|
}
|
|
|
|
void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
|
|
{
|
|
m_CurrentState.ApprovalCheck(request, response);
|
|
}
|
|
|
|
public void StartClientLobby(string playerName)
|
|
{
|
|
m_CurrentState.StartClientLobby(playerName);
|
|
}
|
|
|
|
public void StartClientIp(string playerName, string ipaddress, int port)
|
|
{
|
|
m_CurrentState.StartClientIP(playerName, ipaddress, port);
|
|
}
|
|
|
|
public void StartHostLobby(string playerName)
|
|
{
|
|
m_CurrentState.StartHostLobby(playerName);
|
|
}
|
|
|
|
public void StartHostIp(string playerName, string ipaddress, int port)
|
|
{
|
|
m_CurrentState.StartHostIP(playerName, ipaddress, port);
|
|
}
|
|
|
|
public void StartServerIP(string ipaddress, int port)
|
|
{
|
|
m_CurrentState.StartServerIP(ipaddress, port);
|
|
}
|
|
|
|
public void RequestShutdown()
|
|
{
|
|
m_CurrentState.OnUserRequestedShutdown();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers the message handler for custom named messages. This should only be done once StartClient has been
|
|
/// called (start client will initialize NetworkSceneManager and CustomMessagingManager)
|
|
/// This will override the message handler each time and will use this instance's method.
|
|
/// </summary>
|
|
public void RegisterCustomMessages()
|
|
{
|
|
NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), ReceiveServerToClientSetDisconnectReason_CustomMessage);
|
|
NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(nameof(ReceiveServertoClientSuccessPayload_CustomMessage), ReceiveServertoClientSuccessPayload_CustomMessage);
|
|
}
|
|
|
|
void ReceiveServerToClientSetDisconnectReason_CustomMessage(ulong clientID, FastBufferReader reader)
|
|
{
|
|
reader.ReadValueSafe(out ConnectStatus status);
|
|
m_CurrentState.OnDisconnectReasonReceived(status);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a DisconnectReason to all connected clients. This should only be done on the server, prior to disconnecting the clients.
|
|
/// </summary>
|
|
/// <param name="status"> The reason for the upcoming disconnect.</param>
|
|
public static void SendServerToAllClientsSetDisconnectReason(ConnectStatus status)
|
|
{
|
|
var writer = new FastBufferWriter(sizeof(ConnectStatus), Allocator.Temp);
|
|
writer.WriteValueSafe(status);
|
|
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), writer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a DisconnectReason to the indicated client. This should only be done on the server, prior to disconnecting the client.
|
|
/// </summary>
|
|
/// <param name="clientID"> id of the client to send to </param>
|
|
/// <param name="status"> The reason for the upcoming disconnect.</param>
|
|
public static void SendServerToClientSetDisconnectReason(ulong clientID, ConnectStatus status)
|
|
{
|
|
var writer = new FastBufferWriter(sizeof(ConnectStatus), Allocator.Temp);
|
|
writer.WriteValueSafe(status);
|
|
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), clientID, writer);
|
|
}
|
|
|
|
internal void ReceiveServertoClientSuccessPayload_CustomMessage(ulong clientID, FastBufferReader reader)
|
|
{
|
|
reader.ReadValueSafe(out ServerType isHost);
|
|
IsConnectedToHost = isHost;
|
|
}
|
|
|
|
internal static void SendServertoClientSuccessPayload(ulong clientID, ServerType isHost)
|
|
{
|
|
var writer = new FastBufferWriter(sizeof(bool), Allocator.Temp);
|
|
writer.WriteValueSafe(isHost);
|
|
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServertoClientSuccessPayload_CustomMessage), clientID, writer);
|
|
}
|
|
}
|
|
}
|