forked from tmokmss/com.unity.multiplayer.samples.coop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConnectionManager.cs
214 lines (181 loc) · 8.18 KB
/
ConnectionManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using System;
using System.Collections.Generic;
using Unity.BossRoom.Utils;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UUnity.BossRoom.ConnectionManagement;
using VContainer;
namespace Unity.BossRoom.ConnectionManagement
{
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
{
ConnectionState m_CurrentState;
[Inject]
NetworkManager m_NetworkManager;
public NetworkManager NetworkManager => m_NetworkManager;
[SerializeField]
int m_NbReconnectAttempts = 2;
public int NbReconnectAttempts => m_NbReconnectAttempts;
[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 StartingHostState m_StartingHost = new StartingHostState();
internal readonly HostingState m_Hosting = new HostingState();
void Awake()
{
DontDestroyOnLoad(gameObject);
}
void Start()
{
List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_DisconnectingWithReason, m_StartingHost, m_Hosting };
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;
NetworkManager.OnTransportFailure += OnTransportFailure;
}
void OnDestroy()
{
NetworkManager.OnClientConnectedCallback -= OnClientConnectedCallback;
NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
NetworkManager.OnServerStarted -= OnServerStarted;
NetworkManager.ConnectionApprovalCallback -= ApprovalCheck;
NetworkManager.OnTransportFailure -= OnTransportFailure;
}
internal void ChangeState(ConnectionState nextState)
{
Debug.Log($"{name}: 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);
}
void OnTransportFailure()
{
m_CurrentState.OnTransportFailure();
}
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 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)
/// </summary>
public void RegisterCustomMessages()
{
NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), ReceiveServerToClientSetDisconnectReason_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 void SendServerToAllClientsSetDisconnectReason(ConnectStatus status)
{
var writer = new FastBufferWriter(sizeof(ConnectStatus), Allocator.Temp);
writer.WriteValueSafe(status);
NetworkManager.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 void SendServerToClientSetDisconnectReason(ulong clientID, ConnectStatus status)
{
var writer = new FastBufferWriter(sizeof(ConnectStatus), Allocator.Temp);
writer.WriteValueSafe(status);
NetworkManager.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), clientID, writer);
}
}
}