配置表接入和升级服务器框架到最新版
This commit is contained in:
@@ -40,15 +40,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
||||
<PackageReference Include="mimalloc-csharp" Version="1.0.7" />
|
||||
<PackageReference Include="MongoDB.Bson" Version="3.1.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.1.0" />
|
||||
<PackageReference Include="MongoDB.Bson" Version="3.4.3" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.4.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.45" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<PackageReference Include="System.IO.Pipelines" Version="9.0.0" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.56" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -58,4 +53,8 @@
|
||||
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<PackageReference Include="System.IO.Pipelines" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -92,11 +92,6 @@ namespace Fantasy.DataBase
|
||||
return data == null ? 0 : Convert.ToInt64(data["Result"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mongo 注释
|
||||
/// </summary>
|
||||
public MongoClient Client => _mongoClient;
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetCollection
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Fantasy.Async
|
||||
/// </summary>
|
||||
/// <param name="coroutineLockType"></param>
|
||||
/// <param name="coroutineLockQueueKey"></param>
|
||||
public void Release(int coroutineLockType, long coroutineLockQueueKey)
|
||||
public void Release(long coroutineLockType, long coroutineLockQueueKey)
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
|
||||
@@ -67,11 +67,15 @@ namespace Fantasy.Entitas
|
||||
return HashCode.Combine(CustomEventType, EntitiesType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Entity管理组件
|
||||
/// </summary>
|
||||
#if FANTASY_UNITY
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, ISceneLateUpdate, IAssembly
|
||||
#else
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly
|
||||
#endif
|
||||
{
|
||||
private readonly OneToManyList<long, Type> _assemblyList = new();
|
||||
private readonly OneToManyList<long, Type> _assemblyHashCodes = new();
|
||||
@@ -80,15 +84,19 @@ namespace Fantasy.Entitas
|
||||
private readonly Dictionary<Type, IUpdateSystem> _updateSystems = new();
|
||||
private readonly Dictionary<Type, IDestroySystem> _destroySystems = new();
|
||||
private readonly Dictionary<Type, IDeserializeSystem> _deserializeSystems = new();
|
||||
private readonly Dictionary<Type, IFrameUpdateSystem> _frameUpdateSystem = new();
|
||||
|
||||
private readonly OneToManyList<long, CustomEntitiesSystemKey> _assemblyCustomSystemList = new();
|
||||
private readonly Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem> _customEntitiesSystems = new Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem>();
|
||||
|
||||
private readonly Dictionary<Type, long> _hashCodes = new Dictionary<Type, long>();
|
||||
private readonly Queue<UpdateQueueInfo> _updateQueue = new Queue<UpdateQueueInfo>();
|
||||
private readonly Queue<FrameUpdateQueueInfo> _frameUpdateQueue = new Queue<FrameUpdateQueueInfo>();
|
||||
|
||||
private readonly Dictionary<long, UpdateQueueInfo> _updateQueueDic = new Dictionary<long, UpdateQueueInfo>();
|
||||
#if FANTASY_UNITY
|
||||
private readonly Dictionary<Type, ILateUpdateSystem> _lateUpdateSystems = new();
|
||||
private readonly Queue<UpdateQueueInfo> _lateUpdateQueue = new Queue<UpdateQueueInfo>();
|
||||
private readonly Dictionary<long, UpdateQueueInfo> _lateUpdateQueueDic = new Dictionary<long, UpdateQueueInfo>();
|
||||
#endif
|
||||
|
||||
internal async FTask<EntityComponent> Initialize()
|
||||
{
|
||||
@@ -157,10 +165,6 @@ namespace Fantasy.Entitas
|
||||
case IDestroySystem iDestroySystem:
|
||||
{
|
||||
entitiesType = iDestroySystem.EntitiesType();
|
||||
if (_destroySystems.ContainsKey(entitiesType))
|
||||
{
|
||||
|
||||
}
|
||||
_destroySystems.Add(entitiesType, iDestroySystem);
|
||||
break;
|
||||
}
|
||||
@@ -176,12 +180,14 @@ namespace Fantasy.Entitas
|
||||
_updateSystems.Add(entitiesType, iUpdateSystem);
|
||||
break;
|
||||
}
|
||||
case IFrameUpdateSystem iFrameUpdateSystem:
|
||||
#if FANTASY_UNITY
|
||||
case ILateUpdateSystem iLateUpdateSystem:
|
||||
{
|
||||
entitiesType = iFrameUpdateSystem.EntitiesType();
|
||||
_frameUpdateSystem.Add(entitiesType, iFrameUpdateSystem);
|
||||
entitiesType = iLateUpdateSystem.EntitiesType();
|
||||
_lateUpdateSystems.Add(entitiesType, iLateUpdateSystem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
Log.Error($"IEntitiesSystem not support type {entitiesSystemType}");
|
||||
@@ -220,10 +226,12 @@ namespace Fantasy.Entitas
|
||||
_awakeSystems.Remove(type);
|
||||
_updateSystems.Remove(type);
|
||||
_destroySystems.Remove(type);
|
||||
#if FANTASY_UNITY
|
||||
_lateUpdateSystems.Remove(type);
|
||||
#endif
|
||||
_deserializeSystems.Remove(type);
|
||||
_frameUpdateSystem.Remove(type);
|
||||
}
|
||||
|
||||
|
||||
_assemblyList.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
@@ -333,7 +341,7 @@ namespace Fantasy.Entitas
|
||||
#region Update
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入更新队列,准备进行更新
|
||||
/// 将实体加入Update队列,准备进行Update
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StartUpdate(Entity entity)
|
||||
@@ -341,21 +349,18 @@ namespace Fantasy.Entitas
|
||||
var type = entity.Type;
|
||||
var entityRuntimeId = entity.RuntimeId;
|
||||
|
||||
if (_updateSystems.ContainsKey(type))
|
||||
if (!_updateSystems.ContainsKey(type))
|
||||
{
|
||||
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
|
||||
_updateQueue.Enqueue(updateQueueInfo);
|
||||
_updateQueueDic.Add(entityRuntimeId, updateQueueInfo);
|
||||
}
|
||||
|
||||
if (_frameUpdateSystem.ContainsKey(type))
|
||||
{
|
||||
_frameUpdateQueue.Enqueue(new FrameUpdateQueueInfo(type, entityRuntimeId));
|
||||
return;
|
||||
}
|
||||
|
||||
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
|
||||
_updateQueue.Enqueue(updateQueueInfo);
|
||||
_updateQueueDic.Add(entityRuntimeId, updateQueueInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止实体进行更新
|
||||
/// 停止实体Update
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StopUpdate(Entity entity)
|
||||
@@ -369,7 +374,7 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行实体系统的更新逻辑
|
||||
/// 执行实体系统的Update
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
@@ -410,44 +415,84 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行实体系统的帧更新逻辑
|
||||
/// </summary>
|
||||
public void FrameUpdate()
|
||||
{
|
||||
var count = _frameUpdateQueue.Count;
|
||||
#endregion
|
||||
|
||||
while (count-- > 0)
|
||||
#if FANTASY_UNITY
|
||||
#region LateUpdate
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入LateUpdate队列,准备进行LateUpdate
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StartLateUpdate(Entity entity)
|
||||
{
|
||||
var type = entity.Type;
|
||||
var entityRuntimeId = entity.RuntimeId;
|
||||
|
||||
if (!_lateUpdateSystems.ContainsKey(type))
|
||||
{
|
||||
var frameUpdateQueueStruct = _frameUpdateQueue.Dequeue();
|
||||
|
||||
if (!_frameUpdateSystem.TryGetValue(frameUpdateQueueStruct.Type, out var frameUpdateSystem))
|
||||
return;
|
||||
}
|
||||
|
||||
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
|
||||
_lateUpdateQueue.Enqueue(updateQueueInfo);
|
||||
_lateUpdateQueueDic.Add(entityRuntimeId, updateQueueInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止实体进行LateUpdate
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StopLateUpdate(Entity entity)
|
||||
{
|
||||
if (!_lateUpdateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateQueueInfo.IsStop = true;
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
var lateUpdateQueue = _lateUpdateQueue.Count;
|
||||
|
||||
while (lateUpdateQueue-- > 0)
|
||||
{
|
||||
var lateUpdateQueueStruct = _lateUpdateQueue.Dequeue();
|
||||
|
||||
if (lateUpdateQueueStruct.IsStop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = Scene.GetEntity(frameUpdateQueueStruct.RunTimeId);
|
||||
|
||||
if (!_lateUpdateSystems.TryGetValue(lateUpdateQueueStruct.Type, out var lateUpdateSystem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = Scene.GetEntity(lateUpdateQueueStruct.RunTimeId);
|
||||
|
||||
if (entity == null || entity.IsDisposed)
|
||||
{
|
||||
_lateUpdateQueueDic.Remove(lateUpdateQueueStruct.RunTimeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
_frameUpdateQueue.Enqueue(frameUpdateQueueStruct);
|
||||
|
||||
|
||||
_lateUpdateQueue.Enqueue(lateUpdateQueueStruct);
|
||||
|
||||
try
|
||||
{
|
||||
frameUpdateSystem.Invoke(entity);
|
||||
lateUpdateSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{frameUpdateQueueStruct.Type.FullName} FrameUpdate Error {e}");
|
||||
Log.Error($"{lateUpdateQueueStruct.Type.FullName} Update Error {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
public long GetHashCode(Type type)
|
||||
{
|
||||
return _hashCodes[type];
|
||||
@@ -459,14 +504,17 @@ namespace Fantasy.Entitas
|
||||
public override void Dispose()
|
||||
{
|
||||
_updateQueue.Clear();
|
||||
_frameUpdateQueue.Clear();
|
||||
|
||||
_updateQueueDic.Clear();
|
||||
#if FANTASY_UNITY
|
||||
_lateUpdateQueue.Clear();
|
||||
_lateUpdateQueueDic.Clear();
|
||||
_lateUpdateSystems.Clear();
|
||||
#endif
|
||||
_assemblyList.Clear();
|
||||
_awakeSystems.Clear();
|
||||
_updateSystems.Clear();
|
||||
_destroySystems.Clear();
|
||||
_deserializeSystems.Clear();
|
||||
_frameUpdateSystem.Clear();
|
||||
|
||||
AssemblySystem.UnRegister(this);
|
||||
base.Dispose();
|
||||
|
||||
@@ -169,6 +169,9 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
}
|
||||
|
||||
return entity;
|
||||
@@ -210,6 +213,9 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
}
|
||||
|
||||
return entity;
|
||||
@@ -232,6 +238,9 @@ namespace Fantasy.Entitas
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -248,6 +257,9 @@ namespace Fantasy.Entitas
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -406,6 +418,9 @@ namespace Fantasy.Entitas
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
#if FANTASY_UNITY
|
||||
using System;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
internal interface IFrameUpdateSystem : IEntitiesSystem { }
|
||||
internal interface ILateUpdateSystem : IEntitiesSystem { }
|
||||
|
||||
/// <summary>
|
||||
/// 帧更新时间的抽象接口
|
||||
/// 实体的LateUpdate事件的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class FrameUpdateSystem<T> : IFrameUpdateSystem where T : Entity
|
||||
/// <typeparam name="T">实体的泛型类型</typeparam>
|
||||
public abstract class LateUpdateSystem<T> : ILateUpdateSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void FrameUpdate(T self);
|
||||
protected abstract void LateUpdate(T self);
|
||||
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发FrameUpdate的方法
|
||||
/// 框架内部调用的触发Awake的方法。
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
FrameUpdate((T) self);
|
||||
LateUpdate((T)self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ namespace Fantasy.Helper
|
||||
public static string FileMD5(FileStream fileStream)
|
||||
{
|
||||
var md5 = MD5.Create();
|
||||
return md5.ComputeHash(fileStream).ToHex("x2");
|
||||
return md5.ComputeHash(fileStream).ToHex(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,7 +57,7 @@ namespace Fantasy.Helper
|
||||
{
|
||||
var md5 = MD5.Create();
|
||||
bytes = md5.ComputeHash(bytes);
|
||||
return bytes.ToHex("x2");
|
||||
return bytes.ToHex(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -17,7 +18,7 @@ namespace Fantasy.Helper
|
||||
/// <returns>完整路径。</returns>
|
||||
public static string GetFullPath(string relativePath)
|
||||
{
|
||||
return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath));
|
||||
return Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, relativePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Fantasy.Helper
|
||||
@@ -9,8 +10,6 @@ namespace Fantasy.Helper
|
||||
/// </summary>
|
||||
public static partial class HashCodeHelper
|
||||
{
|
||||
private static readonly SHA256 Sha256Hash = SHA256.Create();
|
||||
|
||||
/// <summary>
|
||||
/// 计算两个字符串的HashCode
|
||||
/// </summary>
|
||||
@@ -24,112 +23,7 @@ namespace Fantasy.Helper
|
||||
hash = hash * 31 + b.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
#if FANTASY_NET || !FANTASY_WEBGL
|
||||
/// <summary>
|
||||
/// 使用bkdr算法生成一个long的值
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static unsafe long GetBKDRHashCode(string str)
|
||||
{
|
||||
ulong hash = 0;
|
||||
// 如果要修改这个种子、建议选择一个质数来做种子
|
||||
const uint seed = 13131; // 31 131 1313 13131 131313 etc..
|
||||
fixed (char* p = str)
|
||||
{
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
var c = p[i];
|
||||
var high = (byte)(c >> 8);
|
||||
var low = (byte)(c & byte.MaxValue);
|
||||
hash = hash * seed + high;
|
||||
hash = hash * seed + low;
|
||||
}
|
||||
}
|
||||
return (long)hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用MurmurHash3算法生成一个uint的值
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static unsafe uint MurmurHash3(string str)
|
||||
{
|
||||
const uint seed = 0xc58f1a7b;
|
||||
uint hash = seed;
|
||||
uint c1 = 0xcc9e2d51;
|
||||
uint c2 = 0x1b873593;
|
||||
|
||||
fixed (char* p = str)
|
||||
{
|
||||
var current = p;
|
||||
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
var k1 = (uint)(*current);
|
||||
k1 *= c1;
|
||||
k1 = (k1 << 15) | (k1 >> (32 - 15));
|
||||
k1 *= c2;
|
||||
|
||||
hash ^= k1;
|
||||
hash = (hash << 13) | (hash >> (32 - 13));
|
||||
hash = hash * 5 + 0xe6546b64;
|
||||
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
hash ^= (uint)str.Length;
|
||||
hash ^= hash >> 16;
|
||||
hash *= 0x85ebca6b;
|
||||
hash ^= hash >> 13;
|
||||
hash *= 0xc2b2ae35;
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用MurmurHash3算法生成一个long的值
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static unsafe long ComputeHash64(string str)
|
||||
{
|
||||
const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed
|
||||
var hash = seed;
|
||||
var c1 = 0x87c37b91114253d5UL;
|
||||
var c2 = 0x4cf5ad432745937fUL;
|
||||
|
||||
fixed (char* p = str)
|
||||
{
|
||||
var current = p;
|
||||
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
var k1 = (ulong)(*current);
|
||||
k1 *= c1;
|
||||
k1 = (k1 << 31) | (k1 >> (64 - 31));
|
||||
k1 *= c2;
|
||||
|
||||
hash ^= k1;
|
||||
hash = (hash << 27) | (hash >> (64 - 27));
|
||||
hash = hash * 5 + 0x52dce729;
|
||||
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
hash ^= (ulong)str.Length;
|
||||
hash ^= hash >> 33;
|
||||
hash *= 0xff51afd7ed558ccdUL;
|
||||
hash ^= hash >> 33;
|
||||
hash *= 0xc4ceb9fe1a85ec53UL;
|
||||
hash ^= hash >> 33;
|
||||
return (long)hash;
|
||||
}
|
||||
#endif
|
||||
#if FANTASY_WEBGL
|
||||
/// <summary>
|
||||
/// 使用bkdr算法生成一个long的值
|
||||
/// </summary>
|
||||
@@ -137,18 +31,23 @@ namespace Fantasy.Helper
|
||||
/// <returns></returns>
|
||||
public static long GetBKDRHashCode(string str)
|
||||
{
|
||||
long hash = 0;
|
||||
// 如果要修改这个种子、建议选择一个质数来做种子
|
||||
const uint seed = 13131; // 31 131 1313 13131 131313 etc..
|
||||
foreach (var c in str)
|
||||
ulong hash = 0;
|
||||
const uint seed = 13131; // 如果要修改这个种子、建议选择一个质数来做种子 31 131 1313 13131 131313 etc..
|
||||
var span = str.AsSpan();
|
||||
ref var local = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
for (var i = 0; i < span.Length; i++)
|
||||
{
|
||||
var c = Unsafe.Add(ref local, i);
|
||||
var high = (byte)(c >> 8);
|
||||
var low = (byte)(c & byte.MaxValue);
|
||||
hash = hash * seed + high;
|
||||
hash = hash * seed + low;
|
||||
}
|
||||
return hash;
|
||||
|
||||
return (long)hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用MurmurHash3算法生成一个uint的值
|
||||
/// </summary>
|
||||
@@ -160,10 +59,13 @@ namespace Fantasy.Helper
|
||||
uint hash = seed;
|
||||
uint c1 = 0xcc9e2d51;
|
||||
uint c2 = 0x1b873593;
|
||||
|
||||
foreach (var t in str)
|
||||
|
||||
var span = str.AsSpan();
|
||||
ref var local = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
for (var i = 0; i < span.Length; i++)
|
||||
{
|
||||
var k1 = (uint)(t);
|
||||
var k1 = (uint)Unsafe.Add(ref local, i);
|
||||
k1 *= c1;
|
||||
k1 = (k1 << 15) | (k1 >> (32 - 15));
|
||||
k1 *= c2;
|
||||
@@ -181,7 +83,7 @@ namespace Fantasy.Helper
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 使用MurmurHash3算法生成一个long的值
|
||||
/// </summary>
|
||||
@@ -193,10 +95,13 @@ namespace Fantasy.Helper
|
||||
var hash = seed;
|
||||
var c1 = 0x87c37b91114253d5UL;
|
||||
var c2 = 0x4cf5ad432745937fUL;
|
||||
|
||||
foreach (var t in str)
|
||||
|
||||
var span = str.AsSpan();
|
||||
ref var local = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
for (var i = 0; i < span.Length; i++)
|
||||
{
|
||||
var k1 = (ulong)(t);
|
||||
var k1 = (ulong)Unsafe.Add(ref local, i);
|
||||
k1 *= c1;
|
||||
k1 = (k1 << 31) | (k1 >> (64 - 31));
|
||||
k1 *= c2;
|
||||
@@ -214,16 +119,218 @@ namespace Fantasy.Helper
|
||||
hash ^= hash >> 33;
|
||||
return (long)hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 根据字符串计算一个Hash值
|
||||
/// </summary>
|
||||
/// <param name="rawData"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="seed"></param>
|
||||
/// <returns></returns>
|
||||
public static int ComputeSha256HashAsInt(string rawData)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32(string obj, uint seed = 0) => Hash32(obj.AsSpan(), seed);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字符串计算一个Hash值
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="seed"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32<T>(in T obj, uint seed = 0) where T : unmanaged => Hash32(
|
||||
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()),
|
||||
seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int Hash32<T>(ReadOnlySpan<T> buffer, uint seed = 0) where T : unmanaged =>
|
||||
Hash32(MemoryMarshal.Cast<T, byte>(buffer), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int Hash32(ReadOnlySpan<byte> buffer, uint seed = 0)
|
||||
{
|
||||
var bytes = Sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
|
||||
return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
|
||||
int length = buffer.Length;
|
||||
ref byte local1 = ref MemoryMarshal.GetReference(buffer);
|
||||
uint num1;
|
||||
if (buffer.Length >= 16)
|
||||
{
|
||||
uint num2 = seed + 606290984U;
|
||||
uint num3 = seed + 2246822519U;
|
||||
uint num4 = seed;
|
||||
uint num5 = seed - 2654435761U;
|
||||
for (; length >= 16; length -= 16)
|
||||
{
|
||||
const nint elementOffset1 = 4;
|
||||
const nint elementOffset2 = 8;
|
||||
const nint elementOffset3 = 12;
|
||||
nint byteOffset = buffer.Length - length;
|
||||
ref byte local2 = ref Unsafe.AddByteOffset(ref local1, byteOffset);
|
||||
uint num6 = num2 + Unsafe.ReadUnaligned<uint>(ref local2) * 2246822519U;
|
||||
num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535);
|
||||
uint num7 = num3 +
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) *
|
||||
2246822519U;
|
||||
num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535);
|
||||
uint num8 = num4 +
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) *
|
||||
2246822519U;
|
||||
num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535);
|
||||
uint num9 = num5 +
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset3)) *
|
||||
2246822519U;
|
||||
num5 = (uint)((((int)num9 << 13) | (int)(num9 >> 19)) * -1640531535);
|
||||
}
|
||||
|
||||
num1 = (uint)((((int)num2 << 1) | (int)(num2 >> 31)) + (((int)num3 << 7) | (int)(num3 >> 25)) +
|
||||
(((int)num4 << 12) | (int)(num4 >> 20)) + (((int)num5 << 18) | (int)(num5 >> 14)) +
|
||||
buffer.Length);
|
||||
}
|
||||
else
|
||||
num1 = (uint)((int)seed + 374761393 + buffer.Length);
|
||||
|
||||
for (; length >= 4; length -= 4)
|
||||
{
|
||||
nint byteOffset = buffer.Length - length;
|
||||
uint num10 = Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local1, byteOffset));
|
||||
uint num11 = num1 + num10 * 3266489917U;
|
||||
num1 = (uint)((((int)num11 << 17) | (int)(num11 >> 15)) * 668265263);
|
||||
}
|
||||
|
||||
nint byteOffset1 = buffer.Length - length;
|
||||
ref byte local3 = ref Unsafe.AddByteOffset(ref local1, byteOffset1);
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
nint byteOffset2 = index;
|
||||
uint num12 = Unsafe.AddByteOffset(ref local3, byteOffset2);
|
||||
uint num13 = num1 + num12 * 374761393U;
|
||||
num1 = (uint)((((int)num13 << 11) | (int)(num13 >> 21)) * -1640531535);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777;
|
||||
int num15 = (num14 ^ (num14 >>> 13)) * -1028477379;
|
||||
return num15 ^ (num15 >>> 16);
|
||||
#else
|
||||
int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777;
|
||||
int num15 = (num14 ^ (int)((uint)num14 >> 13)) * -1028477379;
|
||||
return num15 ^ (int)((uint)num15 >> 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据字符串计算一个Hash值
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="seed"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64(string obj, ulong seed = 0) => Hash64(obj.AsSpan(), seed);
|
||||
|
||||
/// <summary>
|
||||
/// 根据字符串计算一个Hash值
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="seed"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64<T>(in T obj, ulong seed = 0) where T : unmanaged => Hash64(
|
||||
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()),
|
||||
seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static long Hash64<T>(ReadOnlySpan<T> buffer, ulong seed = 0) where T : unmanaged =>
|
||||
Hash64(MemoryMarshal.Cast<T, byte>(buffer), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static long Hash64(ReadOnlySpan<byte> buffer, ulong seed = 0)
|
||||
{
|
||||
ref var local1 = ref MemoryMarshal.GetReference(buffer);
|
||||
var length = buffer.Length;
|
||||
ulong num1;
|
||||
if (buffer.Length >= 32)
|
||||
{
|
||||
var num2 = seed + 6983438078262162902UL;
|
||||
var num3 = seed + 14029467366897019727UL;
|
||||
var num4 = seed;
|
||||
var num5 = seed - 11400714785074694791UL;
|
||||
for (; length >= 32; length -= 32)
|
||||
{
|
||||
ref var local2 = ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length));
|
||||
var num6 = num2 + Unsafe.ReadUnaligned<ulong>(ref local2) * 14029467366897019727UL;
|
||||
num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L);
|
||||
var num7 = num3 +
|
||||
Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) *
|
||||
14029467366897019727UL;
|
||||
num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L);
|
||||
var num8 = num4 +
|
||||
Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) *
|
||||
14029467366897019727UL;
|
||||
num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L);
|
||||
var num9 = num5 +
|
||||
Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(24U))) *
|
||||
14029467366897019727UL;
|
||||
num5 = (ulong)((((long)num9 << 31) | (long)(num9 >> 33)) * -7046029288634856825L);
|
||||
}
|
||||
|
||||
var num10 = (((long)num2 << 1) | (long)(num2 >> 63)) + (((long)num3 << 7) | (long)(num3 >> 57)) +
|
||||
(((long)num4 << 12) | (long)(num4 >> 52)) + (((long)num5 << 18) | (long)(num5 >> 46));
|
||||
var num11 = num2 * 14029467366897019727UL;
|
||||
var num12 = (((long)num11 << 31) | (long)(num11 >> 33)) * -7046029288634856825L;
|
||||
var num13 = (num10 ^ num12) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num14 = num3 * 14029467366897019727UL;
|
||||
var num15 = (((long)num14 << 31) | (long)(num14 >> 33)) * -7046029288634856825L;
|
||||
var num16 = (num13 ^ num15) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num17 = num4 * 14029467366897019727UL;
|
||||
var num18 = (((long)num17 << 31) | (long)(num17 >> 33)) * -7046029288634856825L;
|
||||
var num19 = (num16 ^ num18) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num20 = num5 * 14029467366897019727UL;
|
||||
var num21 = (((long)num20 << 31) | (long)(num20 >> 33)) * -7046029288634856825L;
|
||||
num1 = (ulong)((num19 ^ num21) * -7046029288634856825L + -8796714831421723037L);
|
||||
}
|
||||
else
|
||||
num1 = seed + 2870177450012600261UL;
|
||||
|
||||
var num22 = num1 + (ulong)buffer.Length;
|
||||
for (; length >= 8; length -= 8)
|
||||
{
|
||||
var num23 = Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local1,
|
||||
(IntPtr)(buffer.Length - length))) * 14029467366897019727UL;
|
||||
var num24 = (ulong)((((long)num23 << 31) | (long)(num23 >> 33)) * -7046029288634856825L);
|
||||
var num25 = num22 ^ num24;
|
||||
num22 = (ulong)((((long)num25 << 27) | (long)(num25 >> 37)) * -7046029288634856825L +
|
||||
-8796714831421723037L);
|
||||
}
|
||||
|
||||
if (length >= 4)
|
||||
{
|
||||
ulong num26 =
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)));
|
||||
var num27 = num22 ^ (num26 * 11400714785074694791UL);
|
||||
num22 = (ulong)((((long)num27 << 23) | (long)(num27 >> 41)) * -4417276706812531889L +
|
||||
1609587929392839161L);
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
for (var byteOffset = 0; byteOffset < length; ++byteOffset)
|
||||
{
|
||||
ulong num28 =
|
||||
Unsafe.AddByteOffset(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)),
|
||||
(IntPtr)byteOffset);
|
||||
var num29 = num22 ^ (num28 * 2870177450012600261UL);
|
||||
num22 = (ulong)((((long)num29 << 11) | (long)(num29 >> 53)) * -7046029288634856825L);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
var num30 = (long)num22;
|
||||
var num31 = (num30 ^ (num30 >>> 33)) * -4417276706812531889L;
|
||||
var num32 = (num31 ^ (num31 >>> 29)) * 1609587929392839161L;
|
||||
return num32 ^ (num32 >>> 32);
|
||||
#else
|
||||
var num30 = (long)num22;
|
||||
var num31 = (num30 ^ (long)((ulong)num30 >> 33)) * -4417276706812531889L;
|
||||
var num32 = (num31 ^ (long)((ulong)num31 >> 29)) * 1609587929392839161L;
|
||||
return num32 ^ (long)((ulong)num32 >> 32);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ namespace Fantasy.Helper
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 克隆一个IPEndPoint
|
||||
/// </summary>
|
||||
@@ -66,7 +66,7 @@ namespace Fantasy.Helper
|
||||
var ip = (IPEndPoint)endPoint;
|
||||
return new IPEndPoint(ip.Address, ip.Port);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个IPEndPoint是否相等
|
||||
/// </summary>
|
||||
@@ -79,7 +79,7 @@ namespace Fantasy.Helper
|
||||
var ip = (IPEndPoint)endPoint;
|
||||
return ip.Address.Equals(ipEndPoint.Address) && ip.Port == ipEndPoint.Port;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个IPEndPoint是否相等
|
||||
/// </summary>
|
||||
@@ -91,7 +91,6 @@ namespace Fantasy.Helper
|
||||
{
|
||||
return endPoint.Address.Equals(ipEndPoint.Address) && endPoint.Port == ipEndPoint.Port;
|
||||
}
|
||||
|
||||
#if !FANTASY_WEBGL
|
||||
/// <summary>
|
||||
/// 将SocketAddress写入到Byte[]中
|
||||
@@ -100,13 +99,13 @@ namespace Fantasy.Helper
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset)
|
||||
public static void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset)
|
||||
{
|
||||
if (socketAddress == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(socketAddress), "The SocketAddress cannot be null.");
|
||||
}
|
||||
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null.");
|
||||
@@ -114,20 +113,21 @@ namespace Fantasy.Helper
|
||||
|
||||
if (buffer.Length < socketAddress.Size + offset + 8)
|
||||
{
|
||||
throw new ArgumentException("The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.", nameof(buffer));
|
||||
throw new ArgumentException(
|
||||
"The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.",
|
||||
nameof(buffer));
|
||||
}
|
||||
|
||||
fixed (byte* pBuffer = buffer)
|
||||
|
||||
var span = buffer.AsSpan(offset);
|
||||
var addressFamilyValue = (int)socketAddress.Family;
|
||||
var socketAddressSizeValue = socketAddress.Size;
|
||||
|
||||
Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(span), addressFamilyValue);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), 4), socketAddressSizeValue);
|
||||
|
||||
for (var i = 0; i < socketAddress.Size - 2; i++)
|
||||
{
|
||||
var pOffsetBuffer = pBuffer + offset;
|
||||
var addressFamilyValue = (int)socketAddress.Family;
|
||||
var socketAddressSizeValue = socketAddress.Size;
|
||||
Buffer.MemoryCopy(&addressFamilyValue, pOffsetBuffer, buffer.Length - offset, sizeof(int));
|
||||
Buffer.MemoryCopy(&socketAddressSizeValue, pOffsetBuffer + 4, buffer.Length - offset -4, sizeof(int));
|
||||
for (var i = 0; i < socketAddress.Size - 2; i++)
|
||||
{
|
||||
pOffsetBuffer[8 + i] = socketAddress[i + 2];
|
||||
}
|
||||
Unsafe.Add(ref MemoryMarshal.GetReference(span), 8 + i) = socketAddress[i + 2];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,40 +141,41 @@ namespace Fantasy.Helper
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress)
|
||||
public static int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null.");
|
||||
}
|
||||
|
||||
|
||||
if (buffer.Length < 8)
|
||||
{
|
||||
throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer));
|
||||
throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.",
|
||||
nameof(buffer));
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
fixed (byte* pBuffer = buffer)
|
||||
var span = buffer.AsSpan(offset);
|
||||
ref var spanRef = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
var addressFamily = (AddressFamily)Unsafe.ReadUnaligned<int>(ref spanRef);
|
||||
var socketAddressSize = Unsafe.ReadUnaligned<int>(ref Unsafe.Add(ref spanRef, 4));
|
||||
|
||||
if (buffer.Length < offset + 8 + socketAddressSize)
|
||||
{
|
||||
var pOffsetBuffer = pBuffer + offset;
|
||||
var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer);
|
||||
var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4));
|
||||
|
||||
if (buffer.Length < offset + 8 + socketAddressSize)
|
||||
{
|
||||
throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer));
|
||||
}
|
||||
|
||||
socketAddress = new SocketAddress(addressFamily, socketAddressSize);
|
||||
|
||||
for (var i = 0; i < socketAddressSize - 2; i++)
|
||||
{
|
||||
socketAddress[i + 2] = *(pOffsetBuffer + 8 + i);
|
||||
}
|
||||
|
||||
return 8 + offset + socketAddressSize;
|
||||
throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.",
|
||||
nameof(buffer));
|
||||
}
|
||||
|
||||
socketAddress = new SocketAddress(addressFamily, socketAddressSize);
|
||||
|
||||
for (var i = 0; i < socketAddressSize - 2; i++)
|
||||
{
|
||||
socketAddress[i + 2] = Unsafe.Add(ref spanRef, 8 + i);
|
||||
}
|
||||
|
||||
return 8 + offset + socketAddressSize;
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
@@ -199,35 +200,36 @@ namespace Fantasy.Helper
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe int ByteToSocketAddress(ReadOnlyMemory<byte> buffer, int offset, out SocketAddress socketAddress)
|
||||
public static int ByteToSocketAddress(ReadOnlyMemory<byte> buffer, int offset, out SocketAddress socketAddress)
|
||||
{
|
||||
if (buffer.Length < 8)
|
||||
{
|
||||
throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer));
|
||||
throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.",
|
||||
nameof(buffer));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fixed (byte* pBuffer = buffer.Span)
|
||||
var span = buffer.Span.Slice(offset);
|
||||
ref var spanRef = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
var addressFamily = (AddressFamily)Unsafe.ReadUnaligned<int>(ref spanRef);
|
||||
var socketAddressSize = Unsafe.ReadUnaligned<int>(ref Unsafe.Add(ref spanRef, 4));
|
||||
|
||||
if (buffer.Length < offset + 8 + socketAddressSize)
|
||||
{
|
||||
var pOffsetBuffer = pBuffer + offset;
|
||||
var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer);
|
||||
var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4));
|
||||
|
||||
if (buffer.Length < offset + 8 + socketAddressSize)
|
||||
{
|
||||
throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer));
|
||||
}
|
||||
|
||||
socketAddress = new SocketAddress(addressFamily, socketAddressSize);
|
||||
|
||||
for (var i = 0; i < socketAddressSize - 2; i++)
|
||||
{
|
||||
socketAddress[i + 2] = *(pOffsetBuffer + 8 + i);
|
||||
}
|
||||
|
||||
return 8 + offset + socketAddressSize;
|
||||
throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.",
|
||||
nameof(buffer));
|
||||
}
|
||||
|
||||
socketAddress = new SocketAddress(addressFamily, socketAddressSize);
|
||||
|
||||
for (var i = 0; i < socketAddressSize - 2; i++)
|
||||
{
|
||||
socketAddress[i + 2] = Unsafe.Add(ref spanRef, 8 + i);
|
||||
}
|
||||
|
||||
return 8 + offset + socketAddressSize;
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
@@ -249,7 +251,7 @@ namespace Fantasy.Helper
|
||||
/// <param name="socketAddress"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static unsafe IPEndPoint GetIPEndPoint(this SocketAddress socketAddress)
|
||||
public static IPEndPoint GetIPEndPoint(this SocketAddress socketAddress)
|
||||
{
|
||||
switch (socketAddress.Family)
|
||||
{
|
||||
@@ -260,6 +262,7 @@ namespace Fantasy.Helper
|
||||
{
|
||||
ipBytes[i] = socketAddress[4 + i];
|
||||
}
|
||||
|
||||
var port = (socketAddress[2] << 8) + socketAddress[3];
|
||||
var ip = new IPAddress(ipBytes);
|
||||
return new IPEndPoint(ip, port);
|
||||
@@ -268,24 +271,23 @@ namespace Fantasy.Helper
|
||||
{
|
||||
var ipBytes = new byte[16];
|
||||
Span<byte> socketAddressSpan = stackalloc byte[28];
|
||||
|
||||
|
||||
for (var i = 0; i < 28; i++)
|
||||
{
|
||||
socketAddressSpan[i] = socketAddress[i];
|
||||
}
|
||||
|
||||
fixed (byte* pSocketAddress = socketAddressSpan)
|
||||
|
||||
ref var spanRef = ref MemoryMarshal.GetReference(socketAddressSpan);
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
ipBytes[i] = *(pSocketAddress + 8 + i);
|
||||
}
|
||||
|
||||
var port = (*(pSocketAddress + 2) << 8) + *(pSocketAddress + 3);
|
||||
var scopeId = Marshal.ReadInt64((IntPtr)(pSocketAddress + 24));
|
||||
var ip = new IPAddress(ipBytes, scopeId);
|
||||
return new IPEndPoint(ip, port);
|
||||
ipBytes[i] = Unsafe.Add(ref spanRef, 8 + i);
|
||||
}
|
||||
|
||||
var port = (Unsafe.Add(ref spanRef, 2) << 8) + Unsafe.Add(ref spanRef, 3);
|
||||
var scopeId = Unsafe.ReadUnaligned<long>(ref Unsafe.Add(ref spanRef, 24));
|
||||
var ip = new IPAddress(ipBytes, scopeId);
|
||||
return new IPEndPoint(ip, port);
|
||||
}
|
||||
default:
|
||||
{
|
||||
@@ -308,13 +310,13 @@ namespace Fantasy.Helper
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
foreach (var add in networkInterface.GetIPProperties().UnicastAddresses)
|
||||
{
|
||||
list.Add(add.Address.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
@@ -363,7 +365,7 @@ namespace Fantasy.Helper
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
目前这个问题只有Windows下才会出现。
|
||||
服务器端在发送数据时捕获到了一个异常,
|
||||
@@ -374,11 +376,11 @@ namespace Fantasy.Helper
|
||||
想详细了解看下https://blog.csdn.net/sunzhen6251/article/details/124168805*/
|
||||
const uint IOC_IN = 0x80000000;
|
||||
const uint IOC_VENDOR = 0x18000000;
|
||||
const int SIO_UDP_CONNRESET = unchecked((int) (IOC_IN | IOC_VENDOR | 12));
|
||||
|
||||
socket.IOControl(SIO_UDP_CONNRESET, new[] {Convert.ToByte(false)}, null);
|
||||
const int SIO_UDP_CONNRESET = unchecked((int)(IOC_IN | IOC_VENDOR | 12));
|
||||
|
||||
socket.IOControl(SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将 Socket 缓冲区大小设置为操作系统限制。
|
||||
/// </summary>
|
||||
@@ -440,4 +442,4 @@ namespace Fantasy.Helper
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Fantasy.LowLevel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
namespace Fantasy.Helper
|
||||
@@ -307,5 +309,107 @@ namespace Fantasy.Helper
|
||||
return num.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#region FixedBytes
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes1
|
||||
{
|
||||
private byte _e0;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes2
|
||||
{
|
||||
private FixedBytes1 _e0;
|
||||
private FixedBytes1 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes2, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes2>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes4
|
||||
{
|
||||
private FixedBytes2 _e0;
|
||||
private FixedBytes2 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes4, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes4>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes8
|
||||
{
|
||||
private FixedBytes4 _e0;
|
||||
private FixedBytes4 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes8, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes8>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes16
|
||||
{
|
||||
private FixedBytes8 _e0;
|
||||
private FixedBytes8 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes16, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes16>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes32
|
||||
{
|
||||
private FixedBytes16 _e0;
|
||||
private FixedBytes16 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes32, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes32>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes64
|
||||
{
|
||||
private FixedBytes32 _e0;
|
||||
private FixedBytes32 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes64, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes64>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes128
|
||||
{
|
||||
private FixedBytes64 _e0;
|
||||
private FixedBytes64 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes128, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes128>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes256
|
||||
{
|
||||
private FixedBytes128 _e0;
|
||||
private FixedBytes128 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes256, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes256>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes512
|
||||
{
|
||||
private FixedBytes256 _e0;
|
||||
private FixedBytes256 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes512, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes512>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes1024
|
||||
{
|
||||
private FixedBytes512 _e0;
|
||||
private FixedBytes512 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1024, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1024>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
@@ -47,6 +47,15 @@ namespace Fantasy.IdFactory
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得当前的IdFactoryType
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IdFactoryType GetIdFactoryType()
|
||||
{
|
||||
return _idFactoryType;
|
||||
}
|
||||
|
||||
internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
|
||||
@@ -27,23 +27,7 @@ namespace Fantasy
|
||||
return;
|
||||
}
|
||||
|
||||
var processMode = ProcessMode.None;
|
||||
|
||||
switch (ProcessDefine.Options.Mode)
|
||||
{
|
||||
case "Develop":
|
||||
{
|
||||
processMode = ProcessMode.Develop;
|
||||
break;
|
||||
}
|
||||
case "Release":
|
||||
{
|
||||
processMode = ProcessMode.Release;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_logCore.Initialize(processMode);
|
||||
_logCore.Initialize(ProgramDefine.RuntimeMode);
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
#if FANTASY_NET
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using mimalloc;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#endif
|
||||
|
||||
namespace Fantasy.LowLevel
|
||||
{
|
||||
public static unsafe class FantasyMemory
|
||||
{
|
||||
private static delegate* managed<nuint, void*> _alloc;
|
||||
private static delegate* managed<nuint, void*> _allocZeroed;
|
||||
private static delegate* managed<void*, void> _free;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Initialize()
|
||||
{
|
||||
// KCP 使用 FantasyMemory
|
||||
kcp.KCP.ikcp_allocator(&Alloc, &Free);
|
||||
|
||||
try
|
||||
{
|
||||
_ = MiMalloc.mi_version();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Info("mimalloc的二进制文件丢失");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ptr = MiMalloc.mi_malloc(MiMalloc.MI_SMALL_SIZE_MAX);
|
||||
MiMalloc.mi_free(ptr);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Info("mimalloc权限不足,\r\n可能的问题:\r\n1. 禁止了虚拟内存分配 -> 允许虚拟内存分配;\r\n2. 没有硬盘读写权限 -> 管理员获取所有权限");
|
||||
return;
|
||||
}
|
||||
|
||||
Custom(&MiAlloc, &MiAllocZeroed, &MiFree);
|
||||
|
||||
return;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void* MiAlloc(nuint size) => MiMalloc.mi_malloc(size);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void* MiAllocZeroed(nuint size)
|
||||
{
|
||||
var ptr = MiAlloc(size);
|
||||
Unsafe.InitBlockUnaligned(ptr, 0, (uint)size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void MiFree(void* ptr) => MiMalloc.mi_free(ptr);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Custom(delegate*<nuint, void*> alloc, delegate*<nuint, void*> allocZeroed, delegate*<void*, void> free)
|
||||
{
|
||||
_alloc = alloc;
|
||||
_allocZeroed = allocZeroed;
|
||||
_free = free;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static nuint Align(nuint size) => AlignUp(size, (nuint)sizeof(nint));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static nuint AlignUp(nuint size, nuint alignment) => (size + (alignment - 1)) & ~(alignment - 1);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static nuint AlignDown(nuint size, nuint alignment) => size - (size & (alignment - 1));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void* Alloc(nuint byteCount)
|
||||
{
|
||||
if (_alloc != null)
|
||||
return _alloc(byteCount);
|
||||
#if NET6_0_OR_GREATER
|
||||
return NativeMemory.Alloc(byteCount);
|
||||
#else
|
||||
return (void*)Marshal.AllocHGlobal((nint)byteCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void* AllocZeroed(nuint byteCount)
|
||||
{
|
||||
if (_allocZeroed != null)
|
||||
return _allocZeroed(byteCount);
|
||||
void* ptr;
|
||||
if (_alloc != null)
|
||||
{
|
||||
ptr = _alloc(byteCount);
|
||||
Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteCount);
|
||||
return ptr;
|
||||
}
|
||||
#if NET6_0_OR_GREATER
|
||||
return NativeMemory.AllocZeroed(byteCount, 1);
|
||||
#else
|
||||
ptr = (void*)Marshal.AllocHGlobal((nint)byteCount);
|
||||
Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteCount);
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Free(void* ptr)
|
||||
{
|
||||
if (_free != null)
|
||||
{
|
||||
_free(ptr);
|
||||
return;
|
||||
}
|
||||
#if NET6_0_OR_GREATER
|
||||
NativeMemory.Free(ptr);
|
||||
#else
|
||||
Marshal.FreeHGlobal((nint)ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Copy(void* destination, void* source, nuint byteCount) => Unsafe.CopyBlockUnaligned(destination, source, (uint)byteCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Move(void* destination, void* source, nuint byteCount) => Buffer.MemoryCopy(source, destination, byteCount, byteCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set(void* startAddress, byte value, nuint byteCount) => Unsafe.InitBlockUnaligned(startAddress, value, (uint)byteCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Compare(void* left, void* right, nuint byteCount)
|
||||
{
|
||||
ref var first = ref *(byte*)left;
|
||||
ref var second = ref *(byte*)right;
|
||||
if (byteCount >= (nuint)sizeof(nuint))
|
||||
{
|
||||
if (!Unsafe.AreSame(ref first, ref second))
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
if (Vector128.IsHardwareAccelerated)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
if (Vector512.IsHardwareAccelerated && byteCount >= (nuint)Vector512<byte>.Count)
|
||||
{
|
||||
nuint offset = 0;
|
||||
var lengthToExamine = byteCount - (nuint)Vector512<byte>.Count;
|
||||
if (lengthToExamine != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (Vector512.LoadUnsafe(ref first, offset) != Vector512.LoadUnsafe(ref second, offset))
|
||||
return false;
|
||||
offset += (nuint)Vector512<byte>.Count;
|
||||
} while (lengthToExamine > offset);
|
||||
}
|
||||
return Vector512.LoadUnsafe(ref first, lengthToExamine) == Vector512.LoadUnsafe(ref second, lengthToExamine);
|
||||
}
|
||||
#endif
|
||||
if (Vector256.IsHardwareAccelerated && byteCount >= (nuint)Vector256<byte>.Count)
|
||||
{
|
||||
nuint offset = 0;
|
||||
var lengthToExamine = byteCount - (nuint)Vector256<byte>.Count;
|
||||
if (lengthToExamine != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (Vector256.LoadUnsafe(ref first, offset) != Vector256.LoadUnsafe(ref second, offset))
|
||||
return false;
|
||||
offset += (nuint)Vector256<byte>.Count;
|
||||
} while (lengthToExamine > offset);
|
||||
}
|
||||
return Vector256.LoadUnsafe(ref first, lengthToExamine) == Vector256.LoadUnsafe(ref second, lengthToExamine);
|
||||
}
|
||||
if (byteCount >= (nuint)Vector128<byte>.Count)
|
||||
{
|
||||
nuint offset = 0;
|
||||
var lengthToExamine = byteCount - (nuint)Vector128<byte>.Count;
|
||||
if (lengthToExamine != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (Vector128.LoadUnsafe(ref first, offset) != Vector128.LoadUnsafe(ref second, offset))
|
||||
return false;
|
||||
offset += (nuint)Vector128<byte>.Count;
|
||||
} while (lengthToExamine > offset);
|
||||
}
|
||||
return Vector128.LoadUnsafe(ref first, lengthToExamine) == Vector128.LoadUnsafe(ref second, lengthToExamine);
|
||||
}
|
||||
}
|
||||
if (sizeof(nint) == 8 && Vector128.IsHardwareAccelerated)
|
||||
{
|
||||
var offset = byteCount - (nuint)sizeof(nuint);
|
||||
var differentBits = Unsafe.ReadUnaligned<nuint>(ref first) - Unsafe.ReadUnaligned<nuint>(ref second);
|
||||
differentBits |= Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, offset));
|
||||
return differentBits == 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
nuint offset = 0;
|
||||
var lengthToExamine = byteCount - (nuint)sizeof(nuint);
|
||||
if (lengthToExamine > 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
if (Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, offset)) != Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, offset)))
|
||||
#else
|
||||
if (Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, (nint)offset)) != Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, (nint)offset)))
|
||||
#endif
|
||||
return false;
|
||||
offset += (nuint)sizeof(nuint);
|
||||
} while (lengthToExamine > offset);
|
||||
}
|
||||
#if NET7_0_OR_GREATER
|
||||
return Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, lengthToExamine)) == Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, lengthToExamine));
|
||||
#else
|
||||
return Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, (nint)lengthToExamine)) == Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, (nint)lengthToExamine));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (byteCount < sizeof(uint) || sizeof(nint) != 8)
|
||||
{
|
||||
uint differentBits = 0;
|
||||
var offset = byteCount & 2;
|
||||
if (offset != 0)
|
||||
{
|
||||
differentBits = Unsafe.ReadUnaligned<ushort>(ref first);
|
||||
differentBits -= Unsafe.ReadUnaligned<ushort>(ref second);
|
||||
}
|
||||
|
||||
if ((byteCount & 1) != 0)
|
||||
#if NET7_0_OR_GREATER
|
||||
differentBits |= Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset);
|
||||
#else
|
||||
differentBits |= Unsafe.AddByteOffset(ref first, (nint)offset) - (uint)Unsafe.AddByteOffset(ref second, (nint)offset);
|
||||
#endif
|
||||
return differentBits == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var offset = byteCount - sizeof(uint);
|
||||
var differentBits = Unsafe.ReadUnaligned<uint>(ref first) - Unsafe.ReadUnaligned<uint>(ref second);
|
||||
#if NET7_0_OR_GREATER
|
||||
differentBits |= Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref second, offset));
|
||||
#else
|
||||
differentBits |= Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref first, (nint)offset)) - Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref second, (nint)offset));
|
||||
#endif
|
||||
return differentBits == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
#if FANTASY_NET || !FANTASY_WEBGL
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.LowLevel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes1
|
||||
{
|
||||
private byte _e0;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes2
|
||||
{
|
||||
private FixedBytes1 _e0;
|
||||
private FixedBytes1 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes2, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes2>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes4
|
||||
{
|
||||
private FixedBytes2 _e0;
|
||||
private FixedBytes2 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes4, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes4>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes8
|
||||
{
|
||||
private FixedBytes4 _e0;
|
||||
private FixedBytes4 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes8, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes8>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes16
|
||||
{
|
||||
private FixedBytes8 _e0;
|
||||
private FixedBytes8 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes16, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes16>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes32
|
||||
{
|
||||
private FixedBytes16 _e0;
|
||||
private FixedBytes16 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes32, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes32>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes64
|
||||
{
|
||||
private FixedBytes32 _e0;
|
||||
private FixedBytes32 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes64, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes64>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes128
|
||||
{
|
||||
private FixedBytes64 _e0;
|
||||
private FixedBytes64 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes128, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes128>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes256
|
||||
{
|
||||
private FixedBytes128 _e0;
|
||||
private FixedBytes128 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes256, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes256>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes512
|
||||
{
|
||||
private FixedBytes256 _e0;
|
||||
private FixedBytes256 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes512, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes512>());
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FixedBytes1024
|
||||
{
|
||||
private FixedBytes512 _e0;
|
||||
private FixedBytes512 _e1;
|
||||
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1024, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1024>());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,171 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace Fantasy.LowLevel
|
||||
{
|
||||
public static class XxHash
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32(string obj, uint seed = 0) => Hash32(obj.AsSpan(), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32<T>(in T obj, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32<T>(ReadOnlySpan<T> buffer, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.Cast<T, byte>(buffer), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Hash32(ReadOnlySpan<byte> buffer, uint seed = 0)
|
||||
{
|
||||
int length = buffer.Length;
|
||||
ref byte local1 = ref MemoryMarshal.GetReference(buffer);
|
||||
uint num1;
|
||||
if (buffer.Length >= 16)
|
||||
{
|
||||
uint num2 = seed + 606290984U;
|
||||
uint num3 = seed + 2246822519U;
|
||||
uint num4 = seed;
|
||||
uint num5 = seed - 2654435761U;
|
||||
for (; length >= 16; length -= 16)
|
||||
{
|
||||
const nint elementOffset1 = 4;
|
||||
const nint elementOffset2 = 8;
|
||||
const nint elementOffset3 = 12;
|
||||
nint byteOffset = buffer.Length - length;
|
||||
ref byte local2 = ref Unsafe.AddByteOffset(ref local1, byteOffset);
|
||||
uint num6 = num2 + Unsafe.ReadUnaligned<uint>(ref local2) * 2246822519U;
|
||||
num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535);
|
||||
uint num7 = num3 + Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) * 2246822519U;
|
||||
num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535);
|
||||
uint num8 = num4 + Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) * 2246822519U;
|
||||
num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535);
|
||||
uint num9 = num5 + Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset3)) * 2246822519U;
|
||||
num5 = (uint)((((int)num9 << 13) | (int)(num9 >> 19)) * -1640531535);
|
||||
}
|
||||
|
||||
num1 = (uint)((((int)num2 << 1) | (int)(num2 >> 31)) + (((int)num3 << 7) | (int)(num3 >> 25)) + (((int)num4 << 12) | (int)(num4 >> 20)) + (((int)num5 << 18) | (int)(num5 >> 14)) + buffer.Length);
|
||||
}
|
||||
else
|
||||
num1 = (uint)((int)seed + 374761393 + buffer.Length);
|
||||
|
||||
for (; length >= 4; length -= 4)
|
||||
{
|
||||
nint byteOffset = buffer.Length - length;
|
||||
uint num10 = Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local1, byteOffset));
|
||||
uint num11 = num1 + num10 * 3266489917U;
|
||||
num1 = (uint)((((int)num11 << 17) | (int)(num11 >> 15)) * 668265263);
|
||||
}
|
||||
|
||||
nint byteOffset1 = buffer.Length - length;
|
||||
ref byte local3 = ref Unsafe.AddByteOffset(ref local1, byteOffset1);
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
nint byteOffset2 = index;
|
||||
uint num12 = Unsafe.AddByteOffset(ref local3, byteOffset2);
|
||||
uint num13 = num1 + num12 * 374761393U;
|
||||
num1 = (uint)((((int)num13 << 11) | (int)(num13 >> 21)) * -1640531535);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777;
|
||||
int num15 = (num14 ^ (num14 >>> 13)) * -1028477379;
|
||||
return num15 ^ (num15 >>> 16);
|
||||
#else
|
||||
int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777;
|
||||
int num15 = (num14 ^ (int)((uint)num14 >> 13)) * -1028477379;
|
||||
return num15 ^ (int)((uint)num15 >> 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64(string obj, ulong seed = 0) => Hash64(obj.AsSpan(), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64<T>(in T obj, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64<T>(ReadOnlySpan<T> buffer, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.Cast<T, byte>(buffer), seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Hash64(ReadOnlySpan<byte> buffer, ulong seed = 0)
|
||||
{
|
||||
ref var local1 = ref MemoryMarshal.GetReference(buffer);
|
||||
var length = buffer.Length;
|
||||
ulong num1;
|
||||
if (buffer.Length >= 32)
|
||||
{
|
||||
var num2 = seed + 6983438078262162902UL;
|
||||
var num3 = seed + 14029467366897019727UL;
|
||||
var num4 = seed;
|
||||
var num5 = seed - 11400714785074694791UL;
|
||||
for (; length >= 32; length -= 32)
|
||||
{
|
||||
ref var local2 = ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length));
|
||||
var num6 = num2 + Unsafe.ReadUnaligned<ulong>(ref local2) * 14029467366897019727UL;
|
||||
num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L);
|
||||
var num7 = num3 + Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) * 14029467366897019727UL;
|
||||
num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L);
|
||||
var num8 = num4 + Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) * 14029467366897019727UL;
|
||||
num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L);
|
||||
var num9 = num5 + Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(24U))) * 14029467366897019727UL;
|
||||
num5 = (ulong)((((long)num9 << 31) | (long)(num9 >> 33)) * -7046029288634856825L);
|
||||
}
|
||||
|
||||
var num10 = (((long)num2 << 1) | (long)(num2 >> 63)) + (((long)num3 << 7) | (long)(num3 >> 57)) + (((long)num4 << 12) | (long)(num4 >> 52)) + (((long)num5 << 18) | (long)(num5 >> 46));
|
||||
var num11 = num2 * 14029467366897019727UL;
|
||||
var num12 = (((long)num11 << 31) | (long)(num11 >> 33)) * -7046029288634856825L;
|
||||
var num13 = (num10 ^ num12) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num14 = num3 * 14029467366897019727UL;
|
||||
var num15 = (((long)num14 << 31) | (long)(num14 >> 33)) * -7046029288634856825L;
|
||||
var num16 = (num13 ^ num15) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num17 = num4 * 14029467366897019727UL;
|
||||
var num18 = (((long)num17 << 31) | (long)(num17 >> 33)) * -7046029288634856825L;
|
||||
var num19 = (num16 ^ num18) * -7046029288634856825L + -8796714831421723037L;
|
||||
var num20 = num5 * 14029467366897019727UL;
|
||||
var num21 = (((long)num20 << 31) | (long)(num20 >> 33)) * -7046029288634856825L;
|
||||
num1 = (ulong)((num19 ^ num21) * -7046029288634856825L + -8796714831421723037L);
|
||||
}
|
||||
else
|
||||
num1 = seed + 2870177450012600261UL;
|
||||
|
||||
var num22 = num1 + (ulong)buffer.Length;
|
||||
for (; length >= 8; length -= 8)
|
||||
{
|
||||
var num23 = Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length))) * 14029467366897019727UL;
|
||||
var num24 = (ulong)((((long)num23 << 31) | (long)(num23 >> 33)) * -7046029288634856825L);
|
||||
var num25 = num22 ^ num24;
|
||||
num22 = (ulong)((((long)num25 << 27) | (long)(num25 >> 37)) * -7046029288634856825L + -8796714831421723037L);
|
||||
}
|
||||
|
||||
if (length >= 4)
|
||||
{
|
||||
ulong num26 = Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)));
|
||||
var num27 = num22 ^ (num26 * 11400714785074694791UL);
|
||||
num22 = (ulong)((((long)num27 << 23) | (long)(num27 >> 41)) * -4417276706812531889L + 1609587929392839161L);
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
for (var byteOffset = 0; byteOffset < length; ++byteOffset)
|
||||
{
|
||||
ulong num28 = Unsafe.AddByteOffset(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)), (IntPtr)byteOffset);
|
||||
var num29 = num22 ^ (num28 * 2870177450012600261UL);
|
||||
num22 = (ulong)((((long)num29 << 11) | (long)(num29 >> 53)) * -7046029288634856825L);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
var num30 = (long)num22;
|
||||
var num31 = (num30 ^ (num30 >>> 33)) * -4417276706812531889L;
|
||||
var num32 = (num31 ^ (num31 >>> 29)) * 1609587929392839161L;
|
||||
return num32 ^ (num32 >>> 32);
|
||||
#else
|
||||
var num30 = (long)num22;
|
||||
var num31 = (num30 ^ (long)((ulong)num30 >> 33)) * -4417276706812531889L;
|
||||
var num32 = (num31 ^ (long)((ulong)num31 >> 29)) * 1609587929392839161L;
|
||||
return num32 ^ (long)((ulong)num32 >> 32);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -433,7 +433,7 @@ namespace Fantasy.Network.Interface
|
||||
|
||||
if (entity is not TEntity tEntity)
|
||||
{
|
||||
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
|
||||
Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using ProtoBuf;
|
||||
#if FANTASY_NET
|
||||
using Fantasy.Network.Roaming;
|
||||
#endif
|
||||
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
// ReSharper disable InconsistentNaming
|
||||
// ReSharper disable PropertyCanBeMadeInitOnly.Global
|
||||
@@ -22,7 +21,6 @@ namespace Fantasy.InnerMessage
|
||||
return Fantasy.Network.OpCode.BenchmarkMessage;
|
||||
}
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class BenchmarkRequest : AMessage, IRequest
|
||||
{
|
||||
@@ -30,11 +28,12 @@ namespace Fantasy.InnerMessage
|
||||
{
|
||||
return Fantasy.Network.OpCode.BenchmarkRequest;
|
||||
}
|
||||
|
||||
[ProtoIgnore] public BenchmarkResponse ResponseType { get; set; }
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public BenchmarkResponse ResponseType { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[ProtoContract]
|
||||
public partial class BenchmarkResponse : AMessage, IResponse
|
||||
{
|
||||
@@ -42,22 +41,22 @@ namespace Fantasy.InnerMessage
|
||||
{
|
||||
return Fantasy.Network.OpCode.BenchmarkResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
public sealed partial class Response : AMessage, IResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.DefaultResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed partial class RouteResponse : AMessage, IRouteResponse
|
||||
{
|
||||
@@ -65,11 +64,11 @@ namespace Fantasy.InnerMessage
|
||||
{
|
||||
return Fantasy.Network.OpCode.DefaultRouteResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class PingRequest : AMessage, IRequest
|
||||
{
|
||||
@@ -77,11 +76,12 @@ namespace Fantasy.InnerMessage
|
||||
{
|
||||
return Fantasy.Network.OpCode.PingRequest;
|
||||
}
|
||||
|
||||
[ProtoIgnore] public PingResponse ResponseType { get; set; }
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public PingResponse ResponseType { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[ProtoContract]
|
||||
public partial class PingResponse : AMessage, IResponse
|
||||
{
|
||||
@@ -89,334 +89,231 @@ namespace Fantasy.InnerMessage
|
||||
{
|
||||
return Fantasy.Network.OpCode.PingResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RpcId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
[ProtoMember(3)] public long Now;
|
||||
[ProtoMember(1)]
|
||||
public long RpcId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
[ProtoMember(3)]
|
||||
public long Now;
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableAdd_Request : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_AddressableAdd_Response ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableAddRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long AddressableId { get; set; }
|
||||
[ProtoMember(2)] public long RouteId { get; set; }
|
||||
[ProtoMember(3)] public bool IsLock { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_AddressableAdd_Response ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long AddressableId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public long RouteId { get; set; }
|
||||
[ProtoMember(3)]
|
||||
public bool IsLock { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableAdd_Response : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableAddResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableGet_Request : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_AddressableGet_Response ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableGetRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long AddressableId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_AddressableGet_Response ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long AddressableId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableGet_Response : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableGetResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
[ProtoMember(1)] public long RouteId { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetResponse; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
[ProtoMember(1)]
|
||||
public long RouteId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableRemove_Request : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_AddressableRemove_Response ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableRemoveRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long AddressableId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_AddressableRemove_Response ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long AddressableId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableRemove_Response : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableRemoveResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableLock_Request : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_AddressableLock_Response ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableLockRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long AddressableId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_AddressableLock_Response ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long AddressableId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableLock_Response : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableLockResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableUnLock_Request : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_AddressableUnLock_Response ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableUnLockRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long AddressableId { get; set; }
|
||||
[ProtoMember(2)] public long RouteId { get; set; }
|
||||
[ProtoMember(3)] public string Source { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_AddressableUnLock_Response ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long AddressableId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public long RouteId { get; set; }
|
||||
[ProtoMember(3)]
|
||||
public string Source { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_AddressableUnLock_Response : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.AddressableUnLockResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
#if FANTASY_NET
|
||||
[ProtoContract]
|
||||
public sealed class I_LinkRoamingRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_LinkRoamingResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.LinkRoamingRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RoamingId { get; set; }
|
||||
[ProtoMember(2)] public int RoamingType { get; set; }
|
||||
[ProtoMember(3)] public long ForwardSessionRouteId { get; set; }
|
||||
[ProtoMember(4)] public long SceneRouteId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_LinkRoamingResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.LinkRoamingRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long RoamingId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public int RoamingType { get; set; }
|
||||
[ProtoMember(3)]
|
||||
public long ForwardSessionRouteId { get; set; }
|
||||
[ProtoMember(4)]
|
||||
public long SceneRouteId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed class I_LinkRoamingResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.LinkRoamingResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long TerminusId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.LinkRoamingResponse; }
|
||||
[ProtoMember(1)]
|
||||
public long TerminusId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed class I_UnLinkRoamingRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_UnLinkRoamingResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.UnLinkRoamingRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long RoamingId { get; set; }
|
||||
[ProtoMember(2)] public bool DisposeRoaming { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_UnLinkRoamingResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.UnLinkRoamingRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long RoamingId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public bool DisposeRoaming { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed class I_UnLinkRoamingResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.UnLinkRoamingResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.UnLinkRoamingResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_LockTerminusIdRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_LockTerminusIdResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.LockTerminusIdRequest;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long SessionRuntimeId { get; set; }
|
||||
[ProtoMember(2)] public int RoamingType { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_LockTerminusIdResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.LockTerminusIdRequest; }
|
||||
[ProtoMember(1)]
|
||||
public long SessionRuntimeId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public int RoamingType { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_LockTerminusIdResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.LockTerminusIdResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.LockTerminusIdResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed class I_UnLockTerminusIdRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_UnLockTerminusIdResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.UnLockTerminusIdRequest;
|
||||
}
|
||||
|
||||
public long RouteTypeOpCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long SessionRuntimeId { get; set; }
|
||||
[ProtoMember(2)] public int RoamingType { get; set; }
|
||||
[ProtoMember(3)] public long TerminusId { get; set; }
|
||||
[ProtoMember(4)] public long TargetSceneRouteId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_UnLockTerminusIdResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.UnLockTerminusIdRequest; }
|
||||
public long RouteTypeOpCode() { return 1; }
|
||||
[ProtoMember(1)]
|
||||
public long SessionRuntimeId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public int RoamingType { get; set; }
|
||||
[ProtoMember(3)]
|
||||
public long TerminusId { get; set; }
|
||||
[ProtoMember(4)]
|
||||
public long TargetSceneRouteId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public sealed class I_UnLockTerminusIdResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.UnLockTerminusIdResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.UnLockTerminusIdResponse; }
|
||||
[ProtoMember(1)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 漫游传送终端的请求
|
||||
/// </summary>
|
||||
public partial class I_TransferTerminusRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[BsonIgnore] public I_TransferTerminusResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.TransferTerminusRequest;
|
||||
}
|
||||
|
||||
[BsonIgnore]
|
||||
public I_TransferTerminusResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.TransferTerminusRequest; }
|
||||
public Terminus Terminus { get; set; }
|
||||
}
|
||||
|
||||
public partial class I_TransferTerminusResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.TransferTerminusResponse;
|
||||
}
|
||||
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.TransferTerminusResponse; }
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于服务器之间获取漫游的TerminusId。
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class I_GetTerminusIdRequest : AMessage, IRouteRequest
|
||||
{
|
||||
[ProtoIgnore] public I_GetTerminusIdResponse ResponseType { get; set; }
|
||||
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.GetTerminusIdRequest;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public int RoamingType { get; set; }
|
||||
[ProtoMember(2)] public long SessionRuntimeId { get; set; }
|
||||
[ProtoIgnore]
|
||||
public I_GetTerminusIdResponse ResponseType { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.GetTerminusIdRequest; }
|
||||
[ProtoMember(1)]
|
||||
public int RoamingType { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public long SessionRuntimeId { get; set; }
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class I_GetTerminusIdResponse : AMessage, IRouteResponse
|
||||
{
|
||||
public uint OpCode()
|
||||
{
|
||||
return Fantasy.Network.OpCode.GetTerminusIdResponse;
|
||||
}
|
||||
|
||||
[ProtoMember(1)] public long TerminusId { get; set; }
|
||||
[ProtoMember(2)] public uint ErrorCode { get; set; }
|
||||
public uint OpCode() { return Fantasy.Network.OpCode.GetTerminusIdResponse; }
|
||||
[ProtoMember(1)]
|
||||
public long TerminusId { get; set; }
|
||||
[ProtoMember(2)]
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -73,21 +73,21 @@ namespace Fantasy.PacketParser
|
||||
return false;
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
MessagePacketLength = *(int*)bufferPtr;
|
||||
var span = buffer.AsSpan();
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
MessagePacketLength = Unsafe.ReadUnaligned<int>(ref bufferRef);
|
||||
|
||||
if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength);
|
||||
RpcId = *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation);
|
||||
RouteId = *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation);
|
||||
if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
ProtocolCode = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
|
||||
RpcId = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation));
|
||||
RouteId = Unsafe.ReadUnaligned<long>(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation));
|
||||
|
||||
packInfo = InnerPackInfo.Create(Network);
|
||||
packInfo.RpcId = RpcId;
|
||||
packInfo.RouteId = RouteId;
|
||||
@@ -102,19 +102,19 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream)
|
||||
{
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId;
|
||||
*(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
@@ -142,19 +142,19 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(int*)bufferPtr = packetBodyCount;
|
||||
*(uint*)(bufferPtr + Packet.PacketLength) = opCode;
|
||||
*(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId;
|
||||
*(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
@@ -173,7 +173,7 @@ namespace Fantasy.PacketParser
|
||||
/// <param name="packInfo"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ScanException"></exception>
|
||||
public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo)
|
||||
public override bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo)
|
||||
{
|
||||
packInfo = null;
|
||||
|
||||
@@ -188,19 +188,19 @@ namespace Fantasy.PacketParser
|
||||
return false;
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
var span = buffer.AsSpan();
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
MessagePacketLength = Unsafe.ReadUnaligned<int>(ref bufferRef);
|
||||
|
||||
if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength)
|
||||
{
|
||||
MessagePacketLength = *(int*)bufferPtr;
|
||||
|
||||
if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength);
|
||||
RpcId = *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation);
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
ProtocolCode = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
|
||||
RpcId = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation));
|
||||
|
||||
packInfo = OuterPackInfo.Create(Network);
|
||||
packInfo.RpcId = RpcId;
|
||||
@@ -213,20 +213,22 @@ namespace Fantasy.PacketParser
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream)
|
||||
{
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId;
|
||||
}
|
||||
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
#if FANTASY_UNITY
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan());
|
||||
#else
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
#endif
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
@@ -254,18 +256,21 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(int*)bufferPtr = packetBodyCount;
|
||||
*(uint*)(bufferPtr + Packet.PacketLength) = opCode;
|
||||
*(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
#if FANTASY_UNITY
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan());
|
||||
#else
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
#endif
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
@@ -298,16 +303,19 @@ namespace Fantasy.PacketParser
|
||||
return false;
|
||||
}
|
||||
|
||||
MessagePacketLength = BitConverter.ToInt32(buffer, 0);
|
||||
var span = buffer.AsSpan();
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength)
|
||||
MessagePacketLength = Unsafe.ReadUnaligned<int>(ref bufferRef);
|
||||
|
||||
if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
ProtocolCode = BitConverter.ToUInt32(buffer, Packet.PacketLength);
|
||||
RpcId = BitConverter.ToUInt32(buffer, Packet.OuterPacketRpcIdLocation);
|
||||
ProtocolCode = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
|
||||
RpcId = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation));
|
||||
|
||||
packInfo = OuterPackInfo.Create(Network);
|
||||
packInfo.RpcId = RpcId;
|
||||
@@ -363,23 +371,21 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
var buffer = memoryStream.GetBuffer().AsSpan();
|
||||
#if FANTASY_NET
|
||||
MemoryMarshal.Write(buffer, in packetBodyCount);
|
||||
MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), in opCode);
|
||||
MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId);
|
||||
#endif
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
#if FANTASY_UNITY
|
||||
MemoryMarshal.Write(buffer, ref packetBodyCount);
|
||||
MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), ref opCode);
|
||||
MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId);
|
||||
#endif
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan());
|
||||
#else
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
#endif
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId);
|
||||
return memoryStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#if FANTASY_NET
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Network.Interface;
|
||||
@@ -22,7 +23,7 @@ namespace Fantasy.PacketParser
|
||||
/// <returns>打包完成会返回一个MemoryStreamBuffer</returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength)
|
||||
public static MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength)
|
||||
{
|
||||
memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
@@ -51,18 +52,18 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(int*)bufferPtr = packetBodyCount;
|
||||
*(uint*)(bufferPtr + Packet.PacketLength) = opCode;
|
||||
*(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
@@ -47,56 +47,61 @@ namespace Fantasy.PacketParser
|
||||
#if FANTASY_NET
|
||||
internal sealed class InnerReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser
|
||||
{
|
||||
public override unsafe bool UnPack(ref ReadOnlyMemory<byte> buffer, out APackInfo packInfo)
|
||||
public override bool UnPack(ref ReadOnlyMemory<byte> buffer, out APackInfo packInfo)
|
||||
{
|
||||
packInfo = null;
|
||||
var readOnlySpan = buffer.Span;
|
||||
var bufferLength = buffer.Length - Offset;
|
||||
|
||||
|
||||
if (bufferLength == 0)
|
||||
{
|
||||
// 没有剩余的数据需要处理、等待下一个包再处理。
|
||||
Offset = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (IsUnPackHead)
|
||||
{
|
||||
fixed (byte* bufferPtr = readOnlySpan)
|
||||
fixed (byte* messagePtr = MessageHead)
|
||||
{
|
||||
// 在当前buffer中拿到包头的数据
|
||||
var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset;
|
||||
var copyLength = Math.Min(bufferLength, innerPacketHeadLength);
|
||||
Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, innerPacketHeadLength, copyLength);
|
||||
Offset += copyLength;
|
||||
MessageHeadOffset += copyLength;
|
||||
// 检查是否有完整包头
|
||||
if (MessageHeadOffset == Packet.InnerPacketHeadLength)
|
||||
{
|
||||
// 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId
|
||||
MessagePacketLength = *(int*)messagePtr;
|
||||
// 检查消息体长度是否超出限制
|
||||
if (MessagePacketLength > Packet.PacketBodyMaxLength)
|
||||
{
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
// 在当前buffer中拿到包头的数据
|
||||
var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset;
|
||||
var copyLength = Math.Min(bufferLength, innerPacketHeadLength);
|
||||
|
||||
PackInfo = InnerPackInfo.Create(Network);
|
||||
var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.InnerPacketHeadLength + MessagePacketLength);
|
||||
PackInfo.RpcId = *(uint*)(messagePtr + Packet.InnerPacketRpcIdLocation);
|
||||
PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength);
|
||||
PackInfo.RouteId = *(long*)(messagePtr + Packet.InnerPacketRouteRouteIdLocation);
|
||||
memoryStream.Write(MessageHead);
|
||||
IsUnPackHead = false;
|
||||
bufferLength -= copyLength;
|
||||
MessageHeadOffset = 0;
|
||||
}
|
||||
else
|
||||
readOnlySpan.Slice(Offset, copyLength).CopyTo(MessageHead.AsSpan(MessageHeadOffset, copyLength));
|
||||
|
||||
Offset += copyLength;
|
||||
MessageHeadOffset += copyLength;
|
||||
// 检查是否有完整包头
|
||||
if (MessageHeadOffset == Packet.InnerPacketHeadLength)
|
||||
{
|
||||
// 通过现代API直接读取协议编号、messagePacketLength protocolCode rpcId routeId
|
||||
ref var messageRef = ref MemoryMarshal.GetArrayDataReference(MessageHead);
|
||||
MessagePacketLength = Unsafe.ReadUnaligned<int>(ref messageRef);
|
||||
// 检查消息体长度是否超出限制
|
||||
if (MessagePacketLength > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
Offset = 0;
|
||||
return false;
|
||||
throw new ScanException(
|
||||
$"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
PackInfo = InnerPackInfo.Create(Network);
|
||||
var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack,
|
||||
Packet.InnerPacketHeadLength + MessagePacketLength);
|
||||
PackInfo.RpcId =
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref messageRef, Packet.InnerPacketRpcIdLocation));
|
||||
PackInfo.ProtocolCode =
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref messageRef, Packet.PacketLength));
|
||||
PackInfo.RouteId =
|
||||
Unsafe.ReadUnaligned<long>(ref Unsafe.Add(ref messageRef,
|
||||
Packet.InnerPacketRouteRouteIdLocation));
|
||||
memoryStream.Write(MessageHead);
|
||||
IsUnPackHead = false;
|
||||
bufferLength -= copyLength;
|
||||
MessageHeadOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +138,7 @@ namespace Fantasy.PacketParser
|
||||
MessageBodyOffset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
Offset = 0;
|
||||
return false;
|
||||
}
|
||||
@@ -143,19 +149,19 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream)
|
||||
{
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId;
|
||||
*(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
@@ -184,19 +190,19 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(int*)bufferPtr = packetBodyCount;
|
||||
*(uint*)(bufferPtr + Packet.PacketLength) = opCode;
|
||||
*(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId;
|
||||
*(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
@@ -204,7 +210,7 @@ namespace Fantasy.PacketParser
|
||||
#endif
|
||||
internal sealed class OuterReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser
|
||||
{
|
||||
public override unsafe bool UnPack(ref ReadOnlyMemory<byte> buffer, out APackInfo packInfo)
|
||||
public override bool UnPack(ref ReadOnlyMemory<byte> buffer, out APackInfo packInfo)
|
||||
{
|
||||
packInfo = null;
|
||||
var readOnlySpan = buffer.Span;
|
||||
@@ -216,46 +222,53 @@ namespace Fantasy.PacketParser
|
||||
Offset = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (IsUnPackHead)
|
||||
{
|
||||
fixed (byte* bufferPtr = readOnlySpan)
|
||||
fixed (byte* messagePtr = MessageHead)
|
||||
{
|
||||
// 在当前buffer中拿到包头的数据
|
||||
var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset;
|
||||
var copyLength = Math.Min(bufferLength, outerPacketHeadLength);
|
||||
Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, outerPacketHeadLength, copyLength);
|
||||
Offset += copyLength;
|
||||
MessageHeadOffset += copyLength;
|
||||
// 检查是否有完整包头
|
||||
if (MessageHeadOffset == Packet.OuterPacketHeadLength)
|
||||
{
|
||||
// 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId
|
||||
MessagePacketLength = *(int*)messagePtr;
|
||||
// 检查消息体长度是否超出限制
|
||||
if (MessagePacketLength > Packet.PacketBodyMaxLength)
|
||||
{
|
||||
throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
// 在当前buffer中拿到包头的数据
|
||||
var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset;
|
||||
var copyLength = Math.Min(bufferLength, outerPacketHeadLength);
|
||||
|
||||
PackInfo = OuterPackInfo.Create(Network);
|
||||
PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength);
|
||||
PackInfo.RpcId = *(uint*)(messagePtr + Packet.OuterPacketRpcIdLocation);
|
||||
var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.OuterPacketHeadLength + MessagePacketLength);
|
||||
memoryStream.Write(MessageHead);
|
||||
IsUnPackHead = false;
|
||||
bufferLength -= copyLength;
|
||||
MessageHeadOffset = 0;
|
||||
}
|
||||
else
|
||||
readOnlySpan.Slice(Offset, copyLength).CopyTo(MessageHead.AsSpan(MessageHeadOffset, copyLength));
|
||||
|
||||
Offset += copyLength;
|
||||
MessageHeadOffset += copyLength;
|
||||
// 检查是否有完整包头
|
||||
if (MessageHeadOffset == Packet.OuterPacketHeadLength)
|
||||
{
|
||||
// 通过现代API直接读取协议编号、messagePacketLength protocolCode rpcId routeId
|
||||
#if FANTASY_UNITY
|
||||
ref var messageRef = ref MemoryMarshal.GetReference(buffer.Span);
|
||||
#else
|
||||
ref var messageRef = ref MemoryMarshal.GetArrayDataReference(MessageHead);
|
||||
#endif
|
||||
MessagePacketLength = Unsafe.ReadUnaligned<int>(ref messageRef);
|
||||
// 检查消息体长度是否超出限制
|
||||
if (MessagePacketLength > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
Offset = 0;
|
||||
return false;
|
||||
throw new ScanException(
|
||||
$"The received information exceeds the maximum limit = {MessagePacketLength}");
|
||||
}
|
||||
|
||||
PackInfo = OuterPackInfo.Create(Network);
|
||||
PackInfo.ProtocolCode =
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref messageRef, Packet.PacketLength));
|
||||
PackInfo.RpcId =
|
||||
Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref messageRef, Packet.OuterPacketRpcIdLocation));
|
||||
var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack,
|
||||
Packet.OuterPacketHeadLength + MessagePacketLength);
|
||||
memoryStream.Write(MessageHead);
|
||||
IsUnPackHead = false;
|
||||
bufferLength -= copyLength;
|
||||
MessageHeadOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (MessagePacketLength == -1)
|
||||
{
|
||||
// protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。
|
||||
@@ -299,12 +312,15 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream)
|
||||
{
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
#if FANTASY_UNITY
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan());
|
||||
#else
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
#endif
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
@@ -338,18 +354,21 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
fixed (byte* bufferPtr = memoryStream.GetBuffer())
|
||||
{
|
||||
*(int*)bufferPtr = packetBodyCount;
|
||||
*(uint*)(bufferPtr + Packet.PacketLength) = opCode;
|
||||
*(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId;
|
||||
}
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
#if FANTASY_UNITY
|
||||
ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan());
|
||||
#else
|
||||
ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer);
|
||||
#endif
|
||||
Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode);
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
@@ -77,10 +77,10 @@ namespace Fantasy.PacketParser
|
||||
packetBodyCount = -1;
|
||||
}
|
||||
|
||||
if (packetBodyCount > Packet.PacketBodyMaxLength)
|
||||
if (packetBodyCount > ProgramDefine.MaxMessageSize)
|
||||
{
|
||||
// 检查消息体长度是否超出限制
|
||||
throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes");
|
||||
throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes");
|
||||
}
|
||||
|
||||
var buffer = memoryStream.GetBuffer();
|
||||
|
||||
@@ -5,10 +5,6 @@ namespace Fantasy.PacketParser
|
||||
/// </summary>
|
||||
public struct Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息体最大长度
|
||||
/// </summary>
|
||||
public const int PacketBodyMaxLength = ushort.MaxValue * 16;
|
||||
/// <summary>
|
||||
/// 消息体长度在消息头占用的长度
|
||||
/// </summary>
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Fantasy.Scheduler
|
||||
case OpCodeType.OuterPingRequest:
|
||||
{
|
||||
// 注意心跳目前只有外网才才会有、内网之间不需要心跳。
|
||||
|
||||
session.LastReceiveTime = TimeHelper.Now;
|
||||
_pingResponse.Now = session.LastReceiveTime;
|
||||
|
||||
|
||||
@@ -43,9 +43,8 @@ namespace Fantasy.Network.HTTP
|
||||
if (e.ErrorCode == 5)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("CMD管理员中输入下面其中一个命令,具体根据您是HTTPS或HTTP决定:");
|
||||
sb.AppendLine($"HTTP请输入如下:netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone");
|
||||
sb.AppendLine($"HTTPS请输入如下:netsh http add urlacl url=https://{bindIp}:{port}/ user=Everyone");
|
||||
sb.AppendLine("CMD管理员中输入下面命令:");
|
||||
sb.AppendLine($"netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone");
|
||||
throw new Exception(sb.ToString(), e);
|
||||
}
|
||||
|
||||
@@ -60,10 +59,7 @@ namespace Fantasy.Network.HTTP
|
||||
private void StartAsync(string bindIp, int port)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
// 配置日志级别为 Warning 或更高
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole();
|
||||
builder.Logging.SetMinimumLevel(LogLevel.Warning);
|
||||
// 将Scene注册到 DI 容器中,传递给控制器
|
||||
builder.Services.AddSingleton(Scene);
|
||||
// 注册Scene同步过滤器
|
||||
@@ -75,38 +71,15 @@ namespace Fantasy.Network.HTTP
|
||||
{
|
||||
addControllers.AddApplicationPart(assembly);
|
||||
}
|
||||
var listenUrl = "";
|
||||
var app = builder.Build();
|
||||
// 检测当前路径下是否有证书文件
|
||||
var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}");
|
||||
if (Directory.Exists(certificatePath))
|
||||
{
|
||||
// 加载包含证书链的 PEM 文件
|
||||
var pemCertChain = File.ReadAllText(Path.Combine(certificatePath, "chain.pem"));
|
||||
var pemPrivateKey = File.ReadAllText(Path.Combine(certificatePath, "private-key.pem"));
|
||||
// 配置 HTTPS 监听并使用证书
|
||||
builder.WebHost.ConfigureKestrel(kestrelServerOptions =>
|
||||
{
|
||||
kestrelServerOptions.ConfigureHttpsDefaults(https =>
|
||||
{
|
||||
https.ServerCertificate = X509Certificate2.CreateFromPem(pemCertChain, pemPrivateKey);
|
||||
});
|
||||
});
|
||||
listenUrl = $"https://{bindIp}:{port}/";
|
||||
app.Urls.Add(listenUrl);
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不安全的HTTP地址
|
||||
listenUrl = $"http://{bindIp}:{port}/";
|
||||
app.Urls.Add(listenUrl);
|
||||
}
|
||||
var listenUrl = $"http://{bindIp}:{port}/";;
|
||||
app.Urls.Add(listenUrl);
|
||||
// 启用开发者工具
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
// 路由注册
|
||||
app.MapControllers();
|
||||
// 开启监听
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace KCP
|
||||
/// </summary>
|
||||
/// <param name="buffer">KCP output destination</param>
|
||||
/// <param name="length">KCP output size (excluding reserved)</param>
|
||||
public delegate void KcpCallback(byte[] buffer, int length);
|
||||
internal delegate void KcpCallback(byte[] buffer, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Kcp
|
||||
/// </summary>
|
||||
public sealed unsafe class Kcp : IDisposable
|
||||
internal sealed unsafe class Kcp : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Kcp
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace kcp
|
||||
/// <summary>
|
||||
/// https://github.com/skywind3000/kcp
|
||||
/// </summary>
|
||||
public static unsafe partial class KCP
|
||||
internal static unsafe partial class KCP
|
||||
{
|
||||
//=====================================================================
|
||||
// KCP BASIC
|
||||
@@ -165,50 +165,50 @@ namespace kcp
|
||||
return ((int)(later - earlier));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// manage segment
|
||||
//---------------------------------------------------------------------
|
||||
public static delegate* managed<nuint, void*> ikcp_malloc_hook = null;
|
||||
public static delegate* managed<void*, void> ikcp_free_hook = null;
|
||||
// //---------------------------------------------------------------------
|
||||
// // manage segment
|
||||
// //---------------------------------------------------------------------
|
||||
// public static delegate* managed<nuint, void*> ikcp_malloc_hook = null;
|
||||
// public static delegate* managed<void*, void> ikcp_free_hook = null;
|
||||
|
||||
// internal malloc
|
||||
public static void* ikcp_malloc(nuint size)
|
||||
{
|
||||
if (ikcp_malloc_hook != null)
|
||||
return ikcp_malloc_hook(size);
|
||||
return malloc(size);
|
||||
}
|
||||
// // internal malloc
|
||||
// public static void* ikcp_malloc(nuint size)
|
||||
// {
|
||||
// if (ikcp_malloc_hook != null)
|
||||
// return ikcp_malloc_hook(size);
|
||||
// return malloc(size);
|
||||
// }
|
||||
|
||||
// internal free
|
||||
public static void ikcp_free(void* ptr)
|
||||
{
|
||||
if (ikcp_free_hook != null)
|
||||
{
|
||||
ikcp_free_hook(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
// // internal free
|
||||
// public static void ikcp_free(void* ptr)
|
||||
// {
|
||||
// if (ikcp_free_hook != null)
|
||||
// {
|
||||
// ikcp_free_hook(ptr);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// free(ptr);
|
||||
// }
|
||||
// }
|
||||
|
||||
// redefine allocator
|
||||
public static void ikcp_allocator(delegate* managed<nuint, void*> new_malloc, delegate* managed<void*, void> new_free)
|
||||
{
|
||||
ikcp_malloc_hook = new_malloc;
|
||||
ikcp_free_hook = new_free;
|
||||
}
|
||||
// // redefine allocator
|
||||
// public static void ikcp_allocator(delegate* managed<nuint, void*> new_malloc, delegate* managed<void*, void> new_free)
|
||||
// {
|
||||
// ikcp_malloc_hook = new_malloc;
|
||||
// ikcp_free_hook = new_free;
|
||||
// }
|
||||
|
||||
// allocate a new kcp segment
|
||||
public static IKCPSEG* ikcp_segment_new(IKCPCB* kcp, int size)
|
||||
{
|
||||
return (IKCPSEG*)ikcp_malloc((nuint)(sizeof(IKCPSEG) + size));
|
||||
return (IKCPSEG*)malloc((nuint)(sizeof(IKCPSEG) + size));
|
||||
}
|
||||
|
||||
// delete a segment
|
||||
public static void ikcp_segment_delete(IKCPCB* kcp, IKCPSEG* seg)
|
||||
{
|
||||
ikcp_free(seg);
|
||||
free(seg);
|
||||
}
|
||||
|
||||
// output segment
|
||||
@@ -226,7 +226,7 @@ namespace kcp
|
||||
//---------------------------------------------------------------------
|
||||
public static IKCPCB* ikcp_create(uint conv, int reserved, ref byte[] buffer)
|
||||
{
|
||||
IKCPCB* kcp = (IKCPCB*)ikcp_malloc((nuint)sizeof(IKCPCB));
|
||||
IKCPCB* kcp = (IKCPCB*)malloc((nuint)sizeof(IKCPCB));
|
||||
if (kcp == null) return null;
|
||||
kcp->conv = conv;
|
||||
kcp->snd_una = 0;
|
||||
@@ -318,7 +318,7 @@ namespace kcp
|
||||
|
||||
if (kcp->acklist != null)
|
||||
{
|
||||
ikcp_free(kcp->acklist);
|
||||
free(kcp->acklist);
|
||||
}
|
||||
|
||||
kcp->nrcv_buf = 0;
|
||||
@@ -327,7 +327,7 @@ namespace kcp
|
||||
kcp->nsnd_que = 0;
|
||||
kcp->ackcount = 0;
|
||||
kcp->acklist = null;
|
||||
ikcp_free(kcp);
|
||||
free(kcp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +669,7 @@ namespace kcp
|
||||
uint newblock;
|
||||
|
||||
newblock = newsize <= 8 ? 8 : _iceilpow2_(newsize);
|
||||
acklist = (uint*)ikcp_malloc((nuint)(newblock * sizeof(uint) * 2));
|
||||
acklist = (uint*)malloc((nuint)(newblock * sizeof(uint) * 2));
|
||||
|
||||
if (acklist == null)
|
||||
{
|
||||
@@ -686,7 +686,7 @@ namespace kcp
|
||||
acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1];
|
||||
}
|
||||
|
||||
ikcp_free(kcp->acklist);
|
||||
free(kcp->acklist);
|
||||
}
|
||||
|
||||
kcp->acklist = acklist;
|
||||
|
||||
@@ -9,9 +9,9 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace kcp
|
||||
{
|
||||
public static unsafe partial class KCP
|
||||
internal static unsafe partial class KCP
|
||||
{
|
||||
public static void* malloc(nuint size)
|
||||
private static void* malloc(nuint size)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
return NativeMemory.Alloc((nuint)size);
|
||||
@@ -20,7 +20,7 @@ namespace kcp
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void free(void* memory)
|
||||
private static void free(void* memory)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
NativeMemory.Free(memory);
|
||||
@@ -29,13 +29,13 @@ namespace kcp
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void memcpy(void* dst, void* src, nuint size) => Unsafe.CopyBlockUnaligned(dst, src, (uint)size);
|
||||
private static void memcpy(void* dst, void* src, nuint size) => Unsafe.CopyBlockUnaligned(dst, src, (uint)size);
|
||||
|
||||
public static void memset(void* dst, byte val, nuint size) => Unsafe.InitBlockUnaligned(dst, val, (uint)size);
|
||||
private static void memset(void* dst, byte val, nuint size) => Unsafe.InitBlockUnaligned(dst, val, (uint)size);
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void assert(bool condition) => Debug.Assert(condition);
|
||||
private static void assert(bool condition) => Debug.Assert(condition);
|
||||
|
||||
public static void abort() => Environment.Exit(-1);
|
||||
private static void abort() => Environment.Exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,13 @@ using System.Runtime.InteropServices;
|
||||
namespace kcp
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct IQUEUEHEAD
|
||||
internal unsafe struct IQUEUEHEAD
|
||||
{
|
||||
public IQUEUEHEAD* next;
|
||||
public IQUEUEHEAD* prev;
|
||||
}
|
||||
|
||||
public static unsafe partial class KCP
|
||||
internal static unsafe partial class KCP
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void iqueue_init(IQUEUEHEAD* head)
|
||||
@@ -65,7 +65,7 @@ namespace kcp
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct IKCPSEG
|
||||
internal unsafe struct IKCPSEG
|
||||
{
|
||||
public IQUEUEHEAD node;
|
||||
public uint conv;
|
||||
@@ -84,7 +84,7 @@ namespace kcp
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct IKCPCB
|
||||
internal unsafe struct IKCPCB
|
||||
{
|
||||
public uint conv, mtu, mss, state;
|
||||
public uint snd_una, snd_nxt, rcv_nxt;
|
||||
@@ -109,7 +109,7 @@ namespace kcp
|
||||
public int nocwnd, stream;
|
||||
}
|
||||
|
||||
public static partial class KCP
|
||||
internal static partial class KCP
|
||||
{
|
||||
public const uint IKCP_LOG_OUTPUT = 1;
|
||||
public const uint IKCP_LOG_INPUT = 2;
|
||||
|
||||
@@ -27,14 +27,14 @@ using KCP;
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
namespace Fantasy.Network.KCP
|
||||
{
|
||||
public sealed class KCPClientNetworkUpdateSystem : UpdateSystem<KCPClientNetwork>
|
||||
internal sealed class KCPClientNetworkUpdateSystem : UpdateSystem<KCPClientNetwork>
|
||||
{
|
||||
protected override void Update(KCPClientNetwork self)
|
||||
{
|
||||
self.CheckUpdate();
|
||||
}
|
||||
}
|
||||
public sealed class KCPClientNetwork : AClientNetwork
|
||||
internal sealed class KCPClientNetwork : AClientNetwork
|
||||
{
|
||||
private Kcp _kcp;
|
||||
private Socket _socket;
|
||||
@@ -50,7 +50,7 @@ namespace Fantasy.Network.KCP
|
||||
private BufferPacketParser _packetParser;
|
||||
private readonly Pipe _pipe = new Pipe();
|
||||
private readonly byte[] _sendBuff = new byte[5];
|
||||
private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20];
|
||||
private readonly byte[] _receiveBuffer = new byte[ProgramDefine.MaxMessageSize + 20];
|
||||
private readonly List<uint> _updateTimeOutTime = new List<uint>();
|
||||
private readonly SortedSet<uint> _updateTimer = new SortedSet<uint>();
|
||||
private readonly SocketAsyncEventArgs _connectEventArgs = new SocketAsyncEventArgs();
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Fantasy.Network.KCP
|
||||
}
|
||||
}
|
||||
|
||||
public static class KCPFactory
|
||||
internal static class KCPFactory
|
||||
{
|
||||
public const int FANTASY_KCP_RESERVED_HEAD = 5;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Network.KCP
|
||||
#pragma warning disable CS1591
|
||||
{
|
||||
public enum KcpHeader : byte
|
||||
internal enum KcpHeader : byte
|
||||
{
|
||||
None = 0x00,
|
||||
RequestConnection = 0x01,
|
||||
|
||||
@@ -23,7 +23,7 @@ using Fantasy.Network.Interface;
|
||||
|
||||
namespace Fantasy.Network.KCP
|
||||
{
|
||||
public sealed class KCPServerNetworkUpdateSystem : UpdateSystem<KCPServerNetwork>
|
||||
internal sealed class KCPServerNetworkUpdateSystem : UpdateSystem<KCPServerNetwork>
|
||||
{
|
||||
protected override void Update(KCPServerNetwork self)
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace Fantasy.Network.KCP
|
||||
}
|
||||
}
|
||||
|
||||
public struct PendingConnection
|
||||
internal struct PendingConnection
|
||||
{
|
||||
public readonly uint ChannelId;
|
||||
public readonly uint TimeOutId;
|
||||
@@ -388,7 +388,7 @@ namespace Fantasy.Network.KCP
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (channel.IsDisposed)
|
||||
{
|
||||
_connectionChannel.Remove(channelId);
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Fantasy.Network.KCP
|
||||
/// <summary>
|
||||
/// KCP 服务器网络通道,用于处理服务器与客户端之间的数据通信。
|
||||
/// </summary>
|
||||
public class KCPServerNetworkChannel : ANetworkServerChannel
|
||||
internal class KCPServerNetworkChannel : ANetworkServerChannel
|
||||
{
|
||||
private bool _isInnerDispose;
|
||||
private readonly int _maxSndWnd;
|
||||
private KCPServerNetwork _kcpServerNetwork;
|
||||
private readonly BufferPacketParser _packetParser;
|
||||
private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20];
|
||||
private readonly byte[] _receiveBuffer = new byte[ProgramDefine.MaxMessageSize + 20];
|
||||
public Kcp Kcp { get; private set; }
|
||||
public uint ChannelId { get; private set; }
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Fantasy.Network
|
||||
case NetworkProtocolType.WebSocket:
|
||||
{
|
||||
var network = Entity.Create<WebSocketServerNetwork>(scene, false, true);
|
||||
network.Initialize(networkTarget, bindIp, port);
|
||||
network.Initialize(networkTarget, port);
|
||||
return network;
|
||||
}
|
||||
case NetworkProtocolType.HTTP:
|
||||
|
||||
@@ -46,6 +46,11 @@ namespace Fantasy.Network.WebSocket
|
||||
{
|
||||
_isInnerDispose = true;
|
||||
|
||||
if (_clientWebSocket.State == WebSocketState.Open || _clientWebSocket.State == WebSocketState.CloseReceived)
|
||||
{
|
||||
_clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client Closing", CancellationToken.None).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (!_cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
@@ -59,11 +64,13 @@ namespace Fantasy.Network.WebSocket
|
||||
}
|
||||
|
||||
ClearConnectTimeout();
|
||||
WebSocketClientDisposeAsync().Coroutine();
|
||||
_onConnectDisconnect?.Invoke();
|
||||
_packetParser.Dispose();
|
||||
_packetParser = null;
|
||||
_isSending = false;
|
||||
|
||||
_clientWebSocket.Dispose();
|
||||
_clientWebSocket = null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -75,18 +82,6 @@ namespace Fantasy.Network.WebSocket
|
||||
}
|
||||
}
|
||||
|
||||
private async FTask WebSocketClientDisposeAsync()
|
||||
{
|
||||
if (_clientWebSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||
_clientWebSocket.Dispose();
|
||||
_clientWebSocket = null;
|
||||
}
|
||||
|
||||
public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000)
|
||||
{
|
||||
if (IsInit)
|
||||
@@ -150,10 +145,16 @@ namespace Fantasy.Network.WebSocket
|
||||
var memory = _pipe.Writer.GetMemory(8192);
|
||||
// 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。
|
||||
var receiveResult = await _clientWebSocket.ReceiveAsync(memory, _cancellationTokenSource.Token);
|
||||
|
||||
// 服务器发送了关闭帧,客户端需要响应关闭帧
|
||||
if (receiveResult.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
break;
|
||||
if (_clientWebSocket.State == WebSocketState.CloseReceived)
|
||||
{
|
||||
await _clientWebSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Response Closure",
|
||||
CancellationToken.None);
|
||||
}
|
||||
Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
var count = receiveResult.Count;
|
||||
|
||||
@@ -17,7 +17,7 @@ public class WebSocketServerNetwork : ANetwork
|
||||
private HttpListener _httpListener;
|
||||
private readonly Dictionary<uint, INetworkChannel> _connectionChannel = new Dictionary<uint, INetworkChannel>();
|
||||
|
||||
public void Initialize(NetworkTarget networkTarget, string bindIp, int port)
|
||||
public void Initialize(NetworkTarget networkTarget, int port)
|
||||
{
|
||||
base.Initialize(NetworkType.Server, NetworkProtocolType.WebSocket, networkTarget);
|
||||
|
||||
@@ -25,13 +25,15 @@ public class WebSocketServerNetwork : ANetwork
|
||||
{
|
||||
_random = new Random();
|
||||
_httpListener = new HttpListener();
|
||||
StartAcceptAsync(bindIp, port).Coroutine();
|
||||
StartAcceptAsync(port).Coroutine();
|
||||
}
|
||||
catch (HttpListenerException e)
|
||||
{
|
||||
if (e.ErrorCode == 5)
|
||||
{
|
||||
throw new Exception($"CMD管理员中输入: netsh http add urlacl url=http://*:8080/ user=Everyone", e);
|
||||
throw new Exception($"如果看下如下错误请尝试下面的办法:" +
|
||||
$"1.用管理员运行CMD 输入命令: netsh http add urlacl url=http://+:8080/ user=Everyone。" +
|
||||
$"2.用管理员身份运行编辑器或者程序。", e);
|
||||
}
|
||||
|
||||
Log.Error(e);
|
||||
@@ -64,11 +66,42 @@ public class WebSocketServerNetwork : ANetwork
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
private async FTask StartAcceptAsync(string bindIp, int port)
|
||||
private static bool IsValidWebSocketRequest(HttpListenerRequest request)
|
||||
{
|
||||
var listenUrl = "";
|
||||
var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}");
|
||||
listenUrl = Directory.Exists(certificatePath) ? $"https://{bindIp}:{port}/" : $"http://{bindIp}:{port}/";
|
||||
// 检查必需的WebSocket握手头部
|
||||
var connectionHeader = request.Headers["Connection"];
|
||||
var upgradeHeader = request.Headers["Upgrade"];
|
||||
|
||||
if (string.IsNullOrEmpty(connectionHeader) || string.IsNullOrEmpty(upgradeHeader))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connection头部应该包含"Upgrade" (不区分大小写)
|
||||
if (!connectionHeader.ToLower().Contains("upgrade"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upgrade头部应该是"websocket" (不区分大小写)
|
||||
if (!upgradeHeader.ToLower().Contains("websocket"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查WebSocket版本 (可选但推荐)
|
||||
var versionHeader = request.Headers["Sec-WebSocket-Version"];
|
||||
if (!string.IsNullOrEmpty(versionHeader) && versionHeader != "13")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async FTask StartAcceptAsync(int port)
|
||||
{
|
||||
var listenUrl = $"http://+:{port}/";
|
||||
_httpListener.Prefixes.Add(listenUrl);
|
||||
_httpListener.Start();
|
||||
Log.Info($"SceneConfigId = {Scene.SceneConfigId} WebSocketServer Listen {listenUrl}");
|
||||
@@ -77,15 +110,23 @@ public class WebSocketServerNetwork : ANetwork
|
||||
try
|
||||
{
|
||||
var httpListenerContext = await _httpListener.GetContextAsync();
|
||||
// 验证WebSocket握手请求头部
|
||||
if (!IsValidWebSocketRequest(httpListenerContext.Request))
|
||||
{
|
||||
httpListenerContext.Response.StatusCode = 400;
|
||||
httpListenerContext.Response.StatusDescription = "Bad Request - Invalid WebSocket headers";
|
||||
httpListenerContext.Response.Close();
|
||||
continue;
|
||||
}
|
||||
var webSocketContext = await httpListenerContext.AcceptWebSocketAsync(null);
|
||||
var channelId = 0xC0000000 | (uint) _random.Next();
|
||||
|
||||
while (_connectionChannel.ContainsKey(channelId))
|
||||
{
|
||||
channelId = 0xC0000000 | (uint) _random.Next();
|
||||
}
|
||||
|
||||
_connectionChannel.Add(channelId, new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint));
|
||||
|
||||
var webSocketServerNetworkChannel = new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint);
|
||||
_connectionChannel.Add(channelId, webSocketServerNetworkChannel);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,20 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel
|
||||
}
|
||||
|
||||
_isInnerDispose = true;
|
||||
|
||||
if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived)
|
||||
{
|
||||
try
|
||||
{
|
||||
_webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure",
|
||||
CancellationToken.None).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 关闭过程中的异常可以忽略
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
@@ -53,13 +67,9 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel
|
||||
// 通常情况下,此处的异常可以忽略
|
||||
}
|
||||
}
|
||||
|
||||
_sendBuffers.Clear();
|
||||
_network.RemoveChannel(Id);
|
||||
if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived)
|
||||
{
|
||||
_webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure",
|
||||
_cancellationTokenSource.Token).GetAwaiter().GetResult();
|
||||
}
|
||||
_webSocket.Dispose();
|
||||
_isSending = false;
|
||||
base.Dispose();
|
||||
@@ -76,11 +86,16 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel
|
||||
var memory = _pipe.Writer.GetMemory(8192);
|
||||
// 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。
|
||||
var receiveResult = await _webSocket.ReceiveAsync(memory, _cancellationTokenSource.Token);
|
||||
|
||||
// 客户端发送了关闭帧,服务器需要响应关闭帧
|
||||
if (receiveResult.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
if (_webSocket.State == WebSocketState.CloseReceived)
|
||||
{
|
||||
await _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Response Closure",
|
||||
CancellationToken.None);
|
||||
}
|
||||
Dispose();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
var count = receiveResult.Count;
|
||||
@@ -112,6 +127,9 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel
|
||||
}
|
||||
|
||||
await _pipe.Writer.CompleteAsync();
|
||||
|
||||
// 接收循环结束,自动释放连接
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private async FTask PipeWriterFlushAsync(int count)
|
||||
|
||||
@@ -184,7 +184,118 @@ public sealed class SessionRoamingComponent : Entity
|
||||
|
||||
#endregion
|
||||
|
||||
#region Message
|
||||
#region OuterMessage
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个消息给漫游终
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public void Send(IRoamingMessage message)
|
||||
{
|
||||
Call(message.RouteType, message).Coroutine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个消息给漫游终端
|
||||
/// </summary>
|
||||
/// <param name="roamingType"></param>
|
||||
/// <param name="message"></param>
|
||||
public void Send(int roamingType, IRouteMessage message)
|
||||
{
|
||||
Call(roamingType, message).Coroutine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个RPC消息给漫游终端
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async FTask<IResponse> Call(IRoamingMessage message)
|
||||
{
|
||||
return await Call(message.RouteType, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个RPC消息给漫游终端
|
||||
/// </summary>
|
||||
/// <param name="roamingType"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public async FTask<IResponse> Call(int roamingType, IRouteMessage message)
|
||||
{
|
||||
if (!_roaming.TryGetValue(roamingType, out var roaming))
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(message.GetType(), InnerErrorCode.ErrNotFoundRoaming);
|
||||
}
|
||||
|
||||
var failCount = 0;
|
||||
var runtimeId = RuntimeId;
|
||||
var routeId = roaming.TerminusId;
|
||||
var requestType = message.GetType();
|
||||
|
||||
IResponse iRouteResponse = null;
|
||||
|
||||
using (await RoamingMessageLock.Wait(roaming.RoamingType, "RoamingComponent Call MemoryStream"))
|
||||
{
|
||||
while (!IsDisposed)
|
||||
{
|
||||
if (routeId == 0)
|
||||
{
|
||||
routeId = await roaming.GetTerminusId();
|
||||
}
|
||||
|
||||
if (routeId == 0)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(requestType, InnerErrorCode.ErrNotFoundRoaming);
|
||||
}
|
||||
|
||||
iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(routeId, message);
|
||||
|
||||
if (runtimeId != RuntimeId)
|
||||
{
|
||||
iRouteResponse.ErrorCode = InnerErrorCode.ErrRoamingTimeout;
|
||||
}
|
||||
|
||||
switch (iRouteResponse.ErrorCode)
|
||||
{
|
||||
case InnerErrorCode.ErrRouteTimeout:
|
||||
case InnerErrorCode.ErrRoamingTimeout:
|
||||
{
|
||||
return iRouteResponse;
|
||||
}
|
||||
case InnerErrorCode.ErrNotFoundRoute:
|
||||
case InnerErrorCode.ErrNotFoundRoaming:
|
||||
{
|
||||
if (++failCount > 20)
|
||||
{
|
||||
Log.Error($"RoamingComponent.Call failCount > 20 route send message fail, LinkRoamingId: {routeId}");
|
||||
return iRouteResponse;
|
||||
}
|
||||
|
||||
await TimerComponent.Net.WaitAsync(100);
|
||||
|
||||
if (runtimeId != RuntimeId)
|
||||
{
|
||||
iRouteResponse.ErrorCode = InnerErrorCode.ErrNotFoundRoaming;
|
||||
}
|
||||
|
||||
routeId = 0;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return iRouteResponse; // 对于其他情况,直接返回响应,无需额外处理
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iRouteResponse;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region InnerMessage
|
||||
|
||||
internal async FTask Send(int roamingType, Type requestType, APackInfo packInfo)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#if FANTASY_NET
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.Platform.Net;
|
||||
using Fantasy.Timer;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#if FANTASY_NET
|
||||
namespace Fantasy.Network;
|
||||
|
||||
public class SessionIdleCheckerComponentAwakeSystem : AwakeSystem<SessionIdleCheckerComponent>
|
||||
@@ -57,7 +58,7 @@ public class SessionIdleCheckerComponent : Entity
|
||||
/// </summary>
|
||||
/// <param name="interval">以毫秒为单位的检查间隔。</param>
|
||||
/// <param name="timeOut">以毫秒为单位的空闲超时时间。</param>
|
||||
public void Start(int interval, int timeOut)
|
||||
internal void Start(int interval, int timeOut)
|
||||
{
|
||||
_timeOut = timeOut;
|
||||
_session = (Session)Parent;
|
||||
@@ -66,10 +67,21 @@ public class SessionIdleCheckerComponent : Entity
|
||||
_timerId = TimerComponent.Net.RepeatedTimer(interval, Check);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新开始心跳检查
|
||||
/// </summary>
|
||||
/// <param name="interval">以毫秒为单位的检查间隔。</param>
|
||||
/// <param name="timeOut">以毫秒为单位的空闲超时时间。</param>
|
||||
public void Restart(int interval, int timeOut)
|
||||
{
|
||||
Stop();
|
||||
Start(interval, timeOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止空闲检查功能。
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
private void Stop()
|
||||
{
|
||||
if (_timerId == 0)
|
||||
{
|
||||
@@ -96,8 +108,9 @@ public class SessionIdleCheckerComponent : Entity
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if FANTASY_DEBUG
|
||||
Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}");
|
||||
#endif
|
||||
_session.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
@@ -32,9 +33,20 @@ namespace Fantasy.Network
|
||||
public long TimeOutTimerId;
|
||||
public TimerComponent TimerComponent;
|
||||
public EntityReference<Session> Session;
|
||||
private readonly PingRequest _pingRequest = new PingRequest();
|
||||
private readonly PingRequest _pingRequest = new PingRequest();
|
||||
|
||||
public int Ping { get; private set; }
|
||||
// Ping滑动窗口及其累加和
|
||||
private int _pingSum;
|
||||
private int _maxPingSamples;
|
||||
private readonly Queue<int> _pingSamples = new Queue<int>();
|
||||
/// <summary>
|
||||
/// 当前Ping延迟(毫秒,滑动均值)
|
||||
/// </summary>
|
||||
public int PingMilliseconds { get; private set; }
|
||||
/// <summary>
|
||||
/// 当前Ping延迟(秒,浮点数,通常用于调试)
|
||||
/// </summary>
|
||||
public float PingSeconds => PingMilliseconds / 1000f;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -44,7 +56,6 @@ namespace Fantasy.Network
|
||||
}
|
||||
|
||||
Stop();
|
||||
Ping = 0;
|
||||
Session = null;
|
||||
TimeOut = 0;
|
||||
LastTime = 0;
|
||||
@@ -58,13 +69,15 @@ namespace Fantasy.Network
|
||||
/// <param name="interval">以毫秒为单位的心跳请求发送间隔。</param>
|
||||
/// <param name="timeOut">设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。</param>
|
||||
/// <param name="timeOutInterval">用于检测与服务器连接超时频率。</param>
|
||||
public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000)
|
||||
/// <param name="maxPingSamples">Ping包的采样数量</param>
|
||||
public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000, int maxPingSamples = 8)
|
||||
{
|
||||
TimeOut = timeOut + interval;
|
||||
Session = (Session)Parent;
|
||||
SelfRunTimeId = RuntimeId;
|
||||
LastTime = TimeHelper.Now;
|
||||
|
||||
_maxPingSamples = maxPingSamples;
|
||||
|
||||
if (TimerComponent == null)
|
||||
{
|
||||
Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包");
|
||||
@@ -109,6 +122,10 @@ namespace Fantasy.Network
|
||||
{
|
||||
TimerComponent?.Unity.Remove(ref TimeOutTimerId);
|
||||
}
|
||||
|
||||
_pingSum = 0;
|
||||
PingMilliseconds = 0;
|
||||
_pingSamples.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -143,8 +160,23 @@ namespace Fantasy.Network
|
||||
|
||||
var responseTime = TimeHelper.Now;
|
||||
LastTime = responseTime;
|
||||
Ping = (int)(responseTime - requestTime) / 2;
|
||||
TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime;
|
||||
|
||||
// 计算Ping(毫秒)
|
||||
var rtt = (int)(responseTime - requestTime);
|
||||
var ping = rtt / 2;
|
||||
|
||||
// 平滑滑动均值
|
||||
_pingSamples.Enqueue(ping);
|
||||
_pingSum += ping;
|
||||
if (_pingSamples.Count > _maxPingSamples)
|
||||
{
|
||||
_pingSum -= _pingSamples.Dequeue();
|
||||
}
|
||||
|
||||
PingMilliseconds = Math.Max(0, _pingSamples.Count > 0 ? _pingSum / _pingSamples.Count : 0);
|
||||
|
||||
// 校正服务器时间(可选)
|
||||
TimeHelper.TimeDiff = pingResponse.Now + ping - responseTime;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -18,7 +17,6 @@ using Fantasy.Serialize;
|
||||
using Fantasy.Network.Route;
|
||||
using Fantasy.Platform.Net;
|
||||
using Fantasy.Network.Roaming;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#endif
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
@@ -38,18 +36,15 @@ namespace Fantasy.Network
|
||||
{
|
||||
private uint _rpcId;
|
||||
internal long LastReceiveTime;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的网络连接通道
|
||||
/// </summary>
|
||||
internal INetworkChannel Channel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前Session的终结点信息
|
||||
/// </summary>
|
||||
public IPEndPoint RemoteEndPoint { get; private set; }
|
||||
|
||||
private ANetworkMessageScheduler NetworkMessageScheduler { get; set; }
|
||||
private ANetworkMessageScheduler NetworkMessageScheduler { get; set;}
|
||||
internal readonly Dictionary<long, FTask<IResponse>> RequestCallback = new();
|
||||
/// <summary>
|
||||
/// Session的Dispose委托
|
||||
@@ -59,8 +54,7 @@ namespace Fantasy.Network
|
||||
internal RouteComponent RouteComponent;
|
||||
internal SessionRoamingComponent SessionRoamingComponent;
|
||||
internal AddressableRouteComponent AddressableRouteComponent;
|
||||
internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel,
|
||||
NetworkTarget networkTarget)
|
||||
internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel, NetworkTarget networkTarget)
|
||||
{
|
||||
var session = Entity.Create<Session>(channel.Scene, false, true);
|
||||
session.Channel = channel;
|
||||
@@ -71,11 +65,10 @@ namespace Fantasy.Network
|
||||
// 在外部网络目标下,添加会话空闲检查组件
|
||||
if (networkTarget == NetworkTarget.Outer)
|
||||
{
|
||||
var interval = ProcessDefine.SessionIdleCheckerInterval;
|
||||
var timeOut = ProcessDefine.SessionIdleCheckerTimeout;
|
||||
var interval = ProgramDefine.SessionIdleCheckerInterval;
|
||||
var timeOut = ProgramDefine.SessionIdleCheckerTimeout;
|
||||
session.AddComponent<SessionIdleCheckerComponent>().Start(interval, timeOut);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
#endif
|
||||
@@ -159,7 +152,7 @@ namespace Fantasy.Network
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_rpcId = 0;
|
||||
LastReceiveTime = 0;
|
||||
Channel = null;
|
||||
@@ -177,11 +170,11 @@ namespace Fantasy.Network
|
||||
{
|
||||
requestCallback.SetException(new Exception($"session is dispose: {Id}"));
|
||||
}
|
||||
|
||||
|
||||
RequestCallback.Clear();
|
||||
OnDispose?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个消息
|
||||
/// </summary>
|
||||
@@ -194,10 +187,10 @@ namespace Fantasy.Network
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Channel.Send(rpcId, routeId, null, message);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个消息
|
||||
/// </summary>
|
||||
@@ -213,7 +206,7 @@ namespace Fantasy.Network
|
||||
|
||||
Channel.Send(rpcId, routeId, null, routeMessage);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个RPC消息
|
||||
/// </summary>
|
||||
@@ -226,14 +219,14 @@ namespace Fantasy.Network
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var requestCallback = FTask<IResponse>.Create();
|
||||
var rpcId = ++_rpcId;
|
||||
var rpcId = ++_rpcId;
|
||||
RequestCallback.Add(rpcId, requestCallback);
|
||||
Send(request, rpcId, routeId);
|
||||
return requestCallback;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个RPC消息
|
||||
/// </summary>
|
||||
@@ -246,9 +239,9 @@ namespace Fantasy.Network
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var requestCallback = FTask<IResponse>.Create();
|
||||
var rpcId = ++_rpcId;
|
||||
var rpcId = ++_rpcId;
|
||||
RequestCallback.Add(rpcId, requestCallback);
|
||||
Send(request, rpcId, routeId);
|
||||
return requestCallback;
|
||||
@@ -275,5 +268,31 @@ namespace Fantasy.Network
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 重新开始心跳检查
|
||||
/// </summary>
|
||||
/// <param name="interval"></param>
|
||||
/// <param name="timeOut"></param>
|
||||
public void RestartIdleChecker(int interval, int timeOut)
|
||||
{
|
||||
var sessionIdleCheckerComponent = GetComponent<SessionIdleCheckerComponent>();
|
||||
if (sessionIdleCheckerComponent == null)
|
||||
{
|
||||
Log.Error("SessionIdleCheckerComponent is null");
|
||||
return;
|
||||
}
|
||||
|
||||
sessionIdleCheckerComponent.Restart(interval, timeOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新开始心跳检查(使用框架配置的参数)
|
||||
/// </summary>
|
||||
public void RestartIdleChecker()
|
||||
{
|
||||
RestartIdleChecker(ProgramDefine.SessionIdleCheckerInterval, ProgramDefine.SessionIdleCheckerTimeout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Fantasy.Platform.Console
|
||||
Log.Error("Fantasy has already been initialized and does not need to be initialized again!");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info($"Fantasy Version:{Define.VERSION}");
|
||||
// 初始化程序集管理系统
|
||||
await AssemblySystem.InnerInitialize(assemblies);
|
||||
// 初始化序列化
|
||||
|
||||
@@ -0,0 +1,537 @@
|
||||
#if FANTASY_NET
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.IdFactory;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Platform.Net;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
/// <summary>
|
||||
/// Fantasy框架XML配置文件加载器
|
||||
/// </summary>
|
||||
public static class ConfigLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// 从XML配置文件初始化所有配置
|
||||
/// </summary>
|
||||
/// <param name="configPath"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public static async FTask InitializeFromXml(string configPath)
|
||||
{
|
||||
var configText = await FileHelper.GetTextByRelativePath(configPath);
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(configText);
|
||||
|
||||
var root = doc.DocumentElement;
|
||||
if (root?.LocalName != "fantasy")
|
||||
{
|
||||
throw new InvalidOperationException("Invalid Fantasy config file format");
|
||||
}
|
||||
|
||||
// 创建命名空间管理器
|
||||
|
||||
var nsManager = new XmlNamespaceManager(doc.NameTable);
|
||||
nsManager.AddNamespace("f", "http://fantasy.net/config");
|
||||
|
||||
// 加载运行时配置
|
||||
|
||||
LoadRuntimeConfig(root, nsManager);
|
||||
|
||||
var configTableNode = root.SelectSingleNode("f:configTable", nsManager);
|
||||
if (configTableNode != null)
|
||||
{
|
||||
var configTablePath = configTableNode.Attributes?["path"]?.Value;
|
||||
if (string.IsNullOrEmpty(configTablePath))
|
||||
{
|
||||
throw new InvalidOperationException("The configTable in the Fantasy configuration file lacks path configuration");
|
||||
}
|
||||
await LoadJsonConfig(configTablePath);
|
||||
return;
|
||||
}
|
||||
|
||||
var serverNode = root.SelectSingleNode("f:server", nsManager);
|
||||
if (serverNode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing server configuration in Fantasy config file");
|
||||
}
|
||||
|
||||
// 加载框架需要的四个配置文件
|
||||
LoadMachineConfig(serverNode, nsManager);
|
||||
LoadProcessConfig(serverNode, nsManager);
|
||||
LoadWorldConfig(serverNode, nsManager);
|
||||
LoadSceneConfig(serverNode, nsManager);
|
||||
// 验证所有配置的完整性和正确性
|
||||
CheckConfig();
|
||||
}
|
||||
|
||||
#region LoadJsonConfig
|
||||
|
||||
private static async FTask LoadJsonConfig(string configTablePath)
|
||||
{
|
||||
var machineConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/MachineConfigData.Json");
|
||||
|
||||
if (!File.Exists(machineConfigFullPath))
|
||||
{
|
||||
throw new InvalidOperationException($"MachineConfigData.Json not found in the {machineConfigFullPath} directory");
|
||||
}
|
||||
|
||||
var processConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/ProcessConfigData.Json");
|
||||
|
||||
if (!File.Exists(processConfigFullPath))
|
||||
{
|
||||
throw new InvalidOperationException($"ProcessConfigData.Json not found in the {processConfigFullPath} directory");
|
||||
}
|
||||
|
||||
var worldConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/WorldConfigData.Json");
|
||||
|
||||
if (!File.Exists(worldConfigFullPath))
|
||||
{
|
||||
throw new InvalidOperationException($"WorldConfigData.Json not found in the {worldConfigFullPath} directory");
|
||||
}
|
||||
|
||||
var sceneConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/SceneConfigData.Json");
|
||||
|
||||
if (!File.Exists(sceneConfigFullPath))
|
||||
{
|
||||
throw new InvalidOperationException($"SceneConfigData.Json not found in the {sceneConfigFullPath} directory");
|
||||
}
|
||||
|
||||
MachineConfigData.Initialize(await File.ReadAllTextAsync(machineConfigFullPath, Encoding.UTF8));
|
||||
ProcessConfigData.Initialize(await File.ReadAllTextAsync(processConfigFullPath, Encoding.UTF8));
|
||||
WorldConfigData.Initialize(await File.ReadAllTextAsync(worldConfigFullPath, Encoding.UTF8));
|
||||
SceneConfigData.Initialize(await File.ReadAllTextAsync(sceneConfigFullPath, Encoding.UTF8));
|
||||
|
||||
// 验证所有配置的完整性和正确性
|
||||
CheckConfig();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LoadXMLConfig
|
||||
|
||||
private static void LoadMachineConfig(XmlNode serverNode, XmlNamespaceManager nsManager)
|
||||
{
|
||||
var machinesNode = serverNode.SelectSingleNode("f:machines", nsManager);
|
||||
if (machinesNode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing machines configuration - at least one machine must be configured");
|
||||
}
|
||||
|
||||
var machineNodes = machinesNode.SelectNodes("f:machine", nsManager);
|
||||
if (machineNodes == null || machineNodes.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No machine configurations found - at least one machine must be configured");
|
||||
}
|
||||
|
||||
var machineList = new List<MachineConfig>();
|
||||
foreach (XmlNode machineNode in machineNodes)
|
||||
{
|
||||
var machine = new MachineConfig
|
||||
{
|
||||
Id = uint.Parse(GetRequiredAttribute(machineNode, "id")),
|
||||
OuterIP = GetRequiredAttribute(machineNode, "outerIP"),
|
||||
OuterBindIP = GetRequiredAttribute(machineNode, "outerBindIP"),
|
||||
InnerBindIP = GetRequiredAttribute(machineNode, "innerBindIP")
|
||||
};
|
||||
machineList.Add(machine);
|
||||
}
|
||||
|
||||
MachineConfigData.Initialize(machineList);
|
||||
}
|
||||
|
||||
private static void LoadProcessConfig(XmlNode serverNode, XmlNamespaceManager nsManager)
|
||||
{
|
||||
var processesNode = serverNode.SelectSingleNode("f:processes", nsManager);
|
||||
if (processesNode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing processes configuration - at least one process must be configured");
|
||||
}
|
||||
|
||||
var processNodes = processesNode.SelectNodes("f:process", nsManager);
|
||||
if (processNodes == null || processNodes.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No process configurations found - at least one process must be configured");
|
||||
}
|
||||
|
||||
var processList = new List<ProcessConfig>();
|
||||
foreach (XmlNode processNode in processNodes)
|
||||
{
|
||||
var process = new ProcessConfig
|
||||
{
|
||||
Id = uint.Parse(GetRequiredAttribute(processNode, "id")),
|
||||
MachineId = uint.Parse(GetRequiredAttribute(processNode, "machineId")),
|
||||
StartupGroup = uint.Parse(GetRequiredAttribute(processNode, "startupGroup"))
|
||||
};
|
||||
processList.Add(process);
|
||||
}
|
||||
|
||||
ProcessConfigData.Initialize(processList);
|
||||
}
|
||||
|
||||
private static void LoadWorldConfig(XmlNode serverNode, XmlNamespaceManager nsManager)
|
||||
{
|
||||
var worldsNode = serverNode.SelectSingleNode("f:worlds", nsManager);
|
||||
if (worldsNode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing worlds configuration - at least one world must be configured");
|
||||
}
|
||||
|
||||
var worldNodes = worldsNode.SelectNodes("f:world", nsManager);
|
||||
if (worldNodes == null || worldNodes.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No world configurations found - at least one world must be configured");
|
||||
}
|
||||
|
||||
var worldList = new List<WorldConfig>();
|
||||
foreach (XmlNode worldNode in worldNodes)
|
||||
{
|
||||
var world = new WorldConfig
|
||||
{
|
||||
Id = uint.Parse(GetRequiredAttribute(worldNode, "id")),
|
||||
WorldName = GetRequiredAttribute(worldNode, "worldName"),
|
||||
DbConnection = GetOptionalAttribute(worldNode, "dbConnection") ?? string.Empty,
|
||||
DbName = GetRequiredAttribute(worldNode, "dbName"),
|
||||
DbType = GetRequiredAttribute(worldNode, "dbType")
|
||||
};
|
||||
worldList.Add(world);
|
||||
}
|
||||
|
||||
WorldConfigData.Initialize(worldList);
|
||||
}
|
||||
|
||||
private static void LoadSceneConfig(XmlNode serverNode, XmlNamespaceManager nsManager)
|
||||
{
|
||||
var scenesNode = serverNode.SelectSingleNode("f:scenes", nsManager);
|
||||
if (scenesNode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing scenes configuration - at least one scene must be configured");
|
||||
}
|
||||
|
||||
var sceneNodes = scenesNode.SelectNodes("f:scene", nsManager);
|
||||
if (sceneNodes == null || sceneNodes.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No scene configurations found - at least one scene must be configured");
|
||||
}
|
||||
|
||||
var sceneList = new List<SceneConfig>();
|
||||
foreach (XmlNode sceneNode in sceneNodes)
|
||||
{
|
||||
var scene = new SceneConfig
|
||||
{
|
||||
Id = uint.Parse(GetRequiredAttribute(sceneNode, "id")),
|
||||
ProcessConfigId = uint.Parse(GetRequiredAttribute(sceneNode, "processConfigId")),
|
||||
WorldConfigId = uint.Parse(GetRequiredAttribute(sceneNode, "worldConfigId")),
|
||||
SceneRuntimeMode = GetRequiredAttribute(sceneNode, "sceneRuntimeMode"),
|
||||
SceneTypeString = GetRequiredAttribute(sceneNode, "sceneTypeString"),
|
||||
NetworkProtocol = GetOptionalAttribute(sceneNode, "networkProtocol") ?? string.Empty,
|
||||
OuterPort = int.Parse(GetOptionalAttribute(sceneNode, "outerPort") ?? "0"),
|
||||
InnerPort = int.Parse(GetRequiredAttribute(sceneNode, "innerPort")),
|
||||
SceneType = int.Parse(GetRequiredAttribute(sceneNode, "sceneType"))
|
||||
};
|
||||
sceneList.Add(scene);
|
||||
}
|
||||
|
||||
SceneConfigData.Initialize(sceneList);
|
||||
}
|
||||
|
||||
private static string GetRequiredAttribute(XmlNode node, string attributeName)
|
||||
{
|
||||
return node.Attributes?[attributeName]?.Value ?? throw new InvalidOperationException($"Required attribute '{attributeName}' is missing or null");
|
||||
}
|
||||
|
||||
private static string? GetOptionalAttribute(XmlNode? node, string attributeName)
|
||||
{
|
||||
return node?.Attributes?[attributeName]?.Value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CheckConfig
|
||||
|
||||
private static void CheckConfig()
|
||||
{
|
||||
// 检查Machine配置
|
||||
CheckMachineConfig();
|
||||
// 检查Process配置
|
||||
CheckProcessConfig();
|
||||
// 检查World配置
|
||||
CheckWorldConfig();
|
||||
// 检查Scene配置
|
||||
CheckSceneConfig();
|
||||
// 检查引用关系
|
||||
CheckConfigReferences();
|
||||
// 检查端口冲突
|
||||
CheckPortConflicts();
|
||||
}
|
||||
|
||||
private static void CheckMachineConfig()
|
||||
{
|
||||
var machines = MachineConfigData.Instance.List;
|
||||
var machineIds = new HashSet<uint>();
|
||||
|
||||
foreach (var machine in machines)
|
||||
{
|
||||
// 检查ID重复
|
||||
if (!machineIds.Add(machine.Id))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate machine ID: {machine.Id}");
|
||||
}
|
||||
|
||||
// 检查必填字段
|
||||
if (string.IsNullOrWhiteSpace(machine.OuterIP))
|
||||
{
|
||||
throw new InvalidOperationException($"Machine {machine.Id}: OuterIP cannot be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(machine.OuterBindIP))
|
||||
{
|
||||
throw new InvalidOperationException($"Machine {machine.Id}: OuterBindIP cannot be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(machine.InnerBindIP))
|
||||
{
|
||||
throw new InvalidOperationException($"Machine {machine.Id}: InnerBindIP cannot be null or empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckProcessConfig()
|
||||
{
|
||||
var processes = ProcessConfigData.Instance.List;
|
||||
var processIds = new HashSet<uint>();
|
||||
|
||||
foreach (var process in processes)
|
||||
{
|
||||
// 检查ID重复
|
||||
if (!processIds.Add(process.Id))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate process ID: {process.Id}");
|
||||
}
|
||||
|
||||
// 检查必填字段
|
||||
if (process.Id == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Process ID cannot be 0");
|
||||
}
|
||||
|
||||
if (process.MachineId == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Process {process.Id}: MachineId cannot be 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckWorldConfig()
|
||||
{
|
||||
var worlds = WorldConfigData.Instance.List;
|
||||
var worldIds = new HashSet<uint>();
|
||||
|
||||
foreach (var world in worlds)
|
||||
{
|
||||
// 检查ID重复
|
||||
if (!worldIds.Add(world.Id))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate world ID: {world.Id}");
|
||||
}
|
||||
|
||||
// 检查必填字段
|
||||
if (string.IsNullOrWhiteSpace(world.WorldName))
|
||||
{
|
||||
throw new InvalidOperationException($"World {world.Id}: WorldName cannot be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(world.DbName))
|
||||
{
|
||||
throw new InvalidOperationException($"World {world.Id}: DbName cannot be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(world.DbType))
|
||||
{
|
||||
throw new InvalidOperationException($"World {world.Id}: DbType cannot be null or empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckSceneConfig()
|
||||
{
|
||||
var scenes = SceneConfigData.Instance.List;
|
||||
var sceneIds = new HashSet<uint>();
|
||||
|
||||
foreach (var scene in scenes)
|
||||
{
|
||||
// 检查ID重复
|
||||
if (!sceneIds.Add(scene.Id))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate scene ID: {scene.Id}");
|
||||
}
|
||||
|
||||
// 检查必填字段
|
||||
if (scene.ProcessConfigId == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: ProcessConfigId cannot be 0");
|
||||
}
|
||||
|
||||
if (scene.WorldConfigId == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: WorldConfigId cannot be 0");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(scene.SceneRuntimeMode))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: SceneRuntimeMode cannot be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(scene.SceneTypeString))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: SceneTypeString cannot be null or empty");
|
||||
}
|
||||
|
||||
if (scene.InnerPort == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: InnerPort cannot be 0");
|
||||
}
|
||||
|
||||
if (scene.SceneType == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: SceneType cannot be 0");
|
||||
}
|
||||
|
||||
// 检查NetworkProtocol配置
|
||||
if (scene.OuterPort > 0 && string.IsNullOrWhiteSpace(scene.NetworkProtocol))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: NetworkProtocol must be set when OuterPort > 0");
|
||||
}
|
||||
|
||||
// 检查Scene ID范围(仅在IdFactoryType.World模式下)
|
||||
CheckSceneIdRange(scene);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckConfigReferences()
|
||||
{
|
||||
// 检查Process的MachineId引用
|
||||
foreach (var process in ProcessConfigData.Instance.List)
|
||||
{
|
||||
if (MachineConfigData.Instance.List.All(m => m.Id != process.MachineId))
|
||||
{
|
||||
throw new InvalidOperationException($"Process {process.Id}: Referenced MachineId {process.MachineId} not found");
|
||||
}
|
||||
}
|
||||
|
||||
// 检查Scene的ProcessConfigId和WorldConfigId引用
|
||||
foreach (var scene in SceneConfigData.Instance.List)
|
||||
{
|
||||
if (ProcessConfigData.Instance.List.All(p => p.Id != scene.ProcessConfigId))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: Referenced ProcessConfigId {scene.ProcessConfigId} not found");
|
||||
}
|
||||
|
||||
if (WorldConfigData.Instance.List.All(w => w.Id != scene.WorldConfigId))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: Referenced WorldConfigId {scene.WorldConfigId} not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckPortConflicts()
|
||||
{
|
||||
// 按机器分组检查端口冲突
|
||||
var machinePortMap = new Dictionary<uint, Dictionary<int, uint>>(); // MachineId -> (Port -> SceneId)
|
||||
|
||||
foreach (var scene in SceneConfigData.Instance.List)
|
||||
{
|
||||
// 获取Scene所属的机器ID
|
||||
var process = ProcessConfigData.Instance.Get(scene.ProcessConfigId);
|
||||
var machineId = process.MachineId;
|
||||
|
||||
if (!machinePortMap.ContainsKey(machineId))
|
||||
{
|
||||
machinePortMap[machineId] = new Dictionary<int, uint>();
|
||||
}
|
||||
|
||||
var machinePorts = machinePortMap[machineId];
|
||||
|
||||
// 检查同一Scene内InnerPort和OuterPort是否冲突
|
||||
if (scene.OuterPort > 0 && scene.InnerPort == scene.OuterPort)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: InnerPort and OuterPort cannot use the same port {scene.InnerPort}");
|
||||
}
|
||||
|
||||
// 检查InnerPort在同一机器下是否与其他端口冲突
|
||||
if (machinePorts.TryGetValue(scene.InnerPort, out var conflictSceneId1))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: InnerPort {scene.InnerPort} conflicts with another port from Scene {conflictSceneId1} on Machine {machineId}");
|
||||
}
|
||||
machinePorts[scene.InnerPort] = scene.Id;
|
||||
|
||||
// 检查OuterPort在同一机器下是否与其他端口冲突(如果不为0)
|
||||
if (scene.OuterPort > 0)
|
||||
{
|
||||
if (machinePorts.TryGetValue(scene.OuterPort, out var conflictSceneId))
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: OuterPort {scene.OuterPort} conflicts with another port from Scene {conflictSceneId} on Machine {machineId}");
|
||||
}
|
||||
machinePorts[scene.OuterPort] = scene.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckSceneIdRange(SceneConfig scene)
|
||||
{
|
||||
// 检查当前是否为World模式的ID工厂
|
||||
if (IdFactoryHelper.GetIdFactoryType() != IdFactoryType.World)
|
||||
{
|
||||
return; // 非World模式不需要检查
|
||||
}
|
||||
|
||||
var worldConfigId = scene.WorldConfigId;
|
||||
var minAllowedId = worldConfigId * 1000 + 1;
|
||||
var maxAllowedId = worldConfigId * 1000 + 255;
|
||||
|
||||
if (scene.Id < minAllowedId)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: ID must be >= {minAllowedId} (WorldConfigId {worldConfigId} * 1000 + 1)");
|
||||
}
|
||||
|
||||
if (scene.Id > maxAllowedId)
|
||||
{
|
||||
throw new InvalidOperationException($"Scene {scene.Id}: ID must be <= {maxAllowedId} (WorldConfigId {worldConfigId} * 1000 + 255)");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LoadRuntimeConfig
|
||||
|
||||
private static void LoadRuntimeConfig(XmlNode root, XmlNamespaceManager nsManager)
|
||||
{
|
||||
// 加载IdFactory配置
|
||||
|
||||
XmlNode? idFactoryNode = root.SelectSingleNode("f:idFactory", nsManager);
|
||||
string idFactoryType = GetOptionalAttribute(idFactoryNode, "type") ?? "World";
|
||||
IdFactoryHelper.Initialize(Enum.Parse<IdFactoryType>(idFactoryType));
|
||||
|
||||
// 加载网络配置
|
||||
|
||||
XmlNode? networkNode = root.SelectSingleNode("f:network", nsManager);
|
||||
ProgramDefine.InnerNetwork = Enum.Parse<NetworkProtocolType>(GetOptionalAttribute(networkNode, "inner") ?? "TCP");
|
||||
ProgramDefine.MaxMessageSize = int.Parse(GetOptionalAttribute(networkNode, "maxMessageSize") ?? "1048560");
|
||||
|
||||
// 加载会话配置
|
||||
|
||||
XmlNode? sessionNode = root.SelectSingleNode("f:session", nsManager);
|
||||
ProgramDefine.SessionIdleCheckerTimeout = int.Parse(GetOptionalAttribute(sessionNode, "idleTimeout") ?? "8000");
|
||||
ProgramDefine.SessionIdleCheckerInterval = int.Parse(GetOptionalAttribute(sessionNode, "idleInterval") ?? "5000");
|
||||
|
||||
Log.Info($"Current inner network protocol:{ProgramDefine.InnerNetwork.ToString()}");
|
||||
Log.Info($"Max Message Size(byte):{ProgramDefine.MaxMessageSize}");
|
||||
Log.Info($"Current session idle timeout:{ProgramDefine.SessionIdleCheckerTimeout}");
|
||||
Log.Info($"Session-check interval:{ProgramDefine.SessionIdleCheckerInterval} ");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
@@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net
|
||||
/// <param name="machineConfigJson"></param>
|
||||
public static void Initialize(string machineConfigJson)
|
||||
{
|
||||
Instance = machineConfigJson.Deserialize<MachineConfigData>();
|
||||
try
|
||||
{
|
||||
Instance = machineConfigJson.Deserialize<MachineConfigData>();
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException($"MachineConfigData.Json format error {e.Message}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化MachineConfig
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
public static void Initialize(List<MachineConfig> list)
|
||||
{
|
||||
Instance = new MachineConfigData
|
||||
{
|
||||
List = list
|
||||
};
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
|
||||
@@ -26,12 +26,34 @@ namespace Fantasy.Platform.Net
|
||||
/// </summary>
|
||||
public static ProcessConfigData Instance { get; private set; }
|
||||
/// <summary>
|
||||
/// 初始化MachineConfig
|
||||
/// 初始化ProcessConfig
|
||||
/// </summary>
|
||||
/// <param name="processConfigJson"></param>
|
||||
public static void Initialize(string processConfigJson)
|
||||
{
|
||||
Instance = processConfigJson.Deserialize<ProcessConfigData>();
|
||||
try
|
||||
{
|
||||
Instance = processConfigJson.Deserialize<ProcessConfigData>();
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException($"ProcessConfigData.Json format error {e.Message}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化ProcessConfig
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
public static void Initialize(List<ProcessConfig> list)
|
||||
{
|
||||
Instance = new ProcessConfigData
|
||||
{
|
||||
List = list
|
||||
};
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
|
||||
@@ -42,7 +42,27 @@ namespace Fantasy.Platform.Net
|
||||
/// <param name="sceneConfigJson"></param>
|
||||
public static void Initialize(string sceneConfigJson)
|
||||
{
|
||||
Instance = sceneConfigJson.Deserialize<SceneConfigData>();
|
||||
try
|
||||
{
|
||||
Instance = sceneConfigJson.Deserialize<SceneConfigData>();
|
||||
Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException($"SceneConfigData.Json format error {e.Message}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化SceneConfig
|
||||
/// </summary>
|
||||
public static void Initialize(List<SceneConfig> sceneConfigs)
|
||||
{
|
||||
Instance = new SceneConfigData() { List = sceneConfigs };
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
config.Initialize();
|
||||
|
||||
@@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net
|
||||
/// <param name="worldConfigJson"></param>
|
||||
public static void Initialize(string worldConfigJson)
|
||||
{
|
||||
Instance = worldConfigJson.Deserialize<WorldConfigData>();
|
||||
try
|
||||
{
|
||||
Instance = worldConfigJson.Deserialize<WorldConfigData>();
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException($"WorldConfigData.Json format error {e.Message}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化WorldConfig
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
public static void Initialize(List<WorldConfig> list)
|
||||
{
|
||||
Instance = new WorldConfigData
|
||||
{
|
||||
List = list
|
||||
};
|
||||
foreach (var config in Instance.List)
|
||||
{
|
||||
Instance._configs.TryAdd(config.Id, config);
|
||||
|
||||
@@ -3,8 +3,6 @@ using CommandLine;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.IdFactory;
|
||||
using Fantasy.LowLevel;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Serialize;
|
||||
// ReSharper disable FunctionNeverReturns
|
||||
@@ -21,21 +19,33 @@ public static class Entry
|
||||
/// <summary>
|
||||
/// 框架初始化
|
||||
/// </summary>
|
||||
/// <param name="log">日志实例</param>
|
||||
/// <param name="assemblies">注册的Assembly</param>
|
||||
public static async FTask Initialize(params System.Reflection.Assembly[] assemblies)
|
||||
/// <returns></returns>
|
||||
public static async FTask Initialize(ILog? log, params System.Reflection.Assembly[] assemblies)
|
||||
{
|
||||
// 注册日志模块到框架
|
||||
if (log != null)
|
||||
{
|
||||
Log.Register(log);
|
||||
}
|
||||
Log.Info($"Fantasy Version:{ProgramDefine.VERSION}");
|
||||
// 加载Fantasy.config配置文件
|
||||
await ConfigLoader.InitializeFromXml(Path.Combine(AppContext.BaseDirectory, "Fantasy.config"));
|
||||
// 解析命令行参数
|
||||
Parser.Default.ParseArguments<CommandLineOptions>(Environment.GetCommandLineArgs())
|
||||
.WithNotParsed(error => throw new Exception("Command line format error!"))
|
||||
.WithParsed(option =>
|
||||
{
|
||||
ProcessDefine.Options = option;
|
||||
ProcessDefine.InnerNetwork = Enum.Parse<NetworkProtocolType>(option.InnerNetwork);
|
||||
ProgramDefine.ProcessId = option.ProcessId;
|
||||
ProgramDefine.ProcessType = option.ProcessType;
|
||||
ProgramDefine.RuntimeMode = Enum.Parse<ProcessMode>(option.RuntimeMode);
|
||||
ProgramDefine.StartupGroup = option.StartupGroup;
|
||||
});
|
||||
// 初始化Log系统
|
||||
Log.Initialize();
|
||||
// 检查启动参数,后期可能有机器人等不同的启动参数
|
||||
switch (ProcessDefine.Options.ProcessType)
|
||||
switch (ProgramDefine.ProcessType)
|
||||
{
|
||||
case "Game":
|
||||
{
|
||||
@@ -43,7 +53,7 @@ public static class Entry
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException($"ProcessType is {ProcessDefine.Options.ProcessType} Unrecognized!");
|
||||
throw new NotSupportedException($"ProcessType is {ProgramDefine.ProcessType} Unrecognized!");
|
||||
}
|
||||
}
|
||||
// 初始化程序集管理系统
|
||||
@@ -52,8 +62,15 @@ public static class Entry
|
||||
SerializerManager.Initialize();
|
||||
// 精度处理(只针对Windows下有作用、其他系统没有这个问题、一般也不会用Windows来做服务器的)
|
||||
WinPeriod.Initialize();
|
||||
}
|
||||
|
||||
FantasyMemory.Initialize();
|
||||
/// <summary>
|
||||
/// 框架初始化
|
||||
/// </summary>
|
||||
/// <param name="assemblies">注册的Assembly</param>
|
||||
public static FTask Initialize(params System.Reflection.Assembly[] assemblies)
|
||||
{
|
||||
return Initialize(null, assemblies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,9 +100,9 @@ public static class Entry
|
||||
|
||||
private static async FTask StartProcess()
|
||||
{
|
||||
if (ProcessDefine.Options.StartupGroup != 0)
|
||||
if (ProgramDefine.StartupGroup != 0)
|
||||
{
|
||||
foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProcessDefine.Options.StartupGroup))
|
||||
foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProgramDefine.StartupGroup))
|
||||
{
|
||||
await Process.Create(processConfig.Id);
|
||||
}
|
||||
@@ -93,9 +110,9 @@ public static class Entry
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ProcessDefine.Options.Mode)
|
||||
switch (ProgramDefine.RuntimeMode)
|
||||
{
|
||||
case "Develop":
|
||||
case ProcessMode.Develop:
|
||||
{
|
||||
foreach (var processConfig in ProcessConfigData.Instance.List)
|
||||
{
|
||||
@@ -104,9 +121,9 @@ public static class Entry
|
||||
|
||||
return;
|
||||
}
|
||||
case "Release":
|
||||
case ProcessMode.Release:
|
||||
{
|
||||
await Process.Create(ProcessDefine.Options.ProcessId);
|
||||
await Process.Create(ProgramDefine.ProcessId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#if FANTASY_NET
|
||||
using CommandLine;
|
||||
using Fantasy.Network;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
namespace Fantasy.Platform.Net;
|
||||
|
||||
@@ -43,57 +41,12 @@ internal sealed class CommandLineOptions
|
||||
/// Develop - 开发模式(启动Process配置表中的所有Process)
|
||||
/// Release - 发布模式(根据ProcessId启动Process)
|
||||
/// </summary>
|
||||
[Option('m', "Mode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")]
|
||||
public string Mode { get; set; }
|
||||
/// <summary>
|
||||
/// 服务器内部网络协议
|
||||
/// TCP - 服务器内部之间通讯使用TCP协议
|
||||
/// KCP - 服务器内部之间通讯使用KCP协议
|
||||
/// WebSocket - 服务器内部之间通讯使用WebSocket协议(不推荐、TCP或KCP)
|
||||
/// </summary>
|
||||
[Option('n', "InnerNetwork", Required = false, Default = "TCP", HelpText = "TCP、KCP、WebSocket")]
|
||||
public string InnerNetwork { get; set; }
|
||||
/// <summary>
|
||||
/// 会话空闲检查超时时间。
|
||||
/// </summary>
|
||||
[Option('t', "SessionIdleCheckerTimeout", Required = false, Default = 8000, HelpText = "Session idle check timeout")]
|
||||
public int SessionIdleCheckerTimeout { get; set; }
|
||||
/// <summary>
|
||||
/// 会话空闲检查间隔。
|
||||
/// </summary>
|
||||
[Option('i', "SessionIdleCheckerInterval", Required = false, Default = 5000, HelpText = "Session idle check interval")]
|
||||
public int SessionIdleCheckerInterval { get; set; }
|
||||
[Option('m', "RuntimeMode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")]
|
||||
public string RuntimeMode { get; set; }
|
||||
/// <summary>
|
||||
/// 启动组。
|
||||
/// </summary>
|
||||
[Option('g', "StartupGroup", Required = false, Default = 0, HelpText = "Used to start a group of Process")]
|
||||
public int StartupGroup { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AppDefine
|
||||
/// </summary>
|
||||
internal static class ProcessDefine
|
||||
{
|
||||
/// <summary>
|
||||
/// 命令行选项
|
||||
/// </summary>
|
||||
public static CommandLineOptions Options;
|
||||
/// <summary>
|
||||
/// App程序Id
|
||||
/// </summary>
|
||||
public static uint ProcessId => Options.ProcessId;
|
||||
/// <summary>
|
||||
/// 会话空闲检查超时时间。
|
||||
/// </summary>
|
||||
public static int SessionIdleCheckerTimeout => Options.SessionIdleCheckerTimeout;
|
||||
/// <summary>
|
||||
/// 会话空闲检查间隔。
|
||||
/// </summary>
|
||||
public static int SessionIdleCheckerInterval => Options.SessionIdleCheckerInterval;
|
||||
/// <summary>
|
||||
/// 内部网络通讯协议类型
|
||||
/// </summary>
|
||||
public static NetworkProtocolType InnerNetwork;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
#if FANTASY_NET
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Platform.Net;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
#endif
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序定义
|
||||
/// </summary>
|
||||
public static class ProgramDefine
|
||||
{
|
||||
/// <summary>
|
||||
/// Fantasy版本。
|
||||
/// </summary>
|
||||
public const string VERSION = "Fantasy 2.0 Beta";
|
||||
/// <summary>
|
||||
/// 消息体最大长度(字节)。默认1024k。
|
||||
/// 注意:前后端设置的消息大小,一定要一样才可以,不然会不出现问题。
|
||||
/// </summary>
|
||||
public static int MaxMessageSize { get; set; } = ushort.MaxValue * 16;
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// App程序Id。
|
||||
/// </summary>
|
||||
public static uint ProcessId { get; internal set; }
|
||||
/// <summary>
|
||||
/// 应用程序的类型。
|
||||
/// </summary>
|
||||
public static string ProcessType { get; internal set; }
|
||||
/// <summary>
|
||||
/// 服务器运行模式,获取或设置服务器的运行模式。
|
||||
/// </summary>
|
||||
public static ProcessMode RuntimeMode { get; internal set; }
|
||||
/// <summary>
|
||||
/// 服务器启动组
|
||||
/// </summary>
|
||||
public static int StartupGroup { get; internal set; }
|
||||
/// <summary>
|
||||
/// 会话空闲检查超时时间。
|
||||
/// </summary>
|
||||
public static int SessionIdleCheckerTimeout { get; internal set; }
|
||||
/// <summary>
|
||||
/// 会话空闲检查间隔。
|
||||
/// </summary>
|
||||
public static int SessionIdleCheckerInterval { get; internal set; }
|
||||
/// <summary>
|
||||
/// 内部网络通讯协议类型。
|
||||
/// </summary>
|
||||
public static NetworkProtocolType InnerNetwork { get; internal set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#if FANTASY_UNITY
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
@@ -52,6 +53,8 @@ namespace Fantasy.Platform.Unity
|
||||
}
|
||||
FantasyObject.OnRuntimeMethodLoad();
|
||||
Log.Register(new UnityLog());
|
||||
ProgramDefine.MaxMessageSize = ushort.MaxValue * 16;
|
||||
Log.Info($"Fantasy Version:{ProgramDefine.VERSION}");
|
||||
await AssemblySystem.InnerInitialize(assemblies);
|
||||
// 初始化序列化
|
||||
SerializerManager.Initialize();
|
||||
@@ -86,6 +89,11 @@ namespace Fantasy.Platform.Unity
|
||||
ThreadScheduler.Update();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
ThreadScheduler.LateUpdate();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
AssemblySystem.Dispose();
|
||||
|
||||
@@ -9,7 +9,23 @@ namespace Fantasy
|
||||
{
|
||||
public void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#if FANTASY_UNITY
|
||||
internal interface ISceneLateUpdate
|
||||
{
|
||||
void LateUpdate();
|
||||
}
|
||||
|
||||
internal sealed class EmptySceneLateUpdate : ISceneLateUpdate
|
||||
{
|
||||
public void LateUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -163,7 +163,11 @@ namespace Fantasy
|
||||
EntityPool = new EntityPool();
|
||||
EntityListPool = new EntityListPool<Entity>();
|
||||
EntitySortedDictionaryPool = new EntitySortedDictionaryPool<long, Entity>();
|
||||
SceneUpdate = EntityComponent = await Create<EntityComponent>(this, false, false).Initialize();
|
||||
EntityComponent = await Create<EntityComponent>(this, false, false).Initialize();
|
||||
SceneUpdate = EntityComponent;
|
||||
#if FANTASY_UNITY
|
||||
SceneLateUpdate = EntityComponent;
|
||||
#endif
|
||||
MessagePoolComponent = Create<MessagePoolComponent>(this,false,true);
|
||||
EventComponent = await Create<EventComponent>(this,false,true).Initialize();
|
||||
TimerComponent = Create<TimerComponent>(this, false, true).Initialize();
|
||||
@@ -265,6 +269,7 @@ namespace Fantasy
|
||||
#elif FANTASY_UNITY
|
||||
Session = null;
|
||||
UnityNetwork = null;
|
||||
SceneLateUpdate = null;
|
||||
#endif
|
||||
ThreadSynchronizationContext = null;
|
||||
SceneRuntimeType = SceneRuntimeType.None;
|
||||
@@ -273,7 +278,6 @@ namespace Fantasy
|
||||
#endregion
|
||||
|
||||
internal ISceneUpdate SceneUpdate { get; set; }
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
try
|
||||
@@ -285,7 +289,20 @@ namespace Fantasy
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
#if FANTASY_UNITY
|
||||
internal ISceneLateUpdate SceneLateUpdate { get; set; }
|
||||
internal void LateUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
SceneLateUpdate.LateUpdate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#region Create
|
||||
|
||||
#if FANTASY_UNITY || FANTASY_CONSOLE
|
||||
@@ -379,7 +396,7 @@ namespace Fantasy
|
||||
if (sceneConfig.InnerPort != 0)
|
||||
{
|
||||
// 创建内网网络服务器
|
||||
scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort);
|
||||
scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProgramDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort);
|
||||
}
|
||||
|
||||
if (sceneConfig.OuterPort != 0)
|
||||
@@ -446,6 +463,9 @@ namespace Fantasy
|
||||
{
|
||||
scene.ThreadSynchronizationContext = ThreadScheduler.MainScheduler.ThreadSynchronizationContext;
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
#if FANTASY_UNITY
|
||||
scene.SceneLateUpdate = new EmptySceneLateUpdate();
|
||||
#endif
|
||||
ThreadScheduler.AddMainScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
@@ -456,6 +476,9 @@ namespace Fantasy
|
||||
scene.ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
#endif
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
#if FANTASY_UNITY
|
||||
scene.SceneLateUpdate = new EmptySceneLateUpdate();
|
||||
#endif
|
||||
ThreadScheduler.AddToMultiThreadScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
@@ -466,6 +489,9 @@ namespace Fantasy
|
||||
scene.ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
#endif
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
#if FANTASY_UNITY
|
||||
scene.SceneLateUpdate = new EmptySceneLateUpdate();
|
||||
#endif
|
||||
ThreadScheduler.AddToThreadPoolScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
@@ -567,7 +593,7 @@ namespace Fantasy
|
||||
/// <param name="runTimeId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public virtual Session GetSession(long runTimeId)
|
||||
internal virtual Session GetSession(long runTimeId)
|
||||
{
|
||||
var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref runTimeId);
|
||||
|
||||
@@ -605,7 +631,7 @@ namespace Fantasy
|
||||
}
|
||||
|
||||
var remoteAddress = $"{machineConfig.InnerBindIP}:{sceneConfig.InnerPort}";
|
||||
var client = NetworkProtocolFactory.CreateClient(Scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner);
|
||||
var client = NetworkProtocolFactory.CreateClient(Scene, ProgramDefine.InnerNetwork, NetworkTarget.Inner);
|
||||
var session = client.Connect(remoteAddress, null, () =>
|
||||
{
|
||||
Log.Error($"Unable to connect to the target server sourceServerId:{Scene.Process.Id} targetServerId:{sceneConfig.ProcessConfigId}");
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Fantasy
|
||||
public MainScheduler()
|
||||
{
|
||||
ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
#if !FANTASY_WEBGL
|
||||
#if !FANTASY_WEBGL || !UNITY_EDITOR
|
||||
SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext);
|
||||
#endif
|
||||
}
|
||||
@@ -79,5 +79,27 @@ namespace Fantasy
|
||||
_queue.Enqueue(scene);
|
||||
}
|
||||
}
|
||||
#if FANTASY_UNITY
|
||||
public void LateUpdate()
|
||||
{
|
||||
var initialCount = _queue.Count;
|
||||
|
||||
while (initialCount-- > 0)
|
||||
{
|
||||
if(!_queue.TryDequeue(out var scene))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scene.IsDisposed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scene.LateUpdate();
|
||||
_queue.Enqueue(scene);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Fantasy
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private readonly List<Thread> _threads;
|
||||
private readonly ConcurrentBag<Scene> _queue = new ConcurrentBag<Scene>();
|
||||
private readonly ConcurrentQueue<Scene> _queue = new ConcurrentQueue<Scene>();
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
public ThreadPoolScheduler()
|
||||
@@ -63,7 +63,7 @@ namespace Fantasy
|
||||
return;
|
||||
}
|
||||
|
||||
_queue.Add(scene);
|
||||
_queue.Enqueue(scene);
|
||||
}
|
||||
|
||||
public void Remove(Scene scene)
|
||||
@@ -75,20 +75,18 @@ namespace Fantasy
|
||||
|
||||
var newQueue = new Queue<Scene>();
|
||||
|
||||
while (!_queue.IsEmpty)
|
||||
while (_queue.TryDequeue(out var currentScene))
|
||||
{
|
||||
if (_queue.TryTake(out var currentScene))
|
||||
if (currentScene == scene)
|
||||
{
|
||||
if (currentScene != scene)
|
||||
{
|
||||
newQueue.Enqueue(currentScene);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
newQueue.Enqueue(currentScene);
|
||||
}
|
||||
|
||||
while (newQueue.TryDequeue(out var newScene))
|
||||
{
|
||||
_queue.Add(newScene);
|
||||
_queue.Enqueue(newScene);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +99,7 @@ namespace Fantasy
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (_queue.TryTake(out var scene))
|
||||
if (_queue.TryDequeue(out var scene))
|
||||
{
|
||||
if (scene == null || scene.IsDisposed)
|
||||
{
|
||||
@@ -124,9 +122,9 @@ namespace Fantasy
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
|
||||
_queue.Add(scene);
|
||||
// 先停止线程后再如队列,避免同一个Scene多次重复执行
|
||||
Thread.Sleep(1);
|
||||
_queue.Enqueue(scene);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -30,6 +30,13 @@ namespace Fantasy
|
||||
MainScheduler.Update();
|
||||
}
|
||||
|
||||
#if FANTASY_UNITY
|
||||
internal static void LateUpdate()
|
||||
{
|
||||
MainScheduler.LateUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static void AddMainScheduler(Scene scene)
|
||||
{
|
||||
MainScheduler.Add(scene);
|
||||
|
||||
@@ -22,24 +22,27 @@ namespace Fantasy
|
||||
/// 存储当前Scene下管理的实体。
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Entity> _entities = new Dictionary<long, Entity>();
|
||||
|
||||
internal void Initialize(Scene rootScene)
|
||||
|
||||
internal void Initialize(Scene rootScene)
|
||||
{
|
||||
EntityPool = rootScene.EntityPool;
|
||||
EntityListPool = rootScene.EntityListPool;
|
||||
EntitySortedDictionaryPool = rootScene.EntitySortedDictionaryPool;
|
||||
SceneUpdate = rootScene.SceneUpdate;
|
||||
#if FANTASY_UNITY
|
||||
SceneLateUpdate = rootScene.SceneLateUpdate;
|
||||
#endif
|
||||
TimerComponent = rootScene.TimerComponent;
|
||||
EventComponent = rootScene.EventComponent;
|
||||
EntityComponent = rootScene.EntityComponent;
|
||||
MessagePoolComponent = rootScene.MessagePoolComponent;
|
||||
CoroutineLockComponent = rootScene.CoroutineLockComponent;
|
||||
MessageDispatcherComponent = rootScene.MessageDispatcherComponent;
|
||||
#if FANTASY_NET
|
||||
#if FANTASY_NET
|
||||
NetworkMessagingComponent = rootScene.NetworkMessagingComponent;
|
||||
SingleCollectionComponent = rootScene.SingleCollectionComponent;
|
||||
TerminusComponent = rootScene.TerminusComponent;
|
||||
#endif
|
||||
#endif
|
||||
ThreadSynchronizationContext = rootScene.ThreadSynchronizationContext;
|
||||
}
|
||||
|
||||
@@ -162,7 +165,7 @@ namespace Fantasy
|
||||
/// <param name="runTimeId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override Session GetSession(long runTimeId)
|
||||
internal override Session GetSession(long runTimeId)
|
||||
{
|
||||
return RootScene.GetSession(runTimeId);
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace Fantasy.Serialize
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] Serialize(object @object)
|
||||
public byte[] Serialize(object @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
@@ -287,7 +287,7 @@ namespace Fantasy.Serialize
|
||||
/// <param name="object"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static byte[] Serialize<T>(T @object)
|
||||
public byte[] Serialize<T>(T @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,16 @@ namespace Fantasy.Serialize
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte[] Serialize(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte[] Serialize<T>(T @object)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize<T>(T @object, IBufferWriter<byte> buffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -59,6 +59,19 @@ namespace Fantasy.Serialize
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
byte[] Serialize(object obj);
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
byte[] Serialize<T>(T @object);
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
|
||||
@@ -182,7 +182,12 @@ namespace Fantasy.Serialize
|
||||
|
||||
RuntimeTypeModel.Default.Serialize(buffer, @object);
|
||||
}
|
||||
internal byte[] Serialize(object @object)
|
||||
/// <summary>
|
||||
/// 使用ProtoBuf序列化某一个实例到byte[]
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] Serialize(object @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
@@ -195,7 +200,13 @@ namespace Fantasy.Serialize
|
||||
return buffer.ToArray();
|
||||
}
|
||||
}
|
||||
private byte[] Serialize<T>(T @object)
|
||||
/// <summary>
|
||||
/// 使用ProtoBuf序列化某一个实例到byte[]
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public byte[] Serialize<T>(T @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
|
||||
@@ -174,7 +174,30 @@ namespace Fantasy.Serialize
|
||||
|
||||
RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object);
|
||||
}
|
||||
private byte[] Serialize<T>(T @object)
|
||||
/// <summary>
|
||||
/// 使用ProtoBuf序列化某一个实例到byte[]
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] Serialize(object @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
aSerialize.BeginInit();
|
||||
}
|
||||
|
||||
using (var buffer = new MemoryStream())
|
||||
{
|
||||
RuntimeTypeModel.Default.Serialize(buffer, @object);
|
||||
return buffer.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 使用ProtoBuf序列化某一个实例到byte[]
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] Serialize<T>(T @object)
|
||||
{
|
||||
if (@object is ASerialize aSerialize)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,9 @@ namespace Fantasy.Serialize
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
#if FANTASY_DEBUG
|
||||
Log.Info($"初始化序列化器成功,数量为:{_serializers.Length}");
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -118,6 +120,12 @@ namespace Fantasy.Serialize
|
||||
public static void Dispose()
|
||||
{
|
||||
_isInitialized = false;
|
||||
|
||||
if (_serializers == null || _serializers.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Array.Clear(_serializers, 0, _serializers.Length);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user