diff --git a/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs
new file mode 100644
index 00000000..6016bf7e
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 游戏框架链表范围。
+ ///
+ /// 指定链表范围的元素类型。
+ [StructLayout(LayoutKind.Auto)]
+ public struct LinkedListRange : IEnumerable, IEnumerable
+ {
+ private readonly LinkedListNode m_First;
+ private readonly LinkedListNode m_Terminal;
+
+ ///
+ /// 初始化游戏框架链表范围的新实例。
+ ///
+ /// 链表范围的开始结点。
+ /// 链表范围的终结标记结点。
+ public LinkedListRange(LinkedListNode first, LinkedListNode terminal)
+ {
+ if (first == null || terminal == null || first == terminal)
+ {
+ throw new Exception("Range is invalid.");
+ }
+
+ m_First = first;
+ m_Terminal = terminal;
+ }
+
+ ///
+ /// 获取链表范围是否有效。
+ ///
+ public bool IsValid
+ {
+ get
+ {
+ return m_First != null && m_Terminal != null && m_First != m_Terminal;
+ }
+ }
+
+ ///
+ /// 获取链表范围的开始结点。
+ ///
+ public LinkedListNode First
+ {
+ get
+ {
+ return m_First;
+ }
+ }
+
+ ///
+ /// 获取链表范围的终结标记结点。
+ ///
+ public LinkedListNode Terminal
+ {
+ get
+ {
+ return m_Terminal;
+ }
+ }
+
+ ///
+ /// 获取链表范围的结点数量。
+ ///
+ public int Count
+ {
+ get
+ {
+ if (!IsValid)
+ {
+ return 0;
+ }
+
+ int count = 0;
+ for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next)
+ {
+ count++;
+ }
+
+ return count;
+ }
+ }
+
+ ///
+ /// 检查是否包含指定值。
+ ///
+ /// 要检查的值。
+ /// 是否包含指定值。
+ public bool Contains(T value)
+ {
+ for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next)
+ {
+ if (current.Value.Equals(value))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ ///
+ /// 循环访问集合的枚举数。
+ ///
+ [StructLayout(LayoutKind.Auto)]
+ public struct Enumerator : IEnumerator, IEnumerator
+ {
+ private readonly LinkedListRange _mLinkedListRange;
+ private LinkedListNode m_Current;
+ private T m_CurrentValue;
+
+ internal Enumerator(LinkedListRange range)
+ {
+ if (!range.IsValid)
+ {
+ throw new Exception("Range is invalid.");
+ }
+
+ _mLinkedListRange = range;
+ m_Current = _mLinkedListRange.m_First;
+ m_CurrentValue = default(T);
+ }
+
+ ///
+ /// 获取当前结点。
+ ///
+ public T Current
+ {
+ get
+ {
+ return m_CurrentValue;
+ }
+ }
+
+ ///
+ /// 获取当前的枚举数。
+ ///
+ object IEnumerator.Current
+ {
+ get
+ {
+ return m_CurrentValue;
+ }
+ }
+
+ ///
+ /// 清理枚举数。
+ ///
+ public void Dispose()
+ {
+ }
+
+ ///
+ /// 获取下一个结点。
+ ///
+ /// 返回下一个结点。
+ public bool MoveNext()
+ {
+ if (m_Current == null || m_Current == _mLinkedListRange.m_Terminal)
+ {
+ return false;
+ }
+
+ m_CurrentValue = m_Current.Value;
+ m_Current = m_Current.Next;
+ return true;
+ }
+
+ ///
+ /// 重置枚举数。
+ ///
+ void IEnumerator.Reset()
+ {
+ m_Current = _mLinkedListRange.m_First;
+ m_CurrentValue = default(T);
+ }
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs.meta
new file mode 100644
index 00000000..9e81a6f5
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/LinkedListRange.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ae8aa6552d5da4247996a9f313b9cdc7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs
new file mode 100644
index 00000000..0784fb35
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs
@@ -0,0 +1,277 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 游戏框架多值字典类。
+ ///
+ /// 指定多值字典的主键类型。
+ /// 指定多值字典的值类型。
+ public sealed class MultiDictionary : IEnumerable>>, IEnumerable
+ {
+ private readonly LinkedList m_LinkedList;
+ private readonly Dictionary> m_Dictionary;
+
+ ///
+ /// 初始化游戏框架多值字典类的新实例。
+ ///
+ public MultiDictionary()
+ {
+ m_LinkedList = new LinkedList();
+ m_Dictionary = new Dictionary>();
+ }
+
+ ///
+ /// 获取多值字典中实际包含的主键数量。
+ ///
+ public int Count
+ {
+ get
+ {
+ return m_Dictionary.Count;
+ }
+ }
+
+ ///
+ /// 获取多值字典中指定主键的范围。
+ ///
+ /// 指定的主键。
+ /// 指定主键的范围。
+ public LinkedListRange this[TKey key]
+ {
+ get
+ {
+ LinkedListRange range = default(LinkedListRange);
+ m_Dictionary.TryGetValue(key, out range);
+ return range;
+ }
+ }
+
+ ///
+ /// 清理多值字典。
+ ///
+ public void Clear()
+ {
+ m_Dictionary.Clear();
+ m_LinkedList.Clear();
+ }
+
+ ///
+ /// 检查多值字典中是否包含指定主键。
+ ///
+ /// 要检查的主键。
+ /// 多值字典中是否包含指定主键。
+ public bool Contains(TKey key)
+ {
+ return m_Dictionary.ContainsKey(key);
+ }
+
+ ///
+ /// 检查多值字典中是否包含指定值。
+ ///
+ /// 要检查的主键。
+ /// 要检查的值。
+ /// 多值字典中是否包含指定值。
+ public bool Contains(TKey key, TValue value)
+ {
+ LinkedListRange range = default(LinkedListRange);
+ if (m_Dictionary.TryGetValue(key, out range))
+ {
+ return range.Contains(value);
+ }
+
+ return false;
+ }
+
+ ///
+ /// 尝试获取多值字典中指定主键的范围。
+ ///
+ /// 指定的主键。
+ /// 指定主键的范围。
+ /// 是否获取成功。
+ public bool TryGetValue(TKey key, out LinkedListRange range)
+ {
+ return m_Dictionary.TryGetValue(key, out range);
+ }
+
+ ///
+ /// 向指定的主键增加指定的值。
+ ///
+ /// 指定的主键。
+ /// 指定的值。
+ public void Add(TKey key, TValue value)
+ {
+ LinkedListRange range = default(LinkedListRange);
+ if (m_Dictionary.TryGetValue(key, out range))
+ {
+ m_LinkedList.AddBefore(range.Terminal, value);
+ }
+ else
+ {
+ LinkedListNode first = m_LinkedList.AddLast(value);
+ LinkedListNode terminal = m_LinkedList.AddLast(default(TValue));
+ m_Dictionary.Add(key, new LinkedListRange(first, terminal));
+ }
+ }
+
+ ///
+ /// 从指定的主键中移除指定的值。
+ ///
+ /// 指定的主键。
+ /// 指定的值。
+ /// 是否移除成功。
+ public bool Remove(TKey key, TValue value)
+ {
+ LinkedListRange range = default(LinkedListRange);
+ if (m_Dictionary.TryGetValue(key, out range))
+ {
+ for (LinkedListNode current = range.First; current != null && current != range.Terminal; current = current.Next)
+ {
+ if (current.Value.Equals(value))
+ {
+ if (current == range.First)
+ {
+ LinkedListNode next = current.Next;
+ if (next == range.Terminal)
+ {
+ m_LinkedList.Remove(next);
+ m_Dictionary.Remove(key);
+ }
+ else
+ {
+ m_Dictionary[key] = new LinkedListRange(next, range.Terminal);
+ }
+ }
+
+ m_LinkedList.Remove(current);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// 从指定的主键中移除所有的值。
+ ///
+ /// 指定的主键。
+ /// 是否移除成功。
+ public bool RemoveAll(TKey key)
+ {
+ LinkedListRange range = default(LinkedListRange);
+ if (m_Dictionary.TryGetValue(key, out range))
+ {
+ m_Dictionary.Remove(key);
+
+ LinkedListNode current = range.First;
+ while (current != null)
+ {
+ LinkedListNode next = current != range.Terminal ? current.Next : null;
+ m_LinkedList.Remove(current);
+ current = next;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(m_Dictionary);
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ IEnumerator>> IEnumerable>>.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ ///
+ /// 返回循环访问集合的枚举数。
+ ///
+ /// 循环访问集合的枚举数。
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ ///
+ /// 循环访问集合的枚举数。
+ ///
+ [StructLayout(LayoutKind.Auto)]
+ public struct Enumerator : IEnumerator>>, IEnumerator
+ {
+ private Dictionary>.Enumerator m_Enumerator;
+
+ internal Enumerator(Dictionary> dictionary)
+ {
+ if (dictionary == null)
+ {
+ throw new Exception("Dictionary is invalid.");
+ }
+
+ m_Enumerator = dictionary.GetEnumerator();
+ }
+
+ ///
+ /// 获取当前结点。
+ ///
+ public KeyValuePair> Current
+ {
+ get
+ {
+ return m_Enumerator.Current;
+ }
+ }
+
+ ///
+ /// 获取当前的枚举数。
+ ///
+ object IEnumerator.Current
+ {
+ get
+ {
+ return m_Enumerator.Current;
+ }
+ }
+
+ ///
+ /// 清理枚举数。
+ ///
+ public void Dispose()
+ {
+ m_Enumerator.Dispose();
+ }
+
+ ///
+ /// 获取下一个结点。
+ ///
+ /// 返回下一个结点。
+ public bool MoveNext()
+ {
+ return m_Enumerator.MoveNext();
+ }
+
+ ///
+ /// 重置枚举数。
+ ///
+ void IEnumerator.Reset()
+ {
+ ((IEnumerator>>)m_Enumerator).Reset();
+ }
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs.meta
new file mode 100644
index 00000000..fe81dd96
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct/MultiDictionary.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3eff6e3b9f51d4e48a6e454d268538de
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/Event/GameEvent.cs b/Assets/TEngine/Scripts/Runtime/Core/Event/GameEvent.cs
index 995e392a..627479b2 100644
--- a/Assets/TEngine/Scripts/Runtime/Core/Event/GameEvent.cs
+++ b/Assets/TEngine/Scripts/Runtime/Core/Event/GameEvent.cs
@@ -690,5 +690,4 @@ namespace TEngine.Runtime
}
#endregion
}
-
}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork.meta
new file mode 100644
index 00000000..7b259d95
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 69740261aa305b94aa6a2a717d82d8e4
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs
new file mode 100644
index 00000000..fdc3f8fb
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs
@@ -0,0 +1,23 @@
+namespace TEngine.Runtime
+{
+ ///
+ /// 网络地址类型。
+ ///
+ public enum AddressFamily : byte
+ {
+ ///
+ /// 未知。
+ ///
+ Unknown = 0,
+
+ ///
+ /// IP 版本 4。
+ ///
+ IPv4,
+
+ ///
+ /// IP 版本 6。
+ ///
+ IPv6
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs.meta
new file mode 100644
index 00000000..54d65ab7
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/AddressFamily.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6f0c907c7aeb4bd2a19ff78ad8e8b668
+timeCreated: 1661772419
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event.meta
new file mode 100644
index 00000000..73250cfc
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2c4f37bbaa3a4ae45a5aa851ec78c3d0
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs.meta
new file mode 100644
index 00000000..5329bee4
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1b7b82bd3d86d874c978bebc6147b442
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs
new file mode 100644
index 00000000..aed94370
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace TEngine.Runtime
+{
+ public abstract class NetBaseEventArgs : EventArgs, IMemory
+ {
+ ///
+ /// 初始化构造函数
+ ///
+ public NetBaseEventArgs()
+ {
+ }
+
+ ///
+ /// 清理引用。
+ ///
+ public abstract void Clear();
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs.meta
new file mode 100644
index 00000000..5ea01426
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetBaseEventArgs.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dd227169d1cedc64ba3c1454671bca7d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs
new file mode 100644
index 00000000..0f7b5d7f
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs
@@ -0,0 +1,61 @@
+namespace TEngine.Runtime
+{
+ ///
+ /// 网络连接关闭事件。
+ ///
+ public sealed class NetworkClosedEventArgs : GameEventArgs
+ {
+ ///
+ /// 网络连接关闭事件编号。
+ ///
+ public static readonly int EventId = typeof(NetworkClosedEventArgs).GetHashCode();
+
+ ///
+ /// 初始化网络连接关闭事件的新实例。
+ ///
+ public NetworkClosedEventArgs()
+ {
+ NetworkChannel = null;
+ }
+
+ ///
+ /// 获取网络连接关闭事件编号。
+ ///
+ public override int Id
+ {
+ get
+ {
+ return EventId;
+ }
+ }
+
+ ///
+ /// 获取网络频道。
+ ///
+ public INetworkChannel NetworkChannel
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 创建网络连接关闭事件。
+ ///
+ /// 网络频道。
+ /// 创建的网络连接关闭事件。
+ public static NetworkClosedEventArgs Create(INetworkChannel networkChannel)
+ {
+ NetworkClosedEventArgs networkClosedEventArgs = MemoryPool.Acquire();
+ networkClosedEventArgs.NetworkChannel = networkChannel;
+ return networkClosedEventArgs;
+ }
+
+ ///
+ /// 清理网络连接关闭事件。
+ ///
+ public override void Clear()
+ {
+ NetworkChannel = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs.meta
new file mode 100644
index 00000000..d654d3a4
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkClosedEventArgs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6218d5320c6b4a328df908e68d135177
+timeCreated: 1661772187
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs
new file mode 100644
index 00000000..aa764289
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs
@@ -0,0 +1,74 @@
+namespace TEngine.Runtime
+{
+ ///
+ /// 网络连接成功事件。
+ ///
+ public sealed class NetworkConnectedEventArgs : GameEventArgs
+ {
+ ///
+ /// 网络连接成功事件编号。
+ ///
+ public static readonly int EventId = typeof(NetworkConnectedEventArgs).GetHashCode();
+
+ ///
+ /// 初始化网络连接成功事件的新实例。
+ ///
+ public NetworkConnectedEventArgs()
+ {
+ NetworkChannel = null;
+ UserData = null;
+ }
+
+ ///
+ /// 获取网络连接成功事件编号。
+ ///
+ public override int Id
+ {
+ get
+ {
+ return EventId;
+ }
+ }
+
+ ///
+ /// 获取网络频道。
+ ///
+ public INetworkChannel NetworkChannel
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取用户自定义数据。
+ ///
+ public object UserData
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 创建网络连接成功事件。
+ ///
+ /// 网络频道。
+ /// 用户自定义数据。
+ /// 创建的网络连接成功事件。
+ public static NetworkConnectedEventArgs Create(INetworkChannel networkChannel)
+ {
+ NetworkConnectedEventArgs networkConnectedEventArgs = MemoryPool.Acquire();
+ networkConnectedEventArgs.NetworkChannel = networkChannel;
+ networkConnectedEventArgs.UserData = null;
+ return networkConnectedEventArgs;
+ }
+
+ ///
+ /// 清理网络连接成功事件。
+ ///
+ public override void Clear()
+ {
+ NetworkChannel = null;
+ UserData = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs.meta
new file mode 100644
index 00000000..9c4e82a7
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkConnectedEventArgs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 64fffbe4a72442f0b3bbd81f78509b13
+timeCreated: 1661772223
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs
new file mode 100644
index 00000000..b63a9126
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs
@@ -0,0 +1,74 @@
+namespace TEngine.Runtime
+{
+ ///
+ /// 用户自定义网络错误事件。
+ ///
+ public sealed class NetworkCustomErrorEventArgs : GameEventArgs
+ {
+ ///
+ /// 用户自定义网络错误事件编号。
+ ///
+ public static readonly int EventId = typeof(NetworkCustomErrorEventArgs).GetHashCode();
+
+ ///
+ /// 初始化用户自定义网络错误事件的新实例。
+ ///
+ public NetworkCustomErrorEventArgs()
+ {
+ NetworkChannel = null;
+ CustomErrorData = null;
+ }
+
+ ///
+ /// 获取用户自定义网络错误事件编号。
+ ///
+ public override int Id
+ {
+ get
+ {
+ return EventId;
+ }
+ }
+
+ ///
+ /// 获取网络频道。
+ ///
+ public INetworkChannel NetworkChannel
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取用户自定义错误数据。
+ ///
+ public object CustomErrorData
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 创建用户自定义网络错误事件。
+ ///
+ /// 网络频道。
+ /// 用户自定义错误数据。
+ /// 创建的用户自定义网络错误事件。
+ public static NetworkCustomErrorEventArgs Create(INetworkChannel networkChannel, object customErrorData)
+ {
+ NetworkCustomErrorEventArgs networkCustomErrorEventArgs = MemoryPool.Acquire();
+ networkCustomErrorEventArgs.NetworkChannel = networkChannel;
+ networkCustomErrorEventArgs.CustomErrorData = customErrorData;
+ return networkCustomErrorEventArgs;
+ }
+
+ ///
+ /// 清理用户自定义网络错误事件。
+ ///
+ public override void Clear()
+ {
+ NetworkChannel = null;
+ CustomErrorData = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs.meta
new file mode 100644
index 00000000..5a08e28a
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkCustomErrorEventArgs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6947eca0814140a6a7fc564274cdb804
+timeCreated: 1661772258
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs
new file mode 100644
index 00000000..cb3f073e
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs
@@ -0,0 +1,102 @@
+using System.Net.Sockets;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 网络错误事件。
+ ///
+ public sealed class NetworkErrorEventArgs : GameEventArgs
+ {
+ ///
+ /// 网络错误事件编号。
+ ///
+ public static readonly int EventId = typeof(NetworkErrorEventArgs).GetHashCode();
+
+ ///
+ /// 初始化网络错误事件的新实例。
+ ///
+ public NetworkErrorEventArgs()
+ {
+ NetworkChannel = null;
+ ErrorCode = NetworkErrorCode.Unknown;
+ SocketErrorCode = SocketError.Success;
+ ErrorMessage = null;
+ }
+
+ ///
+ /// 获取网络错误事件编号。
+ ///
+ public override int Id
+ {
+ get
+ {
+ return EventId;
+ }
+ }
+
+ ///
+ /// 获取网络频道。
+ ///
+ public INetworkChannel NetworkChannel
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取错误码。
+ ///
+ public NetworkErrorCode ErrorCode
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取 Socket 错误码。
+ ///
+ public SocketError SocketErrorCode
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取错误信息。
+ ///
+ public string ErrorMessage
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 创建网络错误事件。
+ ///
+ /// 网络频道。
+ /// 错误码。
+ /// Socket 错误码。
+ /// 错误信息。
+ /// 创建的网络错误事件。
+ public static NetworkErrorEventArgs Create(INetworkChannel networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
+ {
+ NetworkErrorEventArgs networkErrorEventArgs = MemoryPool.Acquire();
+ networkErrorEventArgs.NetworkChannel = networkChannel;
+ networkErrorEventArgs.ErrorCode = errorCode;
+ networkErrorEventArgs.SocketErrorCode = socketErrorCode;
+ networkErrorEventArgs.ErrorMessage = errorMessage;
+ return networkErrorEventArgs;
+ }
+
+ ///
+ /// 清理网络错误事件。
+ ///
+ public override void Clear()
+ {
+ NetworkChannel = null;
+ ErrorCode = NetworkErrorCode.Unknown;
+ SocketErrorCode = SocketError.Success;
+ ErrorMessage = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs.meta
new file mode 100644
index 00000000..8e0f5fbe
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkErrorEventArgs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7f64b74fa985459b88f908ff182e8672
+timeCreated: 1661772293
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs
new file mode 100644
index 00000000..bf189d6d
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs
@@ -0,0 +1,74 @@
+namespace TEngine.Runtime
+{
+ ///
+ /// 网络心跳包丢失事件。
+ ///
+ public sealed class NetworkMissHeartBeatEventArgs : GameEventArgs
+ {
+ ///
+ /// 网络心跳包丢失事件编号。
+ ///
+ public static readonly int EventId = typeof(NetworkMissHeartBeatEventArgs).GetHashCode();
+
+ ///
+ /// 初始化网络心跳包丢失事件的新实例。
+ ///
+ public NetworkMissHeartBeatEventArgs()
+ {
+ NetworkChannel = null;
+ MissCount = 0;
+ }
+
+ ///
+ /// 获取网络心跳包丢失事件编号。
+ ///
+ public override int Id
+ {
+ get
+ {
+ return EventId;
+ }
+ }
+
+ ///
+ /// 获取网络频道。
+ ///
+ public INetworkChannel NetworkChannel
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 获取心跳包已丢失次数。
+ ///
+ public int MissCount
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// 创建网络心跳包丢失事件。
+ ///
+ /// 网络频道。
+ /// 心跳包已丢失次数。
+ /// 创建的网络心跳包丢失事件。
+ public static NetworkMissHeartBeatEventArgs Create(INetworkChannel networkChannel, int missCount)
+ {
+ NetworkMissHeartBeatEventArgs networkMissHeartBeatEventArgs = MemoryPool.Acquire();
+ networkMissHeartBeatEventArgs.NetworkChannel = networkChannel;
+ networkMissHeartBeatEventArgs.MissCount = missCount;
+ return networkMissHeartBeatEventArgs;
+ }
+
+ ///
+ /// 清理网络心跳包丢失事件。
+ ///
+ public override void Clear()
+ {
+ NetworkChannel = null;
+ MissCount = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs.meta
new file mode 100644
index 00000000..6bf1598c
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventArgs/NetworkMissHeartBeatEventArgs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c2dc35d1fb8047e3b86f4af42124aa06
+timeCreated: 1661772338
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs
new file mode 100644
index 00000000..6dc69906
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 事件管理器。
+ ///
+ internal sealed class EventManager: IEventManager
+ {
+ private readonly EventPool m_EventPool;
+
+ ///
+ /// 初始化事件管理器的新实例。
+ ///
+ public EventManager()
+ {
+ m_EventPool = new EventPool(EventPoolMode.AllowNoHandler | EventPoolMode.AllowMultiHandler);
+ }
+
+ ///
+ /// 获取事件处理函数的数量。
+ ///
+ public int EventHandlerCount
+ {
+ get
+ {
+ return m_EventPool.EventHandlerCount;
+ }
+ }
+
+ ///
+ /// 获取事件数量。
+ ///
+ public int EventCount
+ {
+ get
+ {
+ return m_EventPool.EventCount;
+ }
+ }
+
+ ///
+ /// 事件管理器轮询。
+ ///
+ /// 逻辑流逝时间,以秒为单位。
+ /// 真实流逝时间,以秒为单位。
+ internal void Update(float elapseSeconds, float realElapseSeconds)
+ {
+ m_EventPool.Update(elapseSeconds, realElapseSeconds);
+ }
+
+ ///
+ /// 关闭并清理事件管理器。
+ ///
+ internal void Shutdown()
+ {
+ m_EventPool.Shutdown();
+ }
+
+ ///
+ /// 获取事件处理函数的数量。
+ ///
+ /// 事件类型编号。
+ /// 事件处理函数的数量。
+ public int Count(int id)
+ {
+ return m_EventPool.Count(id);
+ }
+
+ ///
+ /// 检查是否存在事件处理函数。
+ ///
+ /// 事件类型编号。
+ /// 要检查的事件处理函数。
+ /// 是否存在事件处理函数。
+ public bool Check(int id, EventHandler handler)
+ {
+ return m_EventPool.Check(id, handler);
+ }
+
+ ///
+ /// 订阅事件处理函数。
+ ///
+ /// 事件类型编号。
+ /// 要订阅的事件处理函数。
+ public void Subscribe(int id, EventHandler handler)
+ {
+ m_EventPool.Subscribe(id, handler);
+ }
+
+ ///
+ /// 取消订阅事件处理函数。
+ ///
+ /// 事件类型编号。
+ /// 要取消订阅的事件处理函数。
+ public void Unsubscribe(int id, EventHandler handler)
+ {
+ m_EventPool.Unsubscribe(id, handler);
+ }
+
+ ///
+ /// 设置默认事件处理函数。
+ ///
+ /// 要设置的默认事件处理函数。
+ public void SetDefaultHandler(EventHandler handler)
+ {
+ m_EventPool.SetDefaultHandler(handler);
+ }
+
+ ///
+ /// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。
+ ///
+ /// 事件源。
+ /// 事件参数。
+ public void Fire(object sender, GameEventArgs e)
+ {
+ m_EventPool.Fire(sender, e);
+ }
+
+ ///
+ /// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。
+ ///
+ /// 事件源。
+ /// 事件参数。
+ public void FireNow(object sender, GameEventArgs e)
+ {
+ m_EventPool.FireNow(sender, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs.meta
new file mode 100644
index 00000000..a8fa2d15
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventManager.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5caf443f519944048edbf1bea889f6d2
+timeCreated: 1661775799
\ No newline at end of file
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool.meta
new file mode 100644
index 00000000..d5f8af7e
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4b813480944c71f47a87c3facb84bce2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs
new file mode 100644
index 00000000..e174a1b6
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 事件基类。
+ ///
+ public abstract class BaseEventArgs : EventArgs, IMemory
+ {
+ ///
+ /// 构造函数
+ ///
+ public BaseEventArgs()
+ {
+
+ }
+
+ ///
+ /// 获取类型编号。
+ ///
+ public abstract int Id
+ {
+ get;
+ }
+
+ ///
+ /// 清理引用。
+ ///
+ public abstract void Clear();
+ }
+}
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs.meta
new file mode 100644
index 00000000..e3362be3
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/BaseEventArgs.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 996eb2d764ee87b45a2d2aab7b88e148
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs
new file mode 100644
index 00000000..2bfa63a0
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs
@@ -0,0 +1,50 @@
+namespace TEngine.Runtime
+{
+ internal sealed partial class EventPool where T : BaseEventArgs
+ {
+ ///
+ /// 事件结点。
+ ///
+ private sealed class Event : IMemory
+ {
+ private object m_Sender;
+ private T m_EventArgs;
+
+ public Event()
+ {
+ m_Sender = null;
+ m_EventArgs = null;
+ }
+
+ public object Sender
+ {
+ get
+ {
+ return m_Sender;
+ }
+ }
+
+ public T EventArgs
+ {
+ get
+ {
+ return m_EventArgs;
+ }
+ }
+
+ public static Event Create(object sender, T e)
+ {
+ Event eventNode = MemoryPool.Acquire();
+ eventNode.m_Sender = sender;
+ eventNode.m_EventArgs = e;
+ return eventNode;
+ }
+
+ public void Clear()
+ {
+ m_Sender = null;
+ m_EventArgs = null;
+ }
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs.meta b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs.meta
new file mode 100644
index 00000000..7613c093
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.Event.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 342958da5a55f9647a13c573988bdec5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.cs b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.cs
new file mode 100644
index 00000000..a7c20998
--- /dev/null
+++ b/Assets/TEngine/Scripts/Runtime/Core/NetWork/Event/EventPool/EventPool.cs
@@ -0,0 +1,278 @@
+using System;
+using System.Collections.Generic;
+
+namespace TEngine.Runtime
+{
+ ///
+ /// 事件池。
+ ///
+ /// 事件类型。
+ internal sealed partial class EventPool where T : BaseEventArgs
+ {
+ private readonly MultiDictionary> m_EventHandlers;
+ private readonly Queue m_Events;
+ private readonly Dictionary