仿LOL項目開發第八天

仿LOL項目開發第八天

                                                                       by 草帽java

這節咱們繼續上節所講的內容,上節咱們初始化好了LoginWindow,當咱們點擊確認選擇服務器按鈕的時候,就發送服務器id給遊戲服務器。web

這裏就開始涉及到客戶端須要跟服務器的網絡通訊,因此咱們得先來寫個客戶端的Socket框架:服務器

NetworkManager.cs單例腳原本管理。網絡

由於我以前作過了這個腳本,因此我特地封裝了本身的網路管理network.dll,直接就能夠拿來用。框架

至於這裏面的腳本,有興趣的童鞋能夠本身去反編譯下看看。ide

network.dll下載地址測試

這個dll下載完成以後,咱們新建一個文件夾,取名爲Plugin,而後把這個dll拖到裏面去。ui

接着,開始正式的編寫NetworkManager腳本:this

 

using UnityEngine;
using System.Collections;
using System;
using Game;
public class NetworkManager : Singleton<NetworkManager>
{
    private WWW m_wwwRequest = null;
    private float m_fLastTimeForHeartBeat = 0f;
    public static string serverURL = "http://127.0.0.1/LOLGameDemo/serverUrl.xml";
    public static string serverIP = "127.0.0.1";
    public static int serverPort = 8000;
    public CNetProcessor m_netProcessor = null;
    public CNetwork m_network = null;
    private IXLog m_log = XLog.GetLog<NetworkManager>();
    public SocketState NetState
    {
        get
        {
            SocketState result;
            if (null != this.m_network)
            {
                SocketState state = this.m_network.GetState();
                result = state;
            }
            else
            {
                result = SocketState.State_Closed;
            }
            return result;
        }
    }
    public void Init()
    {
        CRegister.RegistProtocol();
        CNetObserver cNetObserver = new CNetObserver();
        this.m_netProcessor = new CNetProcessor();
        this.m_netProcessor.Observer = cNetObserver;
        cNetObserver.oProc = this.m_netProcessor;
        this.m_network = new CNetwork();
        CPacketBreaker oBreaker = new CPacketBreaker();
        string newFullPath = SystemConfig.ResourceFolder;
        if (!this.m_network.Init(this.m_netProcessor, oBreaker, 65536u, 65536u, newFullPath, true))
        {
            this.m_log.Fatal("oNet.Init Error");
        }
        else
        {
            this.m_log.Debug("oNet.Init Success!");
            this.m_netProcessor.Network = this.m_network;
        }
    }
    public void FixedUpdate()
    {
        try
        {
            if (this.m_netProcessor != null && null != this.m_netProcessor.Network)
            {
                this.m_netProcessor.Network.ProcessMsg();
                //this.m_netProcessor.Network.CheckHeartBeat(CommonDefine.IsMobilePlatform);
            }
        }
        catch (Exception ex)
        {
            this.m_log.Fatal(ex.ToString());
        }
    }
    private IEnumerator ConnectToURL()
    {
        Debug.Log("ConnectToURL:" + NetworkManager.serverURL);
        this.m_wwwRequest = new WWW(NetworkManager.serverURL);
        bool flag = false;
        for (int i = 0; i < 10; i++)
        {
            yield return new WaitForSeconds(0.5f);
            if (this.m_wwwRequest.isDone)
            {
                if (string.IsNullOrEmpty(this.m_wwwRequest.error))
                {
                    if (!string.IsNullOrEmpty(this.m_wwwRequest.text))
                    {
                        string[] array = this.m_wwwRequest.text.Split(new char[]
						{
							':'
						});
                        if (array.Length == 2)
                        {
                            NetworkManager.serverIP = array[0];//遊戲網關服務器ip地址
                            NetworkManager.serverPort = Convert.ToInt32(array[1]);
                            flag = true;
                            this.RealConnectToServer();
                        }
                        else
                        {
                            Debug.LogError("m_wwwRequest.text=:" + this.m_wwwRequest.text);
                        }
                    }
                }
                else
                {
                    Debug.LogError(this.m_wwwRequest.error.ToString());
                }
                break;
            }
        }
        if (null != this.m_wwwRequest)
        {
            this.m_wwwRequest.Dispose();
            this.m_wwwRequest = null;
        }
        if (!flag)
        {
            /*if (Singleton<Login>.singleton.IsLogined)
            {
                Singleton<ReConnect>.singleton.OnConnectToURLFailed();
            }
            else
            {
                Singleton<Login>.singleton.OnConnectToURLFailed();
            }*/
        }
        yield break;
    }
    private void RealConnectToServer()
    {
        this.m_log.Info(string.Format("ConnectToServer:{0}:{1}", NetworkManager.serverIP, NetworkManager.serverPort));
        if (!this.m_netProcessor.Network.Connect(NetworkManager.serverIP, NetworkManager.serverPort))
        {
            Debug.Log("Failed");
            /*if (!Singleton<Login>.singleton.IsLogined)
            {
                Singleton<Login>.singleton.OnConnectFailed();
            }
            else
            {
                Singleton<ReConnect>.singleton.OnConnectFailed();
            }*/
        }
        else
        {
            this.m_log.Info("Connecting...");
        }
    }
    public void ConnectToServer()
    {
        if (string.IsNullOrEmpty(NetworkManager.serverURL))
        {
            this.m_log.Error("serverURL IsNullOrEmpty");
        }
        LOLGameDriver.Instance.StartCoroutine(this.ConnectToURL());
    }
    public void SendMsg(CProtocol ptc)
    {
        try
        {
            if (null != this.m_netProcessor)
            {
                this.m_netProcessor.Send(ptc);
            }
        }
        catch (Exception ex)
        {
            this.m_log.Fatal(ex.ToString());
        }
    }
    public void Close()
	{
		Debug.Log("NetWorkManager::Close");
		if (null != this.m_network)
		{
			this.m_network.Close();
		}
		if (null != this.m_wwwRequest)
		{
			this.m_wwwRequest.Dispose();
			this.m_wwwRequest = null;
		}
	}
    public void UnInit()
    {
        Debug.Log("NetWorkManager::OnApplicationQuit");
        if (null != this.m_network)
        {
            this.m_network.UnInit();
            this.m_network = null;
        }
        this.m_netProcessor = null;
    }
    /// <summary>
    /// 發送登錄請求
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    /// <param name="serverId"></param>
    public void SendLogin(string username, string password, int serverId)
    {
        CptcC2GReq_Login instance = new CptcC2GReq_Login() 
        {
            m_strUsername = username,
            m_strPassword = password,
            m_dwServerId = serverId
        };
        SendMsg(instance);
    }
}

由於客戶端和服務器是有協議約定的,因此咱們每條消息都必須準守這個協議,這裏我在network.dll裏面就搞了個協議抽象基類Cptrocol.cs,而後本身在Unity中新建CRegister.cs來管理這些消息。阿里雲

CRegister:

 

using UnityEngine;
using System.Collections;
namespace Game
{
    internal class CRegister
    {
        /// <summary>
        /// 註冊消息協議
        /// </summary>
        public static void RegistProtocol() 
        {
            CProtocol.Register(new CptcG2CNtf_LoginResult());//1001,註冊登陸消息
        }
    }
}

能夠有些童鞋還會有報錯,這裏咱們得在寫個類:CNetObserver:主要用於接收消息的監控

 

using UnityEngine;
using System.Collections;
using Utility;
namespace Game
{
    public class CNetObserver : INetObserver
    {
        public CNetProcessor oProc = null;
        public void OnConnect(bool bSuccess)
        {
            if (!bSuccess)
            {
            }
            else
            {
                XLog.Log.Debug("Connect Success!");
            }
        }
        public void OnClosed(NetErrCode nErrCode)
        {
            XLog.Log.Error(string.Format("OnClosed:{0}", nErrCode.ToString()));
        }
        public void OnReceive(int unType, int nLen)
        {
            Singleton<PerformanceAnalyzer>.singleton.OnRecevie((uint)nLen);
        }
        public void OnSend(int dwType, int nLen)
        {
            Singleton<PerformanceAnalyzer>.singleton.OnSend((uint)nLen);
        }
    }
}

OK,這樣大體的網絡通訊的單例腳本就寫完了。這裏我講下大體的鏈接步驟流程。

首先,咱們點擊確認選擇按鈕,先判斷是否已經鏈接上網關服務器,若是沒有就開始鏈接。

那麼怎麼個鏈接法,我這裏採用的是,先訪問web站點,從站點中獲取網關服務器ip地址和端口號。這樣的好處是能動態的登錄網關服務器,好比網關1崩潰了,我只要改下web站點的ip就能夠了,若是在程序內寫死的話,這樣又得從新更新客戶端,麻煩。

你們能夠看到我這邊寫的是我本身的web站點地址,這裏,大家得改爲大家本身寫的。

這裏我寫的ip地址是127.0.0.1,端口號8000,由於咱們就在本地測試,因此就寫本地ip,若是是騰訊或者阿里雲的話,咱們就改爲他的ip地址便可。

而後咱們回到LoginCtrl裏面,添加一個方法LoginStart,傳遞的參數是選擇的服務器id:

 

    public void LoginStart(int serverId)
    {
        //若是已經鏈接上,就直接發送登錄消息請求
        if (Singleton<NetworkManager>.singleton.NetState == SocketState.State_Connected)
        {
            SystemConfig.SelectedServerIndex = serverId;//保存上次選擇的服務器id
            SystemConfig.LocalSetting.SelectedServer = serverId;//保存到本地配置
            //發送登錄消息請求
            NetworkManager.singleton.SendLogin(this.username,this.password,serverId);
        }
        else 
        {
            Singleton<NetworkManager>.singleton.ConnectToServer();//開始鏈接服務器
        }
    }

而後把這個方法添加到LoginWindow的SelectServerButton當作事件監聽。

 

    /// <summary>
    /// 登錄遊戲服務器
    /// </summary>
    /// <param name="go"></param>
    public void OnLoginServer(GameObject go)
    {
        if (this.m_selectedServerId >= 0)
        {
            LoginCtrl.singleton.LoginStart(this.m_selectedServerId);
        }
        else 
        {
            Debug.LogError("選擇服務器不存在");
        }
    }

OK,咱們回到NetworkManager中,來寫SendLogin這方法,主要是發送登錄消息給遊戲網關服務器。

 

    /// <summary>
    /// 發送登錄請求
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    /// <param name="serverId"></param>
    public void SendLogin(string username, string password, int serverId)
    {
        CptcC2GReq_Login instance = new CptcC2GReq_Login() 
        {
            m_strUsername = username,
            m_strPassword = password,
            m_dwServerId = serverId
        };
        SendMsg(instance);
    }

CptcC2GReq_Login這條就是登錄消息,遵照CProtocol

 

using UnityEngine;
using System.Collections;
using Game;
/// <summary>
/// 客戶端發送給服務器的登錄消息請求
/// </summary>
public class CptcC2GReq_Login : CProtocol
{
    public string m_strUsername;//用戶名
    public string m_strPassword;//密碼
    public int m_dwServerId;//選擇的服務器id
    public CptcC2GReq_Login()
        : base(1000)
    {
        this.m_strUsername = "";
        this.m_strPassword = "";
        this.m_dwServerId = 0;
    }
    public override CByteStream DeSerialize(CByteStream bs)
    {
        bs.Read(ref m_strUsername);
        bs.Read(ref m_strPassword);
        bs.Read(ref m_dwServerId);
        return bs;
    }
    public override CByteStream Serialize(CByteStream bs)
    {
        bs.Write(this.m_strUsername);
        bs.Write(this.m_strPassword);
        bs.Write(this.m_dwServerId);
        return bs;
    }
    public override void Process()
    {
        
    }
}

可見這條消息包括3個須要傳遞的變量:

 

    public string m_strUsername;//用戶名
    public string m_strPassword;//密碼
    public int m_dwServerId;//選擇的服務器i

有用戶名、密碼、還有選擇的遊戲服務器id。

OK,客戶端的通訊已經完成,接着咱們就得開始搭建服務器,我這裏採用的是java的mina框架。

不懂的童鞋能夠去先了解一下,很快就能入門。

 

 

 

CptcC2GReq_Login
相關文章
相關標籤/搜索