diff options
author | chai <215380520@qq.com> | 2023-10-12 22:10:06 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2023-10-12 22:10:06 +0800 |
commit | b33272a12c3204931ad3426c600786a4cac3fb58 (patch) | |
tree | e57e3dac9803f8464190c872ec4b8e6939f1adf2 | |
parent | 8d2a2cd5de40e2b94ef5007c32832ed9a063dc40 (diff) |
* messagereader
14 files changed, 987 insertions, 35 deletions
diff --git a/Documents/~$资料.xlsx b/Documents/~$资料.xlsx Binary files differnew file mode 100644 index 0000000..1e0c8b3 --- /dev/null +++ b/Documents/~$资料.xlsx diff --git a/Documents/资料.xlsx b/Documents/资料.xlsx Binary files differindex 0cec306..224fc20 100644 --- a/Documents/资料.xlsx +++ b/Documents/资料.xlsx diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs new file mode 100644 index 0000000..17d3104 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MultiplayerToolkit +{ + /// <summary> + /// Interface for all items that can be returned to an object pool. + /// </summary> + /// <threadsafety static="true" instance="true"/> + public interface IRecyclable + { + /// <summary> + /// Returns this object back to the object pool. + /// </summary> + /// <remarks> + /// <para> + /// Calling this when you are done with the object returns the object back to a pool in order to be reused. + /// This can reduce the amount of work the GC has to do dramatically but it is optional to call this. + /// </para> + /// <para> + /// Calling this indicates to Hazel that this can be reused and thus you should only call this when you are + /// completely finished with the object as the contents can be overwritten at any point after. + /// </para> + /// </remarks> + void Recycle(); + } +} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs.meta new file mode 100644 index 0000000..396ffcd --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/IRecyclable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b07026b6854d9e749ad6375ae957f557 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs new file mode 100644 index 0000000..3bd5db8 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs @@ -0,0 +1,456 @@ +using System; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; + +namespace MultiplayerToolkit +{ + public class MessageReader : IRecyclable + { + public static readonly ObjectPool<MessageReader> ReaderPool = new ObjectPool<MessageReader>(() => new MessageReader()); + + public byte[] Buffer; + public byte Tag; + + public int Length; + + public int BytesRemaining => this.Length - this.Position; + + private MessageReader Parent; + + public int Position + { + get { return this._position; } + set + { + this._position = value; + this.readHead = value ; + } + } + + private int _position; + private int readHead; + + public static MessageReader GetSized(int minSize) + { + var output = ReaderPool.GetObject(); + + if (output.Buffer == null || output.Buffer.Length < minSize) + { + output.Buffer = new byte[minSize]; + } + else + { + Array.Clear(output.Buffer, 0, output.Buffer.Length); + } + + output.Offset = 0; + output.Position = 0; + output.Tag = byte.MaxValue; + return output; + } + + public static MessageReader Get(byte[] buffer) + { + var output = ReaderPool.GetObject(); + + output.Buffer = buffer; + output.Offset = 0; + output.Position = 0; + output.Length = buffer.Length; + output.Tag = byte.MaxValue; + + return output; + } + + public static MessageReader CopyMessageIntoParent(MessageReader source) + { + var output = MessageReader.GetSized(source.Length + 3); + System.Buffer.BlockCopy(source.Buffer, source.Offset - 3, output.Buffer, 0, source.Length + 3); + + output.Offset = 0; + output.Position = 0; + output.Length = source.Length + 3; + + return output; + } + + /// <summary> + /// 复制一份 + /// </summary> + /// <param name="source"></param> + /// <returns></returns> + public static MessageReader Get(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; + output.Tag = source.Tag; + + return output; + } + + public static MessageReader Get(byte[] buffer, int offset) + { + // Ensure there is at least a header + if (offset + 3 > buffer.Length) return null; + + var output = ReaderPool.GetObject(); + + output.Buffer = buffer; + output.Offset = offset; + output.Position = 0; + + output.Length = output.ReadUInt16(); + output.Tag = output.ReadByte(); + + output.Offset += 3; + output.Position = 0; + + return output; + } + + /// <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}"); + + var output = new MessageReader(); + + output.Parent = this; + output.Buffer = this.Buffer; + output.Offset = this.readHead; + output.Position = 0; + + output.Length = output.ReadUInt16(); + output.Tag = output.ReadByte(); + + output.Offset += 3; + 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}"); + + this.Position += output.Length + 3; + return output; + } + + /// <summary> + /// Produces a MessageReader with a new buffer. This MessageReader should be recycled. + /// </summary> + public MessageReader ReadMessageAsNewBuffer() + { + if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}"); + + var len = this.ReadUInt16(); + var tag = this.ReadByte(); + + if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}"); + + var output = MessageReader.GetSized(len); + + Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len); + + output.Length = len; + output.Tag = tag; + + this.Position += output.Length; + return output; + } + + public MessageWriter StartWriter() + { + var output = new MessageWriter(this.Buffer); + output.Position = this.readHead; + return output; + } + + public MessageReader Duplicate() + { + var output = GetSized(this.Length); + Array.Copy(this.Buffer, this.Offset, output.Buffer, 0, this.Length); + output.Length = this.Length; + output.Offset = 0; + output.Position = 0; + + return output; + } + + public void RemoveMessage(MessageReader reader) + { + var temp = MessageReader.GetSized(reader.Buffer.Length); + try + { + var headerOffset = reader.Offset - 3; + var endOfMessage = reader.Offset + reader.Length; + var len = reader.Buffer.Length - endOfMessage; + + 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); + } + finally + { + 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 = 0; + //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(); + } + } + + private void AdjustLength(int offset, int amount) + { + if (this.readHead > offset) + { + this.Position -= amount; + } + + if (Parent != null) + { + var lengthOffset = this.Offset - 3; + var curLen = this.Buffer[lengthOffset] + | (this.Buffer[lengthOffset + 1] << 8); + + curLen -= amount; + this.Length -= amount; + + this.Buffer[lengthOffset] = (byte)curLen; + this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8); + + Parent.AdjustLength(offset, amount); + } + } + + public void Recycle() + { + this.Parent = null; + ReaderPool.PutObject(this); + } + + #region Read Methods + public bool ReadBoolean() + { + byte val = this.FastByte(); + return val != 0; + } + + public sbyte ReadSByte() + { + return (sbyte)this.FastByte(); + } + + public byte ReadByte() + { + return this.FastByte(); + } + + public ushort ReadUInt16() + { + ushort output = + (ushort)(this.FastByte() + | this.FastByte() << 8); + return output; + } + + public short ReadInt16() + { + short output = + (short)(this.FastByte() + | this.FastByte() << 8); + return output; + } + + public uint ReadUInt32() + { + uint output = this.FastByte() + | (uint)this.FastByte() << 8 + | (uint)this.FastByte() << 16 + | (uint)this.FastByte() << 24; + + return output; + } + + public int ReadInt32() + { + int output = this.FastByte() + | this.FastByte() << 8 + | this.FastByte() << 16 + | this.FastByte() << 24; + + return output; + } + + public ulong ReadUInt64() + { + ulong output = (ulong)this.FastByte() + | (ulong)this.FastByte() << 8 + | (ulong)this.FastByte() << 16 + | (ulong)this.FastByte() << 24 + | (ulong)this.FastByte() << 32 + | (ulong)this.FastByte() << 40 + | (ulong)this.FastByte() << 48 + | (ulong)this.FastByte() << 56; + + return output; + } + + public long ReadInt64() + { + long output = (long)this.FastByte() + | (long)this.FastByte() << 8 + | (long)this.FastByte() << 16 + | (long)this.FastByte() << 24 + | (long)this.FastByte() << 32 + | (long)this.FastByte() << 40 + | (long)this.FastByte() << 48 + | (long)this.FastByte() << 56; + + return output; + } + + public unsafe float ReadSingle() + { + float output = 0; + fixed (byte* bufPtr = &this.Buffer[this.readHead]) + { + byte* outPtr = (byte*)&output; + + *outPtr = *bufPtr; + *(outPtr + 1) = *(bufPtr + 1); + *(outPtr + 2) = *(bufPtr + 2); + *(outPtr + 3) = *(bufPtr + 3); + } + + this.Position += 4; + return output; + } + + public string ReadString() + { + int len = this.ReadPackedInt32(); + if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}"); + + string output = UTF8Encoding.UTF8.GetString(this.Buffer, this.readHead, len); + + this.Position += len; + return output; + } + + public byte[] ReadBytesAndSize() + { + int len = this.ReadPackedInt32(); + if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}"); + + return this.ReadBytes(len); + } + + public byte[] ReadBytes(int length) + { + if (this.BytesRemaining < length) throw new InvalidDataException($"Read length is longer than message length: {length} of {this.BytesRemaining}"); + + byte[] output = new byte[length]; + Array.Copy(this.Buffer, this.readHead, output, 0, output.Length); + this.Position += output.Length; + return output; + } + + /// + public int ReadPackedInt32() + { + return (int)this.ReadPackedUInt32(); + } + + /// + public uint ReadPackedUInt32() + { + bool readMore = true; + int shift = 0; + uint output = 0; + + while (readMore) + { + if (this.BytesRemaining < 1) throw new InvalidDataException($"Read length is longer than message length."); + + byte b = this.ReadByte(); + if (b >= 0x80) + { + readMore = true; + b ^= 0x80; + } + else + { + readMore = false; + } + + output |= (uint)(b << shift); + shift += 7; + } + + return output; + } + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte FastByte() + { + this._position++; + return this.Buffer[this.readHead++]; + } + + public unsafe static bool IsLittleEndian() + { + byte b; + unsafe + { + int i = 1; + byte* bp = (byte*)&i; + b = *bp; + } + + return b == 1; + } + } +} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs.meta new file mode 100644 index 0000000..2f470c6 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35714cf36eee0fc458f427f0a6cea532 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs new file mode 100644 index 0000000..226a2d4 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace MultiplayerToolkit +{ + + /// <summary> + /// AmongUsùȥ˰ͷش + /// ṹ + /// ------------------------------------- + /// 2bytes(ushort) Эij + /// Э + /// ------------------------------------- + /// </summary> + public class MessageWriter : IRecyclable + { + public static int BufferSize = 64000; + public static readonly ObjectPool<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => new MessageWriter(BufferSize)); + + public byte[] Buffer; + public int Length; // Эܳ + public int Position; // дλ + + private Stack<int> messageStarts = new Stack<int>(); // ¼ЭbufferеʼλãǶṹ + + public MessageWriter(byte[] buffer) + { + this.Buffer = buffer; + this.Length = this.Buffer.Length; + } + + /// + 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> + public static MessageWriter Get() + { + MessageWriter output = WriterPool.GetObject(); + output.Clear(); + + return output; + } + + public bool HasBytes(int expected) + { + return this.Length >= 3 + expected; + } + + /// + public void StartMessage(/*byte typeFlag*/) + { + var messageStart = this.Position; + messageStarts.Push(messageStart); + this.Buffer[messageStart] = 0; // length + this.Buffer[messageStart + 1] = 0; // length + this.Position += 2; // ushort length + //this.Write(typeFlag); + } + + /// + public void EndMessage() + { + var lastMessageStart = messageStarts.Pop(); + ushort length = (ushort)(this.Position - lastMessageStart - /*3*/2); // Minus length and type byte + this.Buffer[lastMessageStart] = (byte)length; + this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); + } + + /// <summary> + /// ȡǰ༭messageصһ + /// </summary> + public void CancelMessage() + { + this.Position = this.messageStarts.Pop(); + this.Length = this.Position; + } + + public void Clear() + { + Array.Clear(this.Buffer, 0, this.Buffer.Length); + this.messageStarts.Clear(); + this.Length = 0; + this.Position = 0; + } + + /// <summary> + /// message + /// </summary> + public void Recycle() + { + this.Position = this.Length = 0; + WriterPool.PutObject(this); + } + +#region WriteMethods + + public void CopyFrom(MessageReader target) + { + int offset, length; + if (target.Tag == byte.MaxValue) + { + offset = target.Offset; + length = target.Length; + } + else + { + offset = target.Offset - 3; + length = target.Length + 3; + } + + System.Buffer.BlockCopy(target.Buffer, offset, this.Buffer, this.Position, length); + this.Position += length; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(bool value) + { + this.Buffer[this.Position++] = (byte)(value ? 1 : 0); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(sbyte value) + { + this.Buffer[this.Position++] = (byte)value; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(byte value) + { + this.Buffer[this.Position++] = value; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(short value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(ushort value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(uint value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + this.Buffer[this.Position++] = (byte)(value >> 16); + this.Buffer[this.Position++] = (byte)(value >> 24); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(int value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + this.Buffer[this.Position++] = (byte)(value >> 16); + this.Buffer[this.Position++] = (byte)(value >> 24); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(ulong value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + this.Buffer[this.Position++] = (byte)(value >> 16); + this.Buffer[this.Position++] = (byte)(value >> 24); + this.Buffer[this.Position++] = (byte)(value >> 32); + this.Buffer[this.Position++] = (byte)(value >> 40); + this.Buffer[this.Position++] = (byte)(value >> 48); + this.Buffer[this.Position++] = (byte)(value >> 56); + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(long value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + this.Buffer[this.Position++] = (byte)(value >> 16); + this.Buffer[this.Position++] = (byte)(value >> 24); + this.Buffer[this.Position++] = (byte)(value >> 32); + this.Buffer[this.Position++] = (byte)(value >> 40); + this.Buffer[this.Position++] = (byte)(value >> 48); + this.Buffer[this.Position++] = (byte)(value >> 56); + if (this.Position > this.Length) this.Length = this.Position; + } + + public unsafe void Write(float value) + { + fixed (byte* ptr = &this.Buffer[this.Position]) + { + byte* valuePtr = (byte*)&value; + + *ptr = *valuePtr; + *(ptr + 1) = *(valuePtr + 1); + *(ptr + 2) = *(valuePtr + 2); + *(ptr + 3) = *(valuePtr + 3); + } + + this.Position += 4; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(string value) + { + var bytes = UTF8Encoding.UTF8.GetBytes(value); + this.WritePacked(bytes.Length); + this.Write(bytes); + } + + public void WriteBytesAndSize(byte[] bytes) + { + this.WritePacked((uint)bytes.Length); + this.Write(bytes); + } + + public void WriteBytesAndSize(byte[] bytes, int length) + { + this.WritePacked((uint)length); + this.Write(bytes, length); + } + + public void WriteBytesAndSize(byte[] bytes, int offset, int length) + { + this.WritePacked((uint)length); + this.Write(bytes, offset, length); + } + + public void Write(byte[] bytes) + { + Array.Copy(bytes, 0, this.Buffer, this.Position, bytes.Length); + this.Position += bytes.Length; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(byte[] bytes, int offset, int length) + { + Array.Copy(bytes, offset, this.Buffer, this.Position, length); + this.Position += length; + if (this.Position > this.Length) this.Length = this.Position; + } + + public void Write(byte[] bytes, int length) + { + Array.Copy(bytes, 0, this.Buffer, this.Position, length); + this.Position += length; + if (this.Position > this.Length) this.Length = this.Position; + } + + /// + public void WritePacked(int value) + { + this.WritePacked((uint)value); + } + + /// + public void WritePacked(uint value) + { + do + { + byte b = (byte)(value & 0xFF); + if (value >= 0x80) + { + b |= 0x80; + } + + this.Write(b); + value >>= 7; + } while (value > 0); + } +#endregion + + public void Write(MessageWriter msg) + { + this.Write(msg.Buffer, 0, msg.Length); + } + + public unsafe static bool IsLittleEndian() + { + byte b; + unsafe + { + int i = 1; + byte* bp = (byte*)&i; + b = *bp; + } + + return b == 1; + } + } +} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs.meta new file mode 100644 index 0000000..ec9023e --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/MessageWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d9ee77993c8eff4ba8b0a9026505b40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs new file mode 100644 index 0000000..e42cdd6 --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace MultiplayerToolkit +{ + /// <summary> + /// A fairly simple object pool for items that will be created a lot. + /// </summary> + /// <typeparam name="T">The type that is pooled.</typeparam> + /// <threadsafety static="true" instance="true"/> + public sealed class ObjectPool<T> where T : IRecyclable + { + private int numberCreated; + public int NumberCreated { get { return numberCreated; } } + + public int NumberInUse { get { return this.inuse.Count; } } + public int NumberNotInUse { get { return this.pool.Count; } } + public int Size { get { return this.NumberInUse + this.NumberNotInUse; } } + +#if HAZEL_BAG + private readonly ConcurrentBag<T> pool = new ConcurrentBag<T>(); +#else + private readonly List<T> pool = new List<T>(); +#endif + + // Unavailable objects + private readonly ConcurrentDictionary<T, bool> inuse = new ConcurrentDictionary<T, bool>(); + + /// <summary> + /// The generator for creating new objects. + /// </summary> + /// <returns></returns> + private readonly Func<T> objectFactory; + + /// <summary> + /// Internal constructor for our ObjectPool. + /// </summary> + internal ObjectPool(Func<T> objectFactory) + { + this.objectFactory = objectFactory; + } + + /// <summary> + /// Returns a pooled object of type T, if none are available another is created. + /// </summary> + /// <returns>An instance of T.</returns> + internal T GetObject() + { +#if HAZEL_BAG + if (!pool.TryTake(out T item)) + { + Interlocked.Increment(ref numberCreated); + item = objectFactory.Invoke(); + } +#else + T item; + lock (this.pool) + { + if (this.pool.Count > 0) + { + var idx = this.pool.Count - 1; + item = this.pool[idx]; + this.pool.RemoveAt(idx); + } + else + { + Interlocked.Increment(ref numberCreated); + item = objectFactory.Invoke(); + } + } +#endif + + if (!inuse.TryAdd(item, true)) + { + throw new Exception("Duplicate pull " + typeof(T).Name); + } + + return item; + } + + /// <summary> + /// Returns an object to the pool. + /// </summary> + /// <param name="item">The item to return.</param> + internal void PutObject(T item) + { + if (inuse.TryRemove(item, out bool b)) + { +#if HAZEL_BAG + pool.Add(item); +#else + lock (this.pool) + { + pool.Add(item); + } +#endif + } + else + { +#if DEBUG + throw new Exception("Duplicate add " + typeof(T).Name); +#endif + } + } + } +} diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs.meta b/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs.meta new file mode 100644 index 0000000..82ce63a --- /dev/null +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/ObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 752d8b9e476be7941a2b3d333d4e0f4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs index 4e73f80..96e13ca 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Packet.cs @@ -6,12 +6,15 @@ using UnityEngine; namespace MultiplayerToolkit { /// <summary> + /// MUCKģдͨõpacket̫ /// ͨýṹTCP\UDPSteamn /// ṹ + /// -------------------------------------------------- /// 4bytes (ȣ4ֽڣ /// 1byte (ЭͣЭ顢ԶЭ飩 /// (4bytes) (ԶЭ飬ṩһmodderΨһţ /// 2bytes (ЭID + /// -------------------------------------------------- /// </summary> public class Packet : IDisposable { @@ -24,6 +27,7 @@ namespace MultiplayerToolkit { this.writableBuffer = new List<byte>(); this.readPos = 0; + this.disposed = false; } /// <summary> @@ -34,6 +38,7 @@ namespace MultiplayerToolkit { this.writableBuffer = new List<byte>(); this.readPos = 0; + this.disposed = false; this.Write(_id); } @@ -41,6 +46,7 @@ namespace MultiplayerToolkit { this.writableBuffer = new List<byte>(); this.readPos = 0; + this.disposed = false; this.SetBytes(_data); } diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs index 21c5329..2472538 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpClient.cs @@ -25,10 +25,16 @@ 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()); + //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); } diff --git a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs index 7abd2ef..7a73b98 100644 --- a/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs +++ b/MultiplayerToolkit/Assets/MultiplayerToolkit/Test/TestTcp/Test_TcpServer.cs @@ -32,9 +32,6 @@ public class Test_TcpServer : MonoBehaviour Debug.Log("Start, Thread=" + Thread.CurrentThread.ManagedThreadId); - Foo2(); - Debug.Log("Foo2"); - Listen(); Debug.Log("listen"); @@ -54,7 +51,7 @@ public class Test_TcpServer : MonoBehaviour int readLen = await stream.ReadAsync(buffer, 0, BUFFER_SIZE); Packet packet = new Packet(); packet.SetBytes(buffer, 0, readLen); - int value = packet.ReadInt(); + short value = packet.ReadShort(); string str = packet.ReadString(); ExecuteOnMainThread(() => { @@ -64,27 +61,6 @@ public class Test_TcpServer : MonoBehaviour } } - async Task<int> Foo2() - { - Debug.Log("Foo2, Thread=" + Thread.CurrentThread.ManagedThreadId); - await Foo(); - - Thread.Sleep(1000); - - await Task.Run(() => { - int threadid = Thread.CurrentThread.ManagedThreadId; - ExecuteOnMainThread(() => { - Debug.Log("Task, Threadid=" + threadid); - }); - for (int i = 0; i < 100; ++i) - { - Debug.Log(i); - } - }); - - return 1; - } - async Task<int> Foo() { return 1; diff --git a/MultiplayerToolkit/ProjectSettings/ProjectSettings.asset b/MultiplayerToolkit/ProjectSettings/ProjectSettings.asset index 7a0d1e1..ad659a4 100644 --- a/MultiplayerToolkit/ProjectSettings/ProjectSettings.asset +++ b/MultiplayerToolkit/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 23 + serializedVersion: 24 productGUID: 9f52a494a2dbecb4caa35f29277eb304 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -121,6 +121,7 @@ PlayerSettings: switchNVNOtherPoolsGranularity: 16777216 switchNVNMaxPublicTextureIDCount: 0 switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 stadiaPresentMode: 0 stadiaTargetFramerate: 0 vulkanNumSwapchainBuffers: 3 @@ -177,10 +178,10 @@ PlayerSettings: StripUnusedMeshComponents: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 11.0 + iOSTargetOSVersionString: 12.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 11.0 + tvOSTargetOSVersionString: 12.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -498,6 +499,7 @@ PlayerSettings: m_Kind: 1 m_SubKind: m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: [] m_BuildTargetGraphicsJobMode: [] m_BuildTargetGraphicsAPIs: @@ -508,6 +510,8 @@ PlayerSettings: m_APIs: 0b00000008000000 m_Automatic: 0 m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 @@ -614,7 +618,6 @@ PlayerSettings: switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 - switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: @@ -656,6 +659,7 @@ PlayerSettings: switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 @@ -668,6 +672,7 @@ PlayerSettings: switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 switchUseNewStyleFilepaths: 0 + switchUseLegacyFmodPriorities: 1 switchUseMicroSleepForYield: 1 switchEnableRamDiskSupport: 0 switchMicroSleepForYieldTime: 25 @@ -767,16 +772,30 @@ PlayerSettings: webGLLinkerTarget: 1 webGLThreadsSupport: 0 webGLDecompressionFallback: 0 + webGLPowerPreference: 2 scriptingDefineSymbols: Standalone: STEAMWORKS_NET additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: {} il2cppCompilerConfiguration: {} - managedStrippingLevel: {} + managedStrippingLevel: + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Lumin: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + Stadia: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 incrementalIl2cppBuild: {} suppressCommonWarnings: 1 - allowUnsafeCode: 0 + allowUnsafeCode: 1 useDeterministicCompilation: 1 enableRoslynAnalyzers: 1 additionalIl2CppArgs: @@ -857,6 +876,7 @@ PlayerSettings: m_VersionName: apiCompatibilityLevel: 6 activeInputHandler: 0 + windowsGamepadBackendHint: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 qualitySettingsNames: [] |