1、修复了MongoDB在2.18.0以后需要自定义注册ObjectSerializer的问题。 2、Addressable的AddAddressable接口增加isLock参数、用来决定是否需要添加携程锁。 3、修复了APackInfo因为网络多线程的原因导致线程安全的问题。

1、修复了MongoDB在2.18.0以后需要自定义注册ObjectSerializer的问题。
2、Addressable的AddAddressable接口增加isLock参数、用来决定是否需要添加携程锁。
3、修复了APackInfo因为网络多线程的原因导致线程安全的问题。
This commit is contained in:
ALEXTANG
2023-08-04 01:41:31 +08:00
parent 774b73bbbf
commit 36d2c146b0
29 changed files with 253 additions and 26 deletions

View File

@@ -63,6 +63,14 @@ namespace TEngine.Core
LoadAssembly(assemblyName, assembly); LoadAssembly(assemblyName, assembly);
} }
public static IEnumerable<int> ForEachAssemblyName()
{
foreach (var (key, _) in AssemblyList)
{
yield return key;
}
}
public static IEnumerable<Type> ForEach() public static IEnumerable<Type> ForEach()
{ {

View File

@@ -7,5 +7,6 @@ namespace TEngine.Core
public const uint ErrRouteTimeout = 100000004; // 发送Route消息超时 public const uint ErrRouteTimeout = 100000004; // 发送Route消息超时
public const uint Error_NotFindEntity = 100000008; // 没有找到Entity public const uint Error_NotFindEntity = 100000008; // 没有找到Entity
public const uint Error_CopyTimeout = 100000009; // CopyTimeout不能小于或等于0 public const uint Error_CopyTimeout = 100000009; // CopyTimeout不能小于或等于0
public const uint Error_Transfer = 100000010;// 传送发生了错误
} }
} }

View File

@@ -79,6 +79,7 @@ public static class Define
public static readonly HashSet<string> ColTypeSet = new HashSet<string>() public static readonly HashSet<string> ColTypeSet = new HashSet<string>()
{ {
"", "0", "bool", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "string", "AttrConfig", "", "0", "bool", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "string", "AttrConfig",
"IntDictionaryConfig", "StringDictionaryConfig",
"short[]", "int[]", "long[]", "float[]", "string[]" "short[]", "int[]", "long[]", "float[]", "string[]"
}; };
/// <summary> /// <summary>

View File

@@ -13,6 +13,7 @@ using Newtonsoft.Json;
// ReSharper disable SuspiciousTypeConversion.Global // ReSharper disable SuspiciousTypeConversion.Global
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace TEngine namespace TEngine
{ {
@@ -401,11 +402,54 @@ namespace TEngine
} }
#endregion #endregion
#if TENGINE_NET
#region ForEach
public IEnumerable<Entity> ForEachSingleCollection
{
get
{
foreach (var (_, treeEntity) in _tree)
{
if (treeEntity is not ISupportedSingleCollection)
{
continue;
}
yield return treeEntity;
}
}
}
public IEnumerable<Entity> ForEachTransfer
{
get
{
if (_tree != null)
{
foreach (var (_, treeEntity) in _tree)
{
if (treeEntity is ISupportedSingleCollection || treeEntity is ISupportedTransfer)
{
yield return treeEntity;
}
}
}
if (_multiDb != null)
{
foreach (var treeEntity in _multiDb)
{
if (treeEntity is not ISupportedTransfer)
{
continue;
}
yield return treeEntity;
}
}
}
}
#endregion
#endif
#region GetComponent #region GetComponent
public DictionaryPool<Type, Entity> GetTree => _tree;
public T GetComponent<T>() where T : Entity, new() public T GetComponent<T>() where T : Entity, new()
{ {
return GetComponent(typeof(T)) as T; return GetComponent(typeof(T)) as T;

View File

@@ -0,0 +1,30 @@
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace TEngine
{
public readonly struct EntityReference<T> where T : Entity
{
private readonly T _entity;
private readonly long _runTimeId;
private EntityReference(T t)
{
_entity = t;
_runTimeId = t.RuntimeId;
}
public static implicit operator EntityReference<T>(T t)
{
return new EntityReference<T>(t);
}
public static implicit operator T(EntityReference<T> v)
{
if (v._entity == null)
{
return null;
}
return v._entity.RuntimeId != v._runTimeId ? null : v._entity;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c827c6f914b64f5d9eb0a1f29cc2c018
timeCreated: 1691083017

View File

@@ -0,0 +1,8 @@
#if TENGINE_NET
namespace TEngine;
/// <summary>
/// Entity支持传送。
/// </summary>
public interface ISupportedTransfer { }
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06770f37cdfc480fb0c270ea93a10d26
timeCreated: 1691083054

View File

@@ -91,7 +91,7 @@ namespace TEngine
} }
#else #else
/// <summary> /// <summary>
/// 创建一个Scene、但这个Scene是在某个Scene下面的Scene /// 创建一个Scene。
/// </summary> /// </summary>
/// <param name="scene"></param> /// <param name="scene"></param>
/// <param name="sceneType"></param> /// <param name="sceneType"></param>
@@ -101,24 +101,24 @@ namespace TEngine
public static async FTask<T> Create<T>(Scene scene, int sceneType, int sceneSubType) where T : Scene, new() public static async FTask<T> Create<T>(Scene scene, int sceneType, int sceneSubType) where T : Scene, new()
{ {
var newScene = Create<T>(scene); var newScene = Create<T>(scene);
newScene.Scene = scene; newScene.Scene = newScene;
newScene.Parent = scene; newScene.Parent = scene;
newScene.SceneType = sceneType; newScene.SceneType = sceneType;
newScene.SceneSubType = sceneSubType; newScene.SceneSubType = sceneSubType;
newScene.Server = scene.Server; newScene.Server = scene.Server;
newScene.LocationId = scene.Server.Id; newScene.LocationId = scene.Server.Id;
if (scene.World !=null) if (scene.World != null)
{ {
newScene.World = scene.World; newScene.World = scene.World;
} }
if (sceneType > 0) if (sceneType > 0)
{ {
await EventSystem.Instance.PublishAsync(new OnCreateScene(scene)); await EventSystem.Instance.PublishAsync(new OnCreateScene(newScene));
} }
Scenes.Add(scene); Scenes.Add(newScene);
return newScene; return newScene;
} }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2da9efac32374cb1a88c500e7ed43344
timeCreated: 1691084274

View File

@@ -0,0 +1,31 @@
using ProtoBuf;
namespace TEngine.Core
{
[ProtoContract]
public class IntDictionaryConfig
{
[ProtoMember(1, IsRequired = true)]
public Dictionary<int, int> Dic;
public int this[int key] => GetValue(key);
public bool TryGetValue(int key, out int value)
{
value = default;
if (!Dic.ContainsKey(key))
{
return false;
}
value = Dic[key];
return true;
}
private int GetValue(int key)
{
return Dic.TryGetValue(key, out var value) ? value : default;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 34b41344fd6e462bae371207cdf8a5cd
timeCreated: 1691084286

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using ProtoBuf;
namespace TEngine.Core
{
[ProtoContract]
public sealed class StringDictionaryConfig
{
[ProtoMember(1, IsRequired = true)]
public Dictionary<int, string> Dic;
public string this[int key] => GetValue(key);
public bool TryGetValue(int key, out string value)
{
value = default;
if (!Dic.ContainsKey(key))
{
return false;
}
value = Dic[key];
return true;
}
private string GetValue(int key)
{
return Dic.TryGetValue(key, out var value) ? value : default;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a26ad73832de4b3e986ddb58426bcced
timeCreated: 1691084294

View File

@@ -735,6 +735,34 @@ public sealed class ExcelExporter
return; return;
} }
case "IntDictionaryConfig":
{
if (value.Trim() == "" || value.Trim() == "{}")
{
propertyInfo.SetValue(config, null);
return;
}
var attr = new IntDictionaryConfig {Dic = JsonConvert.DeserializeObject<Dictionary<int, int>>(value)};
propertyInfo.SetValue(config, attr);
return;
}
case "StringDictionaryConfig":
{
if (value.Trim() == "" || value.Trim() == "{}")
{
propertyInfo.SetValue(config, null);
return;
}
var attr = new StringDictionaryConfig {Dic = JsonConvert.DeserializeObject<Dictionary<int, string>>(value)};
propertyInfo.SetValue(config, attr);
return;
}
default: default:
throw new NotSupportedException($"不支持此类型: {type}"); throw new NotSupportedException($"不支持此类型: {type}");
} }

View File

@@ -424,7 +424,9 @@ public sealed class ProtoBufExporter
"int32[]" => "int[] { }", "int32[]" => "int[] { }",
"int64[]" => "long[] { }", "int64[]" => "long[] { }",
"int32" => "int", "int32" => "int",
"uint32" => "uint",
"int64" => "long", "int64" => "long",
"uint64" => "ulong",
_ => type _ => type
}; };
} }

View File

@@ -179,9 +179,8 @@ public sealed class MongoHelper : Singleton<MongoHelper>
public void SerializeTo<T>(T t, MemoryStream stream) public void SerializeTo<T>(T t, MemoryStream stream)
{ {
var bytes = t.ToBson(); using var writer = new BsonBinaryWriter(stream, BsonBinaryWriterSettings.Defaults);
BsonSerializer.Serialize(writer, typeof(T), t);
stream.Write(bytes, 0, bytes.Length);
} }
public T Clone<T>(T t) public T Clone<T>(T t)

View File

@@ -51,7 +51,7 @@ public class SessionIdleCheckerComponent: Entity
return; return;
} }
Log.Warning($"session timeout id:{Id}"); Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}");
_session.Dispose(); _session.Dispose();
} }
} }

View File

@@ -19,15 +19,14 @@ namespace TEngine.Core.Network
} }
} }
public static async FTask AddAddressable(Scene scene, long addressableId, long routeId) public static async FTask AddAddressable(Scene scene, long addressableId, long routeId, bool isLock = true)
{ {
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId, var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableAdd_Request new I_AddressableAdd_Request
{ {
AddressableId = addressableId, RouteId = routeId AddressableId = addressableId, RouteId = routeId, IsLock = isLock
}); });
if (response.ErrorCode != 0) if (response.ErrorCode != 0)
{ {
Log.Error($"AddAddressable error is {response.ErrorCode}"); Log.Error($"AddAddressable error is {response.ErrorCode}");

View File

@@ -8,13 +8,28 @@ namespace TEngine.Core.Network
private readonly Dictionary<long, WaitCoroutineLock> _locks = new(); private readonly Dictionary<long, WaitCoroutineLock> _locks = new();
private readonly CoroutineLockQueueType _addressableLock = new CoroutineLockQueueType("AddressableLock"); private readonly CoroutineLockQueueType _addressableLock = new CoroutineLockQueueType("AddressableLock");
public async FTask Add(long addressableId, long routeId) public async FTask Add(long addressableId, long routeId, bool isLock)
{ {
using (await _addressableLock.Lock(addressableId)) WaitCoroutineLock waitCoroutineLock = null;
try
{ {
if (isLock)
{
waitCoroutineLock = await _addressableLock.Lock(addressableId);
}
_addressable[addressableId] = routeId; _addressable[addressableId] = routeId;
Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}"); Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}");
} }
catch (Exception e)
{
Log.Error(e);
}
finally
{
waitCoroutineLock?.Dispose();
}
} }
public async FTask<long> Get(long addressableId) public async FTask<long> Get(long addressableId)
@@ -31,6 +46,7 @@ namespace TEngine.Core.Network
using (await _addressableLock.Lock(addressableId)) using (await _addressableLock.Lock(addressableId))
{ {
_addressable.Remove(addressableId); _addressable.Remove(addressableId);
Log.Debug($"Addressable Remove addressableId: {addressableId} _addressable:{_addressable.Count}");
} }
} }

View File

@@ -19,7 +19,7 @@ namespace TEngine.Core.Network
base.Dispose(); base.Dispose();
} }
public FTask Register() public FTask Register(bool isLock = true)
{ {
if (Parent == null) if (Parent == null)
{ {
@@ -36,7 +36,7 @@ namespace TEngine.Core.Network
#if TENGINE_DEVELOP #if TENGINE_DEVELOP
Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}"); Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}");
#endif #endif
return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId); return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId, isLock);
} }
public FTask Lock() public FTask Lock()

View File

@@ -5,7 +5,7 @@ public sealed class I_AddressableAddHandler : RouteRPC<Scene, I_AddressableAdd_R
{ {
protected override async FTask Run(Scene scene, I_AddressableAdd_Request request, I_AddressableAdd_Response response, Action reply) protected override async FTask Run(Scene scene, I_AddressableAdd_Request request, I_AddressableAdd_Response response, Action reply)
{ {
await scene.GetComponent<AddressableManageComponent>().Add(request.AddressableId, request.RouteId); await scene.GetComponent<AddressableManageComponent>().Add(request.AddressableId, request.RouteId, request.IsLock);
} }
} }
#endif #endif

View File

@@ -78,7 +78,7 @@ namespace TEngine.Core.Network
{ {
if (DisposePackInfo) if (DisposePackInfo)
{ {
packInfo.Dispose(); NetworkThread.Instance.SynchronizationContext.Post(packInfo.Dispose);
} }
} }
} }

View File

@@ -63,6 +63,8 @@ namespace TEngine
public long AddressableId { get; set; } public long AddressableId { get; set; }
[ProtoMember(2)] [ProtoMember(2)]
public long RouteId { get; set; } public long RouteId { get; set; }
[ProtoMember(3)]
public bool IsLock { get; set; }
} }
[ProtoContract] [ProtoContract]
public partial class I_AddressableAdd_Response : AProto, IRouteResponse public partial class I_AddressableAdd_Response : AProto, IRouteResponse

View File

@@ -46,7 +46,7 @@ namespace TEngine.Core.Network
} }
finally finally
{ {
packInfo.Dispose(); NetworkThread.Instance.SynchronizationContext.Post(packInfo.Dispose);
} }
await FTask.CompletedTask; await FTask.CompletedTask;

View File

@@ -103,7 +103,7 @@ namespace TEngine.Core.Network
} }
finally finally
{ {
packInfo.Dispose(); NetworkThread.Instance.SynchronizationContext.Post(packInfo.Dispose);
} }
} }

View File

@@ -120,7 +120,7 @@ namespace TEngine.Core.Network
} }
finally finally
{ {
packInfo.Dispose(); NetworkThread.Instance.SynchronizationContext.Post(packInfo.Dispose);
} }
throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}");

View File

@@ -1,6 +1,8 @@
#if TENGINE_NET #if TENGINE_NET
using System.Buffers; using System.Buffers;
using TEngine.DataStructure; using TEngine.DataStructure;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace TEngine.Core.Network; namespace TEngine.Core.Network;
@@ -199,7 +201,16 @@ public sealed class InnerPacketParser : APacketParser
{ {
if (message is IBsonMessage) if (message is IBsonMessage)
{ {
MongoHelper.Instance.SerializeTo(message, memoryStream); try
{
MongoHelper.Instance.SerializeTo(message, memoryStream);
}
catch (Exception e)
{
Log.Fatal(e);
throw;
}
} }
else else
{ {

View File

@@ -92,7 +92,7 @@ public class SingleCollection : Singleton<SingleCollection>
using var collections = ListPool<Entity>.Create(); using var collections = ListPool<Entity>.Create();
foreach (var (_, treeEntity) in entity.GetTree) foreach (var treeEntity in entity.ForEachSingleCollection)
{ {
if (treeEntity is not ISupportedSingleCollection) if (treeEntity is not ISupportedSingleCollection)
{ {