項目下載地址
https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows
Example /Unity3D_2DShootServer_Client 項目文件位置。
教程編寫有 SuperLinMeng 提供,QQ:2360450496
WeaveSocket通訊框架官方QQ群17375149
WeaveSocket框架-Unity太空大戰(zhàn)游戲-
概述0
先看下最終的效果
服務端
用戶登錄后,認證成功進入游戲后
客戶端
輸入錯誤密碼,有提示信息
主要技術架構
服務端端:
Socket框架【W(wǎng)eaveSocket】
https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows/
數(shù)據(jù)庫【LiteDB】(3.1.4.0)
界面UI【W(wǎng)PF】(.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
{
}
WeaveTcpToken token = TcpToken; { if (token.IsToken) { //生成一個token,后綴帶隨機數(shù) 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) { //向客戶端發(fā)送生成的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 + "");
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; }
}
}
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 { //觸發(fā)接收到信息的事件... /我寫的方法/ WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);
if(hasOnline != null)
{
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);
WeaveReceiveEvent(command, data, uplayer);
} /**/
if (command == 0xff) { //如果是網(wǎng)關command 發(fā)過來的 命名,那么執(zhí)行下面的 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> /// 網(wǎng)關0xff這個command發(fā)來的...命令 /// </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發(fā)來的...命令 /// </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;
重點說下AddMyTcpCommandLibrary方法 加載幾個繼承自 WeaveTCPCommand的類,里面寫有一些方法,當服務器接收到客戶端的一些參數(shù)后,可以直接跳轉執(zhí)行里面的寫的方法,你可以新建一個類庫項目(我這里命名為MyTcpCommandLibrary),然后引用項目 WeaveBase和WeaveSocketServer。在MyTcpCommandLibrary項目下新建幾個類(根據(jù)你想要的邏輯),類繼承WeaveTCPCommand,然后有具體的方法單獨寫出來,如
[InstallFun("forever")] public void CheckLogin(Socket soc, WeaveSession wsession) {
// string jsonstr = _0x01.Getjson(); LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();
//執(zhí)行查找數(shù)據(jù)的操作...... 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); //發(fā)送人數(shù)給客戶端 //參數(shù)1,發(fā)送給客戶端對象,參數(shù)2,發(fā)送給客戶端對應的方法,參數(shù)3,人數(shù)的實例,參數(shù)4,此處無作用,參數(shù)5,客戶端此次token } 當客戶端發(fā)送命名為 Getcommand() 返回的命令byte,并且參數(shù)含方法名,即可直接調用服務端WeaveTCPCommand寫的這個CheckLogin方法 客戶端調用示例
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);
再說下前端WPF啟動服務器開始監(jiān)聽的代碼
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> /// 監(jiān)聽端口列表,,可以選擇監(jiān)聽多個端口 /// </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的數(shù)據(jù)源 LoginedUser_listBox.ItemsSource = loginedUserList; //設置連接到服務器的Socket列表的Listbox的數(shù)據(jù)源 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 = "正在監(jiān)聽";
StartListen_button.IsEnabled = false;
}
private void OnWeaveServerUpdateUnityPlayerSetOnLineEvent(UnityPlayerOnClient gamer) {
//throw new NotImplementedException();
//當有用戶 賬號密碼登陸成功的時候
AddListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer));
SetServerReceiveText("--觸發(fā)了一次(OnWeaveServerUpdateUnityPlayerSetOnLineEvent)" + Environment.NewLine);
}
private void OnWeaveUpdateSocket(UnityPlayerOnClient gamer) { SetServerReceiveText("--觸發(fā)了一次(OnWeaveUpdateSocket)" + Environment.NewLine);
//有 Sokcet客戶端連接到服務器的時候,暫未 賬號,密碼認證狀態(tài)
AddListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer) );
}
private void OnWeaveDeleteSocket(UnityPlayerOnClient gamer) { SetServerReceiveText("--退出事件,,觸發(fā)了一次(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);// 可以立即中斷程序執(zhí)行并退出 }
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, "服務器主動給所有客戶端發(fā)消息了: " + serverMsg); }
// MessageBox.Show("客戶端在線數(shù)量:"+ _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() { //數(shù)據(jù)發(fā)生變化后,重新設置登陸后的用戶列表Listbox的數(shù)據(jù)源 LoginedUser_listBox.ItemsSource = null; LoginedUser_listBox.ItemsSource = loginedUserList; //數(shù)據(jù)發(fā)生變化后,重新設置連接到服務器的Socket列表的Listbox的數(shù)據(jù)源 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);// 可以立即中斷程序執(zhí)行并退出 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; 接受到客戶端發(fā)來的數(shù)據(jù)事件(這里如果發(fā)來的數(shù)據(jù)第一位byte命令跟上面的MyTcpCommandLibrary項目里面,繼承自WeaveTCPCommand類,具體的返回的Getcommand()方法返回的byte命名相同,則會進入那個類進行處理) 假如客戶端發(fā)送代碼如下 weaveSocketGameClient.SendRoot<LoginTempModel>( 0x02 , "CheckLogin", user, 0); 表示客戶端發(fā)送的命名是0x02 ,數(shù)據(jù)實體類是 LoginTempModel (數(shù)據(jù)發(fā)送報文格式,我們稍后再說) 服務端 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類型的數(shù)據(jù),soc是發(fā)送人。
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>();
//執(zhí)行查找數(shù)據(jù)的操作...... 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); //發(fā)送人數(shù)給客戶端 //參數(shù)1,發(fā)送給客戶端對象,參數(shù)2,發(fā)送給客戶端對應的方法,參數(shù)3,人數(shù)的實例,參數(shù)4,此處無作用,參數(shù)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; 這是我根據(jù)源碼修改的一個事件,當客戶端連接成功,并且發(fā)送賬號密碼到服務器,服務器查找數(shù)據(jù)庫后,確認給客戶端可以登陸游戲后,把當前用戶設置為已經上線的游戲玩家的事件
數(shù)據(jù)格式如下圖
發(fā)送數(shù)據(jù)的主要代碼為
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; //表示第三部分數(shù)據(jù)的長度 part3_length.CopyTo(b, 2); //擴充 第四部分數(shù)據(jù)(待發(fā)送的數(shù)據(jù))的長度,擴充到b數(shù)組第三位開始的后面 sendb.CopyTo(b, 2 + part3_length.Length); //擴充 第四部分數(shù)據(jù)實際的數(shù)據(jù),擴充到b數(shù)組第三部分結尾后面... socket.Send( b ); 客戶端代碼結構
登陸界面
游戲場景
主要的邏輯流程
啟動程序
玩家輸入賬號密碼
點擊登陸按鈕
連接服務器(如果成功),繼續(xù)發(fā)送賬號密碼到服務器的命令
服務器接收賬號密碼,進行查找數(shù)據(jù)庫操作
發(fā)送查找結果給客戶端......
如果客戶端接收到服務器發(fā)過來的登陸成功消息(跳轉到游戲場景),
如果返回失敗,那么提示賬號密碼錯誤
客戶端再次發(fā)送查找當前用戶的歷史積分數(shù)據(jù)的命令
(正在游戲場景運行中)
客戶端接受到歷史積分數(shù)據(jù),并更新顯示到UnityUI界面上
P0-玩家戰(zhàn)機生命為0時,向服務器發(fā)送本次游戲積分數(shù)據(jù)
服務器收到玩家本次游戲積分數(shù)據(jù),進行數(shù)據(jù)庫更新操作(根據(jù)用戶名)
客戶端顯示一個按鈕,玩家可點擊再玩一次,再次游戲(跳轉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> /// 在接收數(shù)據(jù) /// </summary> public bool isReceives = false; /// <summary> /// 是否在線了 /// </summary> public bool IsOnline = false;
DateTime timeout;
/// <summary>
/// 數(shù)據(jù)超時時間
/// </summary>
int mytimeout = 90;
/// <summary> /// 隊列中沒有排隊的方法需要執(zhí)行 /// </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;
}
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); } } }
/// <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), // 使用這個這個委托定義的線程的啟動函數(shù)可以接受一個輸入?yún)?shù),
//receives_thread1 = new System.Threading.Thread(new ParameterizedThreadStart(ReceivesThread)); //receives_thread1.IsBackground = true; // receives_thread1.Start(); // ThreadStart這個委托定義為void ThreadStart(),也就是說,所執(zhí)行的方法不能有參數(shù) // checkToken_UpdateList_thread2 = new System.Threading.Thread(new ThreadStart(CheckToken_UpdateListDataThread)); //checkToken_UpdateList_thread2.IsBackground = true; // checkToken_UpdateList_thread2.Start();
/開始執(zhí)行線程開始/ 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 在單線程的程序-------------------- /開始執(zhí)行線程結束/
} 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; } }
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); //擴充 第四部分數(shù)據(jù)(待發(fā)送的數(shù)據(jù))的長度,擴充到b數(shù)組第三位開始的后面 //sendb.CopyTo(b, 2 + part3_length.Length); //擴充 第四部分數(shù)據(jù)實際的數(shù)據(jù),擴充到b數(shù)組第三部分結尾后面...
byte[] b = MyGameClientHelper.CodingProtocol( command, text);
int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1); if (count == 0) { //判定數(shù)據(jù)長度,,實際指的是大小是不是小于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);
//分割發(fā)送......
// 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; }
/// <summary> /// 通過主線程執(zhí)行方法避免跨線程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("隊列中沒有排隊的方法需要執(zhí)行。"); }
public void CloseConnect() { try { isok = false;
IsOnline = false; //發(fā)送我要斷開連接的消息 this.SendRoot<int>((byte)CommandEnum.ClientSendDisConnected, "OneClientDisConnected", 0, 0);
// receives_thread1.Abort(); //checkToken_UpdateList_thread2.Abort();
tcpClient.Close();
AbortThread();
} catch { Debug.Log("CloseConnect失敗,發(fā)生異常"); }
}
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> /// 接收到服務器發(fā)來的數(shù)據(jù)的處理方法 /// </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> /// 線程啟動的方法,初始化連接后要接收服務器發(fā)來的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內部,那么下面的代碼不執(zhí)行,重新到 --》 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個字節(jié),心跳包包頭,無任何意思,那么直接刪除 ListData.RemoveAt(0); continue; } }
//ListData[0]第一個元素的長度 大于2 if (bytesRead > 2) { //第二段是固定一個字節(jié),最高255,代表了第三段的長度 //這樣第三段最高可以255*255位,這樣表示數(shù)據(jù)內容的長度基本可以無限大了 // int a = tempbtye[1]; int part3_Length = tempbtye[1]; //tempbtye既是ListData[0]數(shù)據(jù), //第一位為command,指令 //第二位的數(shù)據(jù)是第三段的長度 //第三段的數(shù)據(jù)是第四段的長度 //第四段是內容數(shù)據(jù) if (bytesRead > 2 + part3_Length) { //如果收到數(shù)據(jù)這段數(shù)據(jù),大于 // 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從第三位開始,復制數(shù)據(jù)到part4_LengthBitArray Array.Copy(tempbtye, 2, part4_LengthBitArray, 0, part3_Length); //len = ConvertToInt(bb); //獲得實際數(shù)據(jù)的長度,也就是第四部分數(shù)據(jù)的長度 part4_Length = MyGameClientHelper. ConvertToInt(part4_LengthBitArray); } else { //如果DataType不是DataType.bytes類型,,, 是Json類型 //從某個Data中第三位開始截取數(shù)據(jù),,獲取第四段數(shù)據(jù)長度的字符串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 { //如果第四段數(shù)據(jù)的長度為0 ,,,說明發(fā)的空消息,,沒有第四段數(shù)據(jù) //如果第二位沒有數(shù)據(jù),,說明發(fā)的是空消息 ListData.RemoveAt(0); continue; } } catch { } }
try { //如果計算出來的(2位數(shù)據(jù)位+第三段長度+第四度長度) 比當前ListData[0]長度還大... if ((part4_Length + 2 + part3_Length) > tempbtye.Length) { if (ListData.Count > 1) { //將第一個數(shù)據(jù)包刪除 ListData.RemoveAt(0); //重新讀取第一個數(shù)據(jù)包(第二個數(shù)據(jù)包變?yōu)榈谝粋€)內容 byte[] temps = new byte[ListData[0].Length]; //將 數(shù)據(jù)表內容 拷貝到 temps中 Array.Copy(ListData[0], temps, temps.Length); //新byte數(shù)組長度擴充,原數(shù)據(jù)長度 + (第二個)元素長度 byte[] temps2 = new byte[tempbtye.Length + temps.Length];
Array.Copy(tempbtye, 0, temps2, 0, tempbtye.Length); //將第一個元素ListData[0]完全從第一個地址開始 ,完全拷貝到 temps2數(shù)組中 Array.Copy(temps, 0, temps2, tempbtye.Length, temps.Length); //將第二個元素拼接到temps2中,從剛復制數(shù)據(jù)的最后一位 +1 開始 ListData[0] = temps2; //最后將更新數(shù)據(jù)包里面的 第一個元素為新元素 } else { // System.Threading.Thread.Sleep(20); // Loom.WaitForNextFrame(10); Loom.WaitForSeconds(0.02f); } continue; } else if (tempbtye.Length > (part4_Length + 2 + part3_Length)) { //如果 數(shù)據(jù)包長度 比 計算出來的(2位數(shù)據(jù)位+第三段長度+第四度長度) 還大 //考慮大出的部分 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]中 后面的數(shù)據(jù),復制到 temps數(shù)組中...
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) { //讀取出第四部分數(shù)據(jù)內容,, string temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2 + part3_Length, part4_Length); TempPakeage str = new TempPakeage(); str.command = tempbtye[0]; //命令等于第一位 str.date = temp; //服務器發(fā)來執(zhí)行是0xff,說明發(fā)送的是token指令 if (tempbtye[0] == 0xff) { if (temp.IndexOf("token") >= 0) tokan = temp.Split('|')[1];
//用單個字符來分隔字符串,并獲取第二個元素,, //這里因為服務端發(fā)來的token后面跟了一個|字符 else if (temp.IndexOf("jump") >= 0) { //0xff就是指服務器滿了 tokan = "連接數(shù)量滿"; if(JumpServerEvent!=null) JumpServerEvent(temp.Split('|')[1]); } else { // 當上面條件都不為真時執(zhí)行 ,如果雖然指令是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屬性判斷接收緩沖區(qū)是否有數(shù)據(jù),來決定是否調用Read方法 int bytesRead = tcpClient.Client.Available; if (bytesRead > 0) { //緩沖區(qū) byte[] tempbtye = new byte[bytesRead]; try { timeout = DateTime.Now; //從綁定接收數(shù)據(jù) Socket 到接收緩沖區(qū)中 tcpClient.Client.Receive(tempbtye); _0x99: if (tempbtye[0] == 0x99) { //如果緩沖區(qū)第一個字符是 0x99心跳包指令 timeout = DateTime.Now; //記錄現(xiàn)在的時間 if (tempbtye.Length > 1) { //去掉第一個字節(jié),長度總體減去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以后的后面的數(shù)據(jù) } catch { } tempbtye = b; //反復執(zhí)行去掉,心跳包,,, goto _0x99; } else continue;
//后面的不執(zhí)行了,回調到 上面的while循環(huán)開始 重新執(zhí)行... }
} catch (Exception ee) { if(ErrorMessageEvent!=null) ErrorMessageEvent(22, ee.Message); } //lock (this)
//{ //將接收到的 非心跳包數(shù)據(jù)加入到 ListData中 ListData.Add(tempbtye); // }
}
//線程每隔指定的過期時間秒,判定,如果沒有數(shù)據(jù)發(fā)送過來,,,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); //在加個發(fā)送 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數(shù)據(jù)"); // throw new NotImplementedException(); }
private void OnErrorMessageEvent(int type, string error) { Debug.Log("發(fā)生了錯誤"); //throw new NotImplementedException(); }
private void OnReceiveMessageEvent(byte command, string text) { // throw new NotImplementedException(); Debug.Log("收到了新數(shù)據(jù)");
//throw new NotImplementedException(); receiveMessage = "指令:" + command + ".內容:" + text; Debug.Log("原始數(shù)據(jù)是:" + receiveMessage); try { WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("接受到的WeaveSession數(shù)據(jù)是:" + 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 = "積分已發(fā)往服務器..."; }
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();
//發(fā)送讀取上次分數(shù)數(shù)據(jù)的邏輯 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"); //觸發(fā)第一次 檢查并連接服務器狀態(tài)事件,用于通知其它Unity腳本,作出相應反應 firstCheckServerEvent.Invoke(bb); 沒什么可說的,代碼已經很明確了,常用的幾個事件都有,,
具體說一下MainClient類里面的 接收數(shù)據(jù)處理用的抽象工廠
在接收事件處理方法里面寫有如下代碼
Debug.Log("收到了新數(shù)據(jù)");
receiveMessage = "指令:" + command + ".內容:" + text; Debug.Log("原始數(shù)據(jù)是:" + receiveMessage); try { WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text); Debug.Log("接受到的WeaveSession數(shù)據(jù)是:" + ws.Request + " " + ws.Root); } catch { Debug.Log("Json轉換對象出錯了"); } Debug.Log("收到的信息是:" + receiveMessage); //根據(jù)收到的指令來確定要生成的工廠 ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command); //調用對應工廠,生成具體的接口實現(xiàn)類 ICheckServerMessage checkSmsg = factory.CheckServerMessage(); //調用具體接口類的 處理數(shù)據(jù)的具體方法 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();
}
數(shù)據(jù)處理接口
using System;
public interface ICheckServerMessage {
void CheckServerMessage( string text);
}
具體實現(xiàn)類
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();
//發(fā)送讀取上次分數(shù)數(shù)據(jù)的邏輯 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 方法
連接服務器(如果成功),繼續(xù)發(fā)送賬號密碼到服務器的命令
再調用MainClient里面的 SendLogin 方法(有個等待0.2秒)
服務器接收賬號密碼,進行查找數(shù)據(jù)庫操作
調用了MyTcpCommandLibrary項目中的LoginManageCommand類的CheckLogin方法(具體LiteDB操作數(shù)據(jù)的代碼不再細說,源碼一看就明白了)
[InstallFun("forever")] public void CheckLogin(Socket soc, WeaveSession wsession) {
// string jsonstr = _0x01.Getjson(); LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();
//執(zhí)行查找數(shù)據(jù)的操作...... bool loginOk = false;
AddSystemData();
loginOk = CheckUserCanLoginIn(get_client_Send_loginModel); if (loginOk) { // UpdatePlayerListSetOnLine 發(fā)送有玩家成功登陸服務器事件,用于通知前端更新UserListBox ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);
} SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token); //發(fā)送人數(shù)給客戶端 //參數(shù)1,發(fā)送給客戶端對象,參數(shù)2,發(fā)送給客戶端對應的方法,參數(shù)3,人數(shù)的實例,參數(shù)4,此處無作用,參數(shù)5,客戶端此次token }
發(fā)送查找結果給客戶端......
如果客戶端接收到服務器發(fā)過來的登陸成功消息(跳轉到游戲場景),
數(shù)據(jù)處理工廠接收到命令調用LoginMessageFactory,并返回一個具體的ICheckServerMessage接口實現(xiàn)類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();
//發(fā)送讀取上次分數(shù)數(shù)據(jù)的邏輯 MainClient.Instance.SendCheckUserScore(); }
else
{
MainClient.Instance.serverBackLoginEvent.Invoke(false);
}
}
}
}
如果返回失敗,那么提示賬號密碼錯誤
客戶端再次發(fā)送查找當前用戶的歷史積分數(shù)據(jù)的命令
既是上面代碼中的//發(fā)送讀取上次分數(shù)數(shù)據(jù)的邏輯 MainClient.Instance.SendCheckUserScore();方法里面已經封裝了用戶的UserName
具體方法代碼是
LoginTempModel user = loginUserModel;
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0);
(正在游戲場景運行中)
客戶端接受到歷史積分數(shù)據(jù),并更新顯示到UnityUI界面上
同上..................調用實現(xiàn)接口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 ) { //觸發(fā)收到服務器發(fā)送來的積分數(shù)據(jù)的事件,并更新到前端UI顯示上 MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);
}
else { // MainClient.Instance.serverBackLoginEvent.Invoke(false); } }
} }
P0-玩家戰(zhàn)機生命為0時,向服務器發(fā)送本次游戲積分數(shù)據(jù)
調用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);
服務器收到玩家本次游戲積分數(shù)據(jù),進行數(shù)據(jù)庫更新操作(根據(jù)用戶名)
調用了MyTcpCommandLibrary項目中的GameScoreCommand類的UpdateScore方法(具體LiteDB操作數(shù)據(jù)的代碼不再細說,源碼一看就明白了)
[InstallFun("forever")] public void UpdateScore(Socket soc, WeaveSession wsession) { GameScoreTempModel gsModel = wsession.GetRoot<GameScoreTempModel>();
//執(zhí)行數(shù)據(jù)更新的操作...... bool updateSocreResult = UpdateUserScore(gsModel.userName, gsModel.score , gsModel.missenemy);
if (updateSocreResult)
{
// 向客戶端發(fā)送 更新積分成功的信息
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);
客戶端顯示一個按鈕,玩家可點擊再玩一次,再次游戲(跳轉P0,當玩家生命為0時)
GameScoreHandler類的ReloadGameScene方法,發(fā)送本次游戲積分數(shù)據(jù)并重新加載游戲場景
其它的Unity3D游戲邏輯代碼在這里不再細說
更多建議: