using System; using System.Collections; using System.Collections.Generic; using UnityEngine; /* Documentation: https://mirror-networking.gitbook.io/docs/components/network-authenticators API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkAuthenticator.html */ namespace Mirror.Examples.Chat { [AddComponentMenu("")] public class ChatAuthenticator : NetworkAuthenticator { readonly HashSet connectionsPendingDisconnect = new HashSet(); [Header("Client Username")] public string playerName; #region Messages public struct AuthRequestMessage : NetworkMessage { // use whatever credentials make sense for your game // for example, you might want to pass the accessToken if using oauth public string authUsername; } public struct AuthResponseMessage : NetworkMessage { public byte code; public string message; } #endregion #region Server /// /// Called on server from StartServer to initialize the Authenticator /// Server message handlers should be registered in this method. /// public override void OnStartServer() { // register a handler for the authentication request we expect from client NetworkServer.RegisterHandler(OnAuthRequestMessage, false); } /// /// Called on server from StopServer to reset the Authenticator /// Server message handlers should be registered in this method. /// public override void OnStopServer() { // unregister the handler for the authentication request NetworkServer.UnregisterHandler(); } /// /// Called on server from OnServerAuthenticateInternal when a client needs to authenticate /// /// Connection to client. public override void OnServerAuthenticate(NetworkConnectionToClient conn) { // do nothing...wait for AuthRequestMessage from client } /// /// Called on server when the client's AuthRequestMessage arrives /// /// Connection to client. /// The message payload public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) { Debug.Log($"Authentication Request: {msg.authUsername}"); if (connectionsPendingDisconnect.Contains(conn)) return; // check the credentials by calling your web server, database table, playfab api, or any method appropriate. if (!Player.playerNames.Contains(msg.authUsername)) { // Add the name to the HashSet Player.playerNames.Add(msg.authUsername); // Store username in authenticationData // This will be read in Player.OnStartServer // to set the playerName SyncVar. conn.authenticationData = msg.authUsername; // create and send msg to client so it knows to proceed AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 100, message = "Success" }; conn.Send(authResponseMessage); // Accept the successful authentication ServerAccept(conn); } else { connectionsPendingDisconnect.Add(conn); // create and send msg to client so it knows to disconnect AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 200, message = "Username already in use...try again" }; conn.Send(authResponseMessage); // must set NetworkConnection isAuthenticated = false conn.isAuthenticated = false; // disconnect the client after 1 second so that response message gets delivered StartCoroutine(DelayedDisconnect(conn, 1f)); } } IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime) { yield return new WaitForSeconds(waitTime); // Reject the unsuccessful authentication ServerReject(conn); yield return null; // remove conn from pending connections connectionsPendingDisconnect.Remove(conn); } #endregion #region Client // Called by UI element UsernameInput.OnValueChanged public void SetPlayername(string username) { playerName = username; LoginUI.instance.errorText.text = string.Empty; LoginUI.instance.errorText.gameObject.SetActive(false); } /// /// Called on client from StartClient to initialize the Authenticator /// Client message handlers should be registered in this method. /// public override void OnStartClient() { // register a handler for the authentication response we expect from server NetworkClient.RegisterHandler(OnAuthResponseMessage, false); } /// /// Called on client from StopClient to reset the Authenticator /// Client message handlers should be unregistered in this method. /// public override void OnStopClient() { // unregister the handler for the authentication response NetworkClient.UnregisterHandler(); } /// /// Called on client from OnClientAuthenticateInternal when a client needs to authenticate /// public override void OnClientAuthenticate() { AuthRequestMessage authRequestMessage = new AuthRequestMessage { authUsername = playerName, }; NetworkClient.connection.Send(authRequestMessage); } /// /// Called on client when the server's AuthResponseMessage arrives /// /// The message payload public void OnAuthResponseMessage(AuthResponseMessage msg) { if (msg.code == 100) { Debug.Log($"Authentication Response: {msg.message}"); // Authentication has been accepted ClientAccept(); } else { Debug.LogError($"Authentication Response: {msg.message}"); // Authentication has been rejected // StopHost works for both host client and remote clients NetworkManager.singleton.StopHost(); // Do this AFTER StopHost so it doesn't get cleared / hidden by OnClientDisconnect LoginUI.instance.errorText.text = msg.message; LoginUI.instance.errorText.gameObject.SetActive(true); } } #endregion } }