Unity太空大战游戏-Socket网络通信教学示例

2018-11-27 14:09 更新

项目下载地址

https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows

Example /Unity3D_2DShootServer_Client 项目文件位置。

教程编写有 SuperLinMeng 提供,QQ:2360450496

WeaveSocket通讯框架官方QQ群17375149

WeaveSocket框架-Unity太空大战游戏-

概述0

先看下最终的效果

服务端

用户登录后,认证成功进入游戏后

客户端

输入错误密码,有提示信息

主要技术架构

服务端端:

Socket框架【WeaveSocket】

https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows/

数据库【LiteDB】(3.1.4.0)

http://www.litedb.org/

界面UI【WPF】(.Net4.5)

项目源码图

Unity3D客户端:

WeaveSocket官方QQ群17375149 服务端运行图:

主要的用到的类为: WeaveTCPcloud类(部分重写,与原作者源码不同,请注意下) 代码如下:

using MyTcpCommandLibrary; using System; using System.Collections.Generic; using System.Net.Sockets; using System.Reflection; using System.Xml; using WeaveBase; using WeaveSocketServer; namespace MyTCPCloud { public class WeaveTCPcloud : IWeaveUniversal { public event WeaveLogDelegate WeaveLogEvent;

public event WeaveServerReceiveDelegate WeaveReceiveEvent;

public event WeaveServerUpdateSocketHander WeaveUpdateEvent;

public event WeaveServerDeleteSocketHander WeaveDeleteEvent;

public event WeaveServerUpdateUnityPlayerSetOnLineHander WeaveServerUpdateUnityPlayerSetOnLineEvent;

//public XmlDocument xml //{ // get;set; //}

public List<CmdWorkItem> CmdWorkItems { get { return _CmdWorkItems; }

set { _CmdWorkItems = value; } }

public WeaveTable weaveTable { get { return _weaveTable; }

set { _weaveTable = value; } }

public List<WeaveOnLine> weaveOnline { get { return _weaveOnline; }

set { _weaveOnline = value; } }

public List<UnityPlayerOnClient> unityPlayerOnClientList { get { return _unityPlayerOnClientList; }

set { _unityPlayerOnClientList = value; } }

// public IWeaveTcpBase P2Server public WeaveP2Server P2Server { get;set; }

public WeaveTcpToken TcpToken { get { return _TcpToken; }

set { _TcpToken = value; } }

List<CmdWorkItem> _CmdWorkItems = new List<CmdWorkItem>();

    
    WeaveTable _weaveTable = new WeaveTable();

 
    List<WeaveOnLine> _weaveOnline = new List<WeaveOnLine>();

    

   
   WeaveTcpToken _TcpToken = new WeaveTcpToken();

//我写的方法 List<UnityPlayerOnClient> _unityPlayerOnClientList = new List<UnityPlayerOnClient>();

    

   

    

public bool Run(WevaeSocketSession myI) { //ReloadFlies(); AddMyTcpCommandLibrary();

weaveTable.Add("onlinetoken", weaveOnline);//初始化一个队列,记录在线人员的token if (WeaveLogEvent != null) WeaveLogEvent("连接", "连接启动成功"); return true; } /// <summary> /// 读取WeavePortTypeEnum类型后,初始化 new WeaveP2Server("127.0.0.1"),并添加端口; /// </summary> /// <param name="WeaveServerPort"></param> public void StartServer(WeaveServerPort _ServerPort) {

       
         // WeaveTcpToken weaveTcpToken = new WeaveTcpToken();

     
           P2Server = new WeaveP2Server("127.0.0.1");

P2Server.waveReceiveEvent += P2ServerReceiveHander; P2Server.weaveUpdateSocketListEvent += P2ServerUpdateSocketHander; P2Server.weaveDeleteSocketListEvent += P2ServerDeleteSocketHander; // p2psev.NATthroughevent += tcp_NATthroughevent;//p2p事件,不需要使用 P2Server.Start( _ServerPort.Port );//myI.Parameter[4]是端口号

TcpToken.PortType = _ServerPort.PortType; TcpToken.P2Server = P2Server; TcpToken.IsToken = _ServerPort.IsToken; TcpToken.WPTE = _ServerPort.PortType;

            
           // TcpToken = weaveTcpToken;

        
           // P2Server = p2psev;

        
    }

public void AddMyTcpCommandLibrary() { try { LoginManageCommand loginCmd = new LoginManageCommand(); loginCmd.ServerLoginOKEvent += UpdatePlayerListSetOnLine; AddCmdWorkItems(loginCmd);

AddCmdWorkItems(new GameScoreCommand());

AddCmdWorkItems(new ClientDisConnectedCommand());

} catch {

} }

public void AddCmdWorkItems(WeaveTCPCommand cmd) { cmd.SetGlobalQueueTable(weaveTable, TcpToken); CmdWorkItem cmdItem = new CmdWorkItem(); // Ic.SetGlobalQueueTable(weaveTable, TcpTokenList); cmdItem.WeaveTcpCmd = cmd; cmdItem.CmdName = cmd.Getcommand(); GetAttributeInfo(cmd, cmd.GetType(), cmd); CmdWorkItems.Add(cmdItem); }

   
    public void GetAttributeInfo(WeaveTCPCommand Ic, Type t, object obj)
    {
        foreach (MethodInfo mi in t.GetMethods())
        {
            InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));
            if (myattribute == null)
            {
            }
            else
            {
                if (myattribute.Dtu)
                {
                    Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDtuDelegate), obj, mi, true);
                    Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDtuDelegate, myattribute.Type, true);
                }
                else
                {
                    Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true);
                    Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type);
                }
            }
        }
    }
    void P2ServerDeleteSocketHander(System.Net.Sockets.Socket soc)
    {

/我写的方法/ WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);

if (hasOnline != null) {

            
            UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);

WeaveDeleteEvent(uplayer);

weaveOnline.Remove(hasOnline);

// unityPlayerOnClientList.Remove(uplayer); DeleteUnityPlayerOnClient(hasOnline.Socket); } /**/

try { int count = CmdWorkItems.Count; CmdWorkItem[] cilist = new CmdWorkItem[count]; CmdWorkItems.CopyTo(0, cilist, 0, count); foreach (CmdWorkItem CI in cilist) { try { CI.WeaveTcpCmd.WeaveDeleteSocketEvent(soc); } catch (Exception ex) { if (WeaveLogEvent != null) WeaveLogEvent("EventDeleteConnSoc", ex.Message); } } } catch { } try { int count = weaveOnline.Count; WeaveOnLine[] ols = new WeaveOnLine[count]; weaveOnline.CopyTo(0, ols, 0, count); foreach (WeaveOnLine ol in ols) { if (ol.Socket.Equals(soc)) { foreach (CmdWorkItem CI in CmdWorkItems) { try { WeaveExcCmdNoCheckCmdName(0xff, "out|" + ol.Token, ol.Socket); CI.WeaveTcpCmd.Tokenout(ol); } catch (Exception ex) { if (WeaveLogEvent != null) WeaveLogEvent("Tokenout", ex.Message); } } weaveOnline.Remove(ol); return; } } } catch { } }

public void UpdatePlayerListSetOnLine(string _userName , System.Net.Sockets.Socket soc) { foreach(UnityPlayerOnClient oneclient in unityPlayerOnClientList) { if(oneclient.Socket == soc) { oneclient.UserName = _userName; oneclient.isLogin = true; WeaveServerUpdateUnityPlayerSetOnLineEvent(oneclient); break; } }

       
    }

void P2ServerUpdateSocketHander(System.Net.Sockets.Socket soc) {

       
        #region  读取 Command接口类,每次有新的Socket加入 重新读取并设置
        try
        {
            int count = CmdWorkItems.Count;
            CmdWorkItem[] cilist = new CmdWorkItem[count];
            CmdWorkItems.CopyTo(0, cilist, 0, count);
            foreach (CmdWorkItem CI in cilist)
            {
                try
                {
                    CI.WeaveTcpCmd.WeaveUpdateSocketEvent(soc);
                }
                catch (Exception ex)
                {
                    if (WeaveLogEvent != null)
                        WeaveLogEvent("EventUpdataConnSoc", ex.Message);
                }
            }
        }
        catch
        {

}

endregion 发送Token的代码

WeaveTcpToken token = TcpToken; { if (token.IsToken) { //生成一个token,后缀带随机数 string Token = DateTime.Now.ToString("yyyyMMddHHmmssfff") + new Random().Next(1000, 9999);// EncryptDES(clientipe.Address.ToString() + "|" + DateTime.Now.ToString(), "lllssscc"); if (token.P2Server.Port == ((System.Net.IPEndPoint)soc.LocalEndPoint).Port) { //向客户端发送生成的token bool sendok = false; if (token.PortType == WeavePortTypeEnum.Bytes) sendok = token.P2Server.Send(soc, 0xff, token.BytesDataparsing.Get_ByteBystring("token|" + Token + "")); else sendok = token.P2Server.Send(soc, 0xff, "token|" + Token + "");

region if(sendok)

                    if (sendok)
                    {
                        WeaveOnLine ol = new WeaveOnLine()
                        {
                            Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                            Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff")
                        };
                        ol.Token = Token;
                        ol.Socket = soc;

                       
                            WeaveOnLine hasOnline = weaveOnline.Find(item => item.Name == ol.Name);
                            {
                               if (hasOnline != null)
                              {
                                weaveOnline.Remove(hasOnline);

weaveOnline.Add(ol);

} else { weaveOnline.Add(ol); } }

                           

                       
                        /*我单独写的UnityClient*/
                        /*我写的新方法*/
                        UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Name == ol.Name);
                            if (hasPlayerIn != null)
                            {
                                WeaveDeleteEvent(hasPlayerIn);
                                unityPlayerOnClientList.Remove(hasPlayerIn);

} /我写的方法结束/

UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol); // unityPlayerOnClientList.Add(uplayer); AddUnityPlayerClient_CheckSameItem(uplayer , ol.Name); WeaveUpdateEvent(uplayer);

                        

                        

/**/

foreach (CmdWorkItem cmdItem in CmdWorkItems) { try { WeaveExcCmdNoCheckCmdName(0xff, "in|" + ol.Token, ol.Socket); cmdItem.WeaveTcpCmd.TokenIn(ol); } catch (Exception ex) { if (WeaveLogEvent != null) WeaveLogEvent("Tokenin", ex.Message); } } return; }

endregion

                }
            }
            else
            {
                WeaveOnLine ol = new WeaveOnLine()
                {
                    Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                    Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                    Socket = soc,
                    Token = DateTime.Now.ToString("yyyyMMddHHmmssfff")

}; weaveOnline.Add(ol);

/我单独写的UnityClient/ UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Socket == soc); if (hasPlayerIn != null) { WeaveDeleteEvent(hasPlayerIn); unityPlayerOnClientList.Remove(hasPlayerIn);

}

UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol); AddUnityPlayerClient_CheckSameItem(uplayer, ol.Name); WeaveUpdateEvent(uplayer); /**/ // ol.Token = DateTime.Now.ToString(); // ol.Socket = soc;

}

} } void P2ServerReceiveHander(byte command, string data, System.Net.Sockets.Socket soc) { if(command == (byte)CommandEnum.ClientSendDisConnected) { P2Server.CliendSendDisConnectedEvent(soc);

/我写的方法/ WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);

if (hasOnline != null) {

UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);

WeaveDeleteEvent(uplayer);

weaveOnline.Remove(hasOnline);

// unityPlayerOnClientList.Remove(uplayer); DeleteUnityPlayerOnClient(hasOnline.Socket); }

          
            /**/
            return;
        }

try { //触发接收到信息的事件... /我写的方法/ WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);

           
            if(hasOnline != null)
            {
                UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);

WeaveReceiveEvent(command, data, uplayer);

} /**/

if (command == 0xff) { //如果是网关command 发过来的 命名,那么执行下面的 WeaveExcCmdNoCheckCmdName(command, data, soc);

               
                try
                {
                    string[] temp = data.Split('|');
                    if (temp[0] == "in")
                    {
                        //加入onlinetoken
                        WeaveOnLine ol = new WeaveOnLine();
                        ol.Token = temp[1];
                        ol.Socket = soc;
                        weaveOnline.Add(ol);
                        foreach (CmdWorkItem CI in CmdWorkItems)
                        {
                            try
                            {
                                CI.WeaveTcpCmd.TokenIn(ol);
                            }
                            catch (Exception ex)
                            {
                                WeaveLogEvent?.Invoke("Tokenin", ex.Message);
                            }
                        }
                        return;
                    }
                    else if (temp[0] == "Restart")
                    {
                        int count = weaveOnline.Count;
                        WeaveOnLine[] ols = new WeaveOnLine[count];
                        weaveOnline.CopyTo(0, ols, 0, count);
                        string IPport = ((System.Net.IPEndPoint)soc.RemoteEndPoint).Address.ToString() + ":" + temp[1];
                        foreach (WeaveOnLine ol in ols)
                        {
                            try
                            {
                                if (ol.Socket != null)
                                {
                                    String IP = ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Address.ToString() + ":" + ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Port;
                                    if (IP == IPport)
                                    {
                                        ol.Socket = soc;
                                    }
                                }
                            }
                            catch { }
                        }
                    }
                    else if (temp[0] == "out")
                    {
                        ////移出onlinetoken
                        int count = weaveOnline.Count;
                        WeaveOnLine[] ols = new WeaveOnLine[count];
                        weaveOnline.CopyTo(0, ols, 0, count);
                        foreach (WeaveOnLine onlinesession in ols)
                        {
                            if (onlinesession.Token == temp[1])
                            {
                                foreach (CmdWorkItem cmdItem in CmdWorkItems)
                                {
                                    try
                                    {
                                        cmdItem.WeaveTcpCmd.Tokenout(onlinesession);
                                    }
                                    catch (Exception ex)
                                    {
                                        WeaveLogEvent?.Invoke("Tokenout", ex.Message);
                                    }
                                }
                                weaveOnline.Remove(onlinesession);
                                return;
                            }
                        }
                    }
                }
                catch { }
                return;
            }

else WeaveExcCmd(command, data, soc); } catch { return; } //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(exec)); }

  

/// <summary> /// 网关0xff这个command发来的...命令 /// </summary> /// <param name="command"></param> /// <param name="data"></param> /// <param name="soc"></param> public void WeaveExcCmdNoCheckCmdName(byte command, string data, System.Net.Sockets.Socket soc) { foreach (CmdWorkItem cmd in CmdWorkItems) { try { cmd.WeaveTcpCmd.Runcommand(command, data, soc); } catch (Exception ex) { WeaveLogEvent?.Invoke("receiveevent", ex.Message); } } }

/// <summary> /// 不是0xff这个command发来的...命令 /// </summary> /// <param name="command"></param> /// <param name="data"></param> /// <param name="soc"></param> public void WeaveExcCmd(byte command, string data, System.Net.Sockets.Socket soc) { foreach (CmdWorkItem cmd in CmdWorkItems) { if (cmd.CmdName == command) { try { cmd.WeaveTcpCmd.Run(data, soc); cmd.WeaveTcpCmd.RunBase(data, soc); } catch (Exception ex) { WeaveLogEvent?.Invoke("receiveevent", ex.Message); } } } }

public UnityPlayerOnClient ConvertWeaveOnlineToUnityPlayerOnClient(WeaveOnLine wonline) { UnityPlayerOnClient uplayer = new UnityPlayerOnClient() { Obj = wonline.Obj, Socket = wonline.Socket, Token = wonline.Token, Name = wonline.Name };

return uplayer;

}

public void DeleteUnityPlayerOnClient(Socket osc) { try { if (unityPlayerOnClientList.Count > 0) unityPlayerOnClientList.Remove(unityPlayerOnClientList.Find(u => u.Socket == osc)); } catch {

} }

public void AddUnityPlayerClient_CheckSameItem(UnityPlayerOnClient item ,string itemName) { System.Threading.Thread.Sleep(500); lock (this) { if (unityPlayerOnClientList.Find(i => i.Name == itemName) != null) return;

else unityPlayerOnClientList.Add(item); } } //public class CmdWorkItem //{ // public byte CmdName // { // get;set; // } // public WeaveTCPCommand WeaveTcpCmd // { // get;set; // } //} } }

重点说下AddMyTcpCommandLibrary方法 加载几个继承自 WeaveTCPCommand的类,里面写有一些方法,当服务器接收到客户端的一些参数后,可以直接跳转执行里面的写的方法,你可以新建一个类库项目(我这里命名为MyTcpCommandLibrary),然后引用项目 WeaveBase和WeaveSocketServer。在MyTcpCommandLibrary项目下新建几个类(根据你想要的逻辑),类继承WeaveTCPCommand,然后有具体的方法单独写出来,如

[InstallFun("forever")] public void CheckLogin(Socket soc, WeaveSession wsession) {

// string jsonstr = _0x01.Getjson(); LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();

//执行查找数据的操作...... bool loginOk = false;

AddSystemData();

loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); if (loginOk) { // UpdatePlayerListSetOnLine
ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);

} SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); //发送人数给客户端 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token } 当客户端发送命名为 Getcommand() 返回的命令byte,并且参数含方法名,即可直接调用服务端WeaveTCPCommand写的这个CheckLogin方法 客户端调用示例

weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);

再说下前端WPF启动服务器开始监听的代码

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using WeaveBase; using System.Net.Sockets; using MyTCPCloud; using System.Windows.Threading;

namespace WeavingSocketServerWPF { /// <summary> /// MyUnityServer.xaml 的交互逻辑 /// </summary> public partial class MyUnityServer : Window { public MyUnityServer() { InitializeComponent();

// DispatcherFunction(); } /// <summary> /// 监听端口列表,,可以选择监听多个端口 /// </summary> WeaveServerPort wserverport = new WeaveServerPort(); WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud();

List<MyListBoxItem> loginedUserList = new List<MyListBoxItem>();

List<MyListBoxItem> connectedSocketItemList = new List<MyListBoxItem>(); // DispatcherTimer dispatcherTimer = new DispatcherTimer();

private void StartListen_button_Click(object sender, RoutedEventArgs e) { //设置登陆后的用户列表Listbox的数据源 LoginedUser_listBox.ItemsSource = loginedUserList; //设置连接到服务器的Socket列表的Listbox的数据源 ConnectedSocket_listBox.ItemsSource = connectedSocketItemList;

WevaeSocketSession mif = new WevaeSocketSession();

       
        weaveTCPcloud.Run(mif);

wserverport.IsToken = true; wserverport.Port = Convert.ToInt32(Port_textBox.Text); wserverport.PortType = WeavePortTypeEnum.Json;

     
        weaveTCPcloud.StartServer(wserverport);

weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage;

weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket;

weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket;

weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent;

StartListen_button.Content = "正在监听";

StartListen_button.IsEnabled = false;

        
    }

private void OnWeaveServerUpdateUnityPlayerSetOnLineEvent(UnityPlayerOnClient gamer) {

        
        //throw new NotImplementedException();
        //当有用户 账号密码登陆成功的时候
        AddListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer));
        SetServerReceiveText("--触发了一次(OnWeaveServerUpdateUnityPlayerSetOnLineEvent)" + Environment.NewLine);

}

private void OnWeaveUpdateSocket(UnityPlayerOnClient gamer) { SetServerReceiveText("--触发了一次(OnWeaveUpdateSocket)" + Environment.NewLine);

//有 Sokcet客户端连接到服务器的时候,暂未 账号,密码认证状态

AddListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer) );

       
    }

   

private void OnWeaveDeleteSocket(UnityPlayerOnClient gamer) { SetServerReceiveText("--退出事件,,触发了一次(OnWeaveDeleteSocket)" + Environment.NewLine);

RemoveListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer));

RemoveListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer));

}

private void OnWeaveReceiveMessage(byte command, string data, UnityPlayerOnClient gamer) {

       

WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(data);

SetServerReceiveText("接收到新信息: " + ws.Root + Environment.NewLine );

     
    }

private void StopListen_button_Click(object sender, RoutedEventArgs e) {

weaveTCPcloud.P2Server = null;

weaveTCPcloud = null;

Application.Current.Shutdown(); Environment.Exit(0);// 可以立即中断程序执行并退出 }

private void SendMsg_button_Click(object sender, RoutedEventArgs e) {

       
        string serverMsg = InputSendMessage_textBox.Text;
        int unityGamecount = weaveTCPcloud.unityPlayerOnClientList.Count;
        if (string.IsNullOrEmpty(serverMsg) || weaveTCPcloud.weaveOnline.Count==0)
            return;

WeaveOnLine[] _allWeaveOnLine = new WeaveOnLine[weaveTCPcloud.weaveOnline.Count];

weaveTCPcloud.weaveOnline.CopyTo(_allWeaveOnLine);

foreach (WeaveOnLine oneWeaveOnLine in _allWeaveOnLine) { weaveTCPcloud.P2Server.Send(oneWeaveOnLine.Socket, 0x01, "服务器主动给所有客户端发消息了: " + serverMsg); }

// MessageBox.Show("客户端在线数量:"+ _allWeaveOnLine.Length); }

private void UpdateServerReceiveTb(TextBlock tb, string text) { tb.Text += text; }

private void SetServerReceiveText(string newtext) { Action<TextBlock, String> updateAction = new Action<TextBlock, string>(UpdateServerReceiveTb); ServerReceive_textBlock.Dispatcher.BeginInvoke(updateAction, ServerReceive_textBlock, newtext);

}

public MyListBoxItem CopyUnityPlayerOnClient(UnityPlayerOnClient one) { MyListBoxItem item = new MyListBoxItem() { UIName_Id = one.Socket.RemoteEndPoint.ToString(), ShowMsg = "UserIP:" + one.Socket.RemoteEndPoint.ToString() + " -Token:" + one.Token, UserName = one.UserName, Ip = one.Socket.RemoteEndPoint.ToString() }; return item; }

public void AddListBoxItem(List<MyListBoxItem> sList , MyListBoxItem one) {

      

sList.Add(one); CheckListBoxSource(); }

public void AddListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one) { Action< List < MyListBoxItem > , MyListBoxItem> addListBoxItemAction =

        
            new Action<List<MyListBoxItem>  , MyListBoxItem>(AddListBoxItem);

this.Dispatcher.BeginInvoke(addListBoxItemAction,sList , one); }

public void RemoveListBoxItem(List<MyListBoxItem> sList, MyListBoxItem one) { MyListBoxItem item = sList.Find(i=>i.Ip == one.Ip);

if(item != null) { sList.Remove(item); }

CheckListBoxSource(); }

public void RemoveListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one) { Action<List<MyListBoxItem>, MyListBoxItem> removeListBoxItemAction =

new Action<List<MyListBoxItem>, MyListBoxItem>(RemoveListBoxItem);

this.Dispatcher.BeginInvoke(removeListBoxItemAction, sList , one); }

public void CheckListBoxSource() { //数据发生变化后,重新设置登陆后的用户列表Listbox的数据源 LoginedUser_listBox.ItemsSource = null; LoginedUser_listBox.ItemsSource = loginedUserList; //数据发生变化后,重新设置连接到服务器的Socket列表的Listbox的数据源 ConnectedSocket_listBox.ItemsSource = null; ConnectedSocket_listBox.ItemsSource = connectedSocketItemList; }

protected override void OnClosed(EventArgs e) { weaveTCPcloud.P2Server = null;

weaveTCPcloud = null;

//Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose; //if (this.IsAfreshLogin == true) return; Application.Current.Shutdown(); Environment.Exit(0);// 可以立即中断程序执行并退出 base.OnClosed(e); }

}

public class MyListBoxItem { public string UIName_Id { get; set; }

public string Ip { get; set; } public string ShowMsg { get; set; }

public string UserName { get; set; } } } 主要的启动服务器的代码为

WeaveServerPort wserverport = new WeaveServerPort(); WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud();

WevaeSocketSession mif = new WevaeSocketSession(); //不知道这里干嘛,没搞懂 weaveTCPcloud.Run(mif);

wserverport.IsToken = true; wserverport.Port = Convert.ToInt32(Port_textBox.Text); wserverport.PortType = WeavePortTypeEnum.Json;

     
        weaveTCPcloud.StartServer(wserverport);

weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage;

weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket;

weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket;

weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent; 事件分别是 weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage; 接受到客户端发来的数据事件(这里如果发来的数据第一位byte命令跟上面的MyTcpCommandLibrary项目里面,继承自WeaveTCPCommand类,具体的返回的Getcommand()方法返回的byte命名相同,则会进入那个类进行处理) 假如客户端发送代码如下 weaveSocketGameClient.SendRoot<LoginTempModel>( 0x02 , "CheckLogin", user, 0); 表示客户端发送的命名是0x02 ,数据实体类是 LoginTempModel (数据发送报文格式,我们稍后再说) 服务端 MyTcpCommandLibrary有个类有如下代码

public class LoginManageCommand : WeaveTCPCommand { public delegate void ServerLoginOK(string _u,Socket _s);

public event ServerLoginOK ServerLoginOKEvent;

public override byte Getcommand() {

//此CLASS的实例,代表的指令,指令从0-254,0x9c与0xff为内部指令不能使用。 //0x01的意思是,只要是0x01的指令,都会进入本实例进行处理 //return 0x01; return (byte)CommandEnum.ClientSendLoginModel; //0x02; }

public override bool Run(string data, Socket soc) {

       
        //此事件是接收事件,data 是String类型的数据,soc是发送人。
        return true;
    }

public override void WeaveBaseErrorMessageEvent(Socket soc, WeaveSession _0x01, string message) { //错误异常事件,message为错误信息,soc为产生异常的连接 }

public override void WeaveDeleteSocketEvent(Socket soc) { //此事件是当有人中断了连接,此事件会被调用 }

public override void WeaveUpdateSocketEvent(Socket soc) { //此事件是当有人新加入了连接,此事件会被调用 }

[InstallFun("forever")] public void CheckLogin(Socket soc, WeaveSession wsession) {

// string jsonstr = _0x01.Getjson(); LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();

//执行查找数据的操作...... bool loginOk = false;

AddSystemData();

loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); if (loginOk) { // UpdatePlayerListSetOnLine
ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);

} SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); //发送人数给客户端 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token }

private void AddSystemData() { GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL();

if( myBLL.CheckDataBaseIsNull()) { myBLL.AddTestData(); } }

private bool CheckUserCanLoginIn(LoginTempModel m) { GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL(); return myBLL.CheckUserNamePassword(m.userName, m.password); }

} 那么则会调用服务端的CheckLogin方法 weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket; 当有Socket连接断开的事件

        

weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket; 当有新的Socket连接-首次连接成功的事件 weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent; 这是我根据源码修改的一个事件,当客户端连接成功,并且发送账号密码到服务器,服务器查找数据库后,确认给客户端可以登陆游戏后,把当前用户设置为已经上线的游戏玩家的事件

数据格式如下图

发送数据的主要代码为

byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text); byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString()); byte[] b = new byte[2 + part3_length.Length + sendb.Length]; b[0] = command; //表示第一位byte的命令 b[1] = (byte)part3_length.Length; //表示第三部分数据的长度 part3_length.CopyTo(b, 2); //扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面 sendb.CopyTo(b, 2 + part3_length.Length); //扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面... socket.Send( b ); 客户端代码结构

登陆界面

游戏场景

主要的逻辑流程

启动程序

玩家输入账号密码

点击登陆按钮

连接服务器(如果成功),继续发送账号密码到服务器的命令

服务器接收账号密码,进行查找数据库操作

发送查找结果给客户端......

如果客户端接收到服务器发过来的登陆成功消息(跳转到游戏场景),

如果返回失败,那么提示账号密码错误

客户端再次发送查找当前用户的历史积分数据的命令

(正在游戏场景运行中)

客户端接受到历史积分数据,并更新显示到UnityUI界面上

P0-玩家战机生命为0时,向服务器发送本次游戏积分数据

服务器收到玩家本次游戏积分数据,进行数据库更新操作(根据用户名)

客户端显示一个按钮,玩家可点击再玩一次,再次游戏(跳转P0,当玩家生命为0时)

客户端主要的代码类为WeaveSocketGameClient

(WeaveSocket框架对应为P2PClient,这里是模仿改写的便于Unity游戏客户端使用,代码内部使用的LoomUnity多线程插件).................................................

using Frankfort.Threading; using MyTcpCommandLibrary; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Reflection; using System.Text; using System.Threading; using UnityEngine; using WeaveBase;

namespace MyTcpClient { public class WeaveSocketGameClient { public Thread threadA; public Thread threadB;

private ThreadPoolScheduler myThreadScheduler;

WeaveBaseManager xmhelper = new WeaveBaseManager();

/// <summary> /// 是否连接成功 /// </summary> public bool isok = false; /// <summary> /// 在接收数据 /// </summary> public bool isReceives = false; /// <summary> /// 是否在线了 /// </summary> public bool IsOnline = false;

    
    DateTime timeout;
    /// <summary>
    /// 数据超时时间
    /// </summary>
    int mytimeout = 90;

/// <summary> /// 队列中没有排队的方法需要执行 /// </summary> List<TempPakeage> mytemppakeList = new List<TempPakeage>();

public List<byte[]> ListData = new List<byte[]>();

public string tokan;

public String ip; public int port;

public event ReceiveMessage ReceiveMessageEvent; public event ConnectOk ConnectOkEvent;

public event ReceiveBit ReceiveBitEvent; public event TimeOut TimeOutEvent; public event ErrorMessage ErrorMessageEvent;

public event JumpServer JumpServerEvent;

public TcpClient tcpClient;

// System.Threading.Thread receives_thread1;

// System.Threading.Thread checkToken_UpdateList_thread2;

SocketDataType s_datatype = SocketDataType.Json; public WeaveSocketGameClient(SocketDataType _type) { s_datatype = _type;

      
    }

region 客户端注册类,,服务端可以按方法名调用

public void AddListenClass(object obj) { GetAttributeInfo(obj.GetType(), obj); //xmhelper.AddListen()

//objlist.Add(obj);

} public void DeleteListenClass(object obj) { deleteAttributeInfo(obj.GetType(), obj); //xmhelper.AddListen()

//objlist.Add(obj);

} public void deleteAttributeInfo(Type t, object obj) { foreach (MethodInfo mi in t.GetMethods()) { InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute)); if (myattribute == null) {

} else { xmhelper.DeleteListen(mi.Name); } } } public void GetAttributeInfo(Type t, object obj) { foreach (MethodInfo mi in t.GetMethods()) { InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute)); if (myattribute == null) { } else { Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true); xmhelper.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type); } } }

endregion

/// <summary> /// 连接服务器 /// </summary> /// <param name="_ip">IP地址</param> /// <param name="_port">端口号</param> /// <param name="_timeout">过期时间</param> /// <param name="_takon">是否takon</param> /// <returns></returns> public bool StartConnect(string _ip, int _port, int _timeout, bool _takon) { mytimeout = _timeout; ip = _ip; port = _port; return StartConnectToServer(ip, port, _takon); } public bool RestartConnectToServer(bool takon) { return StartConnectToServer(ip, port, takon); }

private bool StartConnectToServer(string _ip, int _port, bool _takon) { try { if (s_datatype == SocketDataType.Json && ReceiveMessageEvent == null) Debug.Log("没有注册receiveServerEvent事件");

if (s_datatype == SocketDataType.Json && ReceiveBitEvent == null) Debug.Log("没有注册receiveServerEventbit事件"); ip = _ip; port = _port;

//tcpClient = new TcpClient(ip, port); tcpClient = new TcpClient(); // tcpc.ExclusiveAddressUse = false;

try { tcpClient.Connect(ip, port); } catch { return false; }

            
            IsOnline = true;
            isok = true;

timeout = DateTime.Now; if (!isReceives) { isReceives = true;

              

// ParameterThreadStart的定义为void ParameterizedThreadStart(object state), // 使用这个这个委托定义的线程的启动函数可以接受一个输入参数,

//receives_thread1 = new System.Threading.Thread(new ParameterizedThreadStart(ReceivesThread)); //receives_thread1.IsBackground = true; // receives_thread1.Start(); // ThreadStart这个委托定义为void ThreadStart(),也就是说,所执行的方法不能有参数 // checkToken_UpdateList_thread2 = new System.Threading.Thread(new ThreadStart(CheckToken_UpdateListDataThread)); //checkToken_UpdateList_thread2.IsBackground = true; // checkToken_UpdateList_thread2.Start();

/开始执行线程开始/ myThreadScheduler = Loom.CreateThreadPoolScheduler();

//--------------- Ending Single threaded routine 单线程程序结束-------------------- threadA = Loom.StartSingleThread(ReceivesThread,null, System.Threading.ThreadPriority.Normal, true); //--------------- Ending Single threaded routine 单线程程序结束--------------------

//--------------- Continues Single threaded routine 在单线程的程序-------------------- threadB = Loom.StartSingleThread(CheckToken_UpdateListDataThread, System.Threading.ThreadPriority.Normal, true); //--------------- Continues Single threaded routine 在单线程的程序-------------------- /开始执行线程结束/

} int ss = 0;

if (!_takon) return true;

while (tokan == null) { // System.Threading.Thread.Sleep(1000); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(1); ss++; if (ss > 10) return false; }

if(ConnectOkEvent != null) ConnectOkEvent();

return true; } catch (Exception e) { IsOnline = false; if (ErrorMessageEvent != null) ErrorMessageEvent( 1 , e.Message); return false; } }

region 几个方法的方法

public bool SendParameter<T>(byte command, String Request, T Parameter, int Querycount) { WeaveBase.WeaveSession b = new WeaveBase.WeaveSession(); b.Request = Request; b.Token = this.tokan; b.SetParameter<T>(Parameter); b.Querycount = Querycount; return SendStringCheck(command, b.Getjson()); } public bool SendRoot<T>(byte command, String Request, T Root, int Querycount) { WeaveBase.WeaveSession b = new WeaveBase.WeaveSession(); b.Request = Request; b.Token = this.tokan; b.SetRoot<T>(Root); b.Querycount = Querycount; return SendStringCheck(command, b.Getjson()); } public void Send(byte[] b) { tcpClient.Client.Send(b); } public bool SendStringCheck(byte command, string text) { try { //byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text); //byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString()); //byte[] b = new byte[2 + part3_length.Length + sendb.Length]; //b[0] = command; //b[1] = (byte)part3_length.Length; //part3_length.CopyTo(b, 2); //扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面 //sendb.CopyTo(b, 2 + part3_length.Length); //扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面...

byte[] b = MyGameClientHelper.CodingProtocol( command, text);

int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1); if (count == 0) { //判定数据长度,,实际指的是大小是不是小于40kb,,, tcpClient.Client.Send(b);

              
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960);
                    byte[] temp = new byte[zz];
                    Array.Copy(b, i * 40960, temp, 0, zz);
                    tcpClient.Client.Send(temp);
                    //分割发送......
                   // System.Threading.Thread.Sleep(1);
                    // Loom.WaitForNextFrame(10);
                    Loom.WaitForSeconds(0.001f);
                }
            }
        }
        catch (Exception ee)
        {
            IsOnline = false;
            CloseConnect();
            if (TimeOutEvent != null)
                TimeOutEvent();

          
            SendStringCheck(command, text);
            if (ErrorMessageEvent != null)
                ErrorMessageEvent(9, "send:" + ee.Message);
            return false;
        }
        // tcpc.Close();

return true; } public bool SendByteCheck(byte command, byte[] text) { try { //byte[] sendb = text; //byte[] lens = MyGameClientHelper.ConvertToByteList(sendb.Length); //byte[] b = new byte[2 + lens.Length + sendb.Length]; //b[0] = command; //b[1] = (byte)lens.Length; //lens.CopyTo(b, 2); //sendb.CopyTo(b, 2 + lens.Length); byte[] b = MyGameClientHelper.CodingProtocol(command, text);

int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1); if (count == 0) { tcpClient.Client.Send(b); } else { for (int i = 0; i < count; i++) { int zz = b.Length - (i 40960) > 40960 ? 40960 : b.Length - (i 40960); byte[] temp = new byte[zz]; Array.Copy(b, i * 40960, temp, 0, zz); tcpClient.Client.Send(temp); //System.Threading.Thread.Sleep(1); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(0.001f); } } } catch (Exception ee) { IsOnline = false; CloseConnect(); if (TimeOutEvent != null) TimeOutEvent();

SendByteCheck(command, text); if (ErrorMessageEvent != null) ErrorMessageEvent(9, "send:" + ee.Message); return false; } // tcpc.Close();

return true; }

endregion

/// <summary> /// 通过主线程执行方法避免跨线程UI问题 /// </summary> public void OnTick() { if (mytemppakeList.Count > 0) { try { TempPakeage str = mytemppakeList[0]; //xmhelper.Init(str.date, null); //receiveServerEvent(str.command, str.date);

} catch { } try { mytemppakeList.RemoveAt(0); } catch { } } Debug.Log("队列中没有排队的方法需要执行。"); }

public void CloseConnect() { try { isok = false;

IsOnline = false; //发送我要断开连接的消息 this.SendRoot<int>((byte)CommandEnum.ClientSendDisConnected, "OneClientDisConnected", 0, 0);

// receives_thread1.Abort(); //checkToken_UpdateList_thread2.Abort();

           
            tcpClient.Close();
            AbortThread();

} catch { Debug.Log("CloseConnect失败,发生异常"); }

       

}

void AbortThread() { if (myThreadScheduler.isBusy) //线程在此期间没有完成工作Threaded work didn't finish in the meantime: time to abort.时间终止 { Debug.Log("Terminate all worker Threads."); myThreadScheduler.AbortASyncThreads();

Debug.Log("Terminate thread A & B."); if (threadA != null && threadA.IsAlive) threadA.Interrupt();

if (threadB != null && threadB.IsAlive) threadB.Interrupt(); } else { Debug.Log("Terminate thread A & B."); if (threadA != null && threadA.IsAlive) threadA.Interrupt();

if (threadB != null && threadB.IsAlive) threadB.Interrupt(); }

}

/// <summary> /// 接收到服务器发来的数据的处理方法 /// </summary> /// <param name="obj"></param> void ReceiveData(object obj) { TempPakeage str = obj as TempPakeage; mytemppakeList.Add(str); if (ReceiveMessageEvent != null) ReceiveMessageEvent(str.command, str.date);

}

/// <summary> /// 线程启动的方法,初始化连接后要接收服务器发来的token,并更新 /// </summary> void CheckToken_UpdateListDataThread() { while (isok) { // System.Threading.Thread.Sleep(10); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(0.01f); try { int count = ListData.Count; if (count > 0) { int bytesRead = ListData[0] != null ? ListData[0].Length : 0; if (bytesRead == 0) continue; //如果到这里的continue内部,那么下面的代码不执行,重新到 --》 System.Threading.Thread.Sleep(10);开始

                    

byte[] tempbtye = new byte[bytesRead]; //解析消息体ListData,, Array.Copy(ListData[0], tempbtye, tempbtye.Length); // 检查tempbtye(理论上里面应该没有0x99,有方法已经处理掉了,但是可能会有)检测还有没有0x99开头的心跳包 _0x99: if (tempbtye[0] == 0x99) { if (bytesRead > 1) { byte[] b = new byte[bytesRead - 1]; byte[] t = tempbtye; //把心跳包0x99去掉 Array.Copy(t, 1, b, 0, b.Length); ListData[0] = b; tempbtye = b; goto _0x99; } else { //说明只有1个字节,心跳包包头,无任何意思,那么直接删除 ListData.RemoveAt(0); continue; } }

//ListData[0]第一个元素的长度 大于2 if (bytesRead > 2) { //第二段是固定一个字节,最高255,代表了第三段的长度 //这样第三段最高可以255*255位,这样表示数据内容的长度基本可以无限大了 // int a = tempbtye[1]; int part3_Length = tempbtye[1]; //tempbtye既是ListData[0]数据, //第一位为command,指令 //第二位的数据是第三段的长度 //第三段的数据是第四段的长度 //第四段是内容数据 if (bytesRead > 2 + part3_Length) { //如果收到数据这段数据,大于 // int len = 0; int part4_Length = 0; if (s_datatype == SocketDataType.Bytes) { byte[] bb = new byte[part3_Length]; byte[] part4_LengthBitArray = new byte[part3_Length];

//将tempbtye从第三位开始,复制数据到part4_LengthBitArray Array.Copy(tempbtye, 2, part4_LengthBitArray, 0, part3_Length); //len = ConvertToInt(bb); //获得实际数据的长度,也就是第四部分数据的长度 part4_Length = MyGameClientHelper. ConvertToInt(part4_LengthBitArray); } else { //如果DataType不是DataType.bytes类型,,, 是Json类型 //从某个Data中第三位开始截取数据,,获取第四段数据长度的字符串string String temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length); String part4_Lengthstr = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length);

part4_Length = 0; //len = 0; //int part4_Lengthstrlength = 0; try { // len = int.Parse(temp); part4_Length = int.Parse(part4_Lengthstr); if (part4_Length == 0) //len { //如果第四段数据的长度为0 ,,,说明发的空消息,,没有第四段数据 //如果第二位没有数据,,说明发的是空消息 ListData.RemoveAt(0); continue; } } catch { } }

try { //如果计算出来的(2位数据位+第三段长度+第四度长度) 比当前ListData[0]长度还大... if ((part4_Length + 2 + part3_Length) > tempbtye.Length) { if (ListData.Count > 1) { //将第一个数据包删除 ListData.RemoveAt(0); //重新读取第一个数据包(第二个数据包变为第一个)内容 byte[] temps = new byte[ListData[0].Length]; //将 数据表内容 拷贝到 temps中 Array.Copy(ListData[0], temps, temps.Length); //新byte数组长度扩充,原数据长度 + (第二个)元素长度 byte[] temps2 = new byte[tempbtye.Length + temps.Length];

Array.Copy(tempbtye, 0, temps2, 0, tempbtye.Length); //将第一个元素ListData[0]完全从第一个地址开始 ,完全拷贝到 temps2数组中 Array.Copy(temps, 0, temps2, tempbtye.Length, temps.Length); //将第二个元素拼接到temps2中,从刚复制数据的最后一位 +1 开始 ListData[0] = temps2; //最后将更新数据包里面的 第一个元素为新元素 } else { // System.Threading.Thread.Sleep(20); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(0.02f); } continue; } else if (tempbtye.Length > (part4_Length + 2 + part3_Length)) { //如果 数据包长度 比 计算出来的(2位数据位+第三段长度+第四度长度) 还大 //考虑大出的部分 int currentAddcount = (part4_Length + 2 + part3_Length); int offset_length = tempbtye.Length - currentAddcount; byte[] temps = new byte[offset_length];

//Array.Copy(tempbtye, (part4_Length + 2 + part3_Length), temps, 0, temps.Length); Array.Copy(tempbtye, currentAddcount, temps, 0, temps.Length); //把当前ListData[0]中 后面的数据,复制到 temps数组中...

ListData[0] = temps; } else if (tempbtye.Length == (part4_Length + 2 + part3_Length)) { //长度刚好匹配 ListData.RemoveAt(0); } } catch (Exception e) { if (ErrorMessageEvent != null) ErrorMessageEvent(3, e.StackTrace + "unup001:" + e.Message + "2 + a" + 2 + part3_Length + "---len" + part4_Length + "--tempbtye" + tempbtye.Length); }

try { if (s_datatype == SocketDataType.Json) { //读取出第四部分数据内容,, string temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2 + part3_Length, part4_Length); TempPakeage str = new TempPakeage(); str.command = tempbtye[0]; //命令等于第一位 str.date = temp; //服务器发来执行是0xff,说明发送的是token指令 if (tempbtye[0] == 0xff) { if (temp.IndexOf("token") >= 0) tokan = temp.Split('|')[1];

//用单个字符来分隔字符串,并获取第二个元素,, //这里因为服务端发来的token后面跟了一个|字符 else if (temp.IndexOf("jump") >= 0) { //0xff就是指服务器满了 tokan = "连接数量满"; if(JumpServerEvent!=null) JumpServerEvent(temp.Split('|')[1]); } else { // 当上面条件都不为真时执行 ,如果虽然指令是0xff,但是不包含token或jump ReceiveData(str);

} } else if (ReceiveMessageEvent != null) { //如果tempbtye[0] == 0xff 表示token,不等的情况 ReceiveData(str);

} } //if (DT == DataType.bytes) //{

// byte[] bs = new byte[len - 2 + a]; // Array.Copy(tempbtye, bs, bs.Length); // temppake str = new temppake(); // str.command = tempbtye[0]; // str.datebit = bs; // rec(str);

//} continue; } catch (Exception e) { if (ErrorMessageEvent != null) ErrorMessageEvent(3, e.StackTrace + "unup122:" + e.Message); } } } else { // //ListData[0]第一个元素的Length 不大于2 ,,
if (tempbtye[0] == 0) ListData.RemoveAt(0); } } } catch (Exception e) { if (ErrorMessageEvent != null) ErrorMessageEvent(3, "unup:" + e.Message + "---" + e.StackTrace); try { ListData.RemoveAt(0); } catch { } } } }

/// <summary> /// 线程启动的方法 /// </summary> /// <param name="obj"></param> void ReceivesThread(object obj) { while (isok) { //System.Threading.Thread.Sleep(50); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(0.05f); try { //可以用TcpClient的Available属性判断接收缓冲区是否有数据,来决定是否调用Read方法 int bytesRead = tcpClient.Client.Available; if (bytesRead > 0) { //缓冲区 byte[] tempbtye = new byte[bytesRead]; try { timeout = DateTime.Now; //从绑定接收数据 Socket 到接收缓冲区中 tcpClient.Client.Receive(tempbtye); _0x99: if (tempbtye[0] == 0x99) { //如果缓冲区第一个字符是 0x99心跳包指令 timeout = DateTime.Now; //记录现在的时间 if (tempbtye.Length > 1) { //去掉第一个字节,长度总体减去1个, byte[] b = new byte[bytesRead - 1]; try { //复制 Array 中的一系列元素(从指定的源索引开始), //并将它们粘贴到另一 Array 中(从指定的目标索引开始) //原始 Array 为tempbtye,原始Array的初始位置 //另外一个 目标 Array , 开始位置为0,长度为b.Length Array.Copy(tempbtye, 1, b, 0, b.Length); //那么b中的到的就是去掉心跳包指令0x99以后的后面的数据 } catch { } tempbtye = b; //反复执行去掉,心跳包,,, goto _0x99; } else continue;

//后面的不执行了,回调到 上面的while循环开始 重新执行... }

} catch (Exception ee) { if(ErrorMessageEvent!=null) ErrorMessageEvent(22, ee.Message); } //lock (this)

//{ //将接收到的 非心跳包数据加入到 ListData中 ListData.Add(tempbtye); // }

}

//线程每隔指定的过期时间秒,判定,如果没有数据发送过来,,,tcpc.Client.Available=0 情况下 else { try { TimeSpan ts = DateTime.Now - timeout; if (ts.TotalSeconds > mytimeout) { //判断时间过期 IsOnline = false; CloseConnect(); //isreceives = false;

if (TimeOutEvent != null) TimeOutEvent();

if (ErrorMessageEvent != null) ErrorMessageEvent(2, "连接超时,未收到服务器指令"); continue; } } catch (Exception ee) { if (ErrorMessageEvent != null) ErrorMessageEvent(21, ee.Message); } } } catch (Exception e) { if (ErrorMessageEvent != null) ErrorMessageEvent(2, e.Message); } } }

} } MainClient单例类

using UnityEngine; using System.Collections; using GDGeek; using MyTcpClient; using System; using UnityEngine.SceneManagement; using WeaveBase; using MyTcpCommandLibrary; using UnityEngine.Events; using MyTcpCommandLibrary.Model;

public class MainClient : Singleton<MainClient> {

public WeaveSocketGameClient weaveSocketGameClient;

public ServerBackLoginEvent serverBackLoginEvent =new ServerBackLoginEvent();

public SetLoginTempModelEvent setLoginTempModelEvent = new SetLoginTempModelEvent();

public SetGameScoreTempModelEvent setGameScoreTempModelEvent = new SetGameScoreTempModelEvent();

public FirstCheckServerEvent firstCheckServerEvent = new FirstCheckServerEvent();

public GameScoreTempModel GameScore;

public LoginTempModel loginUserModel; // Use this for initialization void Start() { DontDestroyOnLoad(this); setLoginTempModelEvent.AddListener(SetLoginModel);

} public string receiveMessage;

public void InvokeSetLoginTempModelEvent(LoginTempModel _model) { setLoginTempModelEvent.Invoke(_model); } GameScoreTempModel tempGameScore; public void CallSetGameScoreTempModelEvent(GameScoreTempModel gsModel) { // StartCoroutine(CallSetGameScoreEvent(gsModel)); tempGameScore = gsModel; }

IEnumerator CallSetGameScoreEvent(GameScoreTempModel gsModel) { yield return new WaitForSeconds(0.5f); setGameScoreTempModelEvent.Invoke(gsModel); }

// Update is called once per frame void Update() { //if (receiveMessage.Length != 0) //{ // receiveMessage = string.Empty; //} if (canLoadSceneFlag) { LoadGameScene(); canLoadSceneFlag = false; }

if (weaveSocketGameClient != null) weaveSocketGameClient.OnTick();

if(tempGameScore != null) { StartCoroutine(CallSetGameScoreEvent(tempGameScore)); tempGameScore = null; } }

public void ConnectToServer(string serverIp,int port) { try { weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json); weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent; weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent; weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent; weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent; weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent;

//pcp2.AddListenClass(new MyClientFunction()); Debug.Log("初始化OK"); //bool bb = pcp2.start("61.184.86.126", 10155, false); // bool bb = weaveSocketGameClient.StartConnect("61.184.86.126", 10155, 30, false); bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false); Debug.Log("链接OK"); firstCheckServerEvent.Invoke(bb); } catch { firstCheckServerEvent.Invoke(false); }

}

void CallServerFunc() { try { //weaveSocketGameClient.SendRoot<int>(0x02, "login", 11111, 0); //在加个发送 weaveSocketGameClient.tokan = "UnityTokan"; weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0); //调用服务端方法getnum,是服务端的方法。 //这样就可以了,我们试试 } catch (Exception e) { Debug.Log(e.ToString()); } }

private void OnTimeOutEvent() { Debug.Log("连接超时"); //throw new NotImplementedException(); }

private void OnReceiveBitEvent(byte command, byte[] data) { Debug.Log("收到了Bit数据"); // throw new NotImplementedException(); }

private void OnErrorMessageEvent(int type, string error) { Debug.Log("发生了错误"); //throw new NotImplementedException(); }

private void OnReceiveMessageEvent(byte command, string text) { // throw new NotImplementedException(); Debug.Log("收到了新数据");

//throw new NotImplementedException(); receiveMessage = "指令:" + command + ".内容:" + text; Debug.Log("原始数据是:" + receiveMessage); try { WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root); } catch { Debug.Log("Json转换对象出错了"); } // receiveMessage = "指令:" + command + ".内容:" + text; Debug.Log("收到的信息是:" + receiveMessage); ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command);

ICheckServerMessage checkSmsg = factory.CheckServerMessage(); checkSmsg.CheckServerMessage(text);

}

private void OnConnectOkEvent() { Debug.Log("已经连接成功"); }

private void StopConnect() { if (weaveSocketGameClient != null) {

weaveSocketGameClient.CloseConnect(); weaveSocketGameClient.ConnectOkEvent -= OnConnectOkEvent; weaveSocketGameClient.ReceiveMessageEvent -= OnReceiveMessageEvent; weaveSocketGameClient.ErrorMessageEvent -= OnErrorMessageEvent; weaveSocketGameClient.ReceiveBitEvent -= OnReceiveBitEvent; weaveSocketGameClient.TimeOutEvent -= OnTimeOutEvent;

// weaveSocketGameClient = null;

}

}

public void SendLogin(LoginTempModel user ) { try {

// weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0); StartCoroutine( WaitSendLogin(user) ); Debug.Log("SendLoginFunc"); } catch (Exception e) { Debug.Log(e.ToString()); } }

IEnumerator WaitSendLogin(LoginTempModel user) { yield return new WaitForSeconds(0.2f); weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0); }

public void SendCheckUserScore() { try { LoginTempModel user = loginUserModel; // weaveSocketGameClient.Tokan = "UnityTokan"; // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);

weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0); Debug.Log("SendLoginFunc"); } catch (Exception e) { Debug.Log(e.ToString()); } }

public void SendNewScoreUpdate(int _score,int _missed) { try { GameScoreTempModel gsModel = new GameScoreTempModel() { userName = loginUserModel.userName, missenemy = _missed, score = _score }; //LoginTempModel user = loginUserModel; // weaveSocketGameClient.Tokan = "UnityTokan"; // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);

weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0); Debug.Log("UpdateScore"); } catch (Exception e) { Debug.Log(e.ToString()); } }

public int sceneIndex; public bool canLoadSceneFlag; void LoadGameScene() { SceneManager.LoadScene(1); }

public void SetLoadSceneFlag() { canLoadSceneFlag = true; }

void OnDestroy() { //SetLoginModelEvent.RemoveListener(SetLoginModel);

}

private void SetLoginModel(LoginTempModel _model) { loginUserModel = _model; }

private void OnApplicationQuit() { StopConnect(); }

}

public class SetLoginTempModelEvent : UnityEvent<LoginTempModel> { }

public class SetGameScoreTempModelEvent : UnityEvent<GameScoreTempModel> { }

public class ServerBackLoginEvent : UnityEvent<bool>{}

public class FirstCheckServerEvent : UnityEvent<bool> { } 登陆界面类

using MyTcpCommandLibrary.Model; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class LoginHandler : MonoBehaviour {

public InputField input_Username; public InputField input_Password;


public InputField input_ServerIP;
public InputField input_ServerPort;

public Text server_msg_text; public Button login_button;

// public LoginModel userModel; // Use this for initialization void Start() { MainClient.Instance.serverBackLoginEvent.AddListener(GetServerBackLoginEvent);

MainClient.Instance.firstCheckServerEvent.AddListener(firstCheckServerConfigEvent); }

private void firstCheckServerConfigEvent(bool connectToServerResult) { // throw new NotImplementedException(); connectedServerOK = connectToServerResult; }

public void SetServerIP_Connected() { string ip = input_ServerIP.text; int port = int.Parse(input_ServerPort.text);

if(connectedServerOK ==false) MainClient.Instance.ConnectToServer(ip, port); }

private void GetServerBackLoginEvent(bool arg0) { //throw new NotImplementedException(); server_msg = "登陆失败,账号密码错误...";

   

}

public bool connectedServerOK = false;

public void Login() {

LoginTempModel model = new LoginTempModel() { userName = input_Username.text, password = input_Password.text, //userName = "ssss", //password = "yyyyyy", logintime = System.DateTime.Now.ToString("yyyyMMddHHmmssfff") }; // userModel = model; MainClient.Instance.InvokeSetLoginTempModelEvent(model); MainClient.Instance.SendLogin(model);

}

private string server_msg = "";

public void SetServerMsgShow(string serverMsg) { server_msg_text.text = serverMsg; }

void OnDestroy() { MainClient.Instance.serverBackLoginEvent.RemoveListener(GetServerBackLoginEvent);

MainClient.Instance.firstCheckServerEvent.RemoveListener(firstCheckServerConfigEvent);

}

// Update is called once per frame void Update () { if( string.IsNullOrEmpty( server_msg) ==false || server_msg.Length >2) { SetServerMsgShow(server_msg); login_button.gameObject.SetActive(true); server_msg = ""; } } }

游戏场景界面UI控制显示类

using UnityEngine; using System.Collections;

using UnityEngine.Events; using UnityEngine.UI; using System; using MyTcpCommandLibrary.Model;

public class GameScoreHandler : MonoBehaviour {

public static UpdateScoreEvent updateScoreEvent = new UpdateScoreEvent(); public static UpdateLivesEvent updateLivesEvent = new UpdateLivesEvent(); public static UpdateMissedEvent updateMissedEvent = new UpdateMissedEvent();

public static UnityEvent SendUpdateScoreEvent = new UnityEvent(); // public static UnityEvent<GameScoreTempModel> SetGameScoreUI;

public Text userNameText; public Text now_scoreText; public Text now_livesText; public Text now_missedText; public Text serverText;


public Text last_scoreText;
public Text last_missedText;

// Use this for initialization void Start() { updateScoreEvent.AddListener( OnUpdateScore); updateLivesEvent.AddListener(OnUpdateLives); updateMissedEvent.AddListener(OnUpdateMissed); SendUpdateScoreEvent.AddListener(OnSendUpdateScore); MainClient.Instance.setGameScoreTempModelEvent.AddListener(SetLastData);

}

private void OnSendUpdateScore() { //throw new NotImplementedException(); serverText.text = "积分已发往服务器..."; }

private void OnUpdateScore(int _score) {

   
    now_scoreText.text = "积分:" + _score.ToString();

   
}
void OnDestory()
{

updateScoreEvent.RemoveListener(OnUpdateScore); updateLivesEvent.RemoveListener(OnUpdateLives); updateMissedEvent.RemoveListener(OnUpdateMissed); SendUpdateScoreEvent.RemoveListener(OnSendUpdateScore); MainClient.Instance.setGameScoreTempModelEvent.RemoveListener(SetLastData);

} private void OnUpdateLives(int _lives) { now_livesText.text = "生命:" + _lives.ToString();

   
}

private void OnUpdateMissed(int _missed) {

   
    now_missedText.text = "放走敌人:" + _missed.ToString();
}

private void OnDestroy() {

}

public void SetUserNameData(string _uname) { userNameText.text = _uname; }

public void SetLastData(GameScoreTempModel gsModel) { //userNameText.text = "生命:" + gsModel.userName; //last_scoreText.text = "积分:" + gsModel.score.ToString(); //last_missedText.text = "放走敌人:" + gsModel.missenemy.ToString(); tempScore = gsModel; }

public void SetLastDataText() { userNameText.text = "生命:" + tempScore.userName; last_scoreText.text = "积分:" + tempScore.score.ToString(); last_missedText.text = "放走敌人:" + tempScore.missenemy.ToString(); }

public void SetNowDate(int _lives, int _lastScore, int _lastMissed) { now_livesText.text ="生命:"+ _lives.ToString(); now_scoreText.text = "积分:" + _lastScore.ToString(); now_missedText.text = "放走敌人:" + _lastMissed.ToString(); }

GameScoreTempModel tempScore; // Update is called once per frame void Update() { if(tempScore != null) { SetLastDataText(); tempScore = null; } }

public void ReloadGameScene() { //跳转场景 MainClient.Instance.SetLoadSceneFlag();

//发送读取上次分数数据的逻辑 MainClient.Instance.SendCheckUserScore(); }

} public class UpdateScoreEvent: UnityEvent<int> { } public class UpdateLivesEvent : UnityEvent<int> { } public class UpdateMissedEvent : UnityEvent<int> { } 客户端使用的主要代码为

WeaveSocketGameClient weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json); weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent; weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent; weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent; weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent; weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent; Debug.Log("初始化OK"); bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false); Debug.Log("链接OK"); //触发第一次 检查并连接服务器状态事件,用于通知其它Unity脚本,作出相应反应 firstCheckServerEvent.Invoke(bb); 没什么可说的,代码已经很明确了,常用的几个事件都有,,

具体说一下MainClient类里面的 接收数据处理用的抽象工厂

在接收事件处理方法里面写有如下代码

Debug.Log("收到了新数据");

receiveMessage = "指令:" + command + ".内容:" + text; Debug.Log("原始数据是:" + receiveMessage); try { WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root); } catch { Debug.Log("Json转换对象出错了"); } Debug.Log("收到的信息是:" + receiveMessage); //根据收到的指令来确定要生成的工厂 ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command); //调用对应工厂,生成具体的接口实现类 ICheckServerMessage checkSmsg = factory.CheckServerMessage(); //调用具体接口类的 处理数据的具体方法 checkSmsg.CheckServerMessage(text); 抽象工厂以及相关代码如下

帮助类,也可直接写成Switch,这里避免代码过长,所以封装了一下

using UnityEngine; using System.Collections;

public static class CheckCommandHelper { public static ICheckServerMessageFactory SwitchCheckCommand(byte command) { ICheckServerMessageFactory factory = null; switch (command) { case (0x1): factory = new LoginMessageFactory(); break; case (0x2): factory = new GameScoreMessageFactory(); break; //其他类型略; } return factory; }

}

工厂接口

using System;

public interface ICheckServerMessageFactory {

ICheckServerMessage CheckServerMessage();

}

数据处理接口

using System;

public interface ICheckServerMessage {

void CheckServerMessage( string text);

}

具体实现类

using UnityEngine; using System.Collections; using System; using WeaveBase; public class LoginMessage : ICheckServerMessage { public void CheckServerMessage( string text) { // throw new NotImplementedException(); WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("收到的消息是:"+text); if(ws.Request == "ServerBackLoginResult" ) { if( ws.GetRoot<bool>() == true) { //如果登陆成功,,处理的逻辑...... //先更新用户

//跳转场景 MainClient.Instance.SetLoadSceneFlag();

//发送读取上次分数数据的逻辑 MainClient.Instance.SendCheckUserScore(); }

       
        else
        {
            MainClient.Instance.serverBackLoginEvent.Invoke(false);
        }
    }

   

}

} using UnityEngine; using System.Collections; using System; using WeaveBase; using MyTcpCommandLibrary.Model;

public class GameScoreMessage : ICheckServerMessage { public void CheckServerMessage(string text) { // throw new NotImplementedException(); WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("收到的GameScoreMessage消息是:" + text); if (ws.Request == "ServerSendGameScore") { GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>(); if (gsModel != null ) {

MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);

          
        }

else { // MainClient.Instance.serverBackLoginEvent.Invoke(false); } }

} }

using UnityEngine; using System.Collections; using System;

public class LoginMessageFactory : ICheckServerMessageFactory { public ICheckServerMessage CheckServerMessage() { //throw new NotImplementedException(); return new LoginMessage(); } }

using UnityEngine; using System.Collections;

public class GameScoreMessageFactory : ICheckServerMessageFactory { public ICheckServerMessage CheckServerMessage() { //throw new NotImplementedException(); return new GameScoreMessage(); } }

命令的枚举

using System;

namespace MyTcpCommandLibrary { public enum CommandEnum :byte { /// <summary> /// /// </summary> ClientSendLoginModel = 0x02,

ClientSendGameScoreModel = 0x03,

ServerSendLoginResult = 0x04,

// ServerSendGameScoreModel = 0x05,

ClientSendDisConnected = 0x06,

ServerSendUpdateGameScoreResult = 0x07,

ClientSendCheckScore = 0x08,

ServerSendGetGameScoreResult = 0x09

} }

让我们再次来理一理客户端逻辑

启动程序

玩家输入账号密码

点击登陆按钮,

调用MainClient里面的ConnectToServer 方法

连接服务器(如果成功),继续发送账号密码到服务器的命令

再调用MainClient里面的 SendLogin 方法(有个等待0.2秒)

服务器接收账号密码,进行查找数据库操作

调用了MyTcpCommandLibrary项目中的LoginManageCommand类的CheckLogin方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)

[InstallFun("forever")] public void CheckLogin(Socket soc, WeaveSession wsession) {

// string jsonstr = _0x01.Getjson(); LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();

//执行查找数据的操作...... bool loginOk = false;

AddSystemData();

loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); if (loginOk) { // UpdatePlayerListSetOnLine 发送有玩家成功登陆服务器事件,用于通知前端更新UserListBox ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);

} SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); //发送人数给客户端 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token }

发送查找结果给客户端......

如果客户端接收到服务器发过来的登陆成功消息(跳转到游戏场景),

数据处理工厂接收到命令调用LoginMessageFactory,并返回一个具体的ICheckServerMessage接口实现类LoginMessage

调用它的CheckServerMessage方法

using UnityEngine; using System.Collections; using System; using WeaveBase; public class LoginMessage : ICheckServerMessage { public void CheckServerMessage( string text) { // throw new NotImplementedException(); WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("收到的消息是:"+text); if(ws.Request == "ServerBackLoginResult" ) { if( ws.GetRoot<bool>() == true) { //如果登陆成功,,处理的逻辑...... //先更新用户

//跳转场景 MainClient.Instance.SetLoadSceneFlag();

//发送读取上次分数数据的逻辑 MainClient.Instance.SendCheckUserScore(); }

       
        else
        {
            MainClient.Instance.serverBackLoginEvent.Invoke(false);
        }
    }

   

}

}

如果返回失败,那么提示账号密码错误

客户端再次发送查找当前用户的历史积分数据的命令

既是上面代码中的//发送读取上次分数数据的逻辑 MainClient.Instance.SendCheckUserScore();方法里面已经封装了用户的UserName

具体方法代码是

LoginTempModel user = loginUserModel;

      

weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0);

(正在游戏场景运行中)

客户端接受到历史积分数据,并更新显示到UnityUI界面上

同上..................调用实现接口ICheckServerMessage的具体类GameScoreMessage的CheckServerMessage方法

using UnityEngine; using System.Collections; using System; using WeaveBase; using MyTcpCommandLibrary.Model;

public class GameScoreMessage : ICheckServerMessage { public void CheckServerMessage(string text) { // throw new NotImplementedException(); WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("收到的GameScoreMessage消息是:" + text); if (ws.Request == "ServerSendGameScore") { GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>(); if (gsModel != null ) { //触发收到服务器发送来的积分数据的事件,并更新到前端UI显示上 MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);

          
        }

else { // MainClient.Instance.serverBackLoginEvent.Invoke(false); } }

} }

P0-玩家战机生命为0时,向服务器发送本次游戏积分数据

调用MainClient里面的SendNewScoreUpdate方法

public void SendNewScoreUpdate(int _score,int _missed) { try { GameScoreTempModel gsModel = new GameScoreTempModel() { userName = loginUserModel.userName, missenemy = _missed, score = _score }; //LoginTempModel user = loginUserModel; // weaveSocketGameClient.Tokan = "UnityTokan"; // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);

weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0); Debug.Log("UpdateScore"); } catch (Exception e) { Debug.Log(e.ToString()); } }

服务器收到玩家本次游戏积分数据,进行数据库更新操作(根据用户名)

调用了MyTcpCommandLibrary项目中的GameScoreCommand类的UpdateScore方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)

[InstallFun("forever")] public void UpdateScore(Socket soc, WeaveSession wsession) { GameScoreTempModel gsModel = wsession.GetRoot<GameScoreTempModel>();

      

//执行数据更新的操作...... bool updateSocreResult = UpdateUserScore(gsModel.userName, gsModel.score , gsModel.missenemy);

        
        if (updateSocreResult)
        {
            // 向客户端发送 更新积分成功的信息
            SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);

} else { // 向客户端发送 更新积分失败的信息 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token); //发送人数给客户端 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token } }

客户端显示一个按钮,玩家可点击再玩一次,再次游戏(跳转P0,当玩家生命为0时)

GameScoreHandler类的ReloadGameScene方法,发送本次游戏积分数据并重新加载游戏场景

其它的Unity3D游戏逻辑代码在这里不再细说

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号