6-15 Using Handler To Respond Requisition In Photon Server
本章繼續完成Server端處理Request的部分,基本概念與Client端差不多,只不過在Server時將用詞轉換成Handler。由於本章已經預先完成許多類別了,如果有直接跳到本章節進來看的朋友,建議先從6-1開始看比較好唷。
首先定義BaseHandler,一樣要有OperationCode,然後定義抽象方法OnOperationRequest。
接著撰寫LoginHandler去處理Client端傳來的Login Request,在建構子中先定義opercationCode為Login。
接著就可以覆寫OnOperationRequest,然後再方法內實作與資料庫驗證帳號密碼的動作。
使用我們前幾章寫好的UserManager,內部會處理跟User有關的資料庫操作。然後要特別注意的是,這邊我們使用了ReturnCode,這是由Photon定義的可供傳送小資訊(short)的參數,畢竟不是每一次Responce都需要建立一個Dictionary回傳吧。好比這次處理登入的事件,只需回傳Success或Failed即可。
接著,雖然ReturnCode是short型別,建議還是弄個enum去管理。
接著在NoliahFantasyServer.cs的主類別中新增LoginHandler,並將之Add進Dictionary中進行管理。
在MyClientPeer.cs中的OnOperationRequest中便能夠直接呼叫,先從operationRequest.OperationCode中取得byte碼,再從NoliahFantasyServer的Handler Dictionary中取得對應的BaseHandler,呼叫BaseHandler內的OnOperationRequest進行處理。
底下提供Server端本次修改的完整原始碼。
NoliahFantasyServer.cs:
BaseHandler.cs:
LoginHandler.cs:
MyClientPeer.cs:
ReturnCode.cs:
接下來繼續修改Client端,處理從Server傳回的Response。由於登入部分的處理涉及『場景切換』以及『顯示提示訊息』這兩個與UI比較相關的工作,所以我將這部分的處理劃分到LoginWindow.cs中。
接著在LoginWindow.cs中處理OnLoginResponse,失敗的話應有提示訊息顯示『帳號或密碼錯誤』,成功的話應要跳轉場景,但本章就先顯示個『登入成功』就好了。
以下提供原始碼:
LoginRequest.cs:
LoginWindow.cs:
接著來測試遊戲吧,首先輸入錯誤的帳號密碼。
再來輸入正確的帳號密碼,嗯,成功了!
首先定義BaseHandler,一樣要有OperationCode,然後定義抽象方法OnOperationRequest。
接著撰寫LoginHandler去處理Client端傳來的Login Request,在建構子中先定義opercationCode為Login。
接著就可以覆寫OnOperationRequest,然後再方法內實作與資料庫驗證帳號密碼的動作。
使用我們前幾章寫好的UserManager,內部會處理跟User有關的資料庫操作。然後要特別注意的是,這邊我們使用了ReturnCode,這是由Photon定義的可供傳送小資訊(short)的參數,畢竟不是每一次Responce都需要建立一個Dictionary回傳吧。好比這次處理登入的事件,只需回傳Success或Failed即可。
接著,雖然ReturnCode是short型別,建議還是弄個enum去管理。
接著在NoliahFantasyServer.cs的主類別中新增LoginHandler,並將之Add進Dictionary中進行管理。
在MyClientPeer.cs中的OnOperationRequest中便能夠直接呼叫,先從operationRequest.OperationCode中取得byte碼,再從NoliahFantasyServer的Handler Dictionary中取得對應的BaseHandler,呼叫BaseHandler內的OnOperationRequest進行處理。
底下提供Server端本次修改的完整原始碼。
NoliahFantasyServer.cs:
using System; using System.IO; using System.Collections.Generic; using Photon.SocketServer; using ExitGames.Logging; using ExitGames.Logging.Log4Net; using log4net.Config; using NHibernate; using NHibernate.Cfg; using NoliahFantasyServer.Constant; using NoliahFantasyServer.Handler; using NoliahFantasyServer.Model; using NoliahFantasyServer.Manager; namespace NoliahFantasyServer { public class NoliahFantasyServer : ApplicationBase { public static readonly ILogger logger = LogManager.GetCurrentClassLogger(); public static DictionaryhandlerDict = new Dictionary (); // 當Client端發出Request的時候 protected override PeerBase CreatePeer(InitRequest initRequest) { return new MyClientPeer(initRequest); } // Server端啟動的時候初始化 protected override void Setup() { InitLogger(); InitHandler(); } // Server端關閉的時候 protected override void TearDown() { } void InitLogger() { // 日誌初始化 log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] = Path.Combine(this.ApplicationRootPath, "bin_Win64", "log"); FileInfo loggerConfig = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config")); if (loggerConfig.Exists) { // 設置使用log4net的Log功能 LogManager.SetLoggerFactory(ExitGames.Logging.Log4Net.Log4NetLoggerFactory.Instance); // 讓log4net讀取config XmlConfigurator.ConfigureAndWatch(loggerConfig); } logger.Info("Setup Log4Net Compeleted!"); } void InitHandler(){ LoginHandler loginHandler = new LoginHandler(); handlerDict.Add(loginHandler.operationCode, loginHandler); } } }
BaseHandler.cs:
using System; using Photon.SocketServer; using NoliahFantasyServer.Constant; namespace NoliahFantasyServer.Handler { public abstract class BaseHandler { public OperationCode operationCode; public abstract void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, ClientPeer clientPeer); } }
LoginHandler.cs:
using System; using Photon.SocketServer; using NoliahFantasyServer.Constant; using NoliahFantasyServer.Manager; namespace NoliahFantasyServer.Handler { public class LoginHandler : BaseHandler { public LoginHandler(){ operationCode = OperationCode.Login; } public override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, ClientPeer clientPeer) { // 從OperationRequest取得帳號密碼資訊 object account; operationRequest.Parameters.TryGetValue((byte)ParameterCode.Acccount, out account); object password; operationRequest.Parameters.TryGetValue((byte)ParameterCode.Password, out password); // 使用UserManager向資料庫驗證使用者的帳號密碼 UserManager userManager = new UserManager(); bool isVerify = userManager.VerifyUser(account as string, password as string); // 使用short類型的ReturnCode簡單回傳結果 OperationResponse operationResponse = new OperationResponse((byte)OperationCode.Login); if(isVerify){ operationResponse.ReturnCode = (short)ReturnCode.Success; }else{ operationResponse.ReturnCode = (short)ReturnCode.Failed; } // 發送Response clientPeer.SendOperationResponse(operationResponse, sendParameters); } } }
MyClientPeer.cs:
using System; using System.Collections; using System.Collections.Generic; using Photon.SocketServer; using PhotonHostRuntimeInterfaces; using NoliahFantasyServer.Handler; using NoliahFantasyServer.Constant; namespace NoliahFantasyServer { public class MyClientPeer : ClientPeer { const int SIGNUP = 1; const int BROADCAST = 2; public MyClientPeer(InitRequest initRequest) : base(initRequest) { } // Client端斷開連結的時候 protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail) { } // 處理Client的Request請求 protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters) { BaseHandler baseHandler = null; NoliahFantasyServer.handlerDict.TryGetValue((OperationCode)operationRequest.OperationCode, out baseHandler); baseHandler.OnOperationRequest(operationRequest, sendParameters, this); } } }
ReturnCode.cs:
using System; namespace NoliahFantasyServer.Constant { public enum ReturnCode : short { Success, Failed } }
接下來繼續修改Client端,處理從Server傳回的Response。由於登入部分的處理涉及『場景切換』以及『顯示提示訊息』這兩個與UI比較相關的工作,所以我將這部分的處理劃分到LoginWindow.cs中。
接著在LoginWindow.cs中處理OnLoginResponse,失敗的話應有提示訊息顯示『帳號或密碼錯誤』,成功的話應要跳轉場景,但本章就先顯示個『登入成功』就好了。
以下提供原始碼:
LoginRequest.cs:
using System.Collections; using System.Collections.Generic; using UnityEngine; using ExitGames.Client.Photon; public class LoginRequest : Request { [HideInInspector] public string account; [HideInInspector] public string password; LoginWindow loginWindow; void Start(){ base.Start (); loginWindow = GetComponent(); } public override void OnDefaultRequest () { Dictionary data = new Dictionary (); data.Add((byte)ParameterCode.Acccount, account); data.Add((byte)ParameterCode.Password, password); // 向Server發出Request,true代表建立可靠連接 PhotonEngine.Instance.GetPeer().OpCustom((byte)operationCode, data, true); } public override void OnOperationResponse (OperationResponse operationResponse) { ReturnCode returnCode = (ReturnCode)operationResponse.ReturnCode; loginWindow.OnLoginResponse (returnCode); print (operationResponse.ReturnCode); } }
LoginWindow.cs:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; public class LoginWindow : Panel { [SerializeField] SignupWindow signupWindow; [SerializeField] InputField accountInput; [SerializeField] InputField passwordInput; [SerializeField] Text hintText; LoginRequest loginRequest; void Start(){ base.Start (); loginRequest = GetComponent(); } public void OnLoginButton(){ hintText.text = string.Empty; // 設定帳號及密碼參數後,呼叫OnDefaultRequest發送Request給Photon loginRequest.account = accountInput.text; loginRequest.password = passwordInput.text; loginRequest.OnDefaultRequest (); } public void OnShowSignupButton(){ this.Hide (); signupWindow.Show (); } public void OnLoginResponse(ReturnCode returnCode){ if (returnCode == ReturnCode.Success) { hintText.text = "登入成功"; } else { hintText.text = "帳號或密碼錯誤"; } } }
接著來測試遊戲吧,首先輸入錯誤的帳號密碼。
再來輸入正確的帳號密碼,嗯,成功了!
留言
張貼留言