SKYXY客服
x
第五章 arcalet教程 - DP通訊 | skyxy
快速建站
︿
TOP
首頁 > 入門學習 > 文章內容
第五章 arcalet教程 - DP通訊
7/15/2016
瀏覽數:1718
沈夜
5.1 DP的基本架構
前言:
DP (Distributed Plugin) 是一種服務器邏輯架構,它可以架在任何可連線的電腦或伺服器。
它主要的功能是控管客戶端的資料與數據,如連線時發送獎勵,幫助玩家配對遊戲或更新資料等等。

在說明如何實現前,我們先來談談之前有提到的 “超級使用者” 。
超級使用者
超級使用者 ( Super User ) 又稱特權使用者,這是DP ( Distributed Plug-in ) 登入遊戲所使用的帳號。由於 DP 擔任遊戲主控者的角色,因此必須賦與存取其它玩家資料的特權,也就是說,此處的特權使用者函式並不是讓目前的登入者存取自己的資料,而是以額外的參數指定某個玩家,然後直接存取該玩家的資料。 特權函式只有登入帳號是超級使用者才能呼叫,否則 callback 將會傳回「無使用權限」錯誤碼。超級使用者函式的功能與參數和一般玩家函式相似,函式名稱以 su 開頭,如果該特權函式是針對特定玩家的資料進行操作,函式就會有一個額外的參數 userid,用來指定該特定玩家的帳號。
由此可知,只要不是 超級使用者 ,就不能從客服端修改任何資料,使到安全性大大的提升。

由於之前的範例,我們把一般使用者可以做修改的設定設為 “可讀寫”,所以我們現在要調成 “只可讀”。
(默認為“只可讀”)
設定:
DP 端:
dp端我們可以直接使用 visual studio 來達成。(本範例以2015版本為準)
由於要使用arcalet 的功能,我們需要把 arcalet.dll 拉進專案裡,並新增參考。
1.新建專案
2.加入參考
加入參考-> 遊覽 -> 選擇 arcalet.dll
加入成功後 visual studio 才能使用 arcalet api。
下一頁我們來了解client端是怎麼與DP建立連接。
5.2 Client連接DP
首先我們在 DP 端設定2個 TextBox ,分別顯示目前登入狀況,與目前連接的玩家。
DP 範例Code:
C#
public DP_001()
        {
            InitializeComponent();
        }

        public string dp_user = ""; //輸入超級使用者帳號
        public string dp_password = ""; //輸入超級使用者密碼
        public int onlinePlayerNumber = 0;

        private const string gguid = "";
        private const string sguid = "";
        byte[] certificate = { };
        public ArcaletGame ag = null;

        private void DP_001_Load(object sender, EventArgs e)
        {
            //啟動WindowsForm自動執行登入動作
            ag = new ArcaletGame(dp_user, dp_password, gguid, sguid, certificate);
            ag.onStateChanged += OnStateChanged;
            ag.onMessageIn += MainMessageIn;
            ag.onCompletion += CB_Login;
            ag.Launch();
            label1_look.Text = "On Login";
        }       

        void CB_Login(int code, ArcaletGame game)
        {
            if (code == 0) {
                //Code為0表示登入成功
                label1_look.Text = "Login Successed";
            }
            else {
                //Code非0表示登入失敗
                label1_look.Text = "Login Failed,Error Code:" + code;
            }
        }

        void OnStateChanged(int state, int code, ArcaletGame game)
        {
            //DP斷線的報錯機制
            if (state >= 900) label1_look.Text = "Disconnection,State:" + state +
                " Error Code:" + code;
        }

        void MainMessageIn(string msg, int delay, ArcaletGame game)
        {
            Console.WriteLine("MainMsgIn: " + msg);
            //使用Try Catch處理訊息可以避免收到錯誤訊息造成DP Exception
            try {
                string[] cmds = msg.Split(':'); //將收到的訊息以分號":" 區隔
                switch (cmds[0]) {
                    case "new": PlayerLogin(cmds[1]); break;
                    case "quit": PlayerLogout(); break;
                }
            }
            catch(Exception e){ }
        }

        void PlayerLogin(string msg) 
        {
            //將收到的訊息轉為poid,poid,poid在密頻傳送訊息時是很重要的指標
            int poid = int.Parse(msg);

            //發送給玩家端確認DP已經連接,並且附上DP的poid
            ag.PrivacySend("dp_new:"+ag.poid, poid);

            //線上玩家數+1
            onlinePlayerNumber++;

            //更新Form的資訊
            label2_look.Text = onlinePlayerNumber.ToString(); 
        }

        void PlayerLogout()
        {
            //線上玩家數-1
            onlinePlayerNumber--;

            //更新Form的資訊
            label2_look.Text = onlinePlayerNumber.ToString();
        }
客戶端:
由於我們需要知道dp的poid,我們才能傳輸資料到dp。

這裡有2個方法可以獲取 dp poid:
1. client端登入時發送一個附帶poid的大廳訊息,而dp則通過私人訊息把poid傳給玩家。
這樣就能要讓其他加入的玩家也能知道他登入,dp也能通過大廳訊息知道玩家的poid

2.dp登入的時候修改後台的值,再讓玩家抓取這個值,就可知道dp 的poid的。
訊息處理:
由於不管是dp或client之間都是用 string的格式發送訊息。
所以我們要定義一個指令集,供dp或client做分析處理。(dp的範例code已經包含在內)

如 玩家登入,client 發送的訊息為:
new:clientpoid
(指令):(訊息內容)

dp接受指令後發送回client端:
dp_new:dppoid
(指令):(訊息內容)
由於client 端部分已之前的範例大同小異 所以Code部分請自行下載測試。
PS:雖然界面上已之前範例無異,但卻是通過dp更新數據的。
登入畫面:
下一頁,我們開始學習如何通過DP來讀寫後台的物品。
壓縮檔位置:
*.zip\5.1-5.2_Unity+DP.zip

裡面分別有dp與unity的文件夾

Unity範例位置: 
Unity\Assets\Scene\0

此篇Dp範例位置: 
Dp\DP_Sample01
5.3 DP讀寫操作
了解dp的使用方法後,我們再繼續學習如何使用 super user 去修改後台item的數值。

此範例運用三種超級使用者指令來完成以下的工作:
新增玩家的ItemInstance 取得玩家的ItemInstance 修改玩家ItemInstance的屬性
(超級使用者跟一般使用者的api 大同小異,只差在需要輸入多一個需要修改玩家的Userid)
DP端:
程式碼部分與上一個登入的一樣 但我們要再加入幾行程式碼

1. 在  #region Variables 裡面增加Iguid欄位
    private const string sguid_game = ""; 

2. 由於我們要用到 private message 所以要在 DP_001_Load 函式裡面增加
    ag.onPrivateMessageIn += PrivateMessageIn;
其他需要增加的函式 (下列程式碼):
Code:
C#
void PrivateMessageIn(string msg, int delay, ArcaletGame game)
        {
            Console.WriteLine("PrivateMsgIn: " + msg);
            //使用Try Catch處理訊息可以避免收到錯誤訊息造成DP Exception
            try
            {
                string[] cmds = msg.Split(':'); //將收到的訊息以分號":" 區隔
                switch (cmds[0])
                {
                    case "item_new": DP_NewItemInstance(cmds[1].Split('/')); break;
                    case "attr_set": DP_SetItemAttribute(cmds[1].Split('/')); break;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        void DP_NewItemInstance(string[] msg)
        {
            //將玩家訊息轉換成userid
            string user = msg[0];
            int poid = int.Parse(msg[1]);

            //新增玩家的ItemInstance
            ArcaletItem.suNewItemInstance(ag, user, iguid, CB_NewPlayerItemInstance, msg);
        }

        void CB_NewPlayerItemInstance(int code, object data, object token)
        {
            string[] info = token as string[];
            int poid = int.Parse(info[1]);
            int itemID = (int)data;

            if (code == 0)
            {
                label3.Text = "New ItemInstance Successed,Item ID: " + itemID;
                ag.PrivacySend("dp_succ:New/" + itemID, poid);
            }
            else
            {
                label3.Text = "New ItemInstance Failed,Error Code: " + code;
                ag.PrivacySend("dp_err:New/" + code, poid);
            }
        }

        void DP_SetItemAttribute(string[] msg)
        {
            Console.WriteLine("SetItemAttribute Msg:" + msg);

            string user = msg[0]; //取出user
            int poid = int.Parse(msg[1]);
            string iguid = msg[2];
            string attr_name = msg[3];
            int itemID = int.Parse(msg[4]);
            string attr_value = msg[5];
            ArcaletItem.suSetItemInstanceAttribute(ag, user, iguid, itemID, attr_name, attr_value, CB_SetPlayerAttribute, poid);
        }

    
        void CB_SetPlayerAttribute(int code, object token)
        {
            if (code == 0)
            {
                int poid = (int)token;

                label3.Text = "Set Item Atrribute Successed";
                ag.PrivacySend("dp_succ:set", poid);
            }
            else
            {
                label3.Text = "Set Item Atrribute Failed\r\nError Code: " + code;
            }
        }
訊息處理:
從我們的程式碼可以看出來,我們訊息都是以符號 "/" 或 ":" 寄出去的,這個用意是為了可以讓我們的訊息只發送一行就能附帶各種訊息出去。(使用 split指令 )
當然開發者可以選擇如json等插件來執行這個功能,因為這2個符號會導致日期等格式發生問題。

安全性問題:
當然,由於是範例的關係,我們直接使用了client端呼叫Dp的方式去修改數值。
在正常的服務器邏輯下,這樣做是非常危險的,因為玩家還是能通過修改發出的訊息修改物品。如果要做到這樣的功能,所有數值的計算都要在Dp上執行才能達到安全的效果。
(如:玩家升等不是由client端叫dp修改,而是client端請dp檢查是否升等才傳回正確數值)
Client 端:
client端部分除了GetItemInstance 是從後台直接抓取外,其他都是通過dp更新的。
這麼做的原因是一來 item因為訊息沒辦法夾帶大量的訊息傳送(有最大字數限定),二來是因為讀取不會產生安全性問題。
由於client 端部分已之前的範例大同小異 所以Code部分請自行下載測試。
PS:雖然界面上與之前範例無異,但卻是通過dp更新數據的。(除了GetItemInstance)
執行畫面:
下一頁我們來學習如何使用arcalet來達成基本的玩家與玩家的連線功能。
壓縮檔位置:
*.zip\5.1-5.2_Unity+DP.zip

裡面分別有dp與unity的文件夾

Unity範例位置: 
Unity\Assets\Scene\0

此篇Dp範例位置: 
Dp\DP_Sample01
5.4 配對教程
學完之前的教程後,我們來學習如何使用dp達成配對遊戲。
現今很多遊戲都有支持多人遊戲,而且是不管電腦或手機都有涵蓋。
這章就教大家如何使用 arcalet 來達到簡單快速的配對功能。
Ps: 此範例配對需要導入額外插件,其導入的方法與 arcalet.dll 一樣。

下載鏈接:
此配對功能包含2個功能,分為一般配對與快速配對。

1.一般配對:
根據選擇要配對的 Tag 去配對其他玩家。
如:玩家1 Tag = 100,而此時 Tag = 100 有玩家2 正在等待,就會讓這2個玩家配對成功。

2.快速配對:
根據選擇要配對的 Tag ,從配對列表中抓取不超過這個Tag的值的玩家做配對。
如: 配對列表設定為 int[]{  10, 100,1000   }  ,而當前列表裡面 10 有 1個等待,但 100 與1000沒有等待玩家。
此時選擇Tag = 100,配對就會自動選擇小於等於100的值做配對,此時就會選擇10來完成配對。
Ps: 請注意,使用快速配對時,Tag 必須跟 設定好的配對列表一樣 如  int[]{  10, 100,1000   }   ,Tag必須是 10,100 或1000,否則會出現配對失敗錯誤
API內容:
詳細內容還請參考 google docs:
https://docs.google.com/document/d/1tiJo5X0sKQ7cy8fZ3AQdnco2ZT_YDb0OdFziOXLEG7E/edit?usp=sharing
由於程式碼部分內容比較多難以說明,還請開發者自行下載範例研究。(範例裡程式碼都有清楚標明功能)
一般配對執行畫面:
快速配對執行畫面:
壓縮檔位置:
*.zip\5.3.zip

裡面分別有dp與unity的文件夾

Unity範例位置: 
Unity\Assets\Scene\5\Match

此篇Dp範例位置: 
Dp\DP_Sample_Match
需要注意幾點:
  1. playermatch本身沒辦法取得玩家列表,所以開發者要自己定義一個玩家列表,用作存儲資料的地方。
  2. 雖然場景在沒人的情況下會關閉,但配對場景是由dp創建然後讓2個配對好的玩家加入(總共3個人),所以玩家都離開後要執行 Leave 指令,以免浪費資源。
另外,這裡的配對是因為要配合dp所使用的配對流程。
ArcaletScene也有提供不使用dp配對的api。(效率較差) 開發者可以針對自己的要求去開發研究。
http://developer.arcalet.com/tutorials/index.asp?maintitleclass=8&dirid=239&l=tw
1
2
3
4
 24_20160729152240.zip  (3.45 MB)
您也可能喜歡這些文章
留言給作者
不公開此留言     登入即可留言
讀者留言
載入更多留言