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

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

View File

@@ -7,5 +7,6 @@ namespace TEngine.Core
public const uint ErrRouteTimeout = 100000004; // 发送Route消息超时
public const uint Error_NotFindEntity = 100000008; // 没有找到Entity
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>()
{
"", "0", "bool", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "string", "AttrConfig",
"IntDictionaryConfig", "StringDictionaryConfig",
"short[]", "int[]", "long[]", "float[]", "string[]"
};
/// <summary>

View File

@@ -13,6 +13,7 @@ using Newtonsoft.Json;
// ReSharper disable SuspiciousTypeConversion.Global
// ReSharper disable InconsistentNaming
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace TEngine
{
@@ -402,10 +403,53 @@ namespace TEngine
#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
public DictionaryPool<Type, Entity> GetTree => _tree;
public T GetComponent<T>() where T : Entity, new()
{
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
/// <summary>
/// 创建一个Scene、但这个Scene是在某个Scene下面的Scene
/// 创建一个Scene。
/// </summary>
/// <param name="scene"></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()
{
var newScene = Create<T>(scene);
newScene.Scene = scene;
newScene.Scene = newScene;
newScene.Parent = scene;
newScene.SceneType = sceneType;
newScene.SceneSubType = sceneSubType;
newScene.Server = scene.Server;
newScene.LocationId = scene.Server.Id;
if (scene.World !=null)
if (scene.World != null)
{
newScene.World = scene.World;
}
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;
}

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;
}
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:
throw new NotSupportedException($"不支持此类型: {type}");
}

View File

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

View File

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

View File

@@ -51,7 +51,7 @@ public class SessionIdleCheckerComponent: Entity
return;
}
Log.Warning($"session timeout id:{Id}");
Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}");
_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 response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableAdd_Request
{
AddressableId = addressableId, RouteId = routeId
AddressableId = addressableId, RouteId = routeId, IsLock = isLock
});
if (response.ErrorCode != 0)
{
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 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;
Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}");
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
waitCoroutineLock?.Dispose();
}
}
public async FTask<long> Get(long addressableId)
@@ -31,6 +46,7 @@ namespace TEngine.Core.Network
using (await _addressableLock.Lock(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();
}
public FTask Register()
public FTask Register(bool isLock = true)
{
if (Parent == null)
{
@@ -36,7 +36,7 @@ namespace TEngine.Core.Network
#if TENGINE_DEVELOP
Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}");
#endif
return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId);
return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId, isLock);
}
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)
{
await scene.GetComponent<AddressableManageComponent>().Add(request.AddressableId, request.RouteId);
await scene.GetComponent<AddressableManageComponent>().Add(request.AddressableId, request.RouteId, request.IsLock);
}
}
#endif

View File

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

View File

@@ -63,6 +63,8 @@ namespace TEngine
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 : AProto, IRouteResponse

View File

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

View File

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

View File

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

View File

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

View File

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