Photon Server Login Practice



在前面一篇的 Server 基礎設置範例之後,本篇要介紹的是遊戲常見的 Login 動作,並且在未導入 Unity 之前,實建一個簡易 Client 作為模擬。





開始

建立 Client 測試程式

首先,我們先在先前的方案中新加入一個新的 Console 應用程式專案,.Net Framework 設為 4.6. 1 與 Server 的建置相同,命名則可按照你自己的風格命名,我是用 XXXClient 。 並且為他加入 lib,由於目前只是為了建立簡單的溝通模擬,所以只需要加入這個參考即可。
  • Photon3DotNet
 

實作 Client 類別

打開 Program.cs 將 class Program 繼承自 IphotonPeerListener,然後實作成員。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExitGames.Client.Photon;

namespace PenaltyClient
{
    class Program :IPhotonPeerListener
    {
        public bool isServerConnected;
        public bool isOnLogin;
        PhotonPeer peer;

        public Program()
        {
            isServerConnected = false;
            isOnLogin = false;
            this.peer = new PhotonPeer(this, ConnectionProtocol.Udp);
        }

        static void Main(string[] args)
        {
            new Program().Run();
        }

        private void Run()
        {
            if (peer.Connect("localhost:你的UDP PORT", "你的伺服器程式的真名"))
            {
                do
                {
                    peer.Service();

                    if (isServerConnected && !isOnLogin)
                    {
                        Console.WriteLine("\n請輸入帳號:");
                        string account = Console.ReadLine();
                        Console.WriteLine("\n請輸入密碼:");
                        string password = Console.ReadLine();

                        Dictionary parameter = new Dictionary {
                            { (byte)1, account.Trim()},
                            { (byte)2, password.Trim()}
                        };

                        this.peer.OpCustom(29, parameter, true);
                        isOnLogin = true;
                    }

                    System.Threading.Thread.Sleep(500);

                } while (true);
            }
            else
            {
                Console.WriteLine("Unknown hostname!");
            }
        }

        public void DebugReturn(DebugLevel level, string message)
        {
            Console.WriteLine("Debug message : " + message);
        }

        public void OnEvent(EventData eventData)
        {
        }

        public void OnMessage(object messages)
        {
        }

        public void OnOperationResponse(OperationResponse operationResponse)
        {
        }

        public void OnStatusChanged(StatusCode statusCode)
        {
            Console.WriteLine("PeerStatusCallback:" + statusCode.ToString());
            switch (statusCode)
            {
                case StatusCode.Connect:
                    isServerConnected = true;
                    break;
                case StatusCode.Disconnect:
                    isServerConnected = false;
                    break;
                default:
                    break;
            }
        }
    }
}

框架

  • Main - 模擬遊戲主迴圈,以簡單的 do...while 作為代替。
  • DebugReturn - Debug 的回傳字串。
  • OnEvent - 取得 Server 傳過來的事件。
  • OnMessage - 我還沒查這是要做啥的。
  • OnOperationResponse - 取得 Server 傳過來的命令回傳。
  • OnStatausChanged - 連線狀態變更的通知,Photon 連線後 OnStatusChanged 會接收到 StatusCode.Connect 命令碼,大多的網路遊戲都是要接收到連成功後才繼續做登入或選取伺服器等動作, 可在此處記錄目前伺服器的連線狀態。
 

Peer 物件

在建立時,必須以 ConnectionProtocol 告知建構子用何種傳輸方式
  • UDP - Photon 預設傳輸方式,速度較快,資料安全性較差 ( 但這部分 Photon 的可靠傳輸已處理好,所以可以放心使用 UDP 傳輸。 )
  • TCP - 資料安全性較高,但速度較慢。
額外參考: TCP 與 UDP

重要函式

  • peer.Service() - 框架並不會主動發生任何的傳輸,必需在主迴圈裡呼叫此函式以觸發調度和委派的作業。
  • peer.Connected() - 設定欲連線的 Server 位置與名字。 1.png
  • peer.OpCustom() - 將命令傳到 Server ,這裡設命令的代碼 29 代表是登入,這是自己訂的,不是絕對的。 2.png
 

ServerPeer 修改

改寫 OnOperationRequest 方法,取得傳入值 request 後利用 switch 解讀命令代碼,已假設 Login 代碼為 29,所以這裡直接用 case 29: 去處理登入命令。 此處只直接判斷帳號密碼是否為 test,1234,若成功,傳回
  • 成功 (ReturnCode:0) - 會員資料 (帳號、密碼、暱稱)。
  • 失敗 (ReturnCode:1)
 

protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
   switch (operationRequest.OperationCode)
   {
      case 29:
              if (operationRequest.Parameters.Count < 2)
              {
                 OperationResponse response = new OperationResponse(operationRequest.OperationCode)
                 {
                    ReturnCode = (short)2,
                    DebugMessage = "Login Fail"
                 };
                 SendOperationResponse(response, new SendParameters());
              }
              else
              {
                 string account = (string)operationRequest.Parameters[1];
                 string password = (string)operationRequest.Parameters[2];

                 if (account == "test" && password == "1234")
                 {

                     Dictionary parameter = new Dictionary
                     {
                        { (byte)1, account},
                        { (byte)2, password},
                        { (byte)3, "Venom"},
                     };

                     OperationResponse response = new OperationResponse(operationRequest.OperationCode,parameter)
                     {
                        ReturnCode = (short)0,
                        DebugMessage = ""
                     };

                     SendOperationResponse(response, new SendParameters());
              }
              else
              {
                  OperationResponse response = new OperationResponse(operationRequest.OperationCode)
                  {
                      ReturnCode = (short)1,
                      DebugMessage = "Wrong account or paasword"
                  };
                  SendOperationResponse(response, new SendParameters());
              }
           }
     break;
     default:
     break;
  }
}
 

框架

  • OnOperationRequest - 接收 Client 傳送過來的請求,對應處理判斷內容,並傳回適當的內容給 Client 。
 

重要函式


  • SendOperationResponse() - 透過此函式將要回傳的資料回傳給 Client 。 
  • 3.png


    物件成員

    • OperationResponse -  SendOperationResponse 函式所需的第一個參數物件。4.png

    • SendParameters - SendOperationResponse 函式所需的第二個參數物件。4.png

    Client 對應修改

    打開 client 端 Program.cs 改寫 OnOperationResponse
    
    public void OnOperationResponse(OperationResponse operationResponse)
            {
                switch (operationResponse.OperationCode)
                {
                    case (byte)29:
                        switch (operationResponse.ReturnCode)
                        {
                            case 0:
                                string account = Convert.ToString(operationResponse.Parameters[(byte)1]);
                                string password = Convert.ToString(operationResponse.Parameters[(byte)2]);
                                string nickname = Convert.ToString(operationResponse.Parameters[(byte)3]);
    
                                Console.WriteLine("帳號 : {0}\n 密碼 : {1}\n 暱稱 : {2}", account, password, nickname);
    
                                break;
                            case 1:
                                Console.WriteLine(operationResponse.DebugMessage);
                                break;
                            case 2:
                                Console.WriteLine(operationResponse.DebugMessage);
                                break;
                            default:
                                Console.WriteLine("不明的ReturnCode : {0}", operationResponse.ReturnCode);
                                break;
                        }
                        break;
                    default:
                        Console.WriteLine("不明的OperationCode : {0}", operationResponse.OperationCode);
                        break;
                }
            }
    

    當取得 Server 的回應後

    1. 判斷 OperationCode 是哪個要求的回傳值
    2. 若是 Login,再去判斷 ReturnCode 是否為成功
    3. 若 ReturnCode 為成功,則取得內容印出;失敗則印出 DebugMessage
     

    測試

    1. 將兩個專案進行編譯
    2. 按照昨天的方式將編譯完成的 Server 複製一份放入,作為更新動作
    3. 對 Client 進行 Debug 執行,鍵入我們預設好的帳號、密碼。

    成功回傳畫面

    5

    • Share:

    You Might Also Like

    0 意見