diff options
22 files changed, 1336 insertions, 260 deletions
diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/P2P.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap.meta index 572c8c9..f143fc9 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/P2P.meta +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 43a4c0454d194994e99e9710d70264a1 +guid: e66a36ee97b5bcd419f27aa03af71690 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs new file mode 100644 index 0000000..603d027 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs @@ -0,0 +1,232 @@ +using JetBrains.Annotations; +using Steamworks.Data; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using Unity.VisualScripting; +using UnityEngine; + + +namespace MultiplayerToolkit.Backend.Wrap +{ + + public struct NetClientSetting + { + public IPAddress tcpLocalIp; + public int tcpLocalPort; + + public IPAddress udpLocalIp; + public int udpLocalPort; + + // 服务器IP\port + public IPAddress remoteTcpIP; + public int remoteTcpPort; + + public IPAddress remoteUdpIP; + public int remoteUdpPort; + + } + + public class TcpConnection + { + public static int RECEIVE_BUFFER_SIZE = 4096; + + public Action<byte[], int> onReceiveData; + + private TcpClient connection; + + private NetworkStream stream; + private byte[] receiveBuffer; + + public bool isConnected { get; set; } + + private object _runningDummy = new object(); + private bool m_IsRunning = false; + private bool isRunning + { + get + { + lock (_runningDummy) + { + return m_IsRunning; + } + } + set + { + lock (_runningDummy) + { + m_IsRunning = value; + } + } + } + + public async Task<bool> Connect(NetClientSetting setting) + { + receiveBuffer = new byte[RECEIVE_BUFFER_SIZE]; + + IPEndPoint lcoalEP = new IPEndPoint(setting.tcpLocalIp, setting.tcpLocalPort); + connection = new TcpClient(lcoalEP); + await connection.ConnectAsync(setting.remoteTcpIP, setting.remoteTcpPort); + if (connection.Connected) + { + isConnected = true; + stream = connection.GetStream(); + isRunning = true; + ReceiveAsync(); + return true; + } + return false; + } + + public void Disconnect() + { + isRunning = false; + isConnected = false; + + stream.Close(); + connection.Close(); + receiveBuffer = null; + stream = null; + connection = null; + } + + private async void ReceiveAsync() + { + if (stream == null) + { + return; + } + while (isRunning) + { + int length = await stream.ReadAsync(receiveBuffer, 0, RECEIVE_BUFFER_SIZE); + if (!isRunning) + break; + if (onReceiveData != null) + { + onReceiveData(receiveBuffer, length); + } + } + } + + public async void SendData(byte[] data, int offset, int length) + { + try + { + await stream.WriteAsync(data, offset, length); + } + catch (Exception e) + { + LogNet.LogError(e.Message); + } + } + + } + + public class UdpConncetion + { + public bool isConnected { get; set; } + + public Action<byte[]> onReceiveData; + + private UdpClient m_Connection; + + public void Conncet(NetClientSetting setting) + { + IPEndPoint localEP = new IPEndPoint(setting.udpLocalIp, setting.udpLocalPort); + m_Connection = new UdpClient(localEP); + m_Connection.Connect(new IPEndPoint(setting.remoteUdpIP, setting.remoteUdpPort)); // 仅连接到目标服务器 + ReceiveAsync(); + isConnected = true; + } + + private async void ReceiveAsync() + { + while (true) + { + UdpReceiveResult result = await m_Connection.ReceiveAsync(); + byte[] buffer = result.Buffer; + if(onReceiveData != null) + { + onReceiveData(buffer); + } + } + } + + public async void SendData(byte[] data, int offset, int length) + { + try + { + if (m_Connection != null) + { + byte[] buf = data; + if(offset != 0) + { + buf = new byte[length]; + Array.Copy(data, offset, buf, 0, length); + } + await m_Connection.SendAsync(buf, length); + } + } + catch(Exception e) + { + } + } + + public void Disconnect() + { + isConnected = false; + + m_Connection.Close(); + m_Connection = null; + } + + } + + /// <summary> + /// 客户端 + /// </summary> + public class NetClient + { + public enum ESendOption + { + Reliable, + Unreliable, + } + + private TcpConnection m_TcpConnection; + private UdpConncetion m_UdpConnection; + + public async Task<bool> ConnectToServer(NetClientSetting setting) + { + m_TcpConnection = new TcpConnection(); + m_UdpConnection = new UdpConncetion(); + + await m_TcpConnection.Connect(setting); + m_UdpConnection.Conncet(setting); + LogNet.Log("NetClient.ConnectToServer() successful"); + return true; + } + + public void SendData(byte[] data, int offset, int length, ESendOption option = ESendOption.Reliable) + { + if (option == ESendOption.Reliable) + { + m_TcpConnection.SendData(data, offset, length); + } + else + { + m_UdpConnection.SendData(data, offset, length); + } + } + + public void Disconnect() + { + m_TcpConnection.Disconnect(); + m_UdpConnection.Disconnect(); + } + + } +}
\ No newline at end of file diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs.meta new file mode 100644 index 0000000..0fa8b25 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ef3daa745db3ca439226ee4fa82be21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs new file mode 100644 index 0000000..0e9e0f6 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs @@ -0,0 +1,106 @@ +using JetBrains.Annotations; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using UnityEditor; +using UnityEngine; + +namespace MultiplayerToolkit.Backend.Wrap +{ + + public struct NetServerSetting + { + public IPAddress tcpLocalIP; + public int tcpLocalPort; + + public IPAddress udpLocalIP; + public int udpLocalPort; + } + + /// <summary> + /// 服务器 + /// </summary> + public class NetServer + { + private TcpListener m_TcpListener; + private UdpClient m_UdpClient; + + public event Action<TcpClient> onNewTcpClient; + public event Action<UdpReceiveResult> onNewUdpClient; + public event Action<UdpReceiveResult> onUdpReceiveData; + + private bool m_IsRunning; + + public void Start(NetServerSetting setting) + { + m_IsRunning = true; + + // TCP + IPEndPoint ep = new IPEndPoint(setting.tcpLocalIP, setting.tcpLocalPort); + m_TcpListener = new TcpListener(ep); + m_TcpListener.Start(); + LogNet.Log("TcpListener on " + setting.tcpLocalIP.ToString() + ":" + setting.tcpLocalPort); + ListenTcp(); + + // UDP + IPEndPoint localEP = new IPEndPoint(setting.udpLocalIP, setting.udpLocalPort); + m_UdpClient = new UdpClient(localEP); + LogNet.Log("UdpClient on " + setting.udpLocalIP.ToString() + ":" + setting.udpLocalPort); + ListenUdp(); + } + + public void Stop() + { + m_IsRunning = false; + + m_TcpListener.Stop(); + m_UdpClient.Close(); + } + + private async void ListenTcp() + { + LogNet.Log("Start ListenTcp()"); + while(m_IsRunning) + { + TcpClient client = await m_TcpListener.AcceptTcpClientAsync(); + LogNet.Log("Accept TcpClient from" + client.Client.RemoteEndPoint.ToString()); + if (onNewTcpClient != null) + { + onNewTcpClient(client); + } + } + } + + private async void ListenUdp() + { + LogNet.Log("Start ListenUdp()"); + while (m_IsRunning) + { + UdpReceiveResult result = await m_UdpClient.ReceiveAsync(); + if (onNewUdpClient != null) + { + onNewUdpClient(result); + } + if (onUdpReceiveData != null) + { + onUdpReceiveData(result); + } + } + } + + public async void SendUDPData(IPEndPoint remoteEP, byte[] data, int length) + { + try + { + await m_UdpClient.SendAsync(data, length, remoteEP); + } + catch(Exception e) + { + LogNet.LogError(e.Message); + } + } + + } +}
\ No newline at end of file diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs.meta new file mode 100644 index 0000000..74d7add --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Backend/Wrap/NetServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6572ab7a433dacc4bb0037a49b8ea6e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageReader.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageReader.cs index 7ec134b..32b0218 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageReader.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageReader.cs @@ -7,38 +7,63 @@ using System.Text; namespace MultiplayerToolkit { /// <summary> - /// + /// 鍙互澶勭悊宓屽娑堟伅鐨勭粨鏋勶紝鍜孧essageWriter閰嶅 /// </summary> public class MessageReader : IRecyclable { public static readonly ObjectPool<MessageReader> ReaderPool = new ObjectPool<MessageReader>(() => new MessageReader()); - public byte[] Buffer; // 鈭 缂撳啿鍖猴紝浼氳瀛愬崗璁叡浜繖涓紦鍐插尯 - public byte Tag; // 鈭 鍗忚鍚 + public byte[] Buffer; // 缂撳啿鍖猴紝浼氳瀛愭秷鎭叡浜繖涓紦鍐插尯 - public int Length; // 鈭 鍗忚闀垮害锛屽搴旂殑鏄疢essageWriter閲屽啓鍏ョ殑2bytes鍖呴暱搴︼紙涓嶅惈length鍜宼ag) - public int Offset; // 鈭 length鍜宼ag鍚庨潰鐨勪綅缃紙鍦˙uffer涓殑浣嶇疆锛夛紝涓嶆槸娓告爣锛屼笉浼氶殢璇诲彇鍙戠敓鏀瑰彉銆備細褰卞搷readHead鐨勫 + // 娑堟伅闀垮害锛屽畾鍊 + // * 濡傛灉鏄潪鏍规秷鎭紝瀵瑰簲鐨勬槸MessageWriter閲屽啓鍏ョ殑2bytes鍖呴暱搴︼紝鍗充笉鍚玪ength鐨勯暱搴 + // * 濡傛灉鏄牴娑堟伅锛孡ength鏄暣涓湁鏁堟暟鎹湪Buffer涓殑闀垮害锛屽寘鎷琇ength + public int Length; - //鏁版嵁浣嶄簬Buffer涓璒ffset绱㈠紩寮濮婰ength闀垮害锛屽崗璁綅浜嶣uffer涓璒ffset-3寮濮嬬殑Length+3闀垮害 + // 鏈夋晥鏁版嵁鍋忕Щ锛屽畾鍊硷紝娓告爣浼氬湪杩欎釜鍩虹涓婂亸绉 + // * 濡傛灉鏄潪鏍规秷鎭紝Offset鍦↙ength鍚庨潰鐨勪綅缃 + // * 濡傛灉鏄牴娑堟伅锛孫ffset绛変簬0锛岃〃绀烘湁鏁堟暟鎹湪Buffer涓殑鍋忕Щ + public int Offset; public int BytesRemaining => this.Length - this.Position; - private MessageReader Parent; // 淇濆瓨鐖跺崗璁储寮曪紝鍜岀埗鍗忚鍏变韩鐖跺崗璁殑Buffer + public int TotalLength => this.Length + this.Offset; + + private MessageReader Parent; // 淇濆瓨鐖舵秷鎭储寮曪紝鍜岀埗娑堟伅鍏变韩鐖舵秷鎭殑Buffer + + // 鏄惁鏄牴娑堟伅锛屾牴娑堟伅涓嬮潰鍖呭惈澶氫釜瀛愭秷鎭紝瀛愭秷鎭彲浠ュ祵濂楅噸瀛欐秷鎭 + public bool IsRoot + { + get { return Parent == null; } + } + + // 瀛愭秷鎭彲璇 + public bool IsReadable + { + get { return this.Parent != null; } + } public int Position { get { return this._position; } set { - this._position = value; // value鏄 + this._position = value; this.readHead = value + Offset; } } - private int _position; // 鈭 璇诲彇娓告爣锛岀浉瀵逛簬鍗忚鍐呭閮ㄥ垎鐨勫亸绉伙紝浠0寮濮嬶紝瀛愬崗璁篃鏄粠0寮濮嬶紝涓嶆槸鍦˙uffer涓殑绱㈠紩 - private int readHead; // 鈭 璇诲彇娓告爣锛屽崗璁ご閮ㄥ湪Buffer涓殑浣嶇疆锛屽弬鑰僐eadMessage() + private int _position; // 璇诲彇娓告爣锛岀浉瀵逛簬娑堟伅鍐呭閮ㄥ垎鐨勫亸绉伙紝浠0寮濮嬶紝瀛愭秷鎭篃鏄粠0寮濮嬶紝涓嶆槸鍦˙uffer涓殑绱㈠紩 + private int readHead; // 璇诲彇娓告爣锛屾秷鎭ご閮ㄥ湪Buffer涓殑浣嶇疆锛屽弬鑰僐eadMessage() - public static MessageReader GetSized(int minSize) +#region 鍒涘缓 + /// <summary> + /// 鍒涘缓涓涓閲忚嚦灏戜负minSize鐨勭┖缂撳啿鍖 + /// </summary> + /// <param name="minSize"></param> + /// <param name="exactly"></param> + /// <returns></returns> + public static MessageReader GetSized(int minSize, bool exactly = false) { var output = ReaderPool.GetObject(); @@ -48,15 +73,25 @@ namespace MultiplayerToolkit } else { + if(exactly && output.Buffer.Length > minSize) + { + output.Buffer = new byte[minSize]; + } Array.Clear(output.Buffer, 0, output.Buffer.Length); } output.Offset = 0; + output.Length = 0; output.Position = 0; - output.Tag = byte.MaxValue; + output.Parent = null; return output; } + /// <summary> + /// 灏嗙紦鍐插尯灏佽涓烘牴娑堟伅锛屼笉鎷疯礉 + /// </summary> + /// <param name="buffer"></param> + /// <returns></returns> public static MessageReader Get(byte[] buffer) { var output = ReaderPool.GetObject(); @@ -65,53 +100,60 @@ namespace MultiplayerToolkit output.Offset = 0; output.Position = 0; output.Length = buffer.Length; - output.Tag = byte.MaxValue; + output.Parent = null; return output; } /// <summary> - /// 鍒涘缓涓涓柊鐨勭埗message锛屼繚瀛榮ource銆傜敤浜庣紦瀛榤essage锛屽洜涓簊ource鎵鍦ㄧ殑鍘熺埗message鍙兘浼氳閿姣侊紝濡傛灉闇瑕佸欢杩熷鐞嗘秷鎭紝闇瑕佹嫹璐濅竴浠芥柊鐨 + /// 灏嗙紦鍐插尯灏佽涓烘牴娑堟伅锛屾嫹璐 /// </summary> - /// <param name="source"></param> + /// <param name="buffer"></param> /// <returns></returns> - public static MessageReader CopyMessageIntoParent(MessageReader source) + public static MessageReader GetAndCopy(byte[] buffer) { - var output = MessageReader.GetSized(source.Length + 3); //3=2bytes(length) + 1byte(tag) - System.Buffer.BlockCopy(source.Buffer, source.Offset - 3, output.Buffer, 0, source.Length + 3); + var output = ReaderPool.GetObject(); + byte[] _buffer = new byte[buffer.Length]; + Array.Copy(buffer, _buffer, buffer.Length); + output.Buffer = _buffer; output.Offset = 0; output.Position = 0; - output.Length = source.Length + 3; + output.Length = _buffer.Length; + output.Parent = null; return output; } /// <summary> - /// 瀹屽叏澶嶅埗 涓浠 + /// 鍒涘缓涓涓柊鐨勭埗message锛屼繚瀛榮ource銆傜敤浜庣紦瀛榤essage锛屽洜涓簊ource鎵鍦ㄧ殑鍘熺埗message鍙兘浼氳閿姣侊紝濡傛灉闇瑕佸欢杩熷鐞嗘秷鎭紝闇瑕佹嫹璐濅竴浠芥柊鐨 /// </summary> /// <param name="source"></param> /// <returns></returns> - public static MessageReader Get(MessageReader source) + public static MessageReader CopyMessageIntoParent(MessageReader source) { - var output = MessageReader.GetSized(source.Buffer.Length); - System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length); - - output.Offset = source.Offset; + var output = MessageReader.GetSized(source.Length + 2); //2=2bytes(length) + System.Buffer.BlockCopy(source.Buffer, source.Offset - 2, output.Buffer, 0, source.Length + 2); - output._position = source._position; - output.readHead = source.readHead; - - output.Length = source.Length; - output.Tag = source.Tag; + output.Offset = 0; + output.Position = 0; + output.Length = source.Length + 2; + output.Parent = null; return output; } - public static MessageReader Get(byte[] buffer, int offset) +#if UNIT_TEST + /// <summary> + /// 鐢ㄤ簬娴嬭瘯锛屽紩鐢╞uffer鐨勪竴閮ㄥ垎浣滀负child message锛屽悗缁彲浠ョ洿鎺ヨ鍙 + /// </summary> + /// <param name="buffer"></param> + /// <param name="offset"></param> + /// <returns></returns> + public static MessageReader GetChildMessage(byte[] buffer, int offset) { - // Ensure there is at least a header - if (offset + 3 > buffer.Length) return null; + // 纭繚鑷冲皯鏈変竴涓猯ength + if (offset + 2 > buffer.Length) return null; var output = ReaderPool.GetObject(); @@ -120,52 +162,70 @@ namespace MultiplayerToolkit output.Position = 0; output.Length = output.ReadUInt16(); // 璇诲埌鐨勫间负length - output.Tag = output.ReadByte(); - output.Offset += 3; + output.Offset += 2; output.Position = 0; + output.Parent = null; return output; } + public static MessageReader Copy(MessageReader source) + { + var output = MessageReader.GetSized(source.Buffer.Length); + System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length); + + output.Offset = source.Offset; + + output._position = source._position; + output.readHead = source.readHead; + + output.Length = source.Length; + + return output; + } + +#endif + + #endregion + /// <summary> - /// Produces a MessageReader using the parent's buffer. This MessageReader should **NOT** be recycled. + /// 杩斿洖涓涓彲璇诲瓙娑堟伅锛屽紩鐢ㄤ簡鐖剁紦鍐插尯锛**涓嶈鍥炴敹** /// </summary> public MessageReader ReadMessage() { - // Ensure there is at least a header - if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}"); + // 鑷冲皯鏈変竴涓猯ength + if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}"); MessageReader output = new MessageReader(); output.Parent = this; output.Buffer = this.Buffer; - output.Offset = this.readHead; // 涓嬮潰浼氳鍙 + output.Offset = this.readHead; output.Position = 0; - // 璇籰ength鍜宼ag鐨勫煎苟淇濆瓨鍦ㄥ瓧娈甸噷 - output.Length = output.ReadUInt16(); - output.Tag = output.ReadByte(); + output.Length = output.ReadUInt16(); // length - // Offset, readHead榻愭璧帮紝绉诲埌Length鍜孴ag鍚庨潰锛宊position=0 - output.Offset += 3; // 3=length+tag + output.Offset += 2; // 2=length output.Position = 0; - if (this.BytesRemaining < output.Length + 3) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 3} of {this.BytesRemaining}"); + // 鏁版嵁涓嶅叏 + if (this.BytesRemaining < output.Length + 2) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 2} of {this.BytesRemaining}"); - this.Position += output.Length + 3; //璺宠繃鏁翠釜瀛愬崗璁 + this.Position += output.Length + 2; //璺宠繃鏁翠釜瀛愭秷鎭 return output; } +#if UNIT_TEST /// <summary> - /// Produces a MessageReader with a new buffer. This MessageReader should be recycled. + /// 浠呯敤浜庢祴璇曪紝杩斿洖涓涓彲璇诲瓙娑堟伅锛屽苟涓旀嫹璐濇暟鎹紝鍙洖鏀 + /// Offset涓0锛屽紑澶存病鏈塋ength鏁版嵁 /// </summary> public MessageReader ReadMessageAsNewBuffer() { - if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}"); + if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}"); - var len = this.ReadUInt16(); - var tag = this.ReadByte(); + var len = this.ReadUInt16(); // Position += 2 if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}"); @@ -174,19 +234,13 @@ namespace MultiplayerToolkit Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len); output.Length = len; - output.Tag = tag; this.Position += output.Length; return output; } +#endif - public MessageWriter StartWriter() - { - var output = new MessageWriter(this.Buffer); - output.Position = this.readHead; - return output; - } - +#if UNIT_TEST public MessageReader Duplicate() { var output = GetSized(this.Length); @@ -200,60 +254,65 @@ namespace MultiplayerToolkit public void RemoveMessage(MessageReader reader) { - var temp = MessageReader.GetSized(reader.Buffer.Length); + MessageReader temp = null; try { - var headerOffset = reader.Offset - 3; - var endOfMessage = reader.Offset + reader.Length; + var headerOffset = reader.Offset - 2; + var endOfMessage = reader.Offset + reader.Length; // 鏈夋晥閮ㄥ垎鐨勫悗涓涓猙yte var len = reader.Buffer.Length - endOfMessage; + temp = MessageReader.GetSized(len); Array.Copy(reader.Buffer, endOfMessage, temp.Buffer, 0, len); Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset, len); - this.AdjustLength(reader.Offset, reader.Length + 3); + this.AdjustLength(reader.Offset, reader.Length + 2); } finally { - temp.Recycle(); + if(temp != null) + { + temp.Recycle(); + } } } - //public void InsertMessage(MessageReader reader, MessageWriter writer) - //{ - // var temp = MessageReader.GetSized(reader.Buffer.Length); - // try - // { - // var headerOffset = reader.Offset - 3; - // var startOfMessage = reader.Offset; - // var len = reader.Buffer.Length - startOfMessage; - // int writerOffset = 3; - // switch (writer.SendOption) - // { - // case SendOption.Reliable: - // writerOffset = 3; - // break; - // case SendOption.None: - // writerOffset = 1; - // break; - // } - - // //store the original buffer in temp - // Array.Copy(reader.Buffer, headerOffset, temp.Buffer, 0, len); - - // //put the contents of writer in at headerOffset - // Array.Copy(writer.Buffer, writerOffset, this.Buffer, headerOffset, writer.Length - writerOffset); - - // //put the original buffer in after that - // Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset + (writer.Length - writerOffset), len - writer.Length); - - // this.AdjustLength(-1 * reader.Offset, -1 * (writer.Length - writerOffset)); - // } - // finally - // { - // temp.Recycle(); - // } - //} + /// <summary> + /// 鍦╮eader鍓嶉潰鎻掑叆涓鏉℃秷鎭 + /// </summary> + /// <param name="reader">鐖秗eader</param> + /// <param name="writer"></param> + public void InsertMessage(MessageReader reader, MessageWriter writer) + { + var temp = MessageReader.GetSized(reader.Buffer.Length); + try + { + var headerOffset = reader.Offset - 2; + var startOfMessage = reader.Offset; + var len = reader.Buffer.Length - headerOffset; // 鐤戜技鍐欓敊浜,搴旇鏄痟eaderOffset + int writerOffset = 0; + //store the original buffer in temp + Array.Copy(reader.Buffer, headerOffset, temp.Buffer, 0, len); + + //put the contents of writer in at headerOffset + Array.Copy(writer.Buffer, writerOffset, this.Buffer, headerOffset, writer.Length - writerOffset); + + //put the original buffer in after that + Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset + (writer.Length - writerOffset), len - writer.Length); + + this.AdjustLength(-1 * reader.Offset, -1 * (writer.Length - writerOffset)); + } + finally + { + temp.Recycle(); + } + } + + /// <summary> + /// 閫掑綊璋冩暣length鍊 + /// </summary> + /// <param name="offset">瀛愭秷鎭殑Offset鍊</param> + /// <param name="amount">瀛愭秷鎭婚暱搴︼紝鍚玪ength</param> private void AdjustLength(int offset, int amount) { if (this.readHead > offset) @@ -263,7 +322,7 @@ namespace MultiplayerToolkit if (Parent != null) { - var lengthOffset = this.Offset - 3; + var lengthOffset = this.Offset - 2; var curLen = this.Buffer[lengthOffset] | (this.Buffer[lengthOffset + 1] << 8); @@ -271,19 +330,21 @@ namespace MultiplayerToolkit this.Length -= amount; this.Buffer[lengthOffset] = (byte)curLen; - this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8); + this.Buffer[lengthOffset + 1] = (byte)(curLen >> 8); Parent.AdjustLength(offset, amount); } } +#endif + public void Recycle() { this.Parent = null; ReaderPool.PutObject(this); } - #region Read Methods +#region Read Methods public bool ReadBoolean() { byte val = this.FastByte(); @@ -444,7 +505,7 @@ namespace MultiplayerToolkit return output; } - #endregion +#endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte FastByte() diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageWriter.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageWriter.cs index b23ce82..98d2bfc 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageWriter.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Message/MessageWriter.cs @@ -10,48 +10,42 @@ namespace MultiplayerToolkit /// 从AmongUs拿过来,去掉了包头相关代码 /// 结构 /// ------------------------------------- - /// 2bytes (ushort)协议的长度,不包括这2bytes - /// ------------------------------------- - /// 1byte 协议类型,内置协议0、玩家自定义协议1 - /// (1byte) (如果是玩家自定义协议,提供一个mod序号,Steam.UGC.Item的id是ulong 8bytes有点大,换成序号,最多支持255个mod) - /// 2byte (ushort)协议ID + /// 2bytes (ushort)消息的长度,不包括这2bytes + /// (------------------------------------- + /// 1byte 消息类型,内置消息0、玩家自定义消息1 + /// (2byte) (如果是玩家自定义消息,提供一个mod序号,Steam.UGC.Item的id是ulong 8bytes有点大,换成序号,最多支持65535个mod) + /// 2byte (ushort)消息ID 0-65535 /// 内容 - /// ------------------------------------- + /// -------------------------------------) /// </summary> public class MessageWriter : IRecyclable { - public const int BYTE_COUNT_OF_LENGTH = 2; // 长度占2 bytes - public static int BufferSize = 64000; // 单个协议最长支持64000字节,即62.5KB - public static readonly ObjectPool<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => new MessageWriter(BufferSize)); + public const int BYTE_COUNT_OF_LENGTH = 2; + public const int BUFFER_SIZE = 64000; // 单个消息最长支持64000字节,即62.5KB + public static readonly ObjectPool<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => new MessageWriter(BUFFER_SIZE)); public byte[] Buffer; - public int Length; // 有效数据在buffer中的长度,可能包含多个嵌套子协议 - public int Position; // 写入位标 - - // 有两个length,一个是数据在缓冲区里的大小Length,一个是每个协议或者子协议数据部分的字节数 + public int Length; // 有效数据在buffer中的长度,可能包含多个嵌套子消息 + public int Position; // 写入游标 - private Stack<int> messageStarts = new Stack<int>(); // 记录单个协议在buffer中的起始位置,用于嵌套结构 + // 有两个length,一个是数据在缓冲区里的大小Length,一个是每个消息或者子消息数据部分的字节数 - public MessageWriter(byte[] buffer) - { - this.Buffer = buffer; - this.Length = this.Buffer.Length; - } + private Stack<int> messageStarts = new Stack<int>(); - /// +#region 创建 + /// <summary> + /// 创建一个缓冲区最大为指定大小的Message + /// </summary> + /// <param name="bufferSize"></param> public MessageWriter(int bufferSize) { this.Buffer = new byte[bufferSize]; } - public byte[] ToByteArray() - { - byte[] output = new byte[this.Length]; - System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); - return output; - } - - /// <param name="sendOption">The option specifying how the message should be sent.</param> + /// <summary> + /// 从池子中拿一个缓冲区大小为BufferSize的Message + /// </summary> + /// <returns></returns> public static MessageWriter Get() { MessageWriter output = WriterPool.GetObject(); @@ -59,6 +53,14 @@ namespace MultiplayerToolkit return output; } +#endregion + + public byte[] ToByteArray() + { + byte[] output = new byte[this.Length]; + System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); + return output; + } /// <summary> /// 是否有expected长度的内容 @@ -70,7 +72,14 @@ namespace MultiplayerToolkit return this.Length >= expected; } - /// + public bool HasBytesExactly(int exact) + { + return this.Length == exact; + } + + /// <summary> + /// 开始写入消息,并写入2bytes作为长度 + /// </summary> public void StartMessage() { var messageStart = this.Position; @@ -78,9 +87,19 @@ namespace MultiplayerToolkit this.Buffer[messageStart] = 0; // length this.Buffer[messageStart + 1] = 0; // length this.Position += 2; // ushort length + this.Length = this.Position; } - /// +#if UNIT_TEST + public void StartMessage(int dummy) + { + StartMessage(); + } +#endif + + /// <summary> + /// 设置此消息长度,标志着消息结束 + /// </summary> public void EndMessage() { var lastMessageStart = messageStarts.Pop(); @@ -117,18 +136,22 @@ namespace MultiplayerToolkit #region WriteMethods + /// <summary> + /// 写入读取到的消息,通常用于服务器受到消息后的广播和转发。不需要Start\End + /// </summary> + /// <param name="target"></param> public void CopyFrom(MessageReader target) { int offset, length; - if (target.Tag == byte.MaxValue) + if (target.IsRoot) { offset = target.Offset; length = target.Length; } else { - offset = target.Offset - 3; - length = target.Length + 3; + offset = target.Offset - 2; + length = target.Length + 2; } System.Buffer.BlockCopy(target.Buffer, offset, this.Buffer, this.Position, length); diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.meta new file mode 100644 index 0000000..76405f2 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c5ca010388f6b5941b12b092913c6c3c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet/Packet.cs index 96e13ca..20a2167 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet/Packet.cs @@ -1,87 +1,125 @@ -using System; +锘縰sing System; using System.Collections.Generic; +using System.Runtime.InteropServices.WindowsRuntime; using System.Text; +#if UNITY_5_3_OR_NEWER using UnityEngine; +#endif namespace MultiplayerToolkit { + public enum EPacketMode + { + Write = 0, + Read = 1, + } + /// <summary> - /// 从MUCK抄过来的,读写通用的packet,不太好 - /// 网络包,通用结构,无论是TCP\UDP还是Steamn - /// 结构: - /// -------------------------------------------------- - /// 4bytes (包长度,不含这4字节) - /// 1byte (协议类型,内置协议、玩家自定义协议) - /// (4bytes) (如果是玩家自定义协议,提供一个modder唯一编号) - /// 2bytes (协议ID) + /// 璇诲啓閫氱敤鐨勭畝鏄損acket + /// 缃戠粶鍖咃紝閫氱敤缁撴瀯锛屾棤璁烘槸TCP\UDP杩樻槸Steamn + /// 缁撴瀯锛 /// -------------------------------------------------- + /// 2bytes (ushort)鍖呴暱搴︼紝涓嶅惈杩2瀛楄妭锛 + /// (-------------------------------------------------- + /// 1byte 娑堟伅绫诲瀷锛屽唴缃秷鎭佺帺瀹惰嚜瀹氫箟娑堟伅 + /// (2byte) (濡傛灉鏄帺瀹惰嚜瀹氫箟娑堟伅锛屾彁渚涗竴涓猰od搴忓彿锛孲team.UGC.Item鐨刬d鏄痷long 8bytes鏈夌偣澶э紝鎹㈡垚搴忓彿锛屾渶澶氭敮鎸65535涓猰od) + /// 2byte (ushort)娑堟伅ID 0-65535 + /// 鍐呭 + /// --------------------------------------------------) /// </summary> public class Packet : IDisposable { + // 鍐欏叆缂撳啿鍖 private List<byte> writableBuffer; + + // 璇诲彇缂撳啿鍖猴紝鏈夋晥鏁版嵁涓瀹氭槸浠庡ご寮濮 private byte[] readableBuffer; private int readPos; + + private EPacketMode m_Mode; + public EPacketMode mode { get { return m_Mode; } } + private bool disposed; - public Packet() + #region 鍒涘缓 + + public static Packet GetWritablePacket() { - this.writableBuffer = new List<byte>(); - this.readPos = 0; - this.disposed = false; + Packet packet = new Packet(); + packet.m_Mode = EPacketMode.Write; + packet.writableBuffer = new List<byte>(); + packet.readableBuffer = null; + packet.readPos = 0; + return packet; } - /// <summary> - /// 开头写入一个int作为ID - /// </summary> - /// <param name="_id"></param> - public Packet(int _id) + public static Packet GetWritablePacket(Packet readable) { - this.writableBuffer = new List<byte>(); - this.readPos = 0; - this.disposed = false; - this.Write(_id); + if (readable.mode != EPacketMode.Read) + return null; + Packet packet = GetWritablePacket(); + packet.Write(readable.readableBuffer); + return packet; + } + + public static Packet GetReadablePacket(byte[] srcToCopy, int offset = 0, int length = -1) + { + Packet packet = new Packet(); + packet.m_Mode = EPacketMode.Read; + packet.writableBuffer = null; + int len = length; + if (length == -1) + { + len = srcToCopy.Length - offset; + } + packet.readableBuffer = new byte[len]; + Array.Copy(srcToCopy, offset, packet.readableBuffer, 0, len); + packet.readPos = 0; + return packet; } - public Packet(byte[] _data) + public static Packet GetReadablePacket(Packet writable) + { + if (writable.mode != EPacketMode.Write) + return null; + Packet packet = GetReadablePacket(writable.ToArray()); + return packet; + } + + #endregion + + private Packet() { - this.writableBuffer = new List<byte>(); - this.readPos = 0; this.disposed = false; - this.SetBytes(_data); } - /// <summary> - /// 清空内容并重置 - /// </summary> - /// <param name="_data"></param> - public void SetBytes(byte[] _data) + public void Reset(bool bReset = true) { - if (writableBuffer != null) - writableBuffer.Clear(); - readPos = 0; - disposed = false; - this.Write(_data); - this.readableBuffer = this.writableBuffer.ToArray(); + if (!bReset) + { + return; + } + if (mode == EPacketMode.Write) + { + this.writableBuffer.Clear(); + } + else if (mode == EPacketMode.Read) + { + Array.Clear(this.readableBuffer, 0, this.readableBuffer.Length); + readPos = 0; + } } - /// <summary> - /// 从offset开始的length个字节 - /// </summary> - /// <param name="_data"></param> - /// <param name="offset"></param> - /// <param name="length"></param> - public void SetBytes(byte[] _data, int offset, int length) + private static T[] SubArray<T>(T[] data, int index, int length) { - if (writableBuffer != null) - writableBuffer.Clear(); - readPos = 0; - disposed = false; - this.Write(Utils.SubArray(_data, offset, length)); - this.readableBuffer = this.writableBuffer.ToArray(); + T[] result = new T[length]; + Array.Copy(data, index, result, 0, length); + return result; } + #region 鍐欏叆 /// <summary> - /// 开头写入一个int为当前writableBuffer长度 + /// 寮澶村啓鍏ヤ竴涓猧nt涓哄綋鍓峸ritableBuffer闀垮害锛屼笉鍚繖涓暱搴 /// </summary> public void InsertLength() { @@ -89,7 +127,7 @@ namespace MultiplayerToolkit } /// <summary> - /// 开头写入一个int + /// 寮澶村啓鍏ヤ竴涓猧nt /// </summary> /// <param name="_value"></param> public void InsertInt(int _value) @@ -97,34 +135,26 @@ namespace MultiplayerToolkit this.writableBuffer.InsertRange(0, BitConverter.GetBytes(_value)); } + /// <summary> + /// 杩斿洖鍒涘缓鐨勬暟缁勶紝涓嶈棰戠箒璋冪敤 + /// </summary> + /// <returns></returns> public byte[] ToArray() { - this.readableBuffer = this.writableBuffer.ToArray(); - return this.readableBuffer; + if (this.mode != EPacketMode.Write) + return null; + return this.writableBuffer.ToArray(); } - public int Length() + /// <summary> + /// 鍐欏叆浜嗗灏戝唴瀹 + /// </summary> + /// <returns></returns> + public int GetWritableBufferLength() { return this.writableBuffer.Count; } - public int UnreadLength() - { - return this.Length() - this.readPos; - } - - public void Reset(bool _shouldReset = true) - { - if (_shouldReset) - { - this.writableBuffer.Clear(); - this.readableBuffer = null; - this.readPos = 0; - return; - } - this.readPos -= 4; - } - public void Write(byte _value) { this.writableBuffer.Add(_value); @@ -162,10 +192,12 @@ namespace MultiplayerToolkit public void Write(string _value) { - this.Write(_value.Length); + this.Write((int)_value.Length); this.writableBuffer.AddRange(Encoding.ASCII.GetBytes(_value)); } +#if UNITY_5_3_OR_NEWER + public void Write(Vector3 _value) { this.Write(_value.x); @@ -180,106 +212,119 @@ namespace MultiplayerToolkit this.Write(_value.z); this.Write(_value.w); } +#endif + + #endregion + + #region 璇诲彇 + + public void RewindReadPos(int step, bool bRewind = true) + { + if (bRewind) + { + this.readPos -= step; + } + } + + public int GetUnreadLength() + { + return this.readableBuffer.Length - this.readPos; + } public byte ReadByte(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - byte arg_31_0 = this.readableBuffer[this.readPos]; + byte value = this.readableBuffer[this.readPos]; if (_moveReadPos) { this.readPos++; } - return arg_31_0; + return value; } throw new Exception("Could not read value of type 'byte'!"); } public byte[] ReadBytes(int _length, bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - byte[] arg_3B_0 = this.writableBuffer.GetRange(this.readPos, _length).ToArray(); + byte[] value = SubArray(this.readableBuffer, this.readPos, _length); if (_moveReadPos) { this.readPos += _length; } - return arg_3B_0; + return value; } throw new Exception("Could not read value of type 'byte[]'!"); } - public byte[] CloneBytes() - { - return this.writableBuffer.ToArray(); - } - public short ReadShort(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - short arg_35_0 = BitConverter.ToInt16(this.readableBuffer, this.readPos); + short value = BitConverter.ToInt16(this.readableBuffer, this.readPos); if (_moveReadPos) { this.readPos += 2; } - return arg_35_0; + return value; } throw new Exception("Could not read value of type 'short'!"); } public int ReadInt(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - int arg_35_0 = BitConverter.ToInt32(this.readableBuffer, this.readPos); + int value = BitConverter.ToInt32(this.readableBuffer, this.readPos); if (_moveReadPos) { this.readPos += 4; } - return arg_35_0; + return value; } throw new Exception("Could not read value of type 'int'!"); } public long ReadLong(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - long arg_35_0 = BitConverter.ToInt64(this.readableBuffer, this.readPos); + long value = BitConverter.ToInt64(this.readableBuffer, this.readPos); if (_moveReadPos) { this.readPos += 8; } - return arg_35_0; + return value; } throw new Exception("Could not read value of type 'long'!"); } public float ReadFloat(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - float arg_35_0 = BitConverter.ToSingle(this.readableBuffer, this.readPos); + float value = BitConverter.ToSingle(this.readableBuffer, this.readPos); if (_moveReadPos) { this.readPos += 4; } - return arg_35_0; + return value; } throw new Exception("Could not read value of type 'float'!"); } public bool ReadBool(bool _moveReadPos = true) { - if (this.writableBuffer.Count > this.readPos) + if (this.readableBuffer.Length > this.readPos) { - bool arg_35_0 = BitConverter.ToBoolean(this.readableBuffer, this.readPos); + bool value = BitConverter.ToBoolean(this.readableBuffer, this.readPos); if (_moveReadPos) { this.readPos++; } - return arg_35_0; + return value; } throw new Exception("Could not read value of type 'bool'!"); } @@ -304,6 +349,8 @@ namespace MultiplayerToolkit return result; } +#if UNITY_5_3_OR_NEWER + public Vector3 ReadVector3(bool moveReadPos = true) { return new Vector3(this.ReadFloat(moveReadPos), this.ReadFloat(moveReadPos), this.ReadFloat(moveReadPos)); @@ -313,6 +360,9 @@ namespace MultiplayerToolkit { return new Quaternion(this.ReadFloat(moveReadPos), this.ReadFloat(moveReadPos), this.ReadFloat(moveReadPos), this.ReadFloat(moveReadPos)); } +#endif + + #endregion protected virtual void Dispose(bool _disposing) { diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet/Packet.cs.meta index 0201775..ebcc04b 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs.meta +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet/Packet.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0befe5905310f0b47a1f3d71a4673f7d +guid: f4e6d752947a7c940890141fb6af3376 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs index 2472538..31e2b24 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs @@ -25,18 +25,10 @@ public class Test_TcpClient : MonoBehaviour client = new TcpClient(endpoint); client.Connect("127.0.1.1", 42046); NetworkStream stream = client.GetStream(); - //Packet packet = new Packet(); - //packet.Write((int)123); - //packet.Write("hello"); - //stream.Write(packet.ToArray()); - - MessageWriter msg = MessageWriter.Get(); - msg.StartMessage(); - msg.Write("hello"); - msg.EndMessage(); - stream.Write(msg.ToByteArray()); - Debug.Log("connected, " + client.Connected); - + Packet packet = Packet.GetWritablePacket(); + packet.Write((int)123); + packet.Write("hello"); + stream.Write(packet.ToArray()); } } diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs index 1b64e7d..06271e4 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs @@ -49,15 +49,16 @@ public class Test_TcpServer : MonoBehaviour }); NetworkStream stream = client.GetStream(); int readLen = await stream.ReadAsync(buffer, 0, BUFFER_SIZE); - Packet packet = new Packet(); - packet.SetBytes(buffer, 0, readLen); - short value = packet.ReadShort(); - string str = packet.ReadString(); - ExecuteOnMainThread(() => + using (Packet packet = Packet.GetReadablePacket(buffer)) { - Debug.Log(value); - Debug.Log(str); - }); + int value = packet.ReadInt(); + string str = packet.ReadString(); + ExecuteOnMainThread(() => + { + Debug.Log(value); + Debug.Log(str); + }); + } } } @@ -69,8 +70,7 @@ public class Test_TcpServer : MonoBehaviour Debug.Log("client.Client.RemoteEndPoint=" + client.Client.RemoteEndPoint); NetworkStream stream = client.GetStream(); int readLen = stream.Read(buffer, 0, BUFFER_SIZE); - Packet packet = new Packet(); - packet.SetBytes(buffer, 0, readLen); + Packet packet = Packet.GetReadablePacket(buffer); int value = packet.ReadInt(); Debug.Log(value); diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap.meta new file mode 100644 index 0000000..1b7f8fc --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 886dba869769af74bb38f4e6eab46c79 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity new file mode 100644 index 0000000..df5cb8a --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity @@ -0,0 +1,412 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &38166385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 38166388} + - component: {fileID: 38166387} + - component: {fileID: 38166386} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &38166386 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 38166385} + m_Enabled: 1 +--- !u!20 &38166387 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 38166385} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &38166388 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 38166385} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &931638114 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 931638116} + - component: {fileID: 931638115} + - component: {fileID: 931638117} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &931638115 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 931638114} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &931638116 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 931638114} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &931638117 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 931638114} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Version: 1 + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_LightLayerMask: 1 + m_CustomShadowLayers: 0 + m_ShadowLayerMask: 1 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} +--- !u!1 &1532873825 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1532873826} + - component: {fileID: 1532873827} + m_Layer: 0 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1532873826 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532873825} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1532873827 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532873825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ad9f15734581cf488d657a7e33caf8e, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1784813234 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1784813236} + - component: {fileID: 1784813235} + m_Layer: 0 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1784813235 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1784813234} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: df981652b12997b438a69dfd8af28d1a, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1784813236 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1784813234} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity.meta new file mode 100644 index 0000000..b3c243c --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrap.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fcdf9b74ae412b94d93d7261456f35b3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs new file mode 100644 index 0000000..ad796da --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs @@ -0,0 +1,41 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using MultiplayerToolkit; +using MultiplayerToolkit.Backend.Wrap; +using MultiplayerToolkit.Backend; +using System.Net; + +public class TestWrapClient : MonoBehaviour +{ + NetClient client; + + private void Start() + { + + NetClientSetting setting = new NetClientSetting(); + setting.tcpLocalIp = IPAddress.Any; + setting.tcpLocalPort = 22334; + setting.udpLocalIp = IPAddress.Any; + setting.udpLocalPort = 33445; + + setting.remoteTcpIP = IPAddress.Loopback; + setting.remoteTcpPort = 34543; + setting.remoteUdpIP = IPAddress.Loopback; + setting.remoteUdpPort = 34545; + + client = new NetClient(); + TestConnect(setting); + } + + private async void TestConnect(NetClientSetting setting) + { + await client.ConnectToServer(setting); + + Packet packet = Packet.GetWritablePacket(); + packet.Write("hello, world"); + + client.SendData(packet.ToArray(), 0, packet.GetWritableBufferLength(), NetClient.ESendOption.Reliable); + } + +} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs.meta new file mode 100644 index 0000000..30d0e89 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ad9f15734581cf488d657a7e33caf8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs new file mode 100644 index 0000000..7776878 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs @@ -0,0 +1,61 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using MultiplayerToolkit; +using MultiplayerToolkit.Backend.Wrap; +using System.Net; +using System.Net.Sockets; +using Steamworks; + +public class TestWrapServer : MonoBehaviour +{ + + NetServer server; + + void Start() + { + NetServerSetting setting = new NetServerSetting(); + setting.tcpLocalIP = IPAddress.Any; + setting.tcpLocalPort = 34543; + setting.udpLocalIP = IPAddress.Any; + setting.udpLocalPort = 34545; + + server = new NetServer(); + server.onNewTcpClient += OnNewTcpClient; + server.onNewUdpClient += OnNewUdpClient; + server.onUdpReceiveData += OnUdpReceiveData; + + server.Start(setting); + + } + + private void OnNewTcpClient(TcpClient client) + { + TestReceive(client); + + } + + async void TestReceive(TcpClient client) + { + while(true) + { + var buffer = new byte[4096]; + var stream = client.GetStream(); + int len = await stream.ReadAsync(buffer, 0, 4096); + Packet packet = Packet.GetReadablePacket(buffer, 0, len); + string str = packet.ReadString(); + Debug.Log(str); + } + } + + private void OnNewUdpClient(UdpReceiveResult client) + { + + } + + private void OnUdpReceiveData(UdpReceiveResult result) + { + + } + +}
\ No newline at end of file diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs.meta new file mode 100644 index 0000000..99a44e3 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestWrap/TestWrapServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df981652b12997b438a69dfd8af28d1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs new file mode 100644 index 0000000..46f66d9 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MultiplayerToolkit +{ + + public static class LogNet + { + + public static void Log(object msg) + { + Debug.Log("[MultiplayerToolkit] " + msg); + } + public static void LogError(object msg) + { + Debug.LogError("[MultiplayerToolkit] " + msg); + } + + } +}
\ No newline at end of file diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs.meta new file mode 100644 index 0000000..4c2f21d --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Utils/LogNet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e64ecac30513d6443ade61fcb24cf9d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Projects/Packet/Packet/MultiplayerToolkit/Packet.cs b/Projects/Packet/Packet/MultiplayerToolkit/Packet.cs index bce39b0..20a2167 100644 --- a/Projects/Packet/Packet/MultiplayerToolkit/Packet.cs +++ b/Projects/Packet/Packet/MultiplayerToolkit/Packet.cs @@ -1,5 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing System; using System.Collections.Generic; using System.Runtime.InteropServices.WindowsRuntime; using System.Text; |