ChatAuthenticator.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /*
  5. Documentation: https://mirror-networking.gitbook.io/docs/components/network-authenticators
  6. API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkAuthenticator.html
  7. */
  8. namespace Mirror.Examples.Chat
  9. {
  10. [AddComponentMenu("")]
  11. public class ChatAuthenticator : NetworkAuthenticator
  12. {
  13. readonly HashSet<NetworkConnection> connectionsPendingDisconnect = new HashSet<NetworkConnection>();
  14. internal static readonly HashSet<string> playerNames = new HashSet<string>();
  15. [Header("Client Username")]
  16. public string playerName;
  17. #region Messages
  18. public struct AuthRequestMessage : NetworkMessage
  19. {
  20. // use whatever credentials make sense for your game
  21. // for example, you might want to pass the accessToken if using oauth
  22. public string authUsername;
  23. }
  24. public struct AuthResponseMessage : NetworkMessage
  25. {
  26. public byte code;
  27. public string message;
  28. }
  29. #endregion
  30. #region Server
  31. // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload
  32. [UnityEngine.RuntimeInitializeOnLoadMethod]
  33. static void ResetStatics()
  34. {
  35. playerNames.Clear();
  36. }
  37. /// <summary>
  38. /// Called on server from StartServer to initialize the Authenticator
  39. /// <para>Server message handlers should be registered in this method.</para>
  40. /// </summary>
  41. public override void OnStartServer()
  42. {
  43. // register a handler for the authentication request we expect from client
  44. NetworkServer.RegisterHandler<AuthRequestMessage>(OnAuthRequestMessage, false);
  45. }
  46. /// <summary>
  47. /// Called on server from StopServer to reset the Authenticator
  48. /// <para>Server message handlers should be registered in this method.</para>
  49. /// </summary>
  50. public override void OnStopServer()
  51. {
  52. // unregister the handler for the authentication request
  53. NetworkServer.UnregisterHandler<AuthRequestMessage>();
  54. }
  55. /// <summary>
  56. /// Called on server from OnServerConnectInternal when a client needs to authenticate
  57. /// </summary>
  58. /// <param name="conn">Connection to client.</param>
  59. public override void OnServerAuthenticate(NetworkConnectionToClient conn)
  60. {
  61. // do nothing...wait for AuthRequestMessage from client
  62. }
  63. /// <summary>
  64. /// Called on server when the client's AuthRequestMessage arrives
  65. /// </summary>
  66. /// <param name="conn">Connection to client.</param>
  67. /// <param name="msg">The message payload</param>
  68. public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg)
  69. {
  70. Debug.Log($"Authentication Request: {msg.authUsername}");
  71. if (connectionsPendingDisconnect.Contains(conn)) return;
  72. // check the credentials by calling your web server, database table, playfab api, or any method appropriate.
  73. if (!playerNames.Contains(msg.authUsername))
  74. {
  75. // Add the name to the HashSet
  76. playerNames.Add(msg.authUsername);
  77. // Store username in authenticationData
  78. // This will be read in Player.OnStartServer
  79. // to set the playerName SyncVar.
  80. conn.authenticationData = msg.authUsername;
  81. // create and send msg to client so it knows to proceed
  82. AuthResponseMessage authResponseMessage = new AuthResponseMessage
  83. {
  84. code = 100,
  85. message = "Success"
  86. };
  87. conn.Send(authResponseMessage);
  88. // Accept the successful authentication
  89. ServerAccept(conn);
  90. }
  91. else
  92. {
  93. connectionsPendingDisconnect.Add(conn);
  94. // create and send msg to client so it knows to disconnect
  95. AuthResponseMessage authResponseMessage = new AuthResponseMessage
  96. {
  97. code = 200,
  98. message = "Username already in use...try again"
  99. };
  100. conn.Send(authResponseMessage);
  101. // must set NetworkConnection isAuthenticated = false
  102. conn.isAuthenticated = false;
  103. // disconnect the client after 1 second so that response message gets delivered
  104. StartCoroutine(DelayedDisconnect(conn, 1f));
  105. }
  106. }
  107. IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime)
  108. {
  109. yield return new WaitForSeconds(waitTime);
  110. // Reject the unsuccessful authentication
  111. ServerReject(conn);
  112. yield return null;
  113. // remove conn from pending connections
  114. connectionsPendingDisconnect.Remove(conn);
  115. }
  116. #endregion
  117. #region Client
  118. // Called by UI element UsernameInput.OnValueChanged
  119. public void SetPlayername(string username)
  120. {
  121. playerName = username;
  122. LoginUI.instance.errorText.text = string.Empty;
  123. LoginUI.instance.errorText.gameObject.SetActive(false);
  124. }
  125. /// <summary>
  126. /// Called on client from StartClient to initialize the Authenticator
  127. /// <para>Client message handlers should be registered in this method.</para>
  128. /// </summary>
  129. public override void OnStartClient()
  130. {
  131. // register a handler for the authentication response we expect from server
  132. NetworkClient.RegisterHandler<AuthResponseMessage>(OnAuthResponseMessage, false);
  133. }
  134. /// <summary>
  135. /// Called on client from StopClient to reset the Authenticator
  136. /// <para>Client message handlers should be unregistered in this method.</para>
  137. /// </summary>
  138. public override void OnStopClient()
  139. {
  140. // unregister the handler for the authentication response
  141. NetworkClient.UnregisterHandler<AuthResponseMessage>();
  142. }
  143. /// <summary>
  144. /// Called on client from OnClientConnectInternal when a client needs to authenticate
  145. /// </summary>
  146. public override void OnClientAuthenticate()
  147. {
  148. NetworkClient.Send(new AuthRequestMessage { authUsername = playerName });
  149. }
  150. /// <summary>
  151. /// Called on client when the server's AuthResponseMessage arrives
  152. /// </summary>
  153. /// <param name="msg">The message payload</param>
  154. public void OnAuthResponseMessage(AuthResponseMessage msg)
  155. {
  156. if (msg.code == 100)
  157. {
  158. Debug.Log($"Authentication Response: {msg.code} {msg.message}");
  159. // Authentication has been accepted
  160. ClientAccept();
  161. }
  162. else
  163. {
  164. Debug.LogError($"Authentication Response: {msg.code} {msg.message}");
  165. // Authentication has been rejected
  166. // StopHost works for both host client and remote clients
  167. NetworkManager.singleton.StopHost();
  168. // Do this AFTER StopHost so it doesn't get cleared / hidden by OnClientDisconnect
  169. LoginUI.instance.errorText.text = msg.message;
  170. LoginUI.instance.errorText.gameObject.SetActive(true);
  171. }
  172. }
  173. #endregion
  174. }
  175. }