This commit is contained in:
PC-20230316NUNE\Administrator
2024-09-29 20:18:48 +08:00
parent e822544d9c
commit c5700ce655
1797 changed files with 40580 additions and 23804 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6f8f1e0db70b81f47a0f19fa43c4aab5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 432675d70b0a07649b59b082792671e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 940971d20d6d4082860bf85d1846f422
timeCreated: 1708673958

View File

@@ -0,0 +1,453 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SHFrame
{
/// <summary>
/// 游戏框架链表类。
/// </summary>
/// <typeparam name="T">指定链表的元素类型。</typeparam>
public sealed class GameFrameworkLinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
private readonly LinkedList<T> m_LinkedList;
private readonly Queue<LinkedListNode<T>> m_CachedNodes;
/// <summary>
/// 初始化游戏框架链表类的新实例。
/// </summary>
public GameFrameworkLinkedList()
{
m_LinkedList = new LinkedList<T>();
m_CachedNodes = new Queue<LinkedListNode<T>>();
}
/// <summary>
/// 获取链表中实际包含的结点数量。
/// </summary>
public int Count
{
get
{
return m_LinkedList.Count;
}
}
/// <summary>
/// 获取链表结点缓存数量。
/// </summary>
public int CachedNodeCount
{
get
{
return m_CachedNodes.Count;
}
}
/// <summary>
/// 获取链表的第一个结点。
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_LinkedList.First;
}
}
/// <summary>
/// 获取链表的最后一个结点。
/// </summary>
public LinkedListNode<T> Last
{
get
{
return m_LinkedList.Last;
}
}
/// <summary>
/// 获取一个值,该值指示 ICollection`1 是否为只读。
/// </summary>
public bool IsReadOnly
{
get
{
return ((ICollection<T>)m_LinkedList).IsReadOnly;
}
}
/// <summary>
/// 获取可用于同步对 ICollection 的访问的对象。
/// </summary>
public object SyncRoot
{
get
{
return ((ICollection)m_LinkedList).SyncRoot;
}
}
/// <summary>
/// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。
/// </summary>
public bool IsSynchronized
{
get
{
return ((ICollection)m_LinkedList).IsSynchronized;
}
}
/// <summary>
/// 在链表中指定的现有结点后添加包含指定值的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddAfter(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点后添加指定的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="newNode">指定的新结点。</param>
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddAfter(node, newNode);
}
/// <summary>
/// 在链表中指定的现有结点前添加包含指定值的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddBefore(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点前添加指定的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="newNode">指定的新结点。</param>
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddBefore(node, newNode);
}
/// <summary>
/// 在链表的开头处添加包含指定值的新结点。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddFirst(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddFirst(node);
return node;
}
/// <summary>
/// 在链表的开头处添加指定的新结点。
/// </summary>
/// <param name="node">指定的新结点。</param>
public void AddFirst(LinkedListNode<T> node)
{
m_LinkedList.AddFirst(node);
}
/// <summary>
/// 在链表的结尾处添加包含指定值的新结点。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddLast(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddLast(node);
return node;
}
/// <summary>
/// 在链表的结尾处添加指定的新结点。
/// </summary>
/// <param name="node">指定的新结点。</param>
public void AddLast(LinkedListNode<T> node)
{
m_LinkedList.AddLast(node);
}
/// <summary>
/// 从链表中移除所有结点。
/// </summary>
public void Clear()
{
LinkedListNode<T> current = m_LinkedList.First;
while (current != null)
{
ReleaseNode(current);
current = current.Next;
}
m_LinkedList.Clear();
}
/// <summary>
/// 清除链表结点缓存。
/// </summary>
public void ClearCachedNodes()
{
m_CachedNodes.Clear();
}
/// <summary>
/// 确定某值是否在链表中。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>某值是否在链表中。</returns>
public bool Contains(T value)
{
return m_LinkedList.Contains(value);
}
/// <summary>
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。
/// </summary>
/// <param name="array">一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
public void CopyTo(T[] array, int index)
{
m_LinkedList.CopyTo(array, index);
}
/// <summary>
/// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。
/// </summary>
/// <param name="array">一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
public void CopyTo(Array array, int index)
{
((ICollection)m_LinkedList).CopyTo(array, index);
}
/// <summary>
/// 查找包含指定值的第一个结点。
/// </summary>
/// <param name="value">要查找的指定值。</param>
/// <returns>包含指定值的第一个结点。</returns>
public LinkedListNode<T> Find(T value)
{
return m_LinkedList.Find(value);
}
/// <summary>
/// 查找包含指定值的最后一个结点。
/// </summary>
/// <param name="value">要查找的指定值。</param>
/// <returns>包含指定值的最后一个结点。</returns>
public LinkedListNode<T> FindLast(T value)
{
return m_LinkedList.FindLast(value);
}
/// <summary>
/// 从链表中移除指定值的第一个匹配项。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(T value)
{
LinkedListNode<T> node = m_LinkedList.Find(value);
if (node != null)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
return true;
}
return false;
}
/// <summary>
/// 从链表中移除指定的结点。
/// </summary>
/// <param name="node">指定的结点。</param>
public void Remove(LinkedListNode<T> node)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
}
/// <summary>
/// 移除位于链表开头处的结点。
/// </summary>
public void RemoveFirst()
{
LinkedListNode<T> first = m_LinkedList.First;
if (first == null)
{
throw new GameFrameworkException("First is invalid.");
}
m_LinkedList.RemoveFirst();
ReleaseNode(first);
}
/// <summary>
/// 移除位于链表结尾处的结点。
/// </summary>
public void RemoveLast()
{
LinkedListNode<T> last = m_LinkedList.Last;
if (last == null)
{
throw new GameFrameworkException("Last is invalid.");
}
m_LinkedList.RemoveLast();
ReleaseNode(last);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_LinkedList);
}
private LinkedListNode<T> AcquireNode(T value)
{
LinkedListNode<T> node = null;
if (m_CachedNodes.Count > 0)
{
node = m_CachedNodes.Dequeue();
node.Value = value;
}
else
{
node = new LinkedListNode<T>(value);
}
return node;
}
private void ReleaseNode(LinkedListNode<T> node)
{
node.Value = default(T);
m_CachedNodes.Enqueue(node);
}
/// <summary>
/// 将值添加到 ICollection`1 的结尾处。
/// </summary>
/// <param name="value">要添加的值。</param>
void ICollection<T>.Add(T value)
{
AddLast(value);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private LinkedList<T>.Enumerator m_Enumerator;
internal Enumerator(LinkedList<T> linkedList)
{
if (linkedList == null)
{
throw new GameFrameworkException("Linked list is invalid.");
}
m_Enumerator = linkedList.GetEnumerator();
}
/// <summary>
/// 获取当前结点。
/// </summary>
public T Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<T>)m_Enumerator).Reset();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0bf55be1c3044db1a097fe21337a8378
timeCreated: 1708674214

View File

@@ -0,0 +1,217 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SHFrame
{
/// <summary>
/// 游戏框架链表范围。
/// </summary>
/// <typeparam name="T">指定链表范围的元素类型。</typeparam>
[StructLayout(LayoutKind.Auto)]
public struct GameFrameworkLinkedListRange<T> : IEnumerable<T>, IEnumerable
{
private readonly LinkedListNode<T> m_First;
private readonly LinkedListNode<T> m_Terminal;
/// <summary>
/// 初始化游戏框架链表范围的新实例。
/// </summary>
/// <param name="first">链表范围的开始结点。</param>
/// <param name="terminal">链表范围的终结标记结点。</param>
public GameFrameworkLinkedListRange(LinkedListNode<T> first, LinkedListNode<T> terminal)
{
if (first == null || terminal == null || first == terminal)
{
throw new GameFrameworkException("Range is invalid.");
}
m_First = first;
m_Terminal = terminal;
}
/// <summary>
/// 获取链表范围是否有效。
/// </summary>
public bool IsValid
{
get
{
return m_First != null && m_Terminal != null && m_First != m_Terminal;
}
}
/// <summary>
/// 获取链表范围的开始结点。
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_First;
}
}
/// <summary>
/// 获取链表范围的终结标记结点。
/// </summary>
public LinkedListNode<T> Terminal
{
get
{
return m_Terminal;
}
}
/// <summary>
/// 获取链表范围的结点数量。
/// </summary>
public int Count
{
get
{
if (!IsValid)
{
return 0;
}
int count = 0;
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
count++;
}
return count;
}
}
/// <summary>
/// 检查是否包含指定值。
/// </summary>
/// <param name="value">要检查的值。</param>
/// <returns>是否包含指定值。</returns>
public bool Contains(T value)
{
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
return true;
}
}
return false;
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private readonly GameFrameworkLinkedListRange<T> m_GameFrameworkLinkedListRange;
private LinkedListNode<T> m_Current;
private T m_CurrentValue;
internal Enumerator(GameFrameworkLinkedListRange<T> range)
{
if (!range.IsValid)
{
throw new GameFrameworkException("Range is invalid.");
}
m_GameFrameworkLinkedListRange = range;
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}
/// <summary>
/// 获取当前结点。
/// </summary>
public T Current
{
get
{
return m_CurrentValue;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_CurrentValue;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange.m_Terminal)
{
return false;
}
m_CurrentValue = m_Current.Value;
m_Current = m_Current.Next;
return true;
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 37e57e731a2147e1b9850b6e604a8748
timeCreated: 1708674214

View File

@@ -0,0 +1,283 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SHFrame
{
/// <summary>
/// 游戏框架多值字典类。
/// </summary>
/// <typeparam name="TKey">指定多值字典的主键类型。</typeparam>
/// <typeparam name="TValue">指定多值字典的值类型。</typeparam>
public sealed class GameFrameworkMultiDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerable
{
private readonly GameFrameworkLinkedList<TValue> m_LinkedList;
private readonly Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> m_Dictionary;
/// <summary>
/// 初始化游戏框架多值字典类的新实例。
/// </summary>
public GameFrameworkMultiDictionary()
{
m_LinkedList = new GameFrameworkLinkedList<TValue>();
m_Dictionary = new Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>();
}
/// <summary>
/// 获取多值字典中实际包含的主键数量。
/// </summary>
public int Count
{
get
{
return m_Dictionary.Count;
}
}
/// <summary>
/// 获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>指定主键的范围。</returns>
public GameFrameworkLinkedListRange<TValue> this[TKey key]
{
get
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
m_Dictionary.TryGetValue(key, out range);
return range;
}
}
/// <summary>
/// 清理多值字典。
/// </summary>
public void Clear()
{
m_Dictionary.Clear();
m_LinkedList.Clear();
}
/// <summary>
/// 检查多值字典中是否包含指定主键。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <returns>多值字典中是否包含指定主键。</returns>
public bool Contains(TKey key)
{
return m_Dictionary.ContainsKey(key);
}
/// <summary>
/// 检查多值字典中是否包含指定值。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <param name="value">要检查的值。</param>
/// <returns>多值字典中是否包含指定值。</returns>
public bool Contains(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
return range.Contains(value);
}
return false;
}
/// <summary>
/// 尝试获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="range">指定主键的范围。</param>
/// <returns>是否获取成功。</returns>
public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange<TValue> range)
{
return m_Dictionary.TryGetValue(key, out range);
}
/// <summary>
/// 向指定的主键增加指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
public void Add(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
m_LinkedList.AddBefore(range.Terminal, value);
}
else
{
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
}
}
/// <summary>
/// 从指定的主键中移除指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
for (LinkedListNode<TValue> current = range.First; current != null && current != range.Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
if (current == range.First)
{
LinkedListNode<TValue> next = current.Next;
if (next == range.Terminal)
{
m_LinkedList.Remove(next);
m_Dictionary.Remove(key);
}
else
{
m_Dictionary[key] = new GameFrameworkLinkedListRange<TValue>(next, range.Terminal);
}
}
m_LinkedList.Remove(current);
return true;
}
}
}
return false;
}
/// <summary>
/// 从指定的主键中移除所有的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>是否移除成功。</returns>
public bool RemoveAll(TKey key)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
m_Dictionary.Remove(key);
LinkedListNode<TValue> current = range.First;
while (current != null)
{
LinkedListNode<TValue> next = current != range.Terminal ? current.Next : null;
m_LinkedList.Remove(current);
current = next;
}
return true;
}
return false;
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_Dictionary);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>> IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerator
{
private Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>.Enumerator m_Enumerator;
internal Enumerator(Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> dictionary)
{
if (dictionary == null)
{
throw new GameFrameworkException("Dictionary is invalid.");
}
m_Enumerator = dictionary.GetEnumerator();
}
/// <summary>
/// 获取当前结点。
/// </summary>
public KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>> Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>)m_Enumerator).Reset();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 97d9f0c9d701483bbab0e0390d75ab6f
timeCreated: 1708674203

View File

@@ -0,0 +1,129 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
namespace SHFrame
{
/// <summary>
/// 类型和名称的组合值。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct TypeNamePair : IEquatable<TypeNamePair>
{
private readonly Type m_Type;
private readonly string m_Name;
/// <summary>
/// 初始化类型和名称的组合值的新实例。
/// </summary>
/// <param name="type">类型。</param>
public TypeNamePair(Type type)
: this(type, string.Empty)
{
}
/// <summary>
/// 初始化类型和名称的组合值的新实例。
/// </summary>
/// <param name="type">类型。</param>
/// <param name="name">名称。</param>
public TypeNamePair(Type type, string name)
{
if (type == null)
{
throw new GameFrameworkException("Type is invalid.");
}
m_Type = type;
m_Name = name ?? string.Empty;
}
/// <summary>
/// 获取类型。
/// </summary>
public Type Type
{
get { return m_Type; }
}
/// <summary>
/// 获取名称。
/// </summary>
public string Name
{
get { return m_Name; }
}
/// <summary>
/// 获取类型和名称的组合值字符串。
/// </summary>
/// <returns>类型和名称的组合值字符串。</returns>
public override string ToString()
{
if (m_Type == null)
{
throw new GameFrameworkException("Type is invalid.");
}
string typeName = m_Type.FullName;
return string.IsNullOrEmpty(m_Name) ? typeName : Utility.Text.Format("{0}.{1}", typeName, m_Name);
}
/// <summary>
/// 获取对象的哈希值。
/// </summary>
/// <returns>对象的哈希值。</returns>
public override int GetHashCode()
{
return m_Type.GetHashCode() ^ m_Name.GetHashCode();
}
/// <summary>
/// 比较对象是否与自身相等。
/// </summary>
/// <param name="obj">要比较的对象。</param>
/// <returns>被比较的对象是否与自身相等。</returns>
public override bool Equals(object obj)
{
return obj is TypeNamePair && Equals((TypeNamePair)obj);
}
/// <summary>
/// 比较对象是否与自身相等。
/// </summary>
/// <param name="value">要比较的对象。</param>
/// <returns>被比较的对象是否与自身相等。</returns>
public bool Equals(TypeNamePair value)
{
return m_Type == value.m_Type && m_Name == value.m_Name;
}
/// <summary>
/// 判断两个对象是否相等。
/// </summary>
/// <param name="a">值 a。</param>
/// <param name="b">值 b。</param>
/// <returns>两个对象是否相等。</returns>
public static bool operator ==(TypeNamePair a, TypeNamePair b)
{
return a.Equals(b);
}
/// <summary>
/// 判断两个对象是否不相等。
/// </summary>
/// <param name="a">值 a。</param>
/// <param name="b">值 b。</param>
/// <returns>两个对象是否不相等。</returns>
public static bool operator !=(TypeNamePair a, TypeNamePair b)
{
return !(a == b);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6392d2762b514ba59d1c2313dbd7946e
timeCreated: 1708673974

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f25d7db6a1244938b2eef1e38c1e65be
timeCreated: 1709030835

View File

@@ -0,0 +1,25 @@
namespace SHFrame
{
/// <summary> 事件参数
/// <para>ZhangYu 2019-03-05</para>
/// </summary>
public class EventArgs
{
/// <summary> 事件类型 </summary>
public readonly string type;
/// <summary> 事件参数 </summary>
public readonly object[] args;
public EventArgs(string type)
{
this.type = type;
}
public EventArgs(string type, params object[] args)
{
this.type = type;
this.args = args;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8bc2c30ad9668644ba298f980f2eda6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
using System.Collections.Generic;
namespace SHFrame
{
/// <summary>
/// 事件派发器
/// <para>ZhangYu 2019-03-05</para>
/// </summary>
public class EventDispatcher
{
/// <summary> 事件Map </summary>
private Dictionary<string, EventListener> dic = new Dictionary<string, EventListener>();
/// <summary> 添加事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public void AddListener(string eventType, EventListener.EventHandler eventHandler)
{
EventListener invoker;
if (!dic.TryGetValue(eventType, out invoker))
{
invoker = new EventListener();
dic.Add(eventType, invoker);
}
invoker.eventHandler += eventHandler;
}
/// <summary> 移除事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public void RemoveListener(string eventType, EventListener.EventHandler eventHandler)
{
EventListener invoker;
if (dic.TryGetValue(eventType, out invoker)) invoker.eventHandler -= eventHandler;
}
/// <summary> 是否已经拥有该类型的事件 </summary>
/// <param name="eventType">事件类型</param>
public bool HasListener(string eventType)
{
return dic.ContainsKey(eventType);
}
/// <summary> 派发事件 </summary>
/// <param name="eventType">事件类型</param>
public void DispatchEvent(string eventType, params object[] args)
{
EventListener invoker;
if (dic.TryGetValue(eventType, out invoker))
{
EventArgs evt;
if (args == null || args.Length == 0)
{
evt = new EventArgs(eventType);
}
else
{
evt = new EventArgs(eventType, args);
}
invoker.Invoke(evt);
}
}
/// <summary> 清理所有事件监听器 </summary>
public void Clear()
{
foreach (EventListener value in dic.Values)
{
value.Clear();
}
dic.Clear();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1303100c362aa10459237b5ad8617f4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
namespace SHFrame
{
/// <summary>
/// 事件监听器
/// <para>ZhangYu 2019-03-05</para>
/// </summary>
public class EventListener
{
/// <summary> 事件处理器委托 </summary>
public delegate void EventHandler(EventArgs eventArgs);
/// <summary> 事件处理器集合 </summary>
public EventHandler eventHandler;
/// <summary> 调用所有添加的事件 </summary>
public void Invoke(EventArgs eventArgs)
{
if (eventHandler != null) eventHandler.Invoke(eventArgs);
}
/// <summary> 清理所有事件委托 </summary>
public void Clear()
{
eventHandler = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dae197cb1d1228547a2af3254650955a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
namespace SHFrame
{
/// <summary>
/// 事件工具
/// <para>ZhangYu 2019-03-04</para>
/// </summary>
public static class EventUtil
{
/// <summary> 事件派发器 </summary>
private static EventDispatcher dispatcher = new EventDispatcher();
/// <summary> 添加事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public static void AddListener(string eventType, EventListener.EventHandler eventHandler)
{
dispatcher.AddListener(eventType, eventHandler);
}
/// <summary> 移除事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public static void RemoveListener(string eventType, EventListener.EventHandler eventHandler)
{
dispatcher.RemoveListener(eventType, eventHandler);
}
/// <summary> 是否已经拥有该类型的事件 </summary>
/// <param name="eventType">事件类型</param>
public static bool HasListener(string eventType)
{
return dispatcher.HasListener(eventType);
}
/// <summary> 派发事件 </summary>
/// <param name="eventType">事件类型</param>
public static void DispatchEvent(string eventType, params object[] args)
{
dispatcher.DispatchEvent(eventType, args);
}
/// <summary> 清理所有事件监听器 </summary>
public static void Clear()
{
dispatcher.Clear();
}
// public static void DispatchEvent(string updateItemOrCard, object updateExpCard)
// {
// throw new NotImplementedException();
// }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd0630485bf39a24fb4fbf8a933447af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fb832def3641bc0429ba1ed88e6864ef
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using System;
using System.Runtime.Serialization;
namespace SHFrame
{
/// <summary>
/// 游戏框架异常类。
/// </summary>
[Serializable]
public class GameFrameworkException : Exception
{
/// <summary>
/// 初始化游戏框架异常类的新实例。
/// </summary>
public GameFrameworkException()
: base()
{
}
/// <summary>
/// 使用指定错误消息初始化游戏框架异常类的新实例。
/// </summary>
/// <param name="message">描述错误的消息。</param>
public GameFrameworkException(string message)
: base(message)
{
}
/// <summary>
/// 使用指定错误消息和对作为此异常原因的内部异常的引用来初始化游戏框架异常类的新实例。
/// </summary>
/// <param name="message">解释异常原因的错误消息。</param>
/// <param name="innerException">导致当前异常的异常。如果 innerException 参数不为空引用,则在处理内部异常的 catch 块中引发当前异常。</param>
public GameFrameworkException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// 用序列化数据初始化游戏框架异常类的新实例。
/// </summary>
/// <param name="info">存有有关所引发异常的序列化的对象数据。</param>
/// <param name="context">包含有关源或目标的上下文信息。</param>
protected GameFrameworkException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64a0d4c7981db7540b553dafd57d4766
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using SHFrame;
using EventArgs = System.EventArgs;
namespace GameFramework
{
/// <summary>
/// 游戏框架中包含事件数据的类的基类。
/// </summary>
public abstract class GameFrameworkEventArgs : EventArgs, IReference
{
/// <summary>
/// 初始化游戏框架中包含事件数据的类的新实例。
/// </summary>
public GameFrameworkEventArgs()
{
}
/// <summary>
/// 清理引用。
/// </summary>
public abstract void Clear();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c22c08df08643ef8665d53a2ccf977c
timeCreated: 1721617064

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: db204a57722c74d44be1b3abd4ced8a7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
namespace SHFrame
{
public static partial class GameFrameworkLog
{
/// <summary>
/// 游戏框架日志辅助器接口。
/// </summary>
public interface ILogHelper
{
/// <summary>
/// 记录日志。
/// </summary>
/// <param name="level">游戏框架日志等级。</param>
/// <param name="message">日志内容。</param>
void Log(GameFrameworkLogLevel level, object message);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d65b13152a7569458b4da6d6d896d18
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba33a75fffd3342489eb9f65b4dd5374
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
namespace SHFrame
{
/// <summary>
/// 游戏框架日志等级。
/// </summary>
public enum GameFrameworkLogLevel : byte
{
/// <summary>
/// 调试。
/// </summary>
Debug = 0,
/// <summary>
/// 信息。
/// </summary>
Info,
/// <summary>
/// 警告。
/// </summary>
Warning,
/// <summary>
/// 错误。
/// </summary>
Error,
/// <summary>
/// 严重错误。
/// </summary>
Fatal
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd8dd7c832422a746ac6a2f1571fbe61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02f3ffa8fd9ef5547b732e521ddb6343
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4bfe3877976172c40a676de42ea7e0b0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 64aaa103f0a1fbd4a96e026e7fe7b3a0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d7af9750e0bda15429621c4bd7d0bada
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8b3a2a8f55d4a47f599b1fa3ed612389
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using System;
namespace UnityWebSocket
{
/// <summary>
/// Represents the event data for the <see cref="IWebSocket.OnClose"/> event.
/// </summary>
/// <remarks>
/// <para>
/// That event occurs when the WebSocket connection has been closed.
/// </para>
/// <para>
/// If you would like to get the reason for the close, you should access
/// the <see cref="Code"/> or <see cref="Reason"/> property.
/// </para>
/// </remarks>
public class CloseEventArgs : EventArgs
{
#region Internal Constructors
internal CloseEventArgs()
{
}
internal CloseEventArgs(ushort code)
: this(code, null)
{
}
internal CloseEventArgs(CloseStatusCode code)
: this((ushort)code, null)
{
}
internal CloseEventArgs(CloseStatusCode code, string reason)
: this((ushort)code, reason)
{
}
internal CloseEventArgs(ushort code, string reason)
{
Code = code;
Reason = reason;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the status code for the close.
/// </summary>
/// <value>
/// A <see cref="ushort"/> that represents the status code for the close if any.
/// </value>
public ushort Code { get; private set; }
/// <summary>
/// Gets the reason for the close.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the reason for the close if any.
/// </value>
public string Reason { get; private set; }
/// <summary>
/// Gets a value indicating whether the connection has been closed cleanly.
/// </summary>
/// <value>
/// <c>true</c> if the connection has been closed cleanly; otherwise, <c>false</c>.
/// </value>
public bool WasClean { get; internal set; }
/// <summary>
/// Enum value same as Code
/// </summary>
public CloseStatusCode StatusCode
{
get
{
if (Enum.IsDefined(typeof(CloseStatusCode), Code))
return (CloseStatusCode)Code;
return CloseStatusCode.Unknown;
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 29b987d07ba15434cb1744135a7a5416
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
namespace UnityWebSocket
{
/// <summary>
/// Indicates the status code for the WebSocket connection close.
/// </summary>
/// <remarks>
/// <para>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
/// Section 7.4</see> of RFC 6455.
/// </para>
/// <para>
/// "Reserved value" cannot be sent as a status code in
/// closing handshake by an endpoint.
/// </para>
/// </remarks>
public enum CloseStatusCode : ushort
{
Unknown = 65534,
/// <summary>
/// Equivalent to close status 1000. Indicates normal close.
/// </summary>
Normal = 1000,
/// <summary>
/// Equivalent to close status 1001. Indicates that an endpoint is
/// going away.
/// </summary>
Away = 1001,
/// <summary>
/// Equivalent to close status 1002. Indicates that an endpoint is
/// terminating the connection due to a protocol error.
/// </summary>
ProtocolError = 1002,
/// <summary>
/// Equivalent to close status 1003. Indicates that an endpoint is
/// terminating the connection because it has received a type of
/// data that it cannot accept.
/// </summary>
UnsupportedData = 1003,
/// <summary>
/// Equivalent to close status 1004. Still undefined. A Reserved value.
/// </summary>
Undefined = 1004,
/// <summary>
/// Equivalent to close status 1005. Indicates that no status code was
/// actually present. A Reserved value.
/// </summary>
NoStatus = 1005,
/// <summary>
/// Equivalent to close status 1006. Indicates that the connection was
/// closed abnormally. A Reserved value.
/// </summary>
Abnormal = 1006,
/// <summary>
/// Equivalent to close status 1007. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// contains data that is not consistent with the type of the message.
/// </summary>
InvalidData = 1007,
/// <summary>
/// Equivalent to close status 1008. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// violates its policy.
/// </summary>
PolicyViolation = 1008,
/// <summary>
/// Equivalent to close status 1009. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// is too big to process.
/// </summary>
TooBig = 1009,
/// <summary>
/// Equivalent to close status 1010. Indicates that a client is
/// terminating the connection because it has expected the server to
/// negotiate one or more extension, but the server did not return
/// them in the handshake response.
/// </summary>
MandatoryExtension = 1010,
/// <summary>
/// Equivalent to close status 1011. Indicates that a server is
/// terminating the connection because it has encountered an unexpected
/// condition that prevented it from fulfilling the request.
/// </summary>
ServerError = 1011,
/// <summary>
/// Equivalent to close status 1015. Indicates that the connection was
/// closed due to a failure to perform a TLS handshake. A Reserved value.
/// </summary>
TlsHandshakeFailure = 1015,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e34ee317292e4225a10427cc35f85ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using System;
namespace UnityWebSocket
{
/// <summary>
/// Represents the event data for the <see cref="IWebSocket.OnError"/> event.
/// </summary>
/// <remarks>
/// <para>
/// That event occurs when the <see cref="IWebSocket"/> gets an error.
/// </para>
/// <para>
/// If you would like to get the error message, you should access
/// the <see cref="Message"/> property.
/// </para>
/// <para>
/// And if the error is due to an exception, you can get it by accessing
/// the <see cref="Exception"/> property.
/// </para>
/// </remarks>
public class ErrorEventArgs : EventArgs
{
#region Internal Constructors
internal ErrorEventArgs(string message)
: this(message, null)
{
}
internal ErrorEventArgs(string message, Exception exception)
{
this.Message = message;
this.Exception = exception;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the exception that caused the error.
/// </summary>
/// <value>
/// An <see cref="System.Exception"/> instance that represents the cause of
/// the error if it is due to an exception; otherwise, <see langword="null"/>.
/// </value>
public Exception Exception { get; private set; }
/// <summary>
/// Gets the error message.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the error message.
/// </value>
public string Message { get; private set; }
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 884e7db60b6444154b7200e0e436f2de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
namespace UnityWebSocket
{
/// <summary>
/// <para>IWebSocket indicate a network connection.</para>
/// <para>It can be connecting, connected, closing or closed state. </para>
/// <para>You can send and receive messages by using it.</para>
/// <para>Register callbacks for handling messages.</para>
/// <para> ----------------------------------------------------------- </para>
/// <para>IWebSocket 表示一个网络连接,</para>
/// <para>它可以是 connecting connected closing closed 状态,</para>
/// <para>可以发送和接收消息,</para>
/// <para>通过注册消息回调,来处理接收到的消息。</para>
/// </summary>
public interface IWebSocket
{
/// <summary>
/// Establishes a connection asynchronously.
/// </summary>
/// <remarks>
/// <para>
/// This method does not wait for the connect process to be complete.
/// </para>
/// <para>
/// This method does nothing if the connection has already been
/// established.
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">
/// <para>
/// This instance is not a client.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// The close process is in progress.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// A series of reconnecting has failed.
/// </para>
/// </exception>
void ConnectAsync();
/// <summary>
/// Closes the connection asynchronously.
/// </summary>
/// <remarks>
/// <para>
/// This method does not wait for the close to be complete.
/// </para>
/// <para>
/// This method does nothing if the current state of the connection is
/// Closing or Closed.
/// </para>
/// </remarks>
void CloseAsync();
/// <summary>
/// Sends the specified data asynchronously using the WebSocket connection.
/// </summary>
/// <remarks>
/// This method does not wait for the send to be complete.
/// </remarks>
/// <param name="data">
/// An array of <see cref="byte"/> that represents the binary data to send.
/// </param>
/// <exception cref="InvalidOperationException">
/// The current state of the connection is not Open.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="data"/> is <see langword="null"/>.
/// </exception>
void SendAsync(byte[] data);
/// <summary>
/// Sends the specified data using the WebSocket connection.
/// </summary>
/// <param name="text">
/// A <see cref="string"/> that represents the text data to send.
/// </param>
/// <exception cref="InvalidOperationException">
/// The current state of the connection is not Open.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="text"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="text"/> could not be UTF-8 encoded.
/// </exception>
void SendAsync(string text);
/// <summary>
/// get the address which to connect.
/// </summary>
string Address { get; }
/// <summary>
/// get sub protocols .
/// </summary>
string[] SubProtocols { get; }
/// <summary>
/// Gets the current state of the connection.
/// </summary>
/// <value>
/// <para>
/// One of the <see cref="WebSocketState"/> enum values.
/// </para>
/// <para>
/// It indicates the current state of the connection.
/// </para>
/// <para>
/// The default value is <see cref="WebSocketState.Closed"/>.
/// </para>
/// </value>
WebSocketState ReadyState { get; }
/// <summary>
/// Gets the current binaryType of the connection, supported on WEBGL platform only.
/// </summary>
/// <value>
/// <para>
/// It indicates the current binaryType of the connection.
/// </para>
/// <para>
/// The default value is "arraybuffer", options: "blob" or "arraybuffer".
/// </para>
/// </value>
string BinaryType { get; set; }
/// <summary>
/// Occurs when the WebSocket connection has been established.
/// </summary>
event EventHandler<OpenEventArgs> OnOpen;
/// <summary>
/// Occurs when the WebSocket connection has been closed.
/// </summary>
event EventHandler<CloseEventArgs> OnClose;
/// <summary>
/// Occurs when the <see cref="IWebSocket"/> gets an error.
/// </summary>
event EventHandler<ErrorEventArgs> OnError;
/// <summary>
/// Occurs when the <see cref="IWebSocket"/> receives a message.
/// </summary>
event EventHandler<MessageEventArgs> OnMessage;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 37ee2146eb8c34ffab8b081a632b05cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,115 @@
using System;
using System.Text;
namespace UnityWebSocket
{
public class MessageEventArgs : EventArgs
{
private byte[] _rawData;
private string _data;
internal MessageEventArgs(Opcode opcode, byte[] rawData)
{
Opcode = opcode;
_rawData = rawData;
}
internal MessageEventArgs(Opcode opcode, string data)
{
Opcode = opcode;
_data = data;
}
/// <summary>
/// Gets the opcode for the message.
/// </summary>
/// <value>
/// <see cref="Opcode.Text"/>, <see cref="Opcode.Binary"/>.
/// </value>
internal Opcode Opcode { get; private set; }
/// <summary>
/// Gets the message data as a <see cref="string"/>.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the message data if its type is
/// text and if decoding it to a string has successfully done;
/// otherwise, <see langword="null"/>.
/// </value>
public string Data
{
get
{
SetData();
return _data;
}
}
/// <summary>
/// Gets the message data as an array of <see cref="byte"/>.
/// </summary>
/// <value>
/// An array of <see cref="byte"/> that represents the message data.
/// </value>
public byte[] RawData
{
get
{
SetRawData();
return _rawData;
}
}
/// <summary>
/// Gets a value indicating whether the message type is binary.
/// </summary>
/// <value>
/// <c>true</c> if the message type is binary; otherwise, <c>false</c>.
/// </value>
public bool IsBinary
{
get
{
return Opcode == Opcode.Binary;
}
}
/// <summary>
/// Gets a value indicating whether the message type is text.
/// </summary>
/// <value>
/// <c>true</c> if the message type is text; otherwise, <c>false</c>.
/// </value>
public bool IsText
{
get
{
return Opcode == Opcode.Text;
}
}
private void SetData()
{
if (_data != null) return;
if (RawData == null)
{
return;
}
_data = Encoding.UTF8.GetString(RawData);
}
private void SetRawData()
{
if (_rawData != null) return;
if (_data == null)
{
return;
}
_rawData = Encoding.UTF8.GetBytes(_data);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b44eda173b4924081bab76ae9d1b0a9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
namespace UnityWebSocket
{
/// <summary>
/// Indicates the WebSocket frame type.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">
/// Section 5.2</see> of RFC 6455.
/// </remarks>
public enum Opcode : byte
{
/// <summary>
/// Equivalent to numeric value 1. Indicates text frame.
/// </summary>
Text = 0x1,
/// <summary>
/// Equivalent to numeric value 2. Indicates binary frame.
/// </summary>
Binary = 0x2,
/// <summary>
/// Equivalent to numeric value 8. Indicates connection close frame.
/// </summary>
Close = 0x8,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eeac0ef90273544ebbae046672caf362
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using System;
namespace UnityWebSocket
{
public class OpenEventArgs : EventArgs
{
internal OpenEventArgs()
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fb6fd704bd4e4b8ba63cd0b28712955
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
namespace UnityWebSocket
{
public static class Settings
{
public const string GITHUB = "https://github.com/psygames/UnityWebSocket";
public const string QQ_GROUP = "1126457634";
public const string QQ_GROUP_LINK = "https://qm.qq.com/cgi-bin/qm/qr?k=KcexYJ9aYwogFXbj2aN0XHH5b2G7ICmd";
public const string EMAIL = "799329256@qq.com";
public const string AUHTOR = "psygames";
public const string VERSION = "2.7.0";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e268303c7a605e343b1b132e5559f01f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
namespace UnityWebSocket
{
/// <summary>
/// Reference html5 WebSocket ReadyState Properties
/// Indicates the state of a WebSocket connection.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://www.w3.org/TR/websockets/#dom-websocket-readystate">
/// The WebSocket API</see>.
/// </remarks>
public enum WebSocketState : ushort
{
/// <summary>
/// Equivalent to numeric value 0. Indicates that the connection has not
/// yet been established.
/// </summary>
Connecting = 0,
/// <summary>
/// Equivalent to numeric value 1. Indicates that the connection has
/// been established, and the communication is possible.
/// </summary>
Open = 1,
/// <summary>
/// Equivalent to numeric value 2. Indicates that the connection is
/// going through the closing handshake, or the close method has
/// been invoked.
/// </summary>
Closing = 2,
/// <summary>
/// Equivalent to numeric value 3. Indicates that the connection has
/// been closed or could not be established.
/// </summary>
Closed = 3
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f6567ad13cb147a59f8af784f1c5f60
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 396c66b333d624d539153070900bb73b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6c110a898ae8b0b41bcf4da49c2b0425
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,363 @@
#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL)
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace UnityWebSocket
{
public class WebSocket : IWebSocket
{
public string Address { get; private set; }
public string[] SubProtocols { get; private set; }
public WebSocketState ReadyState
{
get
{
if (socket == null)
return WebSocketState.Closed;
switch (socket.State)
{
case System.Net.WebSockets.WebSocketState.Closed:
case System.Net.WebSockets.WebSocketState.None:
return WebSocketState.Closed;
case System.Net.WebSockets.WebSocketState.CloseReceived:
case System.Net.WebSockets.WebSocketState.CloseSent:
return WebSocketState.Closing;
case System.Net.WebSockets.WebSocketState.Connecting:
return WebSocketState.Connecting;
case System.Net.WebSockets.WebSocketState.Open:
return WebSocketState.Open;
}
return WebSocketState.Closed;
}
}
public string BinaryType { get; set; } = "arraybuffer";
public event EventHandler<OpenEventArgs> OnOpen;
public event EventHandler<CloseEventArgs> OnClose;
public event EventHandler<ErrorEventArgs> OnError;
public event EventHandler<MessageEventArgs> OnMessage;
private ClientWebSocket socket;
private bool isOpening => socket != null && socket.State == System.Net.WebSockets.WebSocketState.Open;
#region APIs
public WebSocket(string address)
{
this.Address = address;
}
public WebSocket(string address, string subProtocol)
{
this.Address = address;
this.SubProtocols = new string[] { subProtocol };
}
public WebSocket(string address, string[] subProtocols)
{
this.Address = address;
this.SubProtocols = subProtocols;
}
public void ConnectAsync()
{
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
WebSocketManager.Instance.Add(this);
#endif
if (socket != null)
{
HandleError(new Exception("Socket is busy."));
return;
}
socket = new ClientWebSocket();
if (this.SubProtocols != null)
{
foreach (var protocol in this.SubProtocols)
{
if (string.IsNullOrEmpty(protocol)) continue;
Log($"Add Sub Protocol {protocol}");
socket.Options.AddSubProtocol(protocol);
}
}
Task.Run(ConnectTask);
}
public void CloseAsync()
{
if (!isOpening) return;
SendBufferAsync(new SendBuffer(null, WebSocketMessageType.Close));
}
public void SendAsync(byte[] data)
{
if (!isOpening) return;
var buffer = new SendBuffer(data, WebSocketMessageType.Binary);
SendBufferAsync(buffer);
}
public void SendAsync(string text)
{
if (!isOpening) return;
var data = Encoding.UTF8.GetBytes(text);
var buffer = new SendBuffer(data, WebSocketMessageType.Text);
SendBufferAsync(buffer);
}
#endregion
private async Task ConnectTask()
{
Log("Connect Task Begin ...");
try
{
var uri = new Uri(Address);
await socket.ConnectAsync(uri, CancellationToken.None);
}
catch (Exception e)
{
HandleError(e);
HandleClose((ushort)CloseStatusCode.Abnormal, e.Message);
SocketDispose();
return;
}
HandleOpen();
Log("Connect Task End !");
await ReceiveTask();
}
class SendBuffer
{
public byte[] data;
public WebSocketMessageType type;
public SendBuffer(byte[] data, WebSocketMessageType type)
{
this.data = data;
this.type = type;
}
}
private object sendQueueLock = new object();
private Queue<SendBuffer> sendQueue = new Queue<SendBuffer>();
private bool isSendTaskRunning;
private void SendBufferAsync(SendBuffer buffer)
{
if (isSendTaskRunning)
{
lock (sendQueueLock)
{
if (buffer.type == WebSocketMessageType.Close)
{
sendQueue.Clear();
}
sendQueue.Enqueue(buffer);
}
}
else
{
isSendTaskRunning = true;
sendQueue.Enqueue(buffer);
Task.Run(SendTask);
}
}
private async Task SendTask()
{
Log("Send Task Begin ...");
try
{
SendBuffer buffer = null;
while (sendQueue.Count > 0 && isOpening)
{
lock (sendQueueLock)
{
buffer = sendQueue.Dequeue();
}
if (buffer.type == WebSocketMessageType.Close)
{
Log($"Close Send Begin ...");
await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", CancellationToken.None);
Log($"Close Send End !");
}
else
{
Log($"Send, type: {buffer.type}, size: {buffer.data.Length}, queue left: {sendQueue.Count}");
await socket.SendAsync(new ArraySegment<byte>(buffer.data), buffer.type, true, CancellationToken.None);
}
}
}
catch (Exception e)
{
HandleError(e);
}
finally
{
isSendTaskRunning = false;
}
Log("Send Task End !");
}
private async Task ReceiveTask()
{
Log("Receive Task Begin ...");
string closeReason = "";
ushort closeCode = 0;
bool isClosed = false;
var segment = new ArraySegment<byte>(new byte[8192]);
var ms = new MemoryStream();
try
{
while (!isClosed)
{
var result = await socket.ReceiveAsync(segment, CancellationToken.None);
ms.Write(segment.Array, 0, result.Count);
if (!result.EndOfMessage) continue;
var data = ms.ToArray();
ms.SetLength(0);
switch (result.MessageType)
{
case WebSocketMessageType.Binary:
HandleMessage(Opcode.Binary, data);
break;
case WebSocketMessageType.Text:
HandleMessage(Opcode.Text, data);
break;
case WebSocketMessageType.Close:
isClosed = true;
closeCode = (ushort)result.CloseStatus;
closeReason = result.CloseStatusDescription;
break;
}
}
}
catch (Exception e)
{
HandleError(e);
closeCode = (ushort)CloseStatusCode.Abnormal;
closeReason = e.Message;
}
finally
{
ms.Close();
}
HandleClose(closeCode, closeReason);
SocketDispose();
Log("Receive Task End !");
}
private void SocketDispose()
{
sendQueue.Clear();
socket.Dispose();
socket = null;
}
private void HandleOpen()
{
Log("OnOpen");
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
HandleEventSync(new OpenEventArgs());
#else
OnOpen?.Invoke(this, new OpenEventArgs());
#endif
}
private void HandleMessage(Opcode opcode, byte[] rawData)
{
Log($"OnMessage, type: {opcode}, size: {rawData.Length}\n{BitConverter.ToString(rawData)}");
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
HandleEventSync(new MessageEventArgs(opcode, rawData));
#else
OnMessage?.Invoke(this, new MessageEventArgs(opcode, rawData));
#endif
}
private void HandleClose(ushort code, string reason)
{
Log($"OnClose, code: {code}, reason: {reason}");
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
HandleEventSync(new CloseEventArgs(code, reason));
#else
OnClose?.Invoke(this, new CloseEventArgs(code, reason));
#endif
}
private void HandleError(Exception exception)
{
Log("OnError, error: " + exception.Message);
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
HandleEventSync(new ErrorEventArgs(exception.Message));
#else
OnError?.Invoke(this, new ErrorEventArgs(exception.Message));
#endif
}
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
private readonly Queue<EventArgs> eventQueue = new Queue<EventArgs>();
private readonly object eventQueueLock = new object();
private void HandleEventSync(EventArgs eventArgs)
{
lock (eventQueueLock)
{
eventQueue.Enqueue(eventArgs);
}
}
internal void Update()
{
EventArgs e;
while (eventQueue.Count > 0)
{
lock (eventQueueLock)
{
e = eventQueue.Dequeue();
}
if (e is CloseEventArgs)
{
OnClose?.Invoke(this, e as CloseEventArgs);
WebSocketManager.Instance.Remove(this);
}
else if (e is OpenEventArgs)
{
OnOpen?.Invoke(this, e as OpenEventArgs);
}
else if (e is MessageEventArgs)
{
OnMessage?.Invoke(this, e as MessageEventArgs);
}
else if (e is ErrorEventArgs)
{
OnError?.Invoke(this, e as ErrorEventArgs);
}
}
}
#endif
[System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")]
static void Log(string msg)
{
UnityEngine.Debug.Log($"<color=yellow>[UnityWebSocket]</color>" +
$"<color=green>[T-{Thread.CurrentThread.ManagedThreadId:D3}]</color>" +
$"<color=red>[{DateTime.Now.TimeOfDay}]</color>" +
$" {msg}");
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d10f88a23641b4beb8df74460fb7f705
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL) && !UNITY_WEB_SOCKET_ENABLE_ASYNC
using System.Collections.Generic;
using UnityEngine;
namespace UnityWebSocket
{
[DefaultExecutionOrder(-10000)]
internal class WebSocketManager : MonoBehaviour
{
private const string rootName = "[UnityWebSocket]";
private static WebSocketManager _instance;
public static WebSocketManager Instance
{
get
{
if (!_instance) CreateInstance();
return _instance;
}
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
public static void CreateInstance()
{
GameObject go = GameObject.Find("/" + rootName);
if (!go) go = new GameObject(rootName);
_instance = go.GetComponent<WebSocketManager>();
if (!_instance) _instance = go.AddComponent<WebSocketManager>();
}
private readonly List<WebSocket> sockets = new List<WebSocket>();
public void Add(WebSocket socket)
{
if (!sockets.Contains(socket))
sockets.Add(socket);
}
public void Remove(WebSocket socket)
{
if (sockets.Contains(socket))
sockets.Remove(socket);
}
private void Update()
{
if (sockets.Count <= 0) return;
for (int i = sockets.Count - 1; i >= 0; i--)
{
sockets[i].Update();
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99157fb5def394c83a9e5342036c92b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1fb37927ec1ce4def9c5e7cff883f9f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
#if !UNITY_EDITOR && UNITY_WEBGL
using System;
namespace UnityWebSocket
{
public class WebSocket : IWebSocket
{
public string Address { get; private set; }
public string[] SubProtocols { get; private set; }
public WebSocketState ReadyState { get { return (WebSocketState)WebSocketManager.WebSocketGetState(instanceId); } }
public string BinaryType { get; set; } = "arraybuffer";
public event EventHandler<OpenEventArgs> OnOpen;
public event EventHandler<CloseEventArgs> OnClose;
public event EventHandler<ErrorEventArgs> OnError;
public event EventHandler<MessageEventArgs> OnMessage;
internal int instanceId = 0;
public WebSocket(string address)
{
this.Address = address;
AllocateInstance();
}
public WebSocket(string address, string subProtocol)
{
this.Address = address;
this.SubProtocols = new string[] { subProtocol };
AllocateInstance();
}
public WebSocket(string address, string[] subProtocols)
{
this.Address = address;
this.SubProtocols = subProtocols;
AllocateInstance();
}
internal void AllocateInstance()
{
instanceId = WebSocketManager.AllocateInstance(this.Address, this.BinaryType);
Log($"Allocate socket with instanceId: {instanceId}");
if (this.SubProtocols == null) return;
foreach (var protocol in this.SubProtocols)
{
if (string.IsNullOrEmpty(protocol)) continue;
Log($"Add Sub Protocol {protocol}, with instanceId: {instanceId}");
int code = WebSocketManager.WebSocketAddSubProtocol(instanceId, protocol);
if (code < 0)
{
HandleOnError(GetErrorMessageFromCode(code));
break;
}
}
}
~WebSocket()
{
Log($"Free socket with instanceId: {instanceId}");
WebSocketManager.WebSocketFree(instanceId);
}
public void ConnectAsync()
{
Log($"Connect with instanceId: {instanceId}");
WebSocketManager.Add(this);
int code = WebSocketManager.WebSocketConnect(instanceId);
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
}
public void CloseAsync()
{
Log($"Close with instanceId: {instanceId}");
int code = WebSocketManager.WebSocketClose(instanceId, (int)CloseStatusCode.Normal, "Normal Closure");
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
}
public void SendAsync(string text)
{
Log($"Send, type: {Opcode.Text}, size: {text.Length}");
int code = WebSocketManager.WebSocketSendStr(instanceId, text);
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
}
public void SendAsync(byte[] data)
{
Log($"Send, type: {Opcode.Binary}, size: {data.Length}");
int code = WebSocketManager.WebSocketSend(instanceId, data, data.Length);
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
}
internal void HandleOnOpen()
{
Log("OnOpen");
OnOpen?.Invoke(this, new OpenEventArgs());
}
internal void HandleOnMessage(byte[] rawData)
{
Log($"OnMessage, type: {Opcode.Binary}, size: {rawData.Length}");
OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Binary, rawData));
}
internal void HandleOnMessageStr(string data)
{
Log($"OnMessage, type: {Opcode.Text}, size: {data.Length}");
OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Text, data));
}
internal void HandleOnClose(ushort code, string reason)
{
Log($"OnClose, code: {code}, reason: {reason}");
OnClose?.Invoke(this, new CloseEventArgs(code, reason));
WebSocketManager.Remove(instanceId);
}
internal void HandleOnError(string msg)
{
Log("OnError, error: " + msg);
OnError?.Invoke(this, new ErrorEventArgs(msg));
}
internal static string GetErrorMessageFromCode(int errorCode)
{
switch (errorCode)
{
case -1: return "WebSocket instance not found.";
case -2: return "WebSocket is already connected or in connecting state.";
case -3: return "WebSocket is not connected.";
case -4: return "WebSocket is already closing.";
case -5: return "WebSocket is already closed.";
case -6: return "WebSocket is not in open state.";
case -7: return "Cannot close WebSocket. An invalid code was specified or reason is too long.";
default: return $"Unknown error code {errorCode}.";
}
}
[System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")]
static void Log(string msg)
{
UnityEngine.Debug.Log($"[UnityWebSocket]" +
$"[{DateTime.Now.TimeOfDay}]" +
$" {msg}");
}
}
}
#endif

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 74a5b3c22251243d2a2f33e74741559d
timeCreated: 1466578513
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,153 @@
#if !UNITY_EDITOR && UNITY_WEBGL
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AOT;
namespace UnityWebSocket
{
/// <summary>
/// Class providing static access methods to work with JSLIB WebSocket
/// </summary>
internal static class WebSocketManager
{
/* Map of websocket instances */
private static Dictionary<int, WebSocket> sockets = new Dictionary<int, WebSocket>();
/* Delegates */
public delegate void OnOpenCallback(int instanceId);
public delegate void OnMessageCallback(int instanceId, IntPtr msgPtr, int msgSize);
public delegate void OnMessageStrCallback(int instanceId, IntPtr msgStrPtr);
public delegate void OnErrorCallback(int instanceId, IntPtr errorPtr);
public delegate void OnCloseCallback(int instanceId, int closeCode, IntPtr reasonPtr);
/* WebSocket JSLIB functions */
[DllImport("__Internal")]
public static extern int WebSocketConnect(int instanceId);
[DllImport("__Internal")]
public static extern int WebSocketClose(int instanceId, int code, string reason);
[DllImport("__Internal")]
public static extern int WebSocketSend(int instanceId, byte[] dataPtr, int dataLength);
[DllImport("__Internal")]
public static extern int WebSocketSendStr(int instanceId, string data);
[DllImport("__Internal")]
public static extern int WebSocketGetState(int instanceId);
/* WebSocket JSLIB callback setters and other functions */
[DllImport("__Internal")]
public static extern int WebSocketAllocate(string url, string binaryType);
[DllImport("__Internal")]
public static extern int WebSocketAddSubProtocol(int instanceId, string protocol);
[DllImport("__Internal")]
public static extern void WebSocketFree(int instanceId);
[DllImport("__Internal")]
public static extern void WebSocketSetOnOpen(OnOpenCallback callback);
[DllImport("__Internal")]
public static extern void WebSocketSetOnMessage(OnMessageCallback callback);
[DllImport("__Internal")]
public static extern void WebSocketSetOnMessageStr(OnMessageStrCallback callback);
[DllImport("__Internal")]
public static extern void WebSocketSetOnError(OnErrorCallback callback);
[DllImport("__Internal")]
public static extern void WebSocketSetOnClose(OnCloseCallback callback);
/* If callbacks was initialized and set */
private static bool isInitialized = false;
/* Initialize WebSocket callbacks to JSLIB */
private static void Initialize()
{
WebSocketSetOnOpen(DelegateOnOpenEvent);
WebSocketSetOnMessage(DelegateOnMessageEvent);
WebSocketSetOnMessageStr(DelegateOnMessageStrEvent);
WebSocketSetOnError(DelegateOnErrorEvent);
WebSocketSetOnClose(DelegateOnCloseEvent);
isInitialized = true;
}
[MonoPInvokeCallback(typeof(OnOpenCallback))]
public static void DelegateOnOpenEvent(int instanceId)
{
if (sockets.TryGetValue(instanceId, out var socket))
{
socket.HandleOnOpen();
}
}
[MonoPInvokeCallback(typeof(OnMessageCallback))]
public static void DelegateOnMessageEvent(int instanceId, IntPtr msgPtr, int msgSize)
{
if (sockets.TryGetValue(instanceId, out var socket))
{
var bytes = new byte[msgSize];
Marshal.Copy(msgPtr, bytes, 0, msgSize);
socket.HandleOnMessage(bytes);
}
}
[MonoPInvokeCallback(typeof(OnMessageCallback))]
public static void DelegateOnMessageStrEvent(int instanceId, IntPtr msgStrPtr)
{
if (sockets.TryGetValue(instanceId, out var socket))
{
string msgStr = Marshal.PtrToStringAuto(msgStrPtr);
socket.HandleOnMessageStr(msgStr);
}
}
[MonoPInvokeCallback(typeof(OnErrorCallback))]
public static void DelegateOnErrorEvent(int instanceId, IntPtr errorPtr)
{
if (sockets.TryGetValue(instanceId, out var socket))
{
string errorMsg = Marshal.PtrToStringAuto(errorPtr);
socket.HandleOnError(errorMsg);
}
}
[MonoPInvokeCallback(typeof(OnCloseCallback))]
public static void DelegateOnCloseEvent(int instanceId, int closeCode, IntPtr reasonPtr)
{
if (sockets.TryGetValue(instanceId, out var socket))
{
string reason = Marshal.PtrToStringAuto(reasonPtr);
socket.HandleOnClose((ushort)closeCode, reason);
}
}
internal static int AllocateInstance(string address, string binaryType)
{
if (!isInitialized) Initialize();
return WebSocketAllocate(address, binaryType);
}
internal static void Add(WebSocket socket)
{
if (!sockets.ContainsKey(socket.instanceId))
{
sockets.Add(socket.instanceId, socket);
}
}
internal static void Remove(int instanceId)
{
if (sockets.ContainsKey(instanceId))
{
sockets.Remove(instanceId);
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 246cdc66a1e2047148371a8e56e17d3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3c8ae854864e4cbd983fc58be762c79f
timeCreated: 1708674128

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
namespace SHFrame
{
/// <summary>
/// 引用接口。
/// </summary>
public interface IReference
{
/// <summary>
/// 清理引用。
/// </summary>
void Clear();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cba846464f634fbb834dc447a0a38a9a
timeCreated: 1708674128

View File

@@ -0,0 +1,57 @@
using System;
namespace SHFrame
{
/// <summary>
/// 内存池对象基类。
/// </summary>
public abstract class MemoryObject : IReference
{
/// <summary>
/// 清理内存对象回收入池。
/// </summary>
public virtual void Clear()
{
}
/// <summary>
/// 从内存池中初始化。
/// </summary>
public abstract void InitFromPool();
/// <summary>
/// 回收到内存池。
/// </summary>
public abstract void RecycleToPool();
}
public static partial class ReferencePool
{
/// <summary>
/// 从内存池获取内存对象。
/// </summary>
/// <typeparam name="T">内存对象类型。</typeparam>
/// <returns>内存对象。</returns>
public static T Alloc<T>() where T : MemoryObject, new()
{
T memory = Acquire<T>();
memory.InitFromPool();
return memory;
}
/// <summary>
/// 将内存对象归还内存池。
/// </summary>
/// <param name="memory">内存对象。</param>
public static void Dealloc(MemoryObject memory)
{
if (memory == null)
{
throw new Exception("Memory is invalid.");
}
memory.RecycleToPool();
Release(memory);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bfed1dd6cf8149568d3c3d50bf75106e
timeCreated: 1709627386

View File

@@ -0,0 +1,202 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace SHFrame
{
public static partial class ReferencePool
{
private sealed class ReferenceCollection
{
private readonly Queue<IReference> m_References;
private readonly Type m_ReferenceType;
private int m_UsingReferenceCount;
private int m_AcquireReferenceCount;
private int m_ReleaseReferenceCount;
private int m_AddReferenceCount;
private int m_RemoveReferenceCount;
public ReferenceCollection(Type referenceType)
{
m_References = new Queue<IReference>();
m_ReferenceType = referenceType;
m_UsingReferenceCount = 0;
m_AcquireReferenceCount = 0;
m_ReleaseReferenceCount = 0;
m_AddReferenceCount = 0;
m_RemoveReferenceCount = 0;
}
public Type ReferenceType
{
get
{
return m_ReferenceType;
}
}
public int UnusedReferenceCount
{
get
{
return m_References.Count;
}
}
public int UsingReferenceCount
{
get
{
return m_UsingReferenceCount;
}
}
public int AcquireReferenceCount
{
get
{
return m_AcquireReferenceCount;
}
}
public int ReleaseReferenceCount
{
get
{
return m_ReleaseReferenceCount;
}
}
public int AddReferenceCount
{
get
{
return m_AddReferenceCount;
}
}
public int RemoveReferenceCount
{
get
{
return m_RemoveReferenceCount;
}
}
public T Acquire<T>() where T : class, IReference, new()
{
if (typeof(T) != m_ReferenceType)
{
throw new GameFrameworkException("Type is invalid.");
}
m_UsingReferenceCount++;
m_AcquireReferenceCount++;
lock (m_References)
{
if (m_References.Count > 0)
{
return (T)m_References.Dequeue();
}
}
m_AddReferenceCount++;
return new T();
}
public IReference Acquire()
{
m_UsingReferenceCount++;
m_AcquireReferenceCount++;
lock (m_References)
{
if (m_References.Count > 0)
{
return m_References.Dequeue();
}
}
m_AddReferenceCount++;
return (IReference)Activator.CreateInstance(m_ReferenceType);
}
public void Release(IReference reference)
{
reference.Clear();
lock (m_References)
{
if (m_EnableStrictCheck && m_References.Contains(reference))
{
throw new GameFrameworkException("The reference has been released.");
}
m_References.Enqueue(reference);
}
m_ReleaseReferenceCount++;
m_UsingReferenceCount--;
}
public void Add<T>(int count) where T : class, IReference, new()
{
if (typeof(T) != m_ReferenceType)
{
throw new GameFrameworkException("Type is invalid.");
}
lock (m_References)
{
m_AddReferenceCount += count;
while (count-- > 0)
{
m_References.Enqueue(new T());
}
}
}
public void Add(int count)
{
lock (m_References)
{
m_AddReferenceCount += count;
while (count-- > 0)
{
m_References.Enqueue((IReference)Activator.CreateInstance(m_ReferenceType));
}
}
}
public void Remove(int count)
{
lock (m_References)
{
if (count > m_References.Count)
{
count = m_References.Count;
}
m_RemoveReferenceCount += count;
while (count-- > 0)
{
m_References.Dequeue();
}
}
}
public void RemoveAll()
{
lock (m_References)
{
m_RemoveReferenceCount += m_References.Count;
m_References.Clear();
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5c27b7f50b84106ba9ac7500e5d5c36
timeCreated: 1708674128

View File

@@ -0,0 +1,225 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace SHFrame
{
/// <summary>
/// 引用池。
/// </summary>
public static partial class ReferencePool
{
private static readonly Dictionary<Type, ReferenceCollection> s_ReferenceCollections = new Dictionary<Type, ReferenceCollection>();
private static bool m_EnableStrictCheck = false;
/// <summary>
/// 获取或设置是否开启强制检查。
/// </summary>
public static bool EnableStrictCheck
{
get
{
return m_EnableStrictCheck;
}
set
{
m_EnableStrictCheck = value;
}
}
/// <summary>
/// 获取引用池的数量。
/// </summary>
public static int Count
{
get
{
return s_ReferenceCollections.Count;
}
}
/// <summary>
/// 获取所有引用池的信息。
/// </summary>
/// <returns>所有引用池的信息。</returns>
public static ReferencePoolInfo[] GetAllReferencePoolInfos()
{
int index = 0;
ReferencePoolInfo[] results = null;
lock (s_ReferenceCollections)
{
results = new ReferencePoolInfo[s_ReferenceCollections.Count];
foreach (KeyValuePair<Type, ReferenceCollection> referenceCollection in s_ReferenceCollections)
{
results[index++] = new ReferencePoolInfo(referenceCollection.Key, referenceCollection.Value.UnusedReferenceCount, referenceCollection.Value.UsingReferenceCount, referenceCollection.Value.AcquireReferenceCount, referenceCollection.Value.ReleaseReferenceCount, referenceCollection.Value.AddReferenceCount, referenceCollection.Value.RemoveReferenceCount);
}
}
return results;
}
/// <summary>
/// 清除所有引用池。
/// </summary>
public static void ClearAll()
{
lock (s_ReferenceCollections)
{
foreach (KeyValuePair<Type, ReferenceCollection> referenceCollection in s_ReferenceCollections)
{
referenceCollection.Value.RemoveAll();
}
s_ReferenceCollections.Clear();
}
}
/// <summary>
/// 从引用池获取引用。
/// </summary>
/// <typeparam name="T">引用类型。</typeparam>
/// <returns>引用。</returns>
public static T Acquire<T>() where T : class, IReference, new()
{
return GetReferenceCollection(typeof(T)).Acquire<T>();
}
/// <summary>
/// 从引用池获取引用。
/// </summary>
/// <param name="referenceType">引用类型。</param>
/// <returns>引用。</returns>
public static IReference Acquire(Type referenceType)
{
InternalCheckReferenceType(referenceType);
return GetReferenceCollection(referenceType).Acquire();
}
/// <summary>
/// 将引用归还引用池。
/// </summary>
/// <param name="reference">引用。</param>
public static void Release(IReference reference)
{
if (reference == null)
{
throw new GameFrameworkException("Reference is invalid.");
}
Type referenceType = reference.GetType();
InternalCheckReferenceType(referenceType);
GetReferenceCollection(referenceType).Release(reference);
}
/// <summary>
/// 向引用池中追加指定数量的引用。
/// </summary>
/// <typeparam name="T">引用类型。</typeparam>
/// <param name="count">追加数量。</param>
public static void Add<T>(int count) where T : class, IReference, new()
{
GetReferenceCollection(typeof(T)).Add<T>(count);
}
/// <summary>
/// 向引用池中追加指定数量的引用。
/// </summary>
/// <param name="referenceType">引用类型。</param>
/// <param name="count">追加数量。</param>
public static void Add(Type referenceType, int count)
{
InternalCheckReferenceType(referenceType);
GetReferenceCollection(referenceType).Add(count);
}
/// <summary>
/// 从引用池中移除指定数量的引用。
/// </summary>
/// <typeparam name="T">引用类型。</typeparam>
/// <param name="count">移除数量。</param>
public static void Remove<T>(int count) where T : class, IReference
{
GetReferenceCollection(typeof(T)).Remove(count);
}
/// <summary>
/// 从引用池中移除指定数量的引用。
/// </summary>
/// <param name="referenceType">引用类型。</param>
/// <param name="count">移除数量。</param>
public static void Remove(Type referenceType, int count)
{
InternalCheckReferenceType(referenceType);
GetReferenceCollection(referenceType).Remove(count);
}
/// <summary>
/// 从引用池中移除所有的引用。
/// </summary>
/// <typeparam name="T">引用类型。</typeparam>
public static void RemoveAll<T>() where T : class, IReference
{
GetReferenceCollection(typeof(T)).RemoveAll();
}
/// <summary>
/// 从引用池中移除所有的引用。
/// </summary>
/// <param name="referenceType">引用类型。</param>
public static void RemoveAll(Type referenceType)
{
InternalCheckReferenceType(referenceType);
GetReferenceCollection(referenceType).RemoveAll();
}
private static void InternalCheckReferenceType(Type referenceType)
{
if (!m_EnableStrictCheck)
{
return;
}
if (referenceType == null)
{
throw new GameFrameworkException("Reference type is invalid.");
}
if (!referenceType.IsClass || referenceType.IsAbstract)
{
throw new GameFrameworkException("Reference type is not a non-abstract class type.");
}
if (!typeof(IReference).IsAssignableFrom(referenceType))
{
throw new GameFrameworkException(Utility.Text.Format("Reference type '{0}' is invalid.", referenceType.FullName));
}
}
private static ReferenceCollection GetReferenceCollection(Type referenceType)
{
if (referenceType == null)
{
throw new GameFrameworkException("ReferenceType is invalid.");
}
ReferenceCollection referenceCollection = null;
lock (s_ReferenceCollections)
{
if (!s_ReferenceCollections.TryGetValue(referenceType, out referenceCollection))
{
referenceCollection = new ReferenceCollection(referenceType);
s_ReferenceCollections.Add(referenceType, referenceCollection);
}
}
return referenceCollection;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 54c8553d02fd4c649f3b76b3a37134aa
timeCreated: 1708674128

View File

@@ -0,0 +1,125 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
namespace SHFrame
{
/// <summary>
/// 引用池信息。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct ReferencePoolInfo
{
private readonly Type m_Type;
private readonly int m_UnusedReferenceCount;
private readonly int m_UsingReferenceCount;
private readonly int m_AcquireReferenceCount;
private readonly int m_ReleaseReferenceCount;
private readonly int m_AddReferenceCount;
private readonly int m_RemoveReferenceCount;
/// <summary>
/// 初始化引用池信息的新实例。
/// </summary>
/// <param name="type">引用池类型。</param>
/// <param name="unusedReferenceCount">未使用引用数量。</param>
/// <param name="usingReferenceCount">正在使用引用数量。</param>
/// <param name="acquireReferenceCount">获取引用数量。</param>
/// <param name="releaseReferenceCount">归还引用数量。</param>
/// <param name="addReferenceCount">增加引用数量。</param>
/// <param name="removeReferenceCount">移除引用数量。</param>
public ReferencePoolInfo(Type type, int unusedReferenceCount, int usingReferenceCount, int acquireReferenceCount, int releaseReferenceCount, int addReferenceCount, int removeReferenceCount)
{
m_Type = type;
m_UnusedReferenceCount = unusedReferenceCount;
m_UsingReferenceCount = usingReferenceCount;
m_AcquireReferenceCount = acquireReferenceCount;
m_ReleaseReferenceCount = releaseReferenceCount;
m_AddReferenceCount = addReferenceCount;
m_RemoveReferenceCount = removeReferenceCount;
}
/// <summary>
/// 获取引用池类型。
/// </summary>
public Type Type
{
get
{
return m_Type;
}
}
/// <summary>
/// 获取未使用引用数量。
/// </summary>
public int UnusedReferenceCount
{
get
{
return m_UnusedReferenceCount;
}
}
/// <summary>
/// 获取正在使用引用数量。
/// </summary>
public int UsingReferenceCount
{
get
{
return m_UsingReferenceCount;
}
}
/// <summary>
/// 获取获取引用数量。
/// </summary>
public int AcquireReferenceCount
{
get
{
return m_AcquireReferenceCount;
}
}
/// <summary>
/// 获取归还引用数量。
/// </summary>
public int ReleaseReferenceCount
{
get
{
return m_ReleaseReferenceCount;
}
}
/// <summary>
/// 获取增加引用数量。
/// </summary>
public int AddReferenceCount
{
get
{
return m_AddReferenceCount;
}
}
/// <summary>
/// 获取移除引用数量。
/// </summary>
public int RemoveReferenceCount
{
get
{
return m_RemoveReferenceCount;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8d7f634c21e544808a2439c6a60bb180
timeCreated: 1708674128

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f574775e0ef37c479b5699fcacaec63
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e189d066e92ffe4daaa48b8cf53925d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 649ee0bd256fddf4a8ea742f065d3c48
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using Newtonsoft.Json;
namespace SHFrame
{
/// <summary>
/// 默认 JSON 函数集辅助器。
/// </summary>
public class DefaultJsonHelper : Utility.Json.IJsonHelper
{
/// <summary>
/// 将对象序列化为 JSON 字符串。
/// </summary>
/// <param name="obj">要序列化的对象。</param>
/// <returns>序列化后的 JSON 字符串。</returns>
public string ToJson(object obj)
{
return JsonConvert.SerializeObject(obj);
}
/// <summary>
/// 将 JSON 字符串反序列化为对象。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
/// <param name="json">要反序列化的 JSON 字符串。</param>
/// <returns>反序列化后的对象。</returns>
public T ToObject<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json);
}
/// <summary>
/// 将 JSON 字符串反序列化为对象。
/// </summary>
/// <param name="objectType">对象类型。</param>
/// <param name="json">要反序列化的 JSON 字符串。</param>
/// <returns>反序列化后的对象。</returns>
public object ToObject(System.Type objectType, string json)
{
return JsonConvert.DeserializeObject(json);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9ac492d5e7d14d199b2c43f48ae9c9f1
timeCreated: 1727610271

View File

@@ -0,0 +1,166 @@
using System;
using System.Diagnostics;
using System.Text;
using Debug = UnityEngine.Debug;
namespace SHFrame
{
/// <summary>
/// 默认游戏框架日志辅助。
/// </summary>
public class DefaultLogHelper : GameFrameworkLog.ILogHelper
{
private enum ELogLevel
{
Info,
Debug,
Assert,
Warning,
Error,
Exception,
}
private const ELogLevel FilterLevel = ELogLevel.Info;
private static readonly StringBuilder _stringBuilder = new StringBuilder(1024);
/// <summary>
/// 打印游戏日志。
/// </summary>
/// <param name="level">游戏框架日志等级。</param>
/// <param name="message">日志信息。</param>
/// <exception cref="GameFrameworkException">游戏框架异常类。</exception>
public void Log(GameFrameworkLogLevel level, object message)
{
switch (level)
{
case GameFrameworkLogLevel.Debug:
LogImp(ELogLevel.Debug, Utility.Text.Format("<color=#888888>{0}</color>", message));
break;
case GameFrameworkLogLevel.Info:
LogImp(ELogLevel.Info, message.ToString());
break;
case GameFrameworkLogLevel.Warning:
LogImp(ELogLevel.Warning, message.ToString());
break;
case GameFrameworkLogLevel.Error:
LogImp(ELogLevel.Error, message.ToString());
break;
case GameFrameworkLogLevel.Fatal:
LogImp(ELogLevel.Exception, message.ToString());
break;
default:
throw new GameFrameworkException(message.ToString());
}
}
/// <summary>
/// 获取日志格式。
/// </summary>
/// <param name="eLogLevel">日志级别。</param>
/// <param name="logString">日志字符。</param>
/// <param name="bColor">是否使用颜色。</param>
/// <returns>StringBuilder。</returns>
private static StringBuilder GetFormatString(ELogLevel eLogLevel, string logString, bool bColor)
{
_stringBuilder.Clear();
switch (eLogLevel)
{
case ELogLevel.Debug:
_stringBuilder.AppendFormat(
bColor
? "<color=gray><b>[Debug] ► </b></color> - <color=#00FF18>{0}</color>"
: "<color=#00FF18><b>[Debug] ► </b></color> - {0}",
logString);
break;
case ELogLevel.Info:
_stringBuilder.AppendFormat(
bColor
? "<color=gray><b>[INFO] ► </b></color> - <color=gray>{0}</color>"
: "<color=gray><b>[INFO] ► </b></color> - {0}",
logString);
break;
case ELogLevel.Assert:
_stringBuilder.AppendFormat(
bColor
? "<color=#FF00BD><b>[ASSERT] ► </b></color> - <color=green>{0}</color>"
: "<color=#FF00BD><b>[ASSERT] ► </b></color> - {0}",
logString);
break;
case ELogLevel.Warning:
_stringBuilder.AppendFormat(
bColor
? "<color=#FF9400><b>[WARNING] ► </b></color> - <color=yellow>{0}</color>"
: "<color=#FF9400><b>[WARNING] ► </b></color> - {0}",
logString);
break;
case ELogLevel.Error:
_stringBuilder.AppendFormat(
bColor
? "<color=red><b>[ERROR] ► </b></color> - <color=red>{0}</color>"
: "<color=red><b>[ERROR] ► </b></color>- {0}",
logString);
break;
case ELogLevel.Exception:
_stringBuilder.AppendFormat(
bColor
? "<color=red><b>[EXCEPTION] ► </b></color> - <color=red>{0}</color>"
: "<color=red><b>[EXCEPTION] ► </b></color> - {0}",
logString);
break;
}
return _stringBuilder;
}
private static void LogImp(ELogLevel type, string logString)
{
if (type < FilterLevel)
{
return;
}
StringBuilder infoBuilder = GetFormatString(type, logString, true);
string logStr = infoBuilder.ToString();
//获取C#堆栈,Warning以上级别日志才获取堆栈
if (type == ELogLevel.Error || type == ELogLevel.Warning || type == ELogLevel.Exception)
{
StackFrame[] stackFrames = new StackTrace().GetFrames();
// ReSharper disable once PossibleNullReferenceException
for (int i = 0; i < stackFrames.Length; i++)
{
StackFrame frame = stackFrames[i];
// ReSharper disable once PossibleNullReferenceException
string declaringTypeName = frame.GetMethod().DeclaringType.FullName;
string methodName = stackFrames[i].GetMethod().Name;
infoBuilder.AppendFormat("[{0}::{1}\n", declaringTypeName, methodName);
}
}
switch (type)
{
case ELogLevel.Info:
case ELogLevel.Debug:
Debug.Log(logStr);
break;
case ELogLevel.Warning:
Debug.LogWarning(logStr);
break;
case ELogLevel.Assert:
Debug.LogAssertion(logStr);
break;
case ELogLevel.Error:
Debug.LogError(logStr);
break;
case ELogLevel.Exception:
throw new Exception(logStr);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0deaa19a4245df849af5c6fbe77cd760
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,584 @@
using System;
using System.Text;
namespace SHFrame
{
/// <summary>
/// 默认字符辅助器。
/// </summary>
public class DefaultTextHelper : Utility.Text.ITextHelper
{
private const int StringBuilderCapacity = 1024;
[ThreadStatic]
private static StringBuilder s_CachedStringBuilder = null;
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T">字符串参数的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg">字符串参数。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T>(string format, T arg)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2>(string format, T1 arg1, T2 arg2)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3>(string format, T1 arg1, T2 arg2, T3 arg3)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <typeparam name="T12">字符串参数 12 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <param name="arg12">字符串参数 12。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <typeparam name="T12">字符串参数 12 的类型。</typeparam>
/// <typeparam name="T13">字符串参数 13 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <param name="arg12">字符串参数 12。</param>
/// <param name="arg13">字符串参数 13。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <typeparam name="T12">字符串参数 12 的类型。</typeparam>
/// <typeparam name="T13">字符串参数 13 的类型。</typeparam>
/// <typeparam name="T14">字符串参数 14 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <param name="arg12">字符串参数 12。</param>
/// <param name="arg13">字符串参数 13。</param>
/// <param name="arg14">字符串参数 14。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <typeparam name="T12">字符串参数 12 的类型。</typeparam>
/// <typeparam name="T13">字符串参数 13 的类型。</typeparam>
/// <typeparam name="T14">字符串参数 14 的类型。</typeparam>
/// <typeparam name="T15">字符串参数 15 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <param name="arg12">字符串参数 12。</param>
/// <param name="arg13">字符串参数 13。</param>
/// <param name="arg14">字符串参数 14。</param>
/// <param name="arg15">字符串参数 15。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
return s_CachedStringBuilder.ToString();
}
/// <summary>
/// 获取格式化字符串。
/// </summary>
/// <typeparam name="T1">字符串参数 1 的类型。</typeparam>
/// <typeparam name="T2">字符串参数 2 的类型。</typeparam>
/// <typeparam name="T3">字符串参数 3 的类型。</typeparam>
/// <typeparam name="T4">字符串参数 4 的类型。</typeparam>
/// <typeparam name="T5">字符串参数 5 的类型。</typeparam>
/// <typeparam name="T6">字符串参数 6 的类型。</typeparam>
/// <typeparam name="T7">字符串参数 7 的类型。</typeparam>
/// <typeparam name="T8">字符串参数 8 的类型。</typeparam>
/// <typeparam name="T9">字符串参数 9 的类型。</typeparam>
/// <typeparam name="T10">字符串参数 10 的类型。</typeparam>
/// <typeparam name="T11">字符串参数 11 的类型。</typeparam>
/// <typeparam name="T12">字符串参数 12 的类型。</typeparam>
/// <typeparam name="T13">字符串参数 13 的类型。</typeparam>
/// <typeparam name="T14">字符串参数 14 的类型。</typeparam>
/// <typeparam name="T15">字符串参数 15 的类型。</typeparam>
/// <typeparam name="T16">字符串参数 16 的类型。</typeparam>
/// <param name="format">字符串格式。</param>
/// <param name="arg1">字符串参数 1。</param>
/// <param name="arg2">字符串参数 2。</param>
/// <param name="arg3">字符串参数 3。</param>
/// <param name="arg4">字符串参数 4。</param>
/// <param name="arg5">字符串参数 5。</param>
/// <param name="arg6">字符串参数 6。</param>
/// <param name="arg7">字符串参数 7。</param>
/// <param name="arg8">字符串参数 8。</param>
/// <param name="arg9">字符串参数 9。</param>
/// <param name="arg10">字符串参数 10。</param>
/// <param name="arg11">字符串参数 11。</param>
/// <param name="arg12">字符串参数 12。</param>
/// <param name="arg13">字符串参数 13。</param>
/// <param name="arg14">字符串参数 14。</param>
/// <param name="arg15">字符串参数 15。</param>
/// <param name="arg16">字符串参数 16。</param>
/// <returns>格式化后的字符串。</returns>
public string Format<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16)
{
if (format == null)
{
throw new GameFrameworkException("Format is invalid.");
}
CheckCachedStringBuilder();
s_CachedStringBuilder.Length = 0;
s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16);
return s_CachedStringBuilder.ToString();
}
private static void CheckCachedStringBuilder()
{
if (s_CachedStringBuilder == null)
{
s_CachedStringBuilder = new StringBuilder(StringBuilderCapacity);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61e71bc7e2431a2448ca193e9267fb2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
namespace SHFrame
{
/// <summary>
/// 默认版本号辅助器。
/// </summary>
public class DefaultVersionHelper : Version.IVersionHelper
{
/// <summary>
/// 获取游戏版本号。
/// </summary>
public string GameVersion => Application.version;
/// <summary>
/// 获取内部游戏版本号。
/// </summary>
public string InternalGameVersion => string.Empty;
// TODO 后续处理
// public string InternalGameVersion => BuiltinQueryMgr.InternalGameVersion;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: addcad79fdfd4864b95c685c1b2dfb11
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,43 @@
using System;
using UnityEngine;
namespace SHFrame
{
/// <summary>
/// 默认 JSON 函数集辅助器。
/// </summary>
public class UnityJsonHelper : Utility.Json.IJsonHelper
{
/// <summary>
/// 将对象序列化为 JSON 字符串。
/// </summary>
/// <param name="obj">要序列化的对象。</param>
/// <returns>序列化后的 JSON 字符串。</returns>
public string ToJson(object obj)
{
return JsonUtility.ToJson(obj);
}
/// <summary>
/// 将 JSON 字符串反序列化为对象。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
/// <param name="json">要反序列化的 JSON 字符串。</param>
/// <returns>反序列化后的对象。</returns>
public T ToObject<T>(string json)
{
return JsonUtility.FromJson<T>(json);
}
/// <summary>
/// 将 JSON 字符串反序列化为对象。
/// </summary>
/// <param name="objectType">对象类型。</param>
/// <param name="json">要反序列化的 JSON 字符串。</param>
/// <returns>反序列化后的对象。</returns>
public object ToObject(Type objectType, string json)
{
return JsonUtility.FromJson(json, objectType);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc9b7d0b47abdc542b1e4e336483fdf3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
namespace SHFrame
{
public static partial class Utility
{
/// <summary>
/// 程序集相关的实用函数。
/// </summary>
public static class Assembly
{
private static readonly System.Reflection.Assembly[] _assemblies = null;
private static readonly Dictionary<string, Type> _cachedTypes = new Dictionary<string, Type>(StringComparer.Ordinal);
static Assembly()
{
_assemblies = AppDomain.CurrentDomain.GetAssemblies();
}
/// <summary>
/// 获取已加载的程序集。
/// </summary>
/// <returns>已加载的程序集。</returns>
public static System.Reflection.Assembly[] GetAssemblies()
{
return _assemblies;
}
/// <summary>
/// 获取已加载的程序集中的所有类型。
/// </summary>
/// <returns>已加载的程序集中的所有类型。</returns>
public static Type[] GetTypes()
{
List<Type> results = new List<Type>();
foreach (System.Reflection.Assembly assembly in _assemblies)
{
results.AddRange(assembly.GetTypes());
}
return results.ToArray();
}
/// <summary>
/// 获取已加载的程序集中的所有类型。
/// </summary>
/// <param name="results">已加载的程序集中的所有类型。</param>
public static void GetTypes(List<Type> results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
foreach (System.Reflection.Assembly assembly in _assemblies)
{
results.AddRange(assembly.GetTypes());
}
}
/// <summary>
/// 获取已加载的程序集中的指定类型。
/// </summary>
/// <param name="typeName">要获取的类型名。</param>
/// <returns>已加载的程序集中的指定类型。</returns>
public static Type GetType(string typeName)
{
if (string.IsNullOrEmpty(typeName))
{
throw new GameFrameworkException("Type name is invalid.");
}
Type type = null;
if (_cachedTypes.TryGetValue(typeName, out type))
{
return type;
}
type = Type.GetType(typeName);
if (type != null)
{
_cachedTypes.Add(typeName, type);
return type;
}
foreach (System.Reflection.Assembly assembly in _assemblies)
{
type = Type.GetType(Text.Format("{0}, {1}", typeName, assembly.FullName));
if (type != null)
{
_cachedTypes.Add(typeName, type);
return type;
}
}
return null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 490e0ee637bd78742ad0c757961df74d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,835 @@
using System;
using System.Text;
namespace SHFrame
{
public static partial class Utility
{
/// <summary>
/// 类型转换相关的实用函数。
/// </summary>
public static class Converter
{
private const float InchesToCentimeters = 2.54f; // 1 inch = 2.54 cm
private const float CentimetersToInches = 1f / InchesToCentimeters; // 1 cm = 0.3937 inches
/// <summary>
/// 获取数据在此计算机结构中存储时的字节顺序。
/// </summary>
public static bool IsLittleEndian => BitConverter.IsLittleEndian;
/// <summary>
/// 获取或设置屏幕每英寸点数。
/// </summary>
public static float ScreenDpi
{
get;
set;
}
/// <summary>
/// 将像素转换为厘米。
/// </summary>
/// <param name="pixels">像素。</param>
/// <returns>厘米。</returns>
public static float GetCentimetersFromPixels(float pixels)
{
if (ScreenDpi <= 0)
{
throw new GameFrameworkException("You must set screen DPI first.");
}
return InchesToCentimeters * pixels / ScreenDpi;
}
/// <summary>
/// 将厘米转换为像素。
/// </summary>
/// <param name="centimeters">厘米。</param>
/// <returns>像素。</returns>
public static float GetPixelsFromCentimeters(float centimeters)
{
if (ScreenDpi <= 0)
{
throw new GameFrameworkException("You must set screen DPI first.");
}
return CentimetersToInches * centimeters * ScreenDpi;
}
/// <summary>
/// 将像素转换为英寸。
/// </summary>
/// <param name="pixels">像素。</param>
/// <returns>英寸。</returns>
public static float GetInchesFromPixels(float pixels)
{
if (ScreenDpi <= 0)
{
throw new GameFrameworkException("You must set screen DPI first.");
}
return pixels / ScreenDpi;
}
/// <summary>
/// 将英寸转换为像素。
/// </summary>
/// <param name="inches">英寸。</param>
/// <returns>像素。</returns>
public static float GetPixelsFromInches(float inches)
{
if (ScreenDpi <= 0)
{
throw new GameFrameworkException("You must set screen DPI first.");
}
return inches * ScreenDpi;
}
/// <summary>
/// 以字节数组的形式获取指定的布尔值。
/// </summary>
/// <param name="value">要转换的布尔值。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(bool value)
{
byte[] buffer = new byte[1];
GetBytes(value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的布尔值。
/// </summary>
/// <param name="value">要转换的布尔值。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(bool value, byte[] buffer)
{
GetBytes(value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的布尔值。
/// </summary>
/// <param name="value">要转换的布尔值。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static void GetBytes(bool value, byte[] buffer, int startIndex)
{
if (buffer == null)
{
throw new GameFrameworkException("Buffer is invalid.");
}
if (startIndex < 0 || startIndex + 1 > buffer.Length)
{
throw new GameFrameworkException("Start index is invalid.");
}
buffer[startIndex] = value ? (byte)1 : (byte)0;
}
/// <summary>
/// 返回由字节数组中首字节转换来的布尔值。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>如果 value 中的首字节非零,则为 true否则为 false。</returns>
public static bool GetBoolean(byte[] value)
{
return BitConverter.ToBoolean(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的一个字节转换来的布尔值。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>如果 value 中指定位置的字节非零,则为 true否则为 false。</returns>
public static bool GetBoolean(byte[] value, int startIndex)
{
return BitConverter.ToBoolean(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 Unicode 字符值。
/// </summary>
/// <param name="value">要转换的字符。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(char value)
{
byte[] buffer = new byte[2];
GetBytes((short)value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 Unicode 字符值。
/// </summary>
/// <param name="value">要转换的字符。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(char value, byte[] buffer)
{
GetBytes((short)value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 Unicode 字符值。
/// </summary>
/// <param name="value">要转换的字符。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static void GetBytes(char value, byte[] buffer, int startIndex)
{
GetBytes((short)value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前两个字节转换来的 Unicode 字符。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由两个字节构成的字符。</returns>
public static char GetChar(byte[] value)
{
return BitConverter.ToChar(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的两个字节转换来的 Unicode 字符。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由两个字节构成的字符。</returns>
public static char GetChar(byte[] value, int startIndex)
{
return BitConverter.ToChar(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(short value)
{
byte[] buffer = new byte[2];
GetBytes(value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(short value, byte[] buffer)
{
GetBytes(value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static unsafe void GetBytes(short value, byte[] buffer, int startIndex)
{
if (buffer == null)
{
throw new GameFrameworkException("Buffer is invalid.");
}
if (startIndex < 0 || startIndex + 2 > buffer.Length)
{
throw new GameFrameworkException("Start index is invalid.");
}
fixed (byte* valueRef = buffer)
{
*(short*)(valueRef + startIndex) = value;
}
}
/// <summary>
/// 返回由字节数组中前两个字节转换来的 16 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由两个字节构成的 16 位有符号整数。</returns>
public static short GetInt16(byte[] value)
{
return BitConverter.ToInt16(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的两个字节转换来的 16 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由两个字节构成的 16 位有符号整数。</returns>
public static short GetInt16(byte[] value, int startIndex)
{
return BitConverter.ToInt16(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(ushort value)
{
byte[] buffer = new byte[2];
GetBytes((short)value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(ushort value, byte[] buffer)
{
GetBytes((short)value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 16 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static void GetBytes(ushort value, byte[] buffer, int startIndex)
{
GetBytes((short)value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前两个字节转换来的 16 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由两个字节构成的 16 位无符号整数。</returns>
public static ushort GetUInt16(byte[] value)
{
return BitConverter.ToUInt16(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的两个字节转换来的 16 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由两个字节构成的 16 位无符号整数。</returns>
public static ushort GetUInt16(byte[] value, int startIndex)
{
return BitConverter.ToUInt16(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(int value)
{
byte[] buffer = new byte[4];
GetBytes(value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(int value, byte[] buffer)
{
GetBytes(value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static unsafe void GetBytes(int value, byte[] buffer, int startIndex)
{
if (buffer == null)
{
throw new GameFrameworkException("Buffer is invalid.");
}
if (startIndex < 0 || startIndex + 4 > buffer.Length)
{
throw new GameFrameworkException("Start index is invalid.");
}
fixed (byte* valueRef = buffer)
{
*(int*)(valueRef + startIndex) = value;
}
}
/// <summary>
/// 返回由字节数组中前四个字节转换来的 32 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由四个字节构成的 32 位有符号整数。</returns>
public static int GetInt32(byte[] value)
{
return BitConverter.ToInt32(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的四个字节转换来的 32 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由四个字节构成的 32 位有符号整数。</returns>
public static int GetInt32(byte[] value, int startIndex)
{
return BitConverter.ToInt32(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(uint value)
{
byte[] buffer = new byte[4];
GetBytes((int)value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(uint value, byte[] buffer)
{
GetBytes((int)value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 32 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static void GetBytes(uint value, byte[] buffer, int startIndex)
{
GetBytes((int)value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前四个字节转换来的 32 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由四个字节构成的 32 位无符号整数。</returns>
public static uint GetUInt32(byte[] value)
{
return BitConverter.ToUInt32(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的四个字节转换来的 32 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由四个字节构成的 32 位无符号整数。</returns>
public static uint GetUInt32(byte[] value, int startIndex)
{
return BitConverter.ToUInt32(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(long value)
{
byte[] buffer = new byte[8];
GetBytes(value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(long value, byte[] buffer)
{
GetBytes(value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位有符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static unsafe void GetBytes(long value, byte[] buffer, int startIndex)
{
if (buffer == null)
{
throw new GameFrameworkException("Buffer is invalid.");
}
if (startIndex < 0 || startIndex + 8 > buffer.Length)
{
throw new GameFrameworkException("Start index is invalid.");
}
fixed (byte* valueRef = buffer)
{
*(long*)(valueRef + startIndex) = value;
}
}
/// <summary>
/// 返回由字节数组中前八个字节转换来的 64 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由八个字节构成的 64 位有符号整数。</returns>
public static long GetInt64(byte[] value)
{
return BitConverter.ToInt64(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的八个字节转换来的 64 位有符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由八个字节构成的 64 位有符号整数。</returns>
public static long GetInt64(byte[] value, int startIndex)
{
return BitConverter.ToInt64(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(ulong value)
{
byte[] buffer = new byte[8];
GetBytes((long)value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static void GetBytes(ulong value, byte[] buffer)
{
GetBytes((long)value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的 64 位无符号整数值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static void GetBytes(ulong value, byte[] buffer, int startIndex)
{
GetBytes((long)value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前八个字节转换来的 64 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由八个字节构成的 64 位无符号整数。</returns>
public static ulong GetUInt64(byte[] value)
{
return BitConverter.ToUInt64(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的八个字节转换来的 64 位无符号整数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由八个字节构成的 64 位无符号整数。</returns>
public static ulong GetUInt64(byte[] value, int startIndex)
{
return BitConverter.ToUInt64(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的单精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static unsafe byte[] GetBytes(float value)
{
byte[] buffer = new byte[4];
GetBytes(*(int*)&value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的单精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static unsafe void GetBytes(float value, byte[] buffer)
{
GetBytes(*(int*)&value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的单精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static unsafe void GetBytes(float value, byte[] buffer, int startIndex)
{
GetBytes(*(int*)&value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前四个字节转换来的单精度浮点数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由四个字节构成的单精度浮点数。</returns>
public static float GetSingle(byte[] value)
{
return BitConverter.ToSingle(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的四个字节转换来的单精度浮点数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由四个字节构成的单精度浮点数。</returns>
public static float GetSingle(byte[] value, int startIndex)
{
return BitConverter.ToSingle(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定的双精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static unsafe byte[] GetBytes(double value)
{
byte[] buffer = new byte[8];
GetBytes(*(long*)&value, buffer, 0);
return buffer;
}
/// <summary>
/// 以字节数组的形式获取指定的双精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
public static unsafe void GetBytes(double value, byte[] buffer)
{
GetBytes(*(long*)&value, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定的双精度浮点值。
/// </summary>
/// <param name="value">要转换的数字。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
public static unsafe void GetBytes(double value, byte[] buffer, int startIndex)
{
GetBytes(*(long*)&value, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组中前八个字节转换来的双精度浮点数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>由八个字节构成的双精度浮点数。</returns>
public static double GetDouble(byte[] value)
{
return BitConverter.ToDouble(value, 0);
}
/// <summary>
/// 返回由字节数组中指定位置的八个字节转换来的双精度浮点数。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <returns>由八个字节构成的双精度浮点数。</returns>
public static double GetDouble(byte[] value, int startIndex)
{
return BitConverter.ToDouble(value, startIndex);
}
/// <summary>
/// 以字节数组的形式获取 UTF-8 编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(string value)
{
return GetBytes(value, Encoding.UTF8);
}
/// <summary>
/// 以字节数组的形式获取 UTF-8 编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <returns>buffer 内实际填充了多少字节。</returns>
public static int GetBytes(string value, byte[] buffer)
{
return GetBytes(value, Encoding.UTF8, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取 UTF-8 编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
/// <returns>buffer 内实际填充了多少字节。</returns>
public static int GetBytes(string value, byte[] buffer, int startIndex)
{
return GetBytes(value, Encoding.UTF8, buffer, startIndex);
}
/// <summary>
/// 以字节数组的形式获取指定编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <param name="encoding">要使用的编码。</param>
/// <returns>用于存放结果的字节数组。</returns>
public static byte[] GetBytes(string value, Encoding encoding)
{
if (value == null)
{
throw new GameFrameworkException("Value is invalid.");
}
if (encoding == null)
{
throw new GameFrameworkException("Encoding is invalid.");
}
return encoding.GetBytes(value);
}
/// <summary>
/// 以字节数组的形式获取指定编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <param name="encoding">要使用的编码。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <returns>buffer 内实际填充了多少字节。</returns>
public static int GetBytes(string value, Encoding encoding, byte[] buffer)
{
return GetBytes(value, encoding, buffer, 0);
}
/// <summary>
/// 以字节数组的形式获取指定编码的字符串。
/// </summary>
/// <param name="value">要转换的字符串。</param>
/// <param name="encoding">要使用的编码。</param>
/// <param name="buffer">用于存放结果的字节数组。</param>
/// <param name="startIndex">buffer 内的起始位置。</param>
/// <returns>buffer 内实际填充了多少字节。</returns>
public static int GetBytes(string value, Encoding encoding, byte[] buffer, int startIndex)
{
if (value == null)
{
throw new GameFrameworkException("Value is invalid.");
}
if (encoding == null)
{
throw new GameFrameworkException("Encoding is invalid.");
}
return encoding.GetBytes(value, 0, value.Length, buffer, startIndex);
}
/// <summary>
/// 返回由字节数组使用 UTF-8 编码转换成的字符串。
/// </summary>
/// <param name="value">字节数组。</param>
/// <returns>转换后的字符串。</returns>
public static string GetString(byte[] value)
{
return GetString(value, Encoding.UTF8);
}
/// <summary>
/// 返回由字节数组使用指定编码转换成的字符串。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="encoding">要使用的编码。</param>
/// <returns>转换后的字符串。</returns>
public static string GetString(byte[] value, Encoding encoding)
{
if (value == null)
{
throw new GameFrameworkException("Value is invalid.");
}
if (encoding == null)
{
throw new GameFrameworkException("Encoding is invalid.");
}
return encoding.GetString(value);
}
/// <summary>
/// 返回由字节数组使用 UTF-8 编码转换成的字符串。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <param name="length">长度。</param>
/// <returns>转换后的字符串。</returns>
public static string GetString(byte[] value, int startIndex, int length)
{
return GetString(value, startIndex, length, Encoding.UTF8);
}
/// <summary>
/// 返回由字节数组使用指定编码转换成的字符串。
/// </summary>
/// <param name="value">字节数组。</param>
/// <param name="startIndex">value 内的起始位置。</param>
/// <param name="length">长度。</param>
/// <param name="encoding">要使用的编码。</param>
/// <returns>转换后的字符串。</returns>
public static string GetString(byte[] value, int startIndex, int length, Encoding encoding)
{
if (value == null)
{
throw new GameFrameworkException("Value is invalid.");
}
if (encoding == null)
{
throw new GameFrameworkException("Encoding is invalid.");
}
return encoding.GetString(value, startIndex, length);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f714d0987f6c0047bb650fb52d32c33
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,127 @@
using System;
namespace SHFrame
{
public static partial class Utility
{
/// <summary>
/// 加密解密相关的实用函数。
/// </summary>
public static class Encryption
{
internal const int QuickEncryptLength = 220;
/// <summary>
/// 将 bytes 使用 code 做异或运算的快速版本。
/// </summary>
/// <param name="bytes">原始二进制流。</param>
/// <param name="code">异或二进制流。</param>
/// <returns>异或后的二进制流。</returns>
public static byte[] GetQuickXorBytes(byte[] bytes, byte[] code)
{
return GetXorBytes(bytes, 0, QuickEncryptLength, code);
}
/// <summary>
/// 将 bytes 使用 code 做异或运算的快速版本。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。
/// </summary>
/// <param name="bytes">原始及异或后的二进制流。</param>
/// <param name="code">异或二进制流。</param>
public static void GetQuickSelfXorBytes(byte[] bytes, byte[] code)
{
GetSelfXorBytes(bytes, 0, QuickEncryptLength, code);
}
/// <summary>
/// 将 bytes 使用 code 做异或运算。
/// </summary>
/// <param name="bytes">原始二进制流。</param>
/// <param name="code">异或二进制流。</param>
/// <returns>异或后的二进制流。</returns>
public static byte[] GetXorBytes(byte[] bytes, byte[] code)
{
if (bytes == null)
{
return null;
}
return GetXorBytes(bytes, 0, bytes.Length, code);
}
/// <summary>
/// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。
/// </summary>
/// <param name="bytes">原始及异或后的二进制流。</param>
/// <param name="code">异或二进制流。</param>
public static void GetSelfXorBytes(byte[] bytes, byte[] code)
{
if (bytes == null)
{
return;
}
GetSelfXorBytes(bytes, 0, bytes.Length, code);
}
/// <summary>
/// 将 bytes 使用 code 做异或运算。
/// </summary>
/// <param name="bytes">原始二进制流。</param>
/// <param name="startIndex">异或计算的开始位置。</param>
/// <param name="length">异或计算长度,若小于 0则计算整个二进制流。</param>
/// <param name="code">异或二进制流。</param>
/// <returns>异或后的二进制流。</returns>
public static byte[] GetXorBytes(byte[] bytes, int startIndex, int length, byte[] code)
{
if (bytes == null)
{
return null;
}
int bytesLength = bytes.Length;
byte[] results = new byte[bytesLength];
Array.Copy(bytes, 0, results, 0, bytesLength);
GetSelfXorBytes(results, startIndex, length, code);
return results;
}
/// <summary>
/// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。
/// </summary>
/// <param name="bytes">原始及异或后的二进制流。</param>
/// <param name="startIndex">异或计算的开始位置。</param>
/// <param name="length">异或计算长度。</param>
/// <param name="code">异或二进制流。</param>
public static void GetSelfXorBytes(byte[] bytes, int startIndex, int length, byte[] code)
{
if (bytes == null)
{
return;
}
if (code == null)
{
throw new GameFrameworkException("Code is invalid.");
}
int codeLength = code.Length;
if (codeLength <= 0)
{
throw new GameFrameworkException("Code length is invalid.");
}
if (startIndex < 0 || length < 0 || startIndex + length > bytes.Length)
{
throw new GameFrameworkException("Start index or length is invalid.");
}
int codeIndex = startIndex % codeLength;
for (int i = startIndex; i < length; i++)
{
bytes[i] ^= code[codeIndex++];
codeIndex %= codeLength;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1af4e7fba2a8f542acebf72bb41dce3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,234 @@
using System;
using System.IO;
using System.Text;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace SHFrame
{
/// <summary>
/// Unity平台路径类型。
/// </summary>
public enum UnityPlatformPathType : int
{
dataPath = 0,
streamingAssetsPath,
persistentDataPath,
temporaryCachePath,
}
public static partial class Utility
{
/// <summary>
/// 文件相关的实用函数。
/// </summary>
public static class File
{
public static bool CreateFile(string filePath, bool isCreateDir = true)
{
if (!System.IO.File.Exists(filePath))
{
string dir = System.IO.Path.GetDirectoryName(filePath);
if (!Directory.Exists(dir))
{
if (isCreateDir)
{
Directory.CreateDirectory(dir);
}
else
{
Log.Error("文件夹不存在 Path=" + dir);
return false;
}
}
System.IO.File.Create(filePath);
}
return true;
}
public static bool CreateFile(string filePath, string info, bool isCreateDir = true)
{
StreamWriter sw;
FileInfo t = new FileInfo(filePath);
if (!t.Exists)
{
string dir = System.IO.Path.GetDirectoryName(filePath);
if (!Directory.Exists(dir))
{
if (isCreateDir)
{
Directory.CreateDirectory(dir);
}
else
{
#if UNITY_EDITOR
EditorUtility.DisplayDialog("Tips", "文件夹不存在", "CANCEL");
#endif
Log.Error("文件夹不存在 Path=" + dir);
return false;
}
}
sw = t.CreateText();
}
else
{
sw = t.AppendText();
}
sw.WriteLine(info);
sw.Close();
sw.Dispose();
return true;
}
public static string GetPersistentDataPlatformPath(string filePath)
{
filePath =
#if UNITY_ANDROID && !UNITY_EDITOR
Application.dataPath + "!assets" + "/" + filePath;
#else
Application.streamingAssetsPath + "/" + filePath;
#endif
return filePath;
}
public static string GetPath(string path)
{
return path.Replace("\\", "/");
}
public static string Md5ByPathName(string pathName)
{
try
{
FileStream file = new FileStream(pathName, FileMode.Open);
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
Log.Error("to md5 fail,error:" + ex.Message);
return "Error";
}
}
public static string GetLengthString(long length)
{
if (length < 1024)
{
return $"{length.ToString()} Bytes";
}
if (length < 1024 * 1024)
{
return $"{(length / 1024f):F2} KB";
}
return length < 1024 * 1024 * 1024 ? $"{(length / 1024f / 1024f):F2} MB" : $"{(length / 1024f / 1024f / 1024f):F2} GB";
}
public static string GetByteLengthString(long byteLength)
{
if (byteLength < 1024L) // 2 ^ 10
{
return Utility.Text.Format("{0} Bytes", byteLength.ToString());
}
if (byteLength < 1048576L) // 2 ^ 20
{
return Utility.Text.Format("{0} KB", (byteLength / 1024f).ToString("F2"));
}
if (byteLength < 1073741824L) // 2 ^ 30
{
return Utility.Text.Format("{0} MB", (byteLength / 1048576f).ToString("F2"));
}
if (byteLength < 1099511627776L) // 2 ^ 40
{
return Utility.Text.Format("{0} GB", (byteLength / 1073741824f).ToString("F2"));
}
if (byteLength < 1125899906842624L) // 2 ^ 50
{
return Utility.Text.Format("{0} TB", (byteLength / 1099511627776f).ToString("F2"));
}
if (byteLength < 1152921504606846976L) // 2 ^ 60
{
return Utility.Text.Format("{0} PB", (byteLength / 1125899906842624f).ToString("F2"));
}
return Utility.Text.Format("{0} EB", (byteLength / 1152921504606846976f).ToString("F2"));
}
public static string BinToUtf8(byte[] total)
{
byte[] result = total;
if (total[0] == 0xef && total[1] == 0xbb && total[2] == 0xbf)
{
// utf8文件的前三个字节为特殊占位符要跳过
result = new byte[total.Length - 3];
System.Array.Copy(total, 3, result, 0, total.Length - 3);
}
string utf8string = System.Text.Encoding.UTF8.GetString(result);
return utf8string;
}
/// <summary>
/// 数据格式转换
/// </summary>
/// <param name="data">数据</param>
/// <returns></returns>
public static string FormatData(long data)
{
string result = "";
if (data < 0)
data = 0;
if (data > 1024 * 1024)
{
result = ((int)(data / (1024 * 1024))).ToString() + "MB";
}
else if (data > 1024)
{
result = ((int)(data / 1024)).ToString() + "KB";
}
else
{
result = data + "B";
}
return result;
}
/// <summary>
/// 获取文件大小
/// </summary>
/// <param name="path">文件路径</param>
/// <returns></returns>
public static long GetFileSize(string path)
{
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return file.Length;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8889bac27c0d1524695104d4bd46185a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
namespace SHFrame
{
public static partial class Utility
{
/// <summary>
/// Http 相关的实用函数。
/// </summary>
public static partial class Http
{
/// <summary>
/// GET请求与获取结果。
/// </summary>
/// <param name="url">网络URL。</param>
/// <param name="timeout">超时时间。</param>
/// <returns>请求结果。</returns>
public static async UniTask<string> Get(string url, float timeout = 5f)
{
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout));
using UnityWebRequest unityWebRequest = UnityWebRequest.Get(url);
return await SendWebRequest(unityWebRequest, cts);
}
/// <summary>
/// Post请求与获取结果.
/// </summary>
/// <param name="url">网络URL。</param>
/// <param name="postData">Post数据。</param>
/// <param name="timeout">超时时间。</param>
/// <returns>请求结果。</returns>
public static async UniTask<string> Post(string url, string postData, float timeout = 5f)
{
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout));
using UnityWebRequest unityWebRequest = UnityWebRequest.PostWwwForm(url, postData);
return await SendWebRequest(unityWebRequest, cts);
}
/// <summary>
/// Post请求与获取结果.
/// </summary>
/// <param name="url">网络URL。</param>
/// <param name="formFields">Post数据。</param>
/// <param name="timeout">超时时间。</param>
/// <returns>请求结果。</returns>
public static async UniTask<string> Post(string url, Dictionary<string, string> formFields, float timeout = 5f)
{
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout));
using UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, formFields);
return await SendWebRequest(unityWebRequest, cts);
}
/// <summary>
/// Post请求与获取结果.
/// </summary>
/// <param name="url">网络URL。</param>
/// <param name="formData">Post数据。</param>
/// <param name="timeout">超时时间。</param>
/// <returns>请求结果。</returns>
public static async UniTask<string> Post(string url, WWWForm formData, float timeout = 5f)
{
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout));
using UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, formData);
return await SendWebRequest(unityWebRequest, cts);
}
/// <summary>
/// 抛出网络请求。
/// </summary>
/// <param name="unityWebRequest">UnityWebRequest。</param>
/// <param name="cts">CancellationTokenSource。</param>
/// <returns>请求结果。</returns>
public static async UniTask<string> SendWebRequest(UnityWebRequest unityWebRequest, CancellationTokenSource cts)
{
try
{
var (isCanceled, _) = await unityWebRequest.SendWebRequest().WithCancellation(cts.Token).SuppressCancellationThrow();
if (isCanceled)
{
Log.Warning($"HttpPost {unityWebRequest.url} be canceled!");
unityWebRequest.Dispose();
return string.Empty;
}
}
catch (OperationCanceledException ex)
{
if (ex.CancellationToken == cts.Token)
{
Log.Warning("HttpPost Timeout");
unityWebRequest.Dispose();
return string.Empty;
}
}
string ret = unityWebRequest.downloadHandler.text;
unityWebRequest.Dispose();
return ret;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More