Unity太空大战游戏

项目下载地址

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类(部分重写,与原作者源码不同,请注意下)
代码如下:

1using MyTcpCommandLibrary; 2using System; 3using System.Collections.Generic; 4using System.Net.Sockets; 5using System.Reflection; 6using System.Xml; 7using WeaveBase; 8using WeaveSocketServer; 9namespace MyTCPCloud 10{ 11 public class WeaveTCPcloud : IWeaveUniversal 12 { 13 public event WeaveLogDelegate WeaveLogEvent; 14 15 public event WeaveServerReceiveDelegate WeaveReceiveEvent; 16 17 public event WeaveServerUpdateSocketHander WeaveUpdateEvent; 18 19 public event WeaveServerDeleteSocketHander WeaveDeleteEvent; 20 21 public event WeaveServerUpdateUnityPlayerSetOnLineHander WeaveServerUpdateUnityPlayerSetOnLineEvent; 22 23 24 //public XmlDocument xml 25 //{ 26 // get;set; 27 //} 28 29 public List<CmdWorkItem> CmdWorkItems 30 { 31 get 32 { 33 return _CmdWorkItems; 34 } 35 36 set 37 { 38 _CmdWorkItems = value; 39 } 40 } 41 42 public WeaveTable weaveTable 43 { 44 get 45 { 46 return _weaveTable; 47 } 48 49 set 50 { 51 _weaveTable = value; 52 } 53 } 54 55 public List<WeaveOnLine> weaveOnline 56 { 57 get 58 { 59 return _weaveOnline; 60 } 61 62 set 63 { 64 _weaveOnline = value; 65 } 66 } 67 68 public List<UnityPlayerOnClient> unityPlayerOnClientList 69 { 70 get 71 { 72 return _unityPlayerOnClientList; 73 } 74 75 set 76 { 77 _unityPlayerOnClientList = value; 78 } 79 } 80 81 // public IWeaveTcpBase P2Server 82 public WeaveP2Server P2Server 83 { 84 get;set; 85 } 86 87 public WeaveTcpToken TcpToken 88 { 89 get 90 { 91 return _TcpToken; 92 } 93 94 set 95 { 96 _TcpToken = value; 97 } 98 } 99 100 List<CmdWorkItem> _CmdWorkItems = new List<CmdWorkItem>(); 101 102 WeaveTable _weaveTable = new WeaveTable(); 103 104 List<WeaveOnLine> _weaveOnline = new List<WeaveOnLine>(); 105 106 107 WeaveTcpToken _TcpToken = new WeaveTcpToken(); 108 109 //我写的方法 110 List<UnityPlayerOnClient> _unityPlayerOnClientList = new List<UnityPlayerOnClient>(); 111 112 113 114 115 public bool Run(WevaeSocketSession myI) 116 { 117 //ReloadFlies(); 118 AddMyTcpCommandLibrary(); 119 120 121 weaveTable.Add("onlinetoken", weaveOnline);//初始化一个队列,记录在线人员的token 122 if (WeaveLogEvent != null) 123 WeaveLogEvent("连接", "连接启动成功"); 124 return true; 125 } 126 /// <summary> 127 /// 读取WeavePortTypeEnum类型后,初始化 new WeaveP2Server("127.0.0.1"),并添加端口; 128 /// </summary> 129 /// <param name="WeaveServerPort"></param> 130 public void StartServer(WeaveServerPort _ServerPort) 131 { 132 133 // WeaveTcpToken weaveTcpToken = new WeaveTcpToken(); 134 135 P2Server = new WeaveP2Server("127.0.0.1"); 136 137 P2Server.waveReceiveEvent += P2ServerReceiveHander; 138 P2Server.weaveUpdateSocketListEvent += P2ServerUpdateSocketHander; 139 P2Server.weaveDeleteSocketListEvent += P2ServerDeleteSocketHander; 140 // p2psev.NATthroughevent += tcp_NATthroughevent;//p2p事件,不需要使用 141 P2Server.Start( _ServerPort.Port );//myI.Parameter[4]是端口号 142 143 TcpToken.PortType = _ServerPort.PortType; 144 TcpToken.P2Server = P2Server; 145 TcpToken.IsToken = _ServerPort.IsToken; 146 TcpToken.WPTE = _ServerPort.PortType; 147 148 // TcpToken = weaveTcpToken; 149 150 // P2Server = p2psev; 151 152 } 153 154 155 public void AddMyTcpCommandLibrary() 156 { 157 try 158 { 159 LoginManageCommand loginCmd = new LoginManageCommand(); 160 loginCmd.ServerLoginOKEvent += UpdatePlayerListSetOnLine; 161 AddCmdWorkItems(loginCmd); 162 163 AddCmdWorkItems(new GameScoreCommand()); 164 165 AddCmdWorkItems(new ClientDisConnectedCommand()); 166 167 168 169 } 170 catch 171 { 172 173 } 174 } 175 176 public void AddCmdWorkItems(WeaveTCPCommand cmd) 177 { 178 cmd.SetGlobalQueueTable(weaveTable, TcpToken); 179 CmdWorkItem cmdItem = new CmdWorkItem(); 180 // Ic.SetGlobalQueueTable(weaveTable, TcpTokenList); 181 cmdItem.WeaveTcpCmd = cmd; 182 cmdItem.CmdName = cmd.Getcommand(); 183 GetAttributeInfo(cmd, cmd.GetType(), cmd); 184 CmdWorkItems.Add(cmdItem); 185 } 186 187 188 public void GetAttributeInfo(WeaveTCPCommand Ic, Type t, object obj) 189 { 190 foreach (MethodInfo mi in t.GetMethods()) 191 { 192 InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute)); 193 if (myattribute == null) 194 { 195 } 196 else 197 { 198 if (myattribute.Dtu) 199 { 200 Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDtuDelegate), obj, mi, true); 201 Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDtuDelegate, myattribute.Type, true); 202 } 203 else 204 { 205 Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true); 206 Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type); 207 } 208 } 209 } 210 } 211 void P2ServerDeleteSocketHander(System.Net.Sockets.Socket soc) 212 { 213 214 /*我写的方法*/ 215 WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc); 216 217 if (hasOnline != null) 218 { 219 220 UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline); 221 222 WeaveDeleteEvent(uplayer); 223 224 weaveOnline.Remove(hasOnline); 225 226 // unityPlayerOnClientList.Remove(uplayer); 227 DeleteUnityPlayerOnClient(hasOnline.Socket); 228 } 229 /**/ 230 231 232 try 233 { 234 int count = CmdWorkItems.Count; 235 CmdWorkItem[] cilist = new CmdWorkItem[count]; 236 CmdWorkItems.CopyTo(0, cilist, 0, count); 237 foreach (CmdWorkItem CI in cilist) 238 { 239 try 240 { 241 CI.WeaveTcpCmd.WeaveDeleteSocketEvent(soc); 242 } 243 catch (Exception ex) 244 { 245 if (WeaveLogEvent != null) 246 WeaveLogEvent("EventDeleteConnSoc", ex.Message); 247 } 248 } 249 } 250 catch { } 251 try 252 { 253 int count = weaveOnline.Count; 254 WeaveOnLine[] ols = new WeaveOnLine[count]; 255 weaveOnline.CopyTo(0, ols, 0, count); 256 foreach (WeaveOnLine ol in ols) 257 { 258 if (ol.Socket.Equals(soc)) 259 { 260 foreach (CmdWorkItem CI in CmdWorkItems) 261 { 262 try 263 { 264 WeaveExcCmdNoCheckCmdName(0xff, "out|" + ol.Token, ol.Socket); 265 CI.WeaveTcpCmd.Tokenout(ol); 266 } 267 catch (Exception ex) 268 { 269 if (WeaveLogEvent != null) 270 WeaveLogEvent("Tokenout", ex.Message); 271 } 272 } 273 weaveOnline.Remove(ol); 274 return; 275 } 276 } 277 } 278 catch { } 279 } 280 281 282 public void UpdatePlayerListSetOnLine(string _userName , System.Net.Sockets.Socket soc) 283 { 284 foreach(UnityPlayerOnClient oneclient in unityPlayerOnClientList) 285 { 286 if(oneclient.Socket == soc) 287 { 288 oneclient.UserName = _userName; 289 oneclient.isLogin = true; 290 WeaveServerUpdateUnityPlayerSetOnLineEvent(oneclient); 291 break; 292 } 293 } 294 295 296 } 297 298 299 void P2ServerUpdateSocketHander(System.Net.Sockets.Socket soc) 300 { 301 302 #region 读取 Command接口类,每次有新的Socket加入 重新读取并设置 303 try 304 { 305 int count = CmdWorkItems.Count; 306 CmdWorkItem[] cilist = new CmdWorkItem[count]; 307 CmdWorkItems.CopyTo(0, cilist, 0, count); 308 foreach (CmdWorkItem CI in cilist) 309 { 310 try 311 { 312 CI.WeaveTcpCmd.WeaveUpdateSocketEvent(soc); 313 } 314 catch (Exception ex) 315 { 316 if (WeaveLogEvent != null) 317 WeaveLogEvent("EventUpdataConnSoc", ex.Message); 318 } 319 } 320 } 321 catch 322 { 323 324 } 325 326 #endregion 发送Token的代码 327 328 WeaveTcpToken token = TcpToken; 329 { 330 if (token.IsToken) 331 { 332 //生成一个token,后缀带随机数 333 string Token = DateTime.Now.ToString("yyyyMMddHHmmssfff") + new Random().Next(1000, 9999);// EncryptDES(clientipe.Address.ToString() + "|" + DateTime.Now.ToString(), "lllssscc"); 334 if (token.P2Server.Port == ((System.Net.IPEndPoint)soc.LocalEndPoint).Port) 335 { 336 //向客户端发送生成的token 337 bool sendok = false; 338 if (token.PortType == WeavePortTypeEnum.Bytes) 339 sendok = token.P2Server.Send(soc, 0xff, token.BytesDataparsing.Get_ByteBystring("token|" + Token + "")); 340 else 341 sendok = token.P2Server.Send(soc, 0xff, "token|" + Token + ""); 342 343 344 #region if(sendok) 345 if (sendok) 346 { 347 WeaveOnLine ol = new WeaveOnLine() 348 { 349 Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"), 350 Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff") 351 }; 352 ol.Token = Token; 353 ol.Socket = soc; 354 355 WeaveOnLine hasOnline = weaveOnline.Find(item => item.Name == ol.Name); 356 { 357 if (hasOnline != null) 358 { 359 weaveOnline.Remove(hasOnline); 360 361 weaveOnline.Add(ol); 362 363 } 364 else 365 { 366 weaveOnline.Add(ol); 367 } 368 } 369 370 371 /*我单独写的UnityClient*/ 372 /*我写的新方法*/ 373 UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Name == ol.Name); 374 if (hasPlayerIn != null) 375 { 376 WeaveDeleteEvent(hasPlayerIn); 377 unityPlayerOnClientList.Remove(hasPlayerIn); 378 379 } 380 /*我写的方法结束*/ 381 382 UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol); 383 // unityPlayerOnClientList.Add(uplayer); 384 AddUnityPlayerClient_CheckSameItem(uplayer , ol.Name); 385 WeaveUpdateEvent(uplayer); 386 387 388 389 /**/ 390 391 392 foreach (CmdWorkItem cmdItem in CmdWorkItems) 393 { 394 try 395 { 396 WeaveExcCmdNoCheckCmdName(0xff, "in|" + ol.Token, ol.Socket); 397 cmdItem.WeaveTcpCmd.TokenIn(ol); 398 } 399 catch (Exception ex) 400 { 401 if (WeaveLogEvent != null) 402 WeaveLogEvent("Tokenin", ex.Message); 403 } 404 } 405 return; 406 } 407 #endregion 408 } 409 } 410 else 411 { 412 WeaveOnLine ol = new WeaveOnLine() 413 { 414 Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"), 415 Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff"), 416 Socket = soc, 417 Token = DateTime.Now.ToString("yyyyMMddHHmmssfff") 418 419 }; 420 weaveOnline.Add(ol); 421 422 423 /*我单独写的UnityClient*/ 424 UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Socket == soc); 425 if (hasPlayerIn != null) 426 { 427 WeaveDeleteEvent(hasPlayerIn); 428 unityPlayerOnClientList.Remove(hasPlayerIn); 429 430 } 431 432 UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol); 433 AddUnityPlayerClient_CheckSameItem(uplayer, ol.Name); 434 WeaveUpdateEvent(uplayer); 435 /**/ 436 // ol.Token = DateTime.Now.ToString(); 437 // ol.Socket = soc; 438 439 440 } 441 442 } 443 } 444 void P2ServerReceiveHander(byte command, string data, System.Net.Sockets.Socket soc) 445 { 446 if(command == (byte)CommandEnum.ClientSendDisConnected) 447 { 448 P2Server.CliendSendDisConnectedEvent(soc); 449 450 /*我写的方法*/ 451 WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc); 452 453 if (hasOnline != null) 454 { 455 456 UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline); 457 458 WeaveDeleteEvent(uplayer); 459 460 weaveOnline.Remove(hasOnline); 461 462 // unityPlayerOnClientList.Remove(uplayer); 463 DeleteUnityPlayerOnClient(hasOnline.Socket); 464 } 465 466 467 /**/ 468 return; 469 } 470 471 try 472 { 473 //触发接收到信息的事件... 474 /*我写的方法*/ 475 WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc); 476 477 if(hasOnline != null) 478 { 479 UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline); 480 481 WeaveReceiveEvent(command, data, uplayer); 482 483 } 484 /**/ 485 486 if (command == 0xff) 487 { 488 //如果是网关command 发过来的 命名,那么执行下面的 489 WeaveExcCmdNoCheckCmdName(command, data, soc); 490 491 try 492 { 493 string[] temp = data.Split('|'); 494 if (temp[0] == "in") 495 { 496 //加入onlinetoken 497 WeaveOnLine ol = new WeaveOnLine(); 498 ol.Token = temp[1]; 499 ol.Socket = soc; 500 weaveOnline.Add(ol); 501 foreach (CmdWorkItem CI in CmdWorkItems) 502 { 503 try 504 { 505 CI.WeaveTcpCmd.TokenIn(ol); 506 } 507 catch (Exception ex) 508 { 509 WeaveLogEvent?.Invoke("Tokenin", ex.Message); 510 } 511 } 512 return; 513 } 514 else if (temp[0] == "Restart") 515 { 516 int count = weaveOnline.Count; 517 WeaveOnLine[] ols = new WeaveOnLine[count]; 518 weaveOnline.CopyTo(0, ols, 0, count); 519 string IPport = ((System.Net.IPEndPoint)soc.RemoteEndPoint).Address.ToString() + ":" + temp[1]; 520 foreach (WeaveOnLine ol in ols) 521 { 522 try 523 { 524 if (ol.Socket != null) 525 { 526 String IP = ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Address.ToString() + ":" + ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Port; 527 if (IP == IPport) 528 { 529 ol.Socket = soc; 530 } 531 } 532 } 533 catch { } 534 } 535 } 536 else if (temp[0] == "out") 537 { 538 ////移出onlinetoken 539 int count = weaveOnline.Count; 540 WeaveOnLine[] ols = new WeaveOnLine[count]; 541 weaveOnline.CopyTo(0, ols, 0, count); 542 foreach (WeaveOnLine onlinesession in ols) 543 { 544 if (onlinesession.Token == temp[1]) 545 { 546 foreach (CmdWorkItem cmdItem in CmdWorkItems) 547 { 548 try 549 { 550 cmdItem.WeaveTcpCmd.Tokenout(onlinesession); 551 } 552 catch (Exception ex) 553 { 554 WeaveLogEvent?.Invoke("Tokenout", ex.Message); 555 } 556 } 557 weaveOnline.Remove(onlinesession); 558 return; 559 } 560 } 561 } 562 } 563 catch { } 564 return; 565 } 566 567 else 568 WeaveExcCmd(command, data, soc); 569 } 570 catch 571 { 572 return; 573 } 574 //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(exec)); 575 } 576 577 578 579 580 581 582 /// <summary> 583 /// 网关0xff这个command发来的...命令 584 /// </summary> 585 /// <param name="command"></param> 586 /// <param name="data"></param> 587 /// <param name="soc"></param> 588 public void WeaveExcCmdNoCheckCmdName(byte command, string data, System.Net.Sockets.Socket soc) 589 { 590 foreach (CmdWorkItem cmd in CmdWorkItems) 591 { 592 try 593 { 594 cmd.WeaveTcpCmd.Runcommand(command, data, soc); 595 } 596 catch (Exception ex) 597 { 598 WeaveLogEvent?.Invoke("receiveevent", ex.Message); 599 } 600 } 601 } 602 603 604 /// <summary> 605 /// 不是0xff这个command发来的...命令 606 /// </summary> 607 /// <param name="command"></param> 608 /// <param name="data"></param> 609 /// <param name="soc"></param> 610 public void WeaveExcCmd(byte command, string data, System.Net.Sockets.Socket soc) 611 { 612 foreach (CmdWorkItem cmd in CmdWorkItems) 613 { 614 if (cmd.CmdName == command) 615 { 616 try 617 { 618 cmd.WeaveTcpCmd.Run(data, soc); 619 cmd.WeaveTcpCmd.RunBase(data, soc); 620 } 621 catch (Exception ex) 622 { 623 WeaveLogEvent?.Invoke("receiveevent", ex.Message); 624 } 625 } 626 } 627 } 628 629 public UnityPlayerOnClient ConvertWeaveOnlineToUnityPlayerOnClient(WeaveOnLine wonline) 630 { 631 UnityPlayerOnClient uplayer = new UnityPlayerOnClient() 632 { 633 Obj = wonline.Obj, 634 Socket = wonline.Socket, 635 Token = wonline.Token, 636 Name = wonline.Name 637 }; 638 639 640 641 return uplayer; 642 643 } 644 645 public void DeleteUnityPlayerOnClient(Socket osc) 646 { 647 try 648 { 649 if (unityPlayerOnClientList.Count > 0) 650 unityPlayerOnClientList.Remove(unityPlayerOnClientList.Find(u => u.Socket == osc)); 651 } 652 catch 653 { 654 655 } 656 } 657 658 659 660 public void AddUnityPlayerClient_CheckSameItem(UnityPlayerOnClient item ,string itemName) 661 { 662 System.Threading.Thread.Sleep(500); 663 lock (this) 664 { 665 if (unityPlayerOnClientList.Find(i => i.Name == itemName) != null) 666 return; 667 668 else 669 unityPlayerOnClientList.Add(item); 670 } 671 } 672 //public class CmdWorkItem 673 //{ 674 // public byte CmdName 675 // { 676 // get;set; 677 // } 678 // public WeaveTCPCommand WeaveTcpCmd 679 // { 680 // get;set; 681 // } 682 //} 683 } 684}

-----------------------------------------

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

1 [InstallFun("forever")] 2 public void CheckLogin(Socket soc, WeaveSession wsession) 3 { 4 5 // string jsonstr = _0x01.Getjson(); 6 LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>(); 7 8 9 10 //执行查找数据的操作...... 11 bool loginOk = false; 12 13 14 AddSystemData(); 15 16 loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); 17 if (loginOk) 18 { 19 // UpdatePlayerListSetOnLine 20 ServerLoginOKEvent(get_client_Send_loginModel.userName, soc); 21 22 23 } 24 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); 25 //发送人数给客户端 26 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token 27 }

当客户端发送命名为 Getcommand() 返回的命令byte,并且参数含方法名,即可直接调用服务端WeaveTCPCommand写的这个CheckLogin方法
客户端调用示例

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

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

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text; 5using System.Threading.Tasks; 6using System.Windows; 7using System.Windows.Controls; 8using System.Windows.Data; 9using System.Windows.Documents; 10using System.Windows.Input; 11using System.Windows.Media; 12using System.Windows.Media.Imaging; 13using System.Windows.Shapes; 14using WeaveBase; 15using System.Net.Sockets; 16using MyTCPCloud; 17using System.Windows.Threading; 18 19namespace WeavingSocketServerWPF 20{ 21 /// <summary> 22 /// MyUnityServer.xaml 的交互逻辑 23 /// </summary> 24 public partial class MyUnityServer : Window 25 { 26 public MyUnityServer() 27 { 28 InitializeComponent(); 29 30 // DispatcherFunction(); 31 } 32 /// <summary> 33 /// 监听端口列表,,可以选择监听多个端口 34 /// </summary> 35 WeaveServerPort wserverport = new WeaveServerPort(); 36 WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud(); 37 38 List<MyListBoxItem> loginedUserList = new List<MyListBoxItem>(); 39 40 List<MyListBoxItem> connectedSocketItemList = new List<MyListBoxItem>(); 41 // DispatcherTimer dispatcherTimer = new DispatcherTimer(); 42 43 private void StartListen_button_Click(object sender, RoutedEventArgs e) 44 { 45 //设置登陆后的用户列表Listbox的数据源 46 LoginedUser_listBox.ItemsSource = loginedUserList; 47 //设置连接到服务器的Socket列表的Listbox的数据源 48 ConnectedSocket_listBox.ItemsSource = connectedSocketItemList; 49 50 WevaeSocketSession mif = new WevaeSocketSession(); 51 52 weaveTCPcloud.Run(mif); 53 54 55 wserverport.IsToken = true; 56 wserverport.Port = Convert.ToInt32(Port_textBox.Text); 57 wserverport.PortType = WeavePortTypeEnum.Json; 58 59 weaveTCPcloud.StartServer(wserverport); 60 61 62 weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage; 63 64 weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket; 65 66 weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket; 67 68 weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent; 69 70 StartListen_button.Content = "正在监听"; 71 72 StartListen_button.IsEnabled = false; 73 74 } 75 76 private void OnWeaveServerUpdateUnityPlayerSetOnLineEvent(UnityPlayerOnClient gamer) 77 { 78 79 80 //throw new NotImplementedException(); 81 //当有用户 账号密码登陆成功的时候 82 AddListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer)); 83 SetServerReceiveText("--触发了一次(OnWeaveServerUpdateUnityPlayerSetOnLineEvent)" + Environment.NewLine); 84 85 } 86 87 private void OnWeaveUpdateSocket(UnityPlayerOnClient gamer) 88 { 89 SetServerReceiveText("--触发了一次(OnWeaveUpdateSocket)" + Environment.NewLine); 90 91 //有 Sokcet客户端连接到服务器的时候,暂未 账号,密码认证状态 92 93 AddListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer) ); 94 95 } 96 97 98 99 private void OnWeaveDeleteSocket(UnityPlayerOnClient gamer) 100 { 101 SetServerReceiveText("--退出事件,,触发了一次(OnWeaveDeleteSocket)" + Environment.NewLine); 102 103 RemoveListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer)); 104 105 RemoveListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer)); 106 107 108 } 109 110 private void OnWeaveReceiveMessage(byte command, string data, UnityPlayerOnClient gamer) 111 { 112 113 114 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(data); 115 116 SetServerReceiveText("接收到新信息: " + ws.Root + Environment.NewLine ); 117 118 119 } 120 121 private void StopListen_button_Click(object sender, RoutedEventArgs e) 122 { 123 124 weaveTCPcloud.P2Server = null; 125 126 weaveTCPcloud = null; 127 128 Application.Current.Shutdown(); 129 Environment.Exit(0);// 可以立即中断程序执行并退出 130 } 131 132 private void SendMsg_button_Click(object sender, RoutedEventArgs e) 133 { 134 135 string serverMsg = InputSendMessage_textBox.Text; 136 int unityGamecount = weaveTCPcloud.unityPlayerOnClientList.Count; 137 if (string.IsNullOrEmpty(serverMsg) || weaveTCPcloud.weaveOnline.Count==0) 138 return; 139 140 WeaveOnLine[] _allWeaveOnLine = new WeaveOnLine[weaveTCPcloud.weaveOnline.Count]; 141 142 weaveTCPcloud.weaveOnline.CopyTo(_allWeaveOnLine); 143 144 foreach (WeaveOnLine oneWeaveOnLine in _allWeaveOnLine) 145 { 146 weaveTCPcloud.P2Server.Send(oneWeaveOnLine.Socket, 0x01, "服务器主动给所有客户端发消息了: " + serverMsg); 147 } 148 149 // MessageBox.Show("客户端在线数量:"+ _allWeaveOnLine.Length); 150 } 151 152 153 private void UpdateServerReceiveTb(TextBlock tb, string text) 154 { 155 tb.Text += text; 156 } 157 158 private void SetServerReceiveText(string newtext) 159 { 160 Action<TextBlock, String> updateAction = new Action<TextBlock, string>(UpdateServerReceiveTb); 161 ServerReceive_textBlock.Dispatcher.BeginInvoke(updateAction, ServerReceive_textBlock, newtext); 162 163 } 164 165 public MyListBoxItem CopyUnityPlayerOnClient(UnityPlayerOnClient one) 166 { 167 MyListBoxItem item = new MyListBoxItem() 168 { 169 UIName_Id = one.Socket.RemoteEndPoint.ToString(), 170 ShowMsg = "UserIP:" + one.Socket.RemoteEndPoint.ToString() + " -Token:" + one.Token, 171 UserName = one.UserName, 172 Ip = one.Socket.RemoteEndPoint.ToString() 173 }; 174 return item; 175 } 176 177 public void AddListBoxItem(List<MyListBoxItem> sList , MyListBoxItem one) 178 { 179 180 181 sList.Add(one); 182 CheckListBoxSource(); 183 } 184 185 public void AddListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one) 186 { 187 Action< List < MyListBoxItem > , MyListBoxItem> addListBoxItemAction = 188 189 new Action<List<MyListBoxItem> , MyListBoxItem>(AddListBoxItem); 190 191 this.Dispatcher.BeginInvoke(addListBoxItemAction,sList , one); 192 } 193 194 195 public void RemoveListBoxItem(List<MyListBoxItem> sList, MyListBoxItem one) 196 { 197 MyListBoxItem item = sList.Find(i=>i.Ip == one.Ip); 198 199 if(item != null) 200 { 201 sList.Remove(item); 202 } 203 204 205 CheckListBoxSource(); 206 } 207 208 public void RemoveListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one) 209 { 210 Action<List<MyListBoxItem>, MyListBoxItem> removeListBoxItemAction = 211 212 new Action<List<MyListBoxItem>, MyListBoxItem>(RemoveListBoxItem); 213 214 this.Dispatcher.BeginInvoke(removeListBoxItemAction, sList , one); 215 } 216 217 public void CheckListBoxSource() 218 { 219 //数据发生变化后,重新设置登陆后的用户列表Listbox的数据源 220 LoginedUser_listBox.ItemsSource = null; 221 LoginedUser_listBox.ItemsSource = loginedUserList; 222 //数据发生变化后,重新设置连接到服务器的Socket列表的Listbox的数据源 223 ConnectedSocket_listBox.ItemsSource = null; 224 ConnectedSocket_listBox.ItemsSource = connectedSocketItemList; 225 } 226 227 protected override void OnClosed(EventArgs e) 228 { 229 weaveTCPcloud.P2Server = null; 230 231 weaveTCPcloud = null; 232 233 //Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose; 234 //if (this.IsAfreshLogin == true) return; 235 Application.Current.Shutdown(); 236 Environment.Exit(0);// 可以立即中断程序执行并退出 237 base.OnClosed(e); 238 } 239 240 241 } 242 243 public class MyListBoxItem 244 { 245 public string UIName_Id { get; set; } 246 247 public string Ip { get; set; } 248 public string ShowMsg { get; set; } 249 250 public string UserName { get; set; } 251 } 252}

主要的启动服务器的代码为

1 WeaveServerPort wserverport = new WeaveServerPort(); 2 WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud(); 3 4 WevaeSocketSession mif = new WevaeSocketSession(); 5 //不知道这里干嘛,没搞懂 6 weaveTCPcloud.Run(mif); 7 8 9 wserverport.IsToken = true; 10 wserverport.Port = Convert.ToInt32(Port_textBox.Text); 11 wserverport.PortType = WeavePortTypeEnum.Json; 12 13 weaveTCPcloud.StartServer(wserverport); 14 15 16 weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage; 17 18 weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket; 19 20 weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket; 21 22 weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent;

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

1 public class LoginManageCommand : WeaveTCPCommand 2 { 3 public delegate void ServerLoginOK(string _u,Socket _s); 4 5 public event ServerLoginOK ServerLoginOKEvent; 6 7 public override byte Getcommand() 8 { 9 10 //此CLASS的实例,代表的指令,指令从0-254,0x9c与0xff为内部指令不能使用。 11 //0x01的意思是,只要是0x01的指令,都会进入本实例进行处理 12 //return 0x01; 13 return (byte)CommandEnum.ClientSendLoginModel; //0x02; 14 } 15 16 public override bool Run(string data, Socket soc) 17 { 18 19 //此事件是接收事件,data 是String类型的数据,soc是发送人。 20 return true; 21 } 22 23 public override void WeaveBaseErrorMessageEvent(Socket soc, WeaveSession _0x01, string message) 24 { 25 //错误异常事件,message为错误信息,soc为产生异常的连接 26 } 27 28 public override void WeaveDeleteSocketEvent(Socket soc) 29 { 30 //此事件是当有人中断了连接,此事件会被调用 31 } 32 33 public override void WeaveUpdateSocketEvent(Socket soc) 34 { 35 //此事件是当有人新加入了连接,此事件会被调用 36 } 37 38 [InstallFun("forever")] 39 public void CheckLogin(Socket soc, WeaveSession wsession) 40 { 41 42 // string jsonstr = _0x01.Getjson(); 43 LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>(); 44 45 46 47 //执行查找数据的操作...... 48 bool loginOk = false; 49 50 51 AddSystemData(); 52 53 loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); 54 if (loginOk) 55 { 56 // UpdatePlayerListSetOnLine 57 ServerLoginOKEvent(get_client_Send_loginModel.userName, soc); 58 59 60 } 61 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); 62 //发送人数给客户端 63 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token 64 } 65 66 67 private void AddSystemData() 68 { 69 GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL(); 70 71 if( myBLL.CheckDataBaseIsNull()) 72 { 73 myBLL.AddTestData(); 74 } 75 } 76 77 private bool CheckUserCanLoginIn(LoginTempModel m) 78 { 79 GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL(); 80 return myBLL.CheckUserNamePassword(m.userName, m.password); 81 } 82 83 84 85 }

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

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

数据格式如下图

发送数据的主要代码为

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

客户端代码结构

登陆界面

游戏场景

-------------------------------------

主要的逻辑流程

----------------------------------------------

启动程序

----------------------------------------------

玩家输入账号密码

----------------------------------------------

点击登陆按钮

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

(正在游戏场景运行中)

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

客户端主要的代码类为WeaveSocketGameClient 

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

1using Frankfort.Threading; 2using MyTcpCommandLibrary; 3using System; 4using System.Collections.Generic; 5using System.Linq; 6using System.Net.Sockets; 7using System.Reflection; 8using System.Text; 9using System.Threading; 10using UnityEngine; 11using WeaveBase; 12 13namespace MyTcpClient 14{ 15 public class WeaveSocketGameClient 16 { 17 public Thread threadA; 18 public Thread threadB; 19 20 private ThreadPoolScheduler myThreadScheduler; 21 22 23 WeaveBaseManager xmhelper = new WeaveBaseManager(); 24 25 /// <summary> 26 /// 是否连接成功 27 /// </summary> 28 public bool isok = false; 29 /// <summary> 30 /// 在接收数据 31 /// </summary> 32 public bool isReceives = false; 33 /// <summary> 34 /// 是否在线了 35 /// </summary> 36 public bool IsOnline = false; 37 38 DateTime timeout; 39 /// <summary> 40 /// 数据超时时间 41 /// </summary> 42 int mytimeout = 90; 43 44 /// <summary> 45 /// 队列中没有排队的方法需要执行 46 /// </summary> 47 List<TempPakeage> mytemppakeList = new List<TempPakeage>(); 48 49 public List<byte[]> ListData = new List<byte[]>(); 50 51 public string tokan; 52 53 public String ip; 54 public int port; 55 56 public event ReceiveMessage ReceiveMessageEvent; 57 public event ConnectOk ConnectOkEvent; 58 59 public event ReceiveBit ReceiveBitEvent; 60 public event TimeOut TimeOutEvent; 61 public event ErrorMessage ErrorMessageEvent; 62 63 public event JumpServer JumpServerEvent; 64 65 public TcpClient tcpClient; 66 67 // System.Threading.Thread receives_thread1; 68 69 // System.Threading.Thread checkToken_UpdateList_thread2; 70 71 72 SocketDataType s_datatype = SocketDataType.Json; 73 public WeaveSocketGameClient(SocketDataType _type) 74 { 75 s_datatype = _type; 76 77 } 78 79 #region 客户端注册类,,服务端可以按方法名调用 80 81 public void AddListenClass(object obj) 82 { 83 GetAttributeInfo(obj.GetType(), obj); 84 //xmhelper.AddListen() 85 86 //objlist.Add(obj); 87 88 } 89 public void DeleteListenClass(object obj) 90 { 91 deleteAttributeInfo(obj.GetType(), obj); 92 //xmhelper.AddListen() 93 94 //objlist.Add(obj); 95 96 } 97 public void deleteAttributeInfo(Type t, object obj) 98 { 99 foreach (MethodInfo mi in t.GetMethods()) 100 { 101 InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute)); 102 if (myattribute == null) 103 { 104 105 } 106 else 107 { 108 xmhelper.DeleteListen(mi.Name); 109 } 110 } 111 } 112 public void GetAttributeInfo(Type t, object obj) 113 { 114 foreach (MethodInfo mi in t.GetMethods()) 115 { 116 InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute)); 117 if (myattribute == null) 118 { } 119 else 120 { 121 Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true); 122 xmhelper.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type); 123 } 124 } 125 } 126 127 #endregion 128 129 130 131 /// <summary> 132 /// 连接服务器 133 /// </summary> 134 /// <param name="_ip">IP地址</param> 135 /// <param name="_port">端口号</param> 136 /// <param name="_timeout">过期时间</param> 137 /// <param name="_takon">是否takon</param> 138 /// <returns></returns> 139 public bool StartConnect(string _ip, int _port, int _timeout, bool _takon) 140 { 141 mytimeout = _timeout; 142 ip = _ip; 143 port = _port; 144 return StartConnectToServer(ip, port, _takon); 145 } 146 public bool RestartConnectToServer(bool takon) 147 { 148 return StartConnectToServer(ip, port, takon); 149 } 150 151 152 private bool StartConnectToServer(string _ip, int _port, bool _takon) 153 { 154 try 155 { 156 if (s_datatype == SocketDataType.Json && ReceiveMessageEvent == null) 157 Debug.Log("没有注册receiveServerEvent事件"); 158 159 if (s_datatype == SocketDataType.Json && ReceiveBitEvent == null) 160 Debug.Log("没有注册receiveServerEventbit事件"); 161 ip = _ip; 162 port = _port; 163 164 //tcpClient = new TcpClient(ip, port); 165 tcpClient = new TcpClient(); 166 // tcpc.ExclusiveAddressUse = false; 167 168 try 169 { 170 tcpClient.Connect(ip, port); 171 } 172 catch 173 { 174 return false; 175 } 176 177 IsOnline = true; 178 isok = true; 179 180 timeout = DateTime.Now; 181 if (!isReceives) 182 { 183 isReceives = true; 184 185 186 // ParameterThreadStart的定义为void ParameterizedThreadStart(object state), 187 // 使用这个这个委托定义的线程的启动函数可以接受一个输入参数, 188 189 //receives_thread1 = new System.Threading.Thread(new ParameterizedThreadStart(ReceivesThread)); 190 //receives_thread1.IsBackground = true; 191 // receives_thread1.Start(); 192 // ThreadStart这个委托定义为void ThreadStart(),也就是说,所执行的方法不能有参数 193 // checkToken_UpdateList_thread2 = new System.Threading.Thread(new ThreadStart(CheckToken_UpdateListDataThread)); 194 //checkToken_UpdateList_thread2.IsBackground = true; 195 // checkToken_UpdateList_thread2.Start(); 196 197 /*开始执行线程开始*/ 198 myThreadScheduler = Loom.CreateThreadPoolScheduler(); 199 200 //--------------- Ending Single threaded routine 单线程程序结束-------------------- 201 threadA = Loom.StartSingleThread(ReceivesThread,null, System.Threading.ThreadPriority.Normal, true); 202 //--------------- Ending Single threaded routine 单线程程序结束-------------------- 203 204 //--------------- Continues Single threaded routine 在单线程的程序-------------------- 205 threadB = Loom.StartSingleThread(CheckToken_UpdateListDataThread, System.Threading.ThreadPriority.Normal, true); 206 //--------------- Continues Single threaded routine 在单线程的程序-------------------- 207 /*开始执行线程结束*/ 208 209 } 210 int ss = 0; 211 212 if (!_takon) 213 return true; 214 215 while (tokan == null) 216 { 217 // System.Threading.Thread.Sleep(1000); 218 // Loom.WaitForNextFrame(10); 219 Loom.WaitForSeconds(1); 220 ss++; 221 if (ss > 10) 222 return false; 223 } 224 225 if(ConnectOkEvent != null) 226 ConnectOkEvent(); 227 228 return true; 229 } 230 catch (Exception e) 231 { 232 IsOnline = false; 233 if (ErrorMessageEvent != null) 234 ErrorMessageEvent( 1 , e.Message); 235 return false; 236 } 237 } 238 239 240 #region 几个方法的方法 241 242 public bool SendParameter<T>(byte command, String Request, T Parameter, int Querycount) 243 { 244 WeaveBase.WeaveSession b = new WeaveBase.WeaveSession(); 245 b.Request = Request; 246 b.Token = this.tokan; 247 b.SetParameter<T>(Parameter); 248 b.Querycount = Querycount; 249 return SendStringCheck(command, b.Getjson()); 250 } 251 public bool SendRoot<T>(byte command, String Request, T Root, int Querycount) 252 { 253 WeaveBase.WeaveSession b = new WeaveBase.WeaveSession(); 254 b.Request = Request; 255 b.Token = this.tokan; 256 b.SetRoot<T>(Root); 257 b.Querycount = Querycount; 258 return SendStringCheck(command, b.Getjson()); 259 } 260 public void Send(byte[] b) 261 { 262 tcpClient.Client.Send(b); 263 } 264 public bool SendStringCheck(byte command, string text) 265 { 266 try 267 { 268 //byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text); 269 //byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString()); 270 //byte[] b = new byte[2 + part3_length.Length + sendb.Length]; 271 //b[0] = command; 272 //b[1] = (byte)part3_length.Length; 273 //part3_length.CopyTo(b, 2); 274 //扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面 275 //sendb.CopyTo(b, 2 + part3_length.Length); 276 //扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面... 277 278 byte[] b = MyGameClientHelper.CodingProtocol( command, text); 279 280 int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1); 281 if (count == 0) 282 { 283 //判定数据长度,,实际指的是大小是不是小于40kb,,, 284 tcpClient.Client.Send(b); 285 286 } 287 else 288 { 289 for (int i = 0; i < count; i++) 290 { 291 int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960); 292 byte[] temp = new byte[zz]; 293 Array.Copy(b, i * 40960, temp, 0, zz); 294 tcpClient.Client.Send(temp); 295 //分割发送...... 296 // System.Threading.Thread.Sleep(1); 297 // Loom.WaitForNextFrame(10); 298 Loom.WaitForSeconds(0.001f); 299 } 300 } 301 } 302 catch (Exception ee) 303 { 304 IsOnline = false; 305 CloseConnect(); 306 if (TimeOutEvent != null) 307 TimeOutEvent(); 308 309 SendStringCheck(command, text); 310 if (ErrorMessageEvent != null) 311 ErrorMessageEvent(9, "send:" + ee.Message); 312 return false; 313 } 314 // tcpc.Close(); 315 316 return true; 317 } 318 public bool SendByteCheck(byte command, byte[] text) 319 { 320 try 321 { 322 //byte[] sendb = text; 323 //byte[] lens = MyGameClientHelper.ConvertToByteList(sendb.Length); 324 //byte[] b = new byte[2 + lens.Length + sendb.Length]; 325 //b[0] = command; 326 //b[1] = (byte)lens.Length; 327 //lens.CopyTo(b, 2); 328 //sendb.CopyTo(b, 2 + lens.Length); 329 byte[] b = MyGameClientHelper.CodingProtocol(command, text); 330 331 int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1); 332 if (count == 0) 333 { 334 tcpClient.Client.Send(b); 335 } 336 else 337 { 338 for (int i = 0; i < count; i++) 339 { 340 int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960); 341 byte[] temp = new byte[zz]; 342 Array.Copy(b, i * 40960, temp, 0, zz); 343 tcpClient.Client.Send(temp); 344 //System.Threading.Thread.Sleep(1); 345 // Loom.WaitForNextFrame(10); 346 Loom.WaitForSeconds(0.001f); 347 } 348 } 349 } 350 catch (Exception ee) 351 { 352 IsOnline = false; 353 CloseConnect(); 354 if (TimeOutEvent != null) 355 TimeOutEvent(); 356 357 SendByteCheck(command, text); 358 if (ErrorMessageEvent != null) 359 ErrorMessageEvent(9, "send:" + ee.Message); 360 return false; 361 } 362 // tcpc.Close(); 363 364 return true; 365 } 366 367 368 #endregion 369 370 371 372 /// <summary> 373 /// 通过主线程执行方法避免跨线程UI问题 374 /// </summary> 375 public void OnTick() 376 { 377 if (mytemppakeList.Count > 0) 378 { 379 try 380 { 381 TempPakeage str = mytemppakeList[0]; 382 //xmhelper.Init(str.date, null); 383 //receiveServerEvent(str.command, str.date); 384 385 } 386 catch 387 { 388 } 389 try 390 { 391 mytemppakeList.RemoveAt(0); 392 } 393 catch { } 394 } 395 Debug.Log("队列中没有排队的方法需要执行。"); 396 } 397 398 399 public void CloseConnect() 400 { 401 try 402 { 403 isok = false; 404 405 IsOnline = false; 406 //发送我要断开连接的消息 407 this.SendRoot<int>((byte)CommandEnum.ClientSendDisConnected, "OneClientDisConnected", 0, 0); 408 409 410 // receives_thread1.Abort(); 411 //checkToken_UpdateList_thread2.Abort(); 412 413 tcpClient.Close(); 414 AbortThread(); 415 416 } 417 catch 418 { 419 Debug.Log("CloseConnect失败,发生异常"); 420 } 421 422 423 } 424 425 426 void AbortThread() 427 { 428 if (myThreadScheduler.isBusy) //线程在此期间没有完成工作Threaded work didn't finish in the meantime: time to abort.时间终止 429 { 430 Debug.Log("Terminate all worker Threads."); 431 myThreadScheduler.AbortASyncThreads(); 432 433 Debug.Log("Terminate thread A & B."); 434 if (threadA != null && threadA.IsAlive) 435 threadA.Interrupt(); 436 437 if (threadB != null && threadB.IsAlive) 438 threadB.Interrupt(); 439 } 440 else 441 { 442 Debug.Log("Terminate thread A & B."); 443 if (threadA != null && threadA.IsAlive) 444 threadA.Interrupt(); 445 446 if (threadB != null && threadB.IsAlive) 447 threadB.Interrupt(); 448 } 449 450 } 451 452 453 /// <summary> 454 /// 接收到服务器发来的数据的处理方法 455 /// </summary> 456 /// <param name="obj"></param> 457 void ReceiveData(object obj) 458 { 459 TempPakeage str = obj as TempPakeage; 460 mytemppakeList.Add(str); 461 if (ReceiveMessageEvent != null) 462 ReceiveMessageEvent(str.command, str.date); 463 464 } 465 466 467 468 /// <summary> 469 /// 线程启动的方法,初始化连接后要接收服务器发来的token,并更新 470 /// </summary> 471 void CheckToken_UpdateListDataThread() 472 { 473 while (isok) 474 { 475 // System.Threading.Thread.Sleep(10); 476 // Loom.WaitForNextFrame(10); 477 Loom.WaitForSeconds(0.01f); 478 try 479 { 480 int count = ListData.Count; 481 if (count > 0) 482 { 483 int bytesRead = ListData[0] != null ? ListData[0].Length : 0; 484 if (bytesRead == 0) 485 continue; 486 //如果到这里的continue内部,那么下面的代码不执行,重新到 --》 System.Threading.Thread.Sleep(10);开始 487 488 489 byte[] tempbtye = new byte[bytesRead]; 490 //解析消息体ListData,, 491 Array.Copy(ListData[0], tempbtye, tempbtye.Length); 492 // 检查tempbtye(理论上里面应该没有0x99,有方法已经处理掉了,但是可能会有)检测还有没有0x99开头的心跳包 493 _0x99: 494 if (tempbtye[0] == 0x99) 495 { 496 if (bytesRead > 1) 497 { 498 byte[] b = new byte[bytesRead - 1]; 499 byte[] t = tempbtye; 500 //把心跳包0x99去掉 501 Array.Copy(t, 1, b, 0, b.Length); 502 ListData[0] = b; 503 tempbtye = b; 504 goto _0x99; 505 } 506 else 507 { //说明只有1个字节,心跳包包头,无任何意思,那么直接删除 508 ListData.RemoveAt(0); 509 continue; 510 } 511 } 512 513 //ListData[0]第一个元素的长度 大于2 514 if (bytesRead > 2) 515 { 516 //第二段是固定一个字节,最高255,代表了第三段的长度 517 //这样第三段最高可以255*255位,这样表示数据内容的长度基本可以无限大了 518 // int a = tempbtye[1]; 519 int part3_Length = tempbtye[1]; 520 //tempbtye既是ListData[0]数据, 521 //第一位为command,指令 522 //第二位的数据是第三段的长度 523 //第三段的数据是第四段的长度 524 //第四段是内容数据 525 if (bytesRead > 2 + part3_Length) 526 { //如果收到数据这段数据,大于 527 // int len = 0; 528 int part4_Length = 0; 529 if (s_datatype == SocketDataType.Bytes) 530 { 531 byte[] bb = new byte[part3_Length]; 532 byte[] part4_LengthBitArray = new byte[part3_Length]; 533 534 //将tempbtye从第三位开始,复制数据到part4_LengthBitArray 535 Array.Copy(tempbtye, 2, part4_LengthBitArray, 0, part3_Length); 536 //len = ConvertToInt(bb); 537 //获得实际数据的长度,也就是第四部分数据的长度 538 part4_Length = MyGameClientHelper. ConvertToInt(part4_LengthBitArray); 539 } 540 else 541 { //如果DataType不是DataType.bytes类型,,, 是Json类型 542 //从某个Data中第三位开始截取数据,,获取第四段数据长度的字符串string 543 String temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length); 544 String part4_Lengthstr = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length); 545 546 part4_Length = 0; 547 //len = 0; 548 //int part4_Lengthstrlength = 0; 549 try 550 { 551 // len = int.Parse(temp); 552 part4_Length = int.Parse(part4_Lengthstr); 553 if (part4_Length == 0) //len 554 { //如果第四段数据的长度为0 ,,,说明发的空消息,,没有第四段数据 555 //如果第二位没有数据,,说明发的是空消息 556 ListData.RemoveAt(0); 557 continue; 558 } 559 } 560 catch 561 { 562 } 563 } 564 565 try 566 { 567 //如果计算出来的(2位数据位+第三段长度+第四度长度) 比当前ListData[0]长度还大... 568 if ((part4_Length + 2 + part3_Length) > tempbtye.Length) 569 { 570 if (ListData.Count > 1) 571 { 572 //将第一个数据包删除 573 ListData.RemoveAt(0); 574 //重新读取第一个数据包(第二个数据包变为第一个)内容 575 byte[] temps = new byte[ListData[0].Length]; 576 //将 数据表内容 拷贝到 temps中 577 Array.Copy(ListData[0], temps, temps.Length); 578 //新byte数组长度扩充,原数据长度 + (第二个)元素长度 579 byte[] temps2 = new byte[tempbtye.Length + temps.Length]; 580 581 Array.Copy(tempbtye, 0, temps2, 0, tempbtye.Length); 582 //将第一个元素ListData[0]完全从第一个地址开始 ,完全拷贝到 temps2数组中 583 Array.Copy(temps, 0, temps2, tempbtye.Length, temps.Length); 584 //将第二个元素拼接到temps2中,从刚复制数据的最后一位 +1 开始 585 ListData[0] = temps2; 586 //最后将更新数据包里面的 第一个元素为新元素 587 } 588 else 589 { 590 // System.Threading.Thread.Sleep(20); 591 // Loom.WaitForNextFrame(10); 592 Loom.WaitForSeconds(0.02f); 593 } 594 continue; 595 } 596 else if (tempbtye.Length > (part4_Length + 2 + part3_Length)) 597 { 598 //如果 数据包长度 比 计算出来的(2位数据位+第三段长度+第四度长度) 还大 599 //考虑大出的部分 600 int currentAddcount = (part4_Length + 2 + part3_Length); 601 int offset_length = tempbtye.Length - currentAddcount; 602 byte[] temps = new byte[offset_length]; 603 604 605 //Array.Copy(tempbtye, (part4_Length + 2 + part3_Length), temps, 0, temps.Length); 606 Array.Copy(tempbtye, currentAddcount, temps, 0, temps.Length); 607 //把当前ListData[0]中 后面的数据,复制到 temps数组中... 608 609 ListData[0] = temps; 610 } 611 else if (tempbtye.Length == (part4_Length + 2 + part3_Length)) 612 { //长度刚好匹配 613 ListData.RemoveAt(0); 614 } 615 } 616 catch (Exception e) 617 { 618 if (ErrorMessageEvent != null) 619 ErrorMessageEvent(3, e.StackTrace + "unup001:" + e.Message + "2 + a" + 2 + part3_Length + "---len" + part4_Length + "--tempbtye" + tempbtye.Length); 620 } 621 622 try 623 { 624 if (s_datatype == SocketDataType.Json) 625 { 626 //读取出第四部分数据内容,, 627 string temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2 + part3_Length, part4_Length); 628 TempPakeage str = new TempPakeage(); 629 str.command = tempbtye[0]; 630 //命令等于第一位 631 str.date = temp; 632 //服务器发来执行是0xff,说明发送的是token指令 633 if (tempbtye[0] == 0xff) 634 { 635 if (temp.IndexOf("token") >= 0) 636 tokan = temp.Split('|')[1]; 637 638 //用单个字符来分隔字符串,并获取第二个元素,, 639 //这里因为服务端发来的token后面跟了一个|字符 640 else if (temp.IndexOf("jump") >= 0) 641 { 642 //0xff就是指服务器满了 643 tokan = "连接数量满"; 644 if(JumpServerEvent!=null) 645 JumpServerEvent(temp.Split('|')[1]); 646 } 647 else 648 { // 当上面条件都不为真时执行 ,如果虽然指令是0xff,但是不包含token或jump 649 ReceiveData(str); 650 651 } 652 } 653 else if (ReceiveMessageEvent != null) 654 { 655 //如果tempbtye[0] == 0xff 表示token,不等的情况 656 ReceiveData(str); 657 658 } 659 } 660 //if (DT == DataType.bytes) 661 //{ 662 663 // byte[] bs = new byte[len - 2 + a]; 664 // Array.Copy(tempbtye, bs, bs.Length); 665 // temppake str = new temppake(); 666 // str.command = tempbtye[0]; 667 // str.datebit = bs; 668 // rec(str); 669 670 //} 671 continue; 672 } 673 catch (Exception e) 674 { 675 if (ErrorMessageEvent != null) 676 ErrorMessageEvent(3, e.StackTrace + "unup122:" + e.Message); 677 } 678 } 679 } 680 else 681 { // //ListData[0]第一个元素的Length 不大于2 ,, 682 if (tempbtye[0] == 0) 683 ListData.RemoveAt(0); 684 } 685 } 686 } 687 catch (Exception e) 688 { 689 if (ErrorMessageEvent != null) 690 ErrorMessageEvent(3, "unup:" + e.Message + "---" + e.StackTrace); 691 try 692 { 693 ListData.RemoveAt(0); 694 } 695 catch { } 696 } 697 } 698 } 699 700 /// <summary> 701 /// 线程启动的方法 702 /// </summary> 703 /// <param name="obj"></param> 704 void ReceivesThread(object obj) 705 { 706 while (isok) 707 { 708 //System.Threading.Thread.Sleep(50); 709 // Loom.WaitForNextFrame(10); 710 Loom.WaitForSeconds(0.05f); 711 try 712 { 713 //可以用TcpClient的Available属性判断接收缓冲区是否有数据,来决定是否调用Read方法 714 int bytesRead = tcpClient.Client.Available; 715 if (bytesRead > 0) 716 { 717 //缓冲区 718 byte[] tempbtye = new byte[bytesRead]; 719 try 720 { 721 timeout = DateTime.Now; 722 //从绑定接收数据 Socket 到接收缓冲区中 723 tcpClient.Client.Receive(tempbtye); 724 _0x99: 725 if (tempbtye[0] == 0x99) 726 { //如果缓冲区第一个字符是 0x99心跳包指令 727 timeout = DateTime.Now; 728 //记录现在的时间 729 if (tempbtye.Length > 1) 730 { 731 //去掉第一个字节,长度总体减去1个, 732 byte[] b = new byte[bytesRead - 1]; 733 try 734 { 735 //复制 Array 中的一系列元素(从指定的源索引开始), 736 //并将它们粘贴到另一 Array 中(从指定的目标索引开始) 737 //原始 Array 为tempbtye,原始Array的初始位置 738 //另外一个 目标 Array , 开始位置为0,长度为b.Length 739 Array.Copy(tempbtye, 1, b, 0, b.Length); 740 //那么b中的到的就是去掉心跳包指令0x99以后的后面的数据 741 } 742 catch { } 743 tempbtye = b; 744 //反复执行去掉,心跳包,,, 745 goto _0x99; 746 } 747 else 748 continue; 749 750 //后面的不执行了,回调到 上面的while循环开始 重新执行... 751 } 752 753 754 } 755 catch (Exception ee) 756 { 757 if(ErrorMessageEvent!=null) 758 ErrorMessageEvent(22, ee.Message); 759 } 760 //lock (this) 761 762 //{ 763 //将接收到的 非心跳包数据加入到 ListData中 764 ListData.Add(tempbtye); 765 // } 766 767 } 768 769 //线程每隔指定的过期时间秒,判定,如果没有数据发送过来,,,tcpc.Client.Available=0 情况下 770 else 771 { 772 try 773 { 774 TimeSpan ts = DateTime.Now - timeout; 775 if (ts.TotalSeconds > mytimeout) 776 { //判断时间过期 777 IsOnline = false; 778 CloseConnect(); 779 //isreceives = false; 780 781 if (TimeOutEvent != null) 782 TimeOutEvent(); 783 784 if (ErrorMessageEvent != null) 785 ErrorMessageEvent(2, "连接超时,未收到服务器指令"); 786 continue; 787 } 788 } 789 catch (Exception ee) 790 { 791 if (ErrorMessageEvent != null) 792 ErrorMessageEvent(21, ee.Message); 793 } 794 } 795 } 796 catch (Exception e) 797 { 798 if (ErrorMessageEvent != null) 799 ErrorMessageEvent(2, e.Message); 800 } 801 } 802 } 803 804 } 805}

MainClient单例类

1using UnityEngine; 2using System.Collections; 3using GDGeek; 4using MyTcpClient; 5using System; 6using UnityEngine.SceneManagement; 7using WeaveBase; 8using MyTcpCommandLibrary; 9using UnityEngine.Events; 10using MyTcpCommandLibrary.Model; 11 12public class MainClient : Singleton<MainClient> 13{ 14 15 16 public WeaveSocketGameClient weaveSocketGameClient; 17 18 public ServerBackLoginEvent serverBackLoginEvent =new ServerBackLoginEvent(); 19 20 21 public SetLoginTempModelEvent setLoginTempModelEvent = new SetLoginTempModelEvent(); 22 23 public SetGameScoreTempModelEvent setGameScoreTempModelEvent = new SetGameScoreTempModelEvent(); 24 25 public FirstCheckServerEvent firstCheckServerEvent = new FirstCheckServerEvent(); 26 27 public GameScoreTempModel GameScore; 28 29 public LoginTempModel loginUserModel; 30 // Use this for initialization 31 void Start() 32 { 33 DontDestroyOnLoad(this); 34 setLoginTempModelEvent.AddListener(SetLoginModel); 35 36 37 } 38 public string receiveMessage; 39 40 public void InvokeSetLoginTempModelEvent(LoginTempModel _model) 41 { 42 setLoginTempModelEvent.Invoke(_model); 43 } 44 GameScoreTempModel tempGameScore; 45 public void CallSetGameScoreTempModelEvent(GameScoreTempModel gsModel) 46 { 47 // StartCoroutine(CallSetGameScoreEvent(gsModel)); 48 tempGameScore = gsModel; 49 } 50 51 IEnumerator CallSetGameScoreEvent(GameScoreTempModel gsModel) 52 { 53 yield return new WaitForSeconds(0.5f); 54 setGameScoreTempModelEvent.Invoke(gsModel); 55 } 56 57 58 // Update is called once per frame 59 void Update() 60 { 61 //if (receiveMessage.Length != 0) 62 //{ 63 // receiveMessage = string.Empty; 64 //} 65 if (canLoadSceneFlag) 66 { 67 LoadGameScene(); 68 canLoadSceneFlag = false; 69 } 70 71 72 if (weaveSocketGameClient != null) 73 weaveSocketGameClient.OnTick(); 74 75 76 77 if(tempGameScore != null) 78 { 79 StartCoroutine(CallSetGameScoreEvent(tempGameScore)); 80 tempGameScore = null; 81 } 82 } 83 84 public void ConnectToServer(string serverIp,int port) 85 { 86 try 87 { 88 weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json); 89 weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent; 90 weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent; 91 weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent; 92 weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent; 93 weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent; 94 95 //pcp2.AddListenClass(new MyClientFunction()); 96 Debug.Log("初始化OK"); 97 //bool bb = pcp2.start("61.184.86.126", 10155, false); 98 // bool bb = weaveSocketGameClient.StartConnect("61.184.86.126", 10155, 30, false); 99 bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false); 100 Debug.Log("链接OK"); 101 firstCheckServerEvent.Invoke(bb); 102 } 103 catch 104 { 105 firstCheckServerEvent.Invoke(false); 106 } 107 108 } 109 110 void CallServerFunc() 111 { 112 try 113 { 114 //weaveSocketGameClient.SendRoot<int>(0x02, "login", 11111, 0); 115 //在加个发送 116 weaveSocketGameClient.tokan = "UnityTokan"; 117 weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0); 118 //调用服务端方法getnum,是服务端的方法。 119 //这样就可以了,我们试试 120 } 121 catch (Exception e) 122 { 123 Debug.Log(e.ToString()); 124 } 125 } 126 127 private void OnTimeOutEvent() 128 { 129 Debug.Log("连接超时"); 130 //throw new NotImplementedException(); 131 } 132 133 private void OnReceiveBitEvent(byte command, byte[] data) 134 { 135 Debug.Log("收到了Bit数据"); 136 // throw new NotImplementedException(); 137 } 138 139 private void OnErrorMessageEvent(int type, string error) 140 { 141 Debug.Log("发生了错误"); 142 //throw new NotImplementedException(); 143 } 144 145 private void OnReceiveMessageEvent(byte command, string text) 146 { 147 // throw new NotImplementedException(); 148 Debug.Log("收到了新数据"); 149 150 //throw new NotImplementedException(); 151 receiveMessage = "指令:" + command + ".内容:" + text; 152 Debug.Log("原始数据是:" + receiveMessage); 153 try 154 { 155 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 156 Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root); 157 } 158 catch 159 { 160 Debug.Log("Json转换对象出错了"); 161 } 162 // receiveMessage = "指令:" + command + ".内容:" + text; 163 Debug.Log("收到的信息是:" + receiveMessage); 164 ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command); 165 166 ICheckServerMessage checkSmsg = factory.CheckServerMessage(); 167 checkSmsg.CheckServerMessage(text); 168 169 } 170 171 private void OnConnectOkEvent() 172 { 173 Debug.Log("已经连接成功"); 174 } 175 176 177 178 private void StopConnect() 179 { 180 if (weaveSocketGameClient != null) 181 { 182 183 weaveSocketGameClient.CloseConnect(); 184 weaveSocketGameClient.ConnectOkEvent -= OnConnectOkEvent; 185 weaveSocketGameClient.ReceiveMessageEvent -= OnReceiveMessageEvent; 186 weaveSocketGameClient.ErrorMessageEvent -= OnErrorMessageEvent; 187 weaveSocketGameClient.ReceiveBitEvent -= OnReceiveBitEvent; 188 weaveSocketGameClient.TimeOutEvent -= OnTimeOutEvent; 189 190 // weaveSocketGameClient = null; 191 192 } 193 194 } 195 196 197 198 public void SendLogin(LoginTempModel user ) 199 { 200 try 201 { 202 203 // weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0); 204 StartCoroutine( WaitSendLogin(user) ); 205 Debug.Log("SendLoginFunc"); 206 } 207 catch (Exception e) 208 { 209 Debug.Log(e.ToString()); 210 } 211 } 212 213 IEnumerator WaitSendLogin(LoginTempModel user) 214 { 215 yield return new WaitForSeconds(0.2f); 216 weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0); 217 } 218 219 public void SendCheckUserScore() 220 { 221 try 222 { 223 LoginTempModel user = loginUserModel; 224 // weaveSocketGameClient.Tokan = "UnityTokan"; 225 // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0); 226 227 weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0); 228 Debug.Log("SendLoginFunc"); 229 } 230 catch (Exception e) 231 { 232 Debug.Log(e.ToString()); 233 } 234 } 235 236 237 public void SendNewScoreUpdate(int _score,int _missed) 238 { 239 try 240 { 241 GameScoreTempModel gsModel = new GameScoreTempModel() 242 { 243 userName = loginUserModel.userName, 244 missenemy = _missed, 245 score = _score 246 }; 247 //LoginTempModel user = loginUserModel; 248 // weaveSocketGameClient.Tokan = "UnityTokan"; 249 // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0); 250 251 weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0); 252 Debug.Log("UpdateScore"); 253 } 254 catch (Exception e) 255 { 256 Debug.Log(e.ToString()); 257 } 258 } 259 260 261 262 263 public int sceneIndex; 264 public bool canLoadSceneFlag; 265 void LoadGameScene() 266 { 267 SceneManager.LoadScene(1); 268 } 269 270 271 public void SetLoadSceneFlag() 272 { 273 canLoadSceneFlag = true; 274 } 275 276 void OnDestroy() 277 { 278 //SetLoginModelEvent.RemoveListener(SetLoginModel); 279 280 } 281 282 private void SetLoginModel(LoginTempModel _model) 283 { 284 loginUserModel = _model; 285 } 286 287 private void OnApplicationQuit() 288 { 289 StopConnect(); 290 } 291 292 293 294} 295 296 297public class SetLoginTempModelEvent : UnityEvent<LoginTempModel> { } 298 299public class SetGameScoreTempModelEvent : UnityEvent<GameScoreTempModel> { } 300 301public class ServerBackLoginEvent : UnityEvent<bool>{} 302 303public class FirstCheckServerEvent : UnityEvent<bool> { }

登陆界面类

1using MyTcpCommandLibrary.Model; 2using System; 3using System.Collections; 4using System.Collections.Generic; 5using UnityEngine; 6using UnityEngine.Events; 7using UnityEngine.UI; 8public class LoginHandler : MonoBehaviour { 9 10 11 public InputField input_Username; 12 public InputField input_Password; 13 14 public InputField input_ServerIP; 15 public InputField input_ServerPort; 16 17 18 public Text server_msg_text; 19 public Button login_button; 20 21 // public LoginModel userModel; 22 // Use this for initialization 23 void Start() { 24 MainClient.Instance.serverBackLoginEvent.AddListener(GetServerBackLoginEvent); 25 26 MainClient.Instance.firstCheckServerEvent.AddListener(firstCheckServerConfigEvent); 27 } 28 29 private void firstCheckServerConfigEvent(bool connectToServerResult) 30 { 31 // throw new NotImplementedException(); 32 connectedServerOK = connectToServerResult; 33 } 34 35 public void SetServerIP_Connected() 36 { 37 string ip = input_ServerIP.text; 38 int port = int.Parse(input_ServerPort.text); 39 40 if(connectedServerOK ==false) 41 MainClient.Instance.ConnectToServer(ip, port); 42 } 43 44 45 private void GetServerBackLoginEvent(bool arg0) 46 { 47 //throw new NotImplementedException(); 48 server_msg = "登陆失败,账号密码错误..."; 49 50 51 } 52 53 public bool connectedServerOK = false; 54 55 public void Login() 56 { 57 58 LoginTempModel model = new LoginTempModel() 59 { 60 userName = input_Username.text, 61 password = input_Password.text, 62 //userName = "ssss", 63 //password = "yyyyyy", 64 logintime = System.DateTime.Now.ToString("yyyyMMddHHmmssfff") 65 }; 66 // userModel = model; 67 MainClient.Instance.InvokeSetLoginTempModelEvent(model); 68 MainClient.Instance.SendLogin(model); 69 70 } 71 72 private string server_msg = ""; 73 74 public void SetServerMsgShow(string serverMsg) 75 { 76 server_msg_text.text = serverMsg; 77 } 78 79 void OnDestroy() 80 { 81 MainClient.Instance.serverBackLoginEvent.RemoveListener(GetServerBackLoginEvent); 82 83 MainClient.Instance.firstCheckServerEvent.RemoveListener(firstCheckServerConfigEvent); 84 85 } 86 87 88 89 90 91 // Update is called once per frame 92 void Update () { 93 if( string.IsNullOrEmpty( server_msg) ==false || server_msg.Length >2) 94 { 95 SetServerMsgShow(server_msg); 96 login_button.gameObject.SetActive(true); 97 server_msg = ""; 98 } 99 } 100} 101 102

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

1using UnityEngine; 2using System.Collections; 3 4using UnityEngine.Events; 5using UnityEngine.UI; 6using System; 7using MyTcpCommandLibrary.Model; 8 9public class GameScoreHandler : MonoBehaviour 10{ 11 12 public static UpdateScoreEvent updateScoreEvent = new UpdateScoreEvent(); 13 public static UpdateLivesEvent updateLivesEvent = new UpdateLivesEvent(); 14 public static UpdateMissedEvent updateMissedEvent = new UpdateMissedEvent(); 15 16 public static UnityEvent SendUpdateScoreEvent = new UnityEvent(); 17 // public static UnityEvent<GameScoreTempModel> SetGameScoreUI; 18 19 20 21 public Text userNameText; 22 public Text now_scoreText; 23 public Text now_livesText; 24 public Text now_missedText; 25 public Text serverText; 26 27 public Text last_scoreText; 28 public Text last_missedText; 29 30 // Use this for initialization 31 void Start() 32 { 33 updateScoreEvent.AddListener( OnUpdateScore); 34 updateLivesEvent.AddListener(OnUpdateLives); 35 updateMissedEvent.AddListener(OnUpdateMissed); 36 SendUpdateScoreEvent.AddListener(OnSendUpdateScore); 37 MainClient.Instance.setGameScoreTempModelEvent.AddListener(SetLastData); 38 39 } 40 41 private void OnSendUpdateScore() 42 { 43 //throw new NotImplementedException(); 44 serverText.text = "积分已发往服务器..."; 45 } 46 47 private void OnUpdateScore(int _score) 48 { 49 50 now_scoreText.text = "积分:" + _score.ToString(); 51 52 } 53 void OnDestory() 54 { 55 56 updateScoreEvent.RemoveListener(OnUpdateScore); 57 updateLivesEvent.RemoveListener(OnUpdateLives); 58 updateMissedEvent.RemoveListener(OnUpdateMissed); 59 SendUpdateScoreEvent.RemoveListener(OnSendUpdateScore); 60 MainClient.Instance.setGameScoreTempModelEvent.RemoveListener(SetLastData); 61 62 63 } 64 private void OnUpdateLives(int _lives) 65 { 66 now_livesText.text = "生命:" + _lives.ToString(); 67 68 } 69 70 private void OnUpdateMissed(int _missed) 71 { 72 73 now_missedText.text = "放走敌人:" + _missed.ToString(); 74 } 75 76 private void OnDestroy() 77 { 78 79 } 80 81 public void SetUserNameData(string _uname) 82 { 83 userNameText.text = _uname; 84 } 85 86 87 88 public void SetLastData(GameScoreTempModel gsModel) 89 { 90 //userNameText.text = "生命:" + gsModel.userName; 91 //last_scoreText.text = "积分:" + gsModel.score.ToString(); 92 //last_missedText.text = "放走敌人:" + gsModel.missenemy.ToString(); 93 tempScore = gsModel; 94 } 95 96 public void SetLastDataText() 97 { 98 userNameText.text = "生命:" + tempScore.userName; 99 last_scoreText.text = "积分:" + tempScore.score.ToString(); 100 last_missedText.text = "放走敌人:" + tempScore.missenemy.ToString(); 101 } 102 103 public void SetNowDate(int _lives, int _lastScore, int _lastMissed) 104 { 105 now_livesText.text ="生命:"+ _lives.ToString(); 106 now_scoreText.text = "积分:" + _lastScore.ToString(); 107 now_missedText.text = "放走敌人:" + _lastMissed.ToString(); 108 } 109 110 GameScoreTempModel tempScore; 111 // Update is called once per frame 112 void Update() 113 { 114 if(tempScore != null) 115 { 116 SetLastDataText(); 117 tempScore = null; 118 } 119 } 120 121 public void ReloadGameScene() 122 { 123 //跳转场景 124 MainClient.Instance.SetLoadSceneFlag(); 125 126 127 //发送读取上次分数数据的逻辑 128 MainClient.Instance.SendCheckUserScore(); 129 } 130 131 132} 133public class UpdateScoreEvent: UnityEvent<int> { } 134public class UpdateLivesEvent : UnityEvent<int> { } 135public class UpdateMissedEvent : UnityEvent<int> { }

客户端使用的主要代码为

1WeaveSocketGameClient weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json); 2weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent; 3weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent; 4weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent; 5weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent; 6weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent; 7 Debug.Log("初始化OK"); 8 bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false); 9 Debug.Log("链接OK"); 10 //触发第一次 检查并连接服务器状态事件,用于通知其它Unity脚本,作出相应反应 11 firstCheckServerEvent.Invoke(bb);

没什么可说的,代码已经很明确了,常用的几个事件都有,,

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

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

1 Debug.Log("收到了新数据"); 2 3 4 receiveMessage = "指令:" + command + ".内容:" + text; 5 Debug.Log("原始数据是:" + receiveMessage); 6 try 7 { 8 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 9 Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root); 10 } 11 catch 12 { 13 Debug.Log("Json转换对象出错了"); 14 } 15 Debug.Log("收到的信息是:" + receiveMessage); 16 //根据收到的指令来确定要生成的工厂 17 ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command); 18 //调用对应工厂,生成具体的接口实现类 19 ICheckServerMessage checkSmsg = factory.CheckServerMessage(); 20 //调用具体接口类的 处理数据的具体方法 21 checkSmsg.CheckServerMessage(text);

抽象工厂以及相关代码如下

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

1using UnityEngine; 2using System.Collections; 3 4public static class CheckCommandHelper 5{ 6 public static ICheckServerMessageFactory SwitchCheckCommand(byte command) 7 { 8 ICheckServerMessageFactory factory = null; 9 switch (command) 10 { 11 case (0x1): 12 factory = new LoginMessageFactory(); 13 break; 14 case (0x2): 15 factory = new GameScoreMessageFactory(); 16 break; 17 //其他类型略; 18 } 19 return factory; 20 } 21 22} 23

工厂接口

1using System; 2 3public interface ICheckServerMessageFactory 4{ 5 6 ICheckServerMessage CheckServerMessage(); 7 8}

数据处理接口

1using System; 2 3 4 5public interface ICheckServerMessage 6{ 7 8 void CheckServerMessage( string text); 9 10} 11 12

具体实现类

1using UnityEngine; 2using System.Collections; 3using System; 4using WeaveBase; 5public class LoginMessage : ICheckServerMessage 6{ 7 public void CheckServerMessage( string text) 8 { 9 // throw new NotImplementedException(); 10 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 11 Debug.Log("收到的消息是:"+text); 12 if(ws.Request == "ServerBackLoginResult" ) 13 { 14 if( ws.GetRoot<bool>() == true) 15 { 16 //如果登陆成功,,处理的逻辑...... 17 //先更新用户 18 19 //跳转场景 20 MainClient.Instance.SetLoadSceneFlag(); 21 22 23 //发送读取上次分数数据的逻辑 24 MainClient.Instance.SendCheckUserScore(); 25 } 26 27 else 28 { 29 MainClient.Instance.serverBackLoginEvent.Invoke(false); 30 } 31 } 32 33 34 } 35 36} 37 38 39using UnityEngine; 40using System.Collections; 41using System; 42using WeaveBase; 43using MyTcpCommandLibrary.Model; 44 45public class GameScoreMessage : ICheckServerMessage 46{ 47 public void CheckServerMessage(string text) 48 { 49 // throw new NotImplementedException(); 50 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 51 Debug.Log("收到的GameScoreMessage消息是:" + text); 52 if (ws.Request == "ServerSendGameScore") 53 { 54 GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>(); 55 if (gsModel != null ) 56 { 57 58 MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel); 59 60 } 61 62 else 63 { 64 // MainClient.Instance.serverBackLoginEvent.Invoke(false); 65 } 66 } 67 68 } 69} 70 71 72using UnityEngine; 73using System.Collections; 74using System; 75 76public class LoginMessageFactory : ICheckServerMessageFactory 77{ 78 public ICheckServerMessage CheckServerMessage() 79 { 80 //throw new NotImplementedException(); 81 return new LoginMessage(); 82 } 83} 84 85 86 87using UnityEngine; 88using System.Collections; 89 90public class GameScoreMessageFactory : ICheckServerMessageFactory 91{ 92 public ICheckServerMessage CheckServerMessage() 93 { 94 //throw new NotImplementedException(); 95 return new GameScoreMessage(); 96 } 97} 98

命令的枚举

1using System; 2 3 4namespace MyTcpCommandLibrary 5{ 6 public enum CommandEnum :byte 7 { 8 /// <summary> 9 /// 10 /// </summary> 11 ClientSendLoginModel = 0x02, 12 13 ClientSendGameScoreModel = 0x03, 14 15 ServerSendLoginResult = 0x04, 16 17 // ServerSendGameScoreModel = 0x05, 18 19 ClientSendDisConnected = 0x06, 20 21 ServerSendUpdateGameScoreResult = 0x07, 22 23 24 ClientSendCheckScore = 0x08, 25 26 ServerSendGetGameScoreResult = 0x09 27 28 } 29} 30

-------------------------------------------

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

-------------------------------------------

----------------------------------------------

启动程序

----------------------------------------------

玩家输入账号密码

----------------------------------------------

点击登陆按钮,

----------------------------------------------

调用MainClient里面的ConnectToServer 方法 

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

1 [InstallFun("forever")] 2 public void CheckLogin(Socket soc, WeaveSession wsession) 3 { 4 5 // string jsonstr = _0x01.Getjson(); 6 LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>(); 7 8 9 10 //执行查找数据的操作...... 11 bool loginOk = false; 12 13 14 AddSystemData(); 15 16 loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); 17 if (loginOk) 18 { 19 // UpdatePlayerListSetOnLine 发送有玩家成功登陆服务器事件,用于通知前端更新UserListBox 20 ServerLoginOKEvent(get_client_Send_loginModel.userName, soc); 21 22 23 } 24 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); 25 //发送人数给客户端 26 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token 27 } 28

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

调用它的CheckServerMessage方法

-----------------------------------------------

1using UnityEngine; 2using System.Collections; 3using System; 4using WeaveBase; 5public class LoginMessage : ICheckServerMessage 6{ 7 public void CheckServerMessage( string text) 8 { 9 // throw new NotImplementedException(); 10 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 11 Debug.Log("收到的消息是:"+text); 12 if(ws.Request == "ServerBackLoginResult" ) 13 { 14 if( ws.GetRoot<bool>() == true) 15 { 16 //如果登陆成功,,处理的逻辑...... 17 //先更新用户 18 19 //跳转场景 20 MainClient.Instance.SetLoadSceneFlag(); 21 22 23 //发送读取上次分数数据的逻辑 24 MainClient.Instance.SendCheckUserScore(); 25 } 26 27 else 28 { 29 MainClient.Instance.serverBackLoginEvent.Invoke(false); 30 } 31 } 32 33 34 } 35 36} 37

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

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

具体方法代码是

1LoginTempModel user = loginUserModel; 2 3weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0); 4

----------------------------------------------

(正在游戏场景运行中)

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

1using UnityEngine; 2using System.Collections; 3using System; 4using WeaveBase; 5using MyTcpCommandLibrary.Model; 6 7public class GameScoreMessage : ICheckServerMessage 8{ 9 public void CheckServerMessage(string text) 10 { 11 // throw new NotImplementedException(); 12 WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); 13 Debug.Log("收到的GameScoreMessage消息是:" + text); 14 if (ws.Request == "ServerSendGameScore") 15 { 16 GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>(); 17 if (gsModel != null ) 18 { 19 //触发收到服务器发送来的积分数据的事件,并更新到前端UI显示上 20 MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel); 21 22 } 23 24 else 25 { 26 // MainClient.Instance.serverBackLoginEvent.Invoke(false); 27 } 28 } 29 30 } 31} 32

----------------------------------------------

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

----------------------------------------------

调用MainClient里面的SendNewScoreUpdate方法

----------------------------------------------

1 public void SendNewScoreUpdate(int _score,int _missed) 2 { 3 try 4 { 5 GameScoreTempModel gsModel = new GameScoreTempModel() 6 { 7 userName = loginUserModel.userName, 8 missenemy = _missed, 9 score = _score 10 }; 11 //LoginTempModel user = loginUserModel; 12 // weaveSocketGameClient.Tokan = "UnityTokan"; 13 // weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0); 14 15 weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0); 16 Debug.Log("UpdateScore"); 17 } 18 catch (Exception e) 19 { 20 Debug.Log(e.ToString()); 21 } 22 }

----------------------------------------------

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

----------------------------------------------

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

----------------------------------------------

1 [InstallFun("forever")] 2 public void UpdateScore(Socket soc, WeaveSession wsession) 3 { 4 GameScoreTempModel gsModel = wsession.GetRoot<GameScoreTempModel>(); 5 6 7 //执行数据更新的操作...... 8 bool updateSocreResult = UpdateUserScore(gsModel.userName, gsModel.score , gsModel.missenemy); 9 10 if (updateSocreResult) 11 { 12 // 向客户端发送 更新积分成功的信息 13 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token); 14 15 } 16 else 17 { 18 // 向客户端发送 更新积分失败的信息 19 SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token); 20 //发送人数给客户端 21 //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token 22 } 23 }

----------------------------------------------

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

----------------------------------------------

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

---------------------------------------

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

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Unity太空大战游戏 - HelloWorld