新增私聊相关

This commit is contained in:
2025-08-18 23:24:33 +08:00
parent 34b25273a7
commit 8122c577f6
68 changed files with 1442 additions and 467 deletions

View File

@@ -0,0 +1,4 @@
syntax = "proto3";
package Fantasy.Network.Message;

View File

@@ -1,32 +1,80 @@
syntax = "proto3"; syntax = "proto3";
package Fantasy.Network.Message; package Fantasy.Network.Message;
////////////// ******** 邮件 *******///////////// ////////////// ******** 私聊/邮件 *******/////////////
///请求邮件列表 /// 会话信息
message C2Game_GetMailsRequest // ICustomRouteRequest,Game2C_GetMailsResponse,GameRoute message ConversationInfo
{
RoleSimpleInfo RoleInfo = 1; //对方信息
repeated MailInfo List = 2;//对话列表
}
message MailInfo
{
int64 Id = 1; //邮件id
int64 Sender = 2; //发送者
string Content = 3; //内容
int64 CreateTime = 4; //发送时间
int32 MailType = 5; //邮件类型
int32 MailState = 6; //邮件状态
repeated AwardInfo Items = 7; //附件列表
}
///请求会话列表
message C2S_GetConversationsRequest // ICustomRouteRequest,S2C_GetConversationsResponse,SocialRoute
{ {
} }
///获取邮件列表响应
message Game2C_GetMailsResponse // ICustomRouteResponse ///请求会话列表响应
message S2C_GetConversationsResponse // ICustomRouteResponse
{ {
repeated MailInfo Mail = 1; repeated ConversationInfo List = 1;
} }
///发送邮件消息
message C2S_SendMailRequest // ICustomRouteRequest,S2C_SendMailResponse,SocialRoute
{
int64 Target = 1; //目标id
string Content = 2; //内容
repeated AwardInfo Items = 3; //附件列表
}
///发送邮件消息响应
message S2C_SendMailResponse // ICustomRouteResponse
{
}
///发送删除会话消息
message C2S_DeleteMailRequest // ICustomRouteRequest,S2C_DeleteMailResponse,SocialRoute
{
int64 Id = 1; //会话id
}
///发送删除会话消息响应
message S2C_DeleteMailResponse // ICustomRouteResponse
{
int64 Id = 1; //会话id
}
///新邮件推送 ///新邮件推送
message Game2C_HaveMail // ICustomRouteMessage,GameRoute message S2C_HaveMail // ICustomRouteMessage,SocialRoute
{ {
MailInfo Mail = 1; MailInfo Mail = 1;
string Key = 2;
} }
message Game2C_MailState // ICustomRouteMessage,GameRoute message S2C_MailState // ICustomRouteMessage,SocialRoute
{ {
int32 MailState = 1; int32 MailState = 1;
int64 MailId = 2; int64 MailId = 2;
} }
////////////// ******** 聊天 *******///////////// ////////////// ******** 频道聊天 *******/////////////
message ChatUserInfo message ChatUserInfo
{ {
int64 Id = 1;//用户id int64 Id = 1;//用户id
@@ -66,34 +114,19 @@ message S2C_JoinChannelResponse // ICustomRouteResponse
} }
///发送聊天 ///发送消息
message C2S_SendMessageRequest // ICustomRouteRequest,S2C_SendMessageResponse,SocialRoute message C2S_SendMessageRequest // ICustomRouteRequest,S2C_SendMessageResponse,SocialRoute
{ {
int32 Type = 1; //消息类型 0.频道聊天 1.私聊 string Message = 1;
string Message = 2; int64 Target = 2; //目标id
int64 Target = 3; //目标id频道id或者好友id
} }
///发送聊天响应 ///发送消息响应
message S2C_SendMessageResponse // ICustomRouteResponse message S2C_SendMessageResponse // ICustomRouteResponse
{ {
} }
///发送聊天
message C2S_GetOfflineMessageRequest // ICustomRouteRequest,S2C_GetOfflineMessageResponse,SocialRoute
{
int32 Type = 1; //消息类型 0.频道聊天 1.私聊
string Message = 2;
int64 Target = 3; //目标id频道id或者好友id
}
///发送聊天响应
message S2C_GetOfflineMessageResponse // ICustomRouteResponse
{
repeated ChatMessageInfo Message = 1;
}
///推送消息 ///推送消息
message S2C_Message // ICustomRouteMessage,SocialRoute message S2C_Message // ICustomRouteMessage,SocialRoute
{ {
@@ -101,20 +134,6 @@ message S2C_Message // ICustomRouteMessage,SocialRoute
} }
///获取聊天记录请求
message C2S_GetChatRecordRequest // ICustomRouteRequest,S2C_GetChatRecordResponse,SocialRoute
{
int64 Target = 1; // 好友id或频道id
int32 Type = 2; // 获取聊天记录类型 0.频道 1.好友
}
///获取聊天记录响应
message S2C_GetChatRecordResponse // ICustomRouteResponse
{
repeated ChatMessageInfo Messages = 1; //聊天记录
}
////////////// ******** 工会 *******///////////// ////////////// ******** 工会 *******/////////////
message ClubInfo message ClubInfo

View File

@@ -1,14 +0,0 @@
syntax = "proto3";
package Fantasy.Network.Message;
message MailInfo
{
int64 Id = 1; //邮件id
string Title = 2; //标题
string Content = 3; //内容
int64 CreateTime = 4; //发送时间
int64 ExpireTime = 4; //发送时间
int32 MailType = 5; //邮件类型
int32 MailState = 6; //邮件状态
repeated AwardInfo Items = 7; //附件列表
}

View File

@@ -2,3 +2,4 @@
GateRoute = 1001 // Gate GateRoute = 1001 // Gate
SocialRoute = 1002 // Social SocialRoute = 1002 // Social
GameRoute = 1003 // Game GameRoute = 1003 // Game
MapRoute = 1004 // Map

View File

@@ -11,4 +11,14 @@ public class AppConfig
/// 玩家数据定时落地间隔 /// 玩家数据定时落地间隔
/// </summary> /// </summary>
public const long PlayerDataAutoSaveTime = 60000; // 600000; public const long PlayerDataAutoSaveTime = 60000; // 600000;
/// <summary>
/// 聊天数据自动保存间隔
/// </summary>
public const long ChatDataAutoSaveTime = 6000;
/// <summary>
/// 最大保留对话记录数
/// </summary>
public const long MaxConversationCount = 20;
} }

View File

@@ -25,13 +25,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.12.1" /> <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.12.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
<PackageReference Include="ToolGood.Words" Version="3.1.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Social\Entity\" /> <Folder Include="Social\Entity\" />
<Folder Include="Social\Mail\" /> <Folder Include="Social\Mail\" />
<Folder Include="Generate\NetworkProtocol\" /> <Folder Include="Generate\NetworkProtocol\" />
<Folder Include="Map\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -25,10 +25,6 @@ public class PlayerBasicCache : Entity
/// </summary> /// </summary>
public int Level; public int Level;
/// <summary>
/// 当前经验
/// </summary>
public int Exp;
/// <summary> /// <summary>
/// 是否是vip /// 是否是vip

View File

@@ -5,4 +5,9 @@ namespace NB.Game;
public class PlayerBasicCacheManageComponent : Entity public class PlayerBasicCacheManageComponent : Entity
{ {
public readonly Dictionary<long, PlayerBasicCache> Players = new(); public readonly Dictionary<long, PlayerBasicCache> Players = new();
/// <summary>
/// 定时检查定时器id
/// </summary>
public long checkTimerId;
} }

View File

@@ -4,6 +4,9 @@ using MongoDB.Bson.Serialization.Options;
namespace NB.Game; namespace NB.Game;
/// <summary>
/// 玩家基本数据
/// </summary>
public sealed class Player : Entity public sealed class Player : Entity
{ {
/// <summary> /// <summary>
@@ -37,39 +40,15 @@ public sealed class Player : Entity
[BsonElement("vip")] public bool IsVip; [BsonElement("vip")] public bool IsVip;
/// <summary> /// <summary>
/// 统计信息 /// 星数
/// </summary> /// </summary>
[BsonElement("stat")] public PlayerStatistics Statistics; [BsonElement("star")] public int Star;
/// <summary> /// <summary>
/// 角色vip信息 /// 高光数
/// </summary> /// </summary>
[BsonElement("vInfo")] public PlayerVip Vip; [BsonElement("high")] public int Highlight;
/// <summary>
/// 钱包
/// </summary>
[BsonElement("wallet")] public PlayerWallet Wallet;
/// <summary>
/// 背包
/// </summary>
[BsonElement("bag")] public ItemContainer ItemContainer;
/// <summary>
/// 鱼护
/// </summary>
[BsonElement("fish")] public FishContainer FishContainer;
/// <summary>
/// 技能
/// </summary>
[BsonElement("skill")] public SkillContainer SkillContainer;
/// <summary>
/// 成就
/// </summary>
[BsonElement("achievement")] public AchievementContainer AchievementContainer;
[BsonIgnore] public long SessionRunTimeId; [BsonIgnore] public long SessionRunTimeId;

View File

@@ -0,0 +1,40 @@
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
namespace NB.Game;
/// <summary>
/// 用户核心信息
/// </summary>
public class PlayerPrivate : Entity
{
/// <summary>
/// 角色vip信息
/// </summary>
[BsonElement("vInfo")] public PlayerVip Vip;
/// <summary>
/// 钱包
/// </summary>
[BsonElement("wallet")] public PlayerWallet Wallet;
/// <summary>
/// 背包
/// </summary>
[BsonElement("bag")] public ItemContainer ItemContainer;
/// <summary>
/// 鱼护
/// </summary>
[BsonElement("fish")] public FishContainer FishContainer;
/// <summary>
/// 技能
/// </summary>
[BsonElement("skill")] public SkillContainer SkillContainer;
/// <summary>
/// 成就
/// </summary>
[BsonElement("achievement")] public AchievementContainer AchievementContainer;
}

View File

@@ -1,58 +0,0 @@
using ProtoBuf;
using System.Collections.Generic;
using MongoDB.Bson.Serialization.Attributes;
using Fantasy;
using Fantasy.Network.Interface;
using Fantasy.Serialize;
// ReSharper disable InconsistentNaming
// ReSharper disable RedundantUsingDirective
// ReSharper disable RedundantOverriddenMember
// ReSharper disable PartialTypeWithSinglePart
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable CheckNamespace
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618
namespace Fantasy
{
[ProtoContract]
public partial class MailInfo : AMessage, IProto
{
public static MailInfo Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<MailInfo>();
}
public override void Dispose()
{
Id = default;
Title = default;
Content = default;
CreateTime = default;
ExpireTime = default;
MailType = default;
MailState = default;
Items.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<MailInfo>(this);
#endif
}
[ProtoMember(1)]
public long Id { get; set; }
[ProtoMember(2)]
public string Title { get; set; }
[ProtoMember(3)]
public string Content { get; set; }
[ProtoMember(4)]
public long CreateTime { get; set; }
[ProtoMember(5)]
public long ExpireTime { get; set; }
[ProtoMember(6)]
public int MailType { get; set; }
[ProtoMember(7)]
public int MailState { get; set; }
[ProtoMember(8)]
public List<AwardInfo> Items = new List<AwardInfo>();
}
}

View File

@@ -9,21 +9,21 @@ namespace Fantasy
public const uint G2C_RepeatLogin = 134227729; public const uint G2C_RepeatLogin = 134227729;
public const uint C2Game_GetRoleInfoRequest = 2281711377; public const uint C2Game_GetRoleInfoRequest = 2281711377;
public const uint Game2C_GetRoleInfoResponse = 2415929105; public const uint Game2C_GetRoleInfoResponse = 2415929105;
public const uint C2Game_GetMailsRequest = 2281711378; public const uint C2S_GetConversationsRequest = 2281711378;
public const uint Game2C_GetMailsResponse = 2415929106; public const uint S2C_GetConversationsResponse = 2415929106;
public const uint Game2C_HaveMail = 2147493649; public const uint C2S_SendMailRequest = 2281711379;
public const uint Game2C_MailState = 2147493650; public const uint S2C_SendMailResponse = 2415929107;
public const uint C2S_CreateChannelRequest = 2281711379; public const uint C2S_DeleteMailRequest = 2281711380;
public const uint S2C_CreateChannelResponse = 2415929107; public const uint S2C_DeleteMailResponse = 2415929108;
public const uint C2S_JoinChannelRequest = 2281711380; public const uint S2C_HaveMail = 2147493649;
public const uint S2C_JoinChannelResponse = 2415929108; public const uint S2C_MailState = 2147493650;
public const uint C2S_SendMessageRequest = 2281711381; public const uint C2S_CreateChannelRequest = 2281711381;
public const uint S2C_SendMessageResponse = 2415929109; public const uint S2C_CreateChannelResponse = 2415929109;
public const uint C2S_GetOfflineMessageRequest = 2281711382; public const uint C2S_JoinChannelRequest = 2281711382;
public const uint S2C_GetOfflineMessageResponse = 2415929110; public const uint S2C_JoinChannelResponse = 2415929110;
public const uint C2S_SendMessageRequest = 2281711383;
public const uint S2C_SendMessageResponse = 2415929111;
public const uint S2C_Message = 2147493651; public const uint S2C_Message = 2147493651;
public const uint C2S_GetChatRecordRequest = 2281711383;
public const uint S2C_GetChatRecordResponse = 2415929111;
public const uint C2S_CreateClubRequest = 2281711384; public const uint C2S_CreateClubRequest = 2281711384;
public const uint S2C_CreateClubResponse = 2415929112; public const uint S2C_CreateClubResponse = 2415929112;
public const uint C2S_GetClubInfoRequest = 2281711385; public const uint C2S_GetClubInfoRequest = 2281711385;

View File

@@ -18,51 +18,210 @@ using Fantasy.Serialize;
namespace Fantasy namespace Fantasy
{ {
/// <summary> /// <summary>
/// /////////// ******** 邮件 *******///////////// /// /////////// ******** 私聊/邮件 *******/////////////
/// </summary> /// </summary>
/// <summary> /// <summary>
/// 请求邮件列表 /// 会话信息
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class C2Game_GetMailsRequest : AMessage, ICustomRouteRequest, IProto public partial class ConversationInfo : AMessage, IProto
{ {
public static C2Game_GetMailsRequest Create(Scene scene) public static ConversationInfo Create(Scene scene)
{ {
return scene.MessagePoolComponent.Rent<C2Game_GetMailsRequest>(); return scene.MessagePoolComponent.Rent<ConversationInfo>();
}
public override void Dispose()
{
RoleInfo = default;
List.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<ConversationInfo>(this);
#endif
}
[ProtoMember(1)]
public RoleSimpleInfo RoleInfo { get; set; }
[ProtoMember(2)]
public List<MailInfo> List = new List<MailInfo>();
}
[ProtoContract]
public partial class MailInfo : AMessage, IProto
{
public static MailInfo Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<MailInfo>();
}
public override void Dispose()
{
Id = default;
Sender = default;
Content = default;
CreateTime = default;
MailType = default;
MailState = default;
Items.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<MailInfo>(this);
#endif
}
[ProtoMember(1)]
public long Id { get; set; }
[ProtoMember(2)]
public long Sender { get; set; }
[ProtoMember(3)]
public string Content { get; set; }
[ProtoMember(4)]
public long CreateTime { get; set; }
[ProtoMember(5)]
public int MailType { get; set; }
[ProtoMember(6)]
public int MailState { get; set; }
[ProtoMember(7)]
public List<AwardInfo> Items = new List<AwardInfo>();
}
/// <summary>
/// 请求会话列表
/// </summary>
[ProtoContract]
public partial class C2S_GetConversationsRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_GetConversationsRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_GetConversationsRequest>();
} }
public override void Dispose() public override void Dispose()
{ {
#if FANTASY_NET || FANTASY_UNITY #if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2Game_GetMailsRequest>(this); GetScene().MessagePoolComponent.Return<C2S_GetConversationsRequest>(this);
#endif #endif
} }
[ProtoIgnore] [ProtoIgnore]
public Game2C_GetMailsResponse ResponseType { get; set; } public S2C_GetConversationsResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2Game_GetMailsRequest; } public uint OpCode() { return OuterOpcode.C2S_GetConversationsRequest; }
[ProtoIgnore] [ProtoIgnore]
public int RouteType => Fantasy.RouteType.GameRoute; public int RouteType => Fantasy.RouteType.SocialRoute;
} }
/// <summary> /// <summary>
/// 获取邮件列表响应 /// 请求会话列表响应
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class Game2C_GetMailsResponse : AMessage, ICustomRouteResponse, IProto public partial class S2C_GetConversationsResponse : AMessage, ICustomRouteResponse, IProto
{ {
public static Game2C_GetMailsResponse Create(Scene scene) public static S2C_GetConversationsResponse Create(Scene scene)
{ {
return scene.MessagePoolComponent.Rent<Game2C_GetMailsResponse>(); return scene.MessagePoolComponent.Rent<S2C_GetConversationsResponse>();
} }
public override void Dispose() public override void Dispose()
{ {
ErrorCode = default; ErrorCode = default;
Mail.Clear(); List.Clear();
#if FANTASY_NET || FANTASY_UNITY #if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Game2C_GetMailsResponse>(this); GetScene().MessagePoolComponent.Return<S2C_GetConversationsResponse>(this);
#endif #endif
} }
public uint OpCode() { return OuterOpcode.Game2C_GetMailsResponse; } public uint OpCode() { return OuterOpcode.S2C_GetConversationsResponse; }
[ProtoMember(1)] [ProtoMember(1)]
public List<MailInfo> Mail = new List<MailInfo>(); public List<ConversationInfo> List = new List<ConversationInfo>();
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// 发送邮件消息
/// </summary>
[ProtoContract]
public partial class C2S_SendMailRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_SendMailRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_SendMailRequest>();
}
public override void Dispose()
{
Target = default;
Content = default;
Items.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2S_SendMailRequest>(this);
#endif
}
[ProtoIgnore]
public S2C_SendMailResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_SendMailRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)]
public long Target { get; set; }
[ProtoMember(2)]
public string Content { get; set; }
[ProtoMember(3)]
public List<AwardInfo> Items = new List<AwardInfo>();
}
/// <summary>
/// 发送邮件消息响应
/// </summary>
[ProtoContract]
public partial class S2C_SendMailResponse : AMessage, ICustomRouteResponse, IProto
{
public static S2C_SendMailResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<S2C_SendMailResponse>();
}
public override void Dispose()
{
ErrorCode = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<S2C_SendMailResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.S2C_SendMailResponse; }
[ProtoMember(1)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// 发送删除会话消息
/// </summary>
[ProtoContract]
public partial class C2S_DeleteMailRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_DeleteMailRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_DeleteMailRequest>();
}
public override void Dispose()
{
Id = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2S_DeleteMailRequest>(this);
#endif
}
[ProtoIgnore]
public S2C_DeleteMailResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_DeleteMailRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)]
public long Id { get; set; }
}
/// <summary>
/// 发送删除会话消息响应
/// </summary>
[ProtoContract]
public partial class S2C_DeleteMailResponse : AMessage, ICustomRouteResponse, IProto
{
public static S2C_DeleteMailResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<S2C_DeleteMailResponse>();
}
public override void Dispose()
{
ErrorCode = default;
Id = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<S2C_DeleteMailResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.S2C_DeleteMailResponse; }
[ProtoMember(1)]
public long Id { get; set; }
[ProtoMember(2)] [ProtoMember(2)]
public uint ErrorCode { get; set; } public uint ErrorCode { get; set; }
} }
@@ -70,50 +229,53 @@ namespace Fantasy
/// 新邮件推送 /// 新邮件推送
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class Game2C_HaveMail : AMessage, ICustomRouteMessage, IProto public partial class S2C_HaveMail : AMessage, ICustomRouteMessage, IProto
{ {
public static Game2C_HaveMail Create(Scene scene) public static S2C_HaveMail Create(Scene scene)
{ {
return scene.MessagePoolComponent.Rent<Game2C_HaveMail>(); return scene.MessagePoolComponent.Rent<S2C_HaveMail>();
} }
public override void Dispose() public override void Dispose()
{ {
Mail = default; Mail = default;
Key = default;
#if FANTASY_NET || FANTASY_UNITY #if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Game2C_HaveMail>(this); GetScene().MessagePoolComponent.Return<S2C_HaveMail>(this);
#endif #endif
} }
public uint OpCode() { return OuterOpcode.Game2C_HaveMail; } public uint OpCode() { return OuterOpcode.S2C_HaveMail; }
[ProtoIgnore] [ProtoIgnore]
public int RouteType => Fantasy.RouteType.GameRoute; public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)] [ProtoMember(1)]
public MailInfo Mail { get; set; } public MailInfo Mail { get; set; }
[ProtoMember(2)]
public string Key { get; set; }
} }
[ProtoContract] [ProtoContract]
public partial class Game2C_MailState : AMessage, ICustomRouteMessage, IProto public partial class S2C_MailState : AMessage, ICustomRouteMessage, IProto
{ {
public static Game2C_MailState Create(Scene scene) public static S2C_MailState Create(Scene scene)
{ {
return scene.MessagePoolComponent.Rent<Game2C_MailState>(); return scene.MessagePoolComponent.Rent<S2C_MailState>();
} }
public override void Dispose() public override void Dispose()
{ {
MailState = default; MailState = default;
MailId = default; MailId = default;
#if FANTASY_NET || FANTASY_UNITY #if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Game2C_MailState>(this); GetScene().MessagePoolComponent.Return<S2C_MailState>(this);
#endif #endif
} }
public uint OpCode() { return OuterOpcode.Game2C_MailState; } public uint OpCode() { return OuterOpcode.S2C_MailState; }
[ProtoIgnore] [ProtoIgnore]
public int RouteType => Fantasy.RouteType.GameRoute; public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)] [ProtoMember(1)]
public int MailState { get; set; } public int MailState { get; set; }
[ProtoMember(2)] [ProtoMember(2)]
public long MailId { get; set; } public long MailId { get; set; }
} }
/// <summary> /// <summary>
/// /////////// ******** 聊天 *******///////////// /// /////////// ******** 频道聊天 *******/////////////
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class ChatUserInfo : AMessage, IProto public partial class ChatUserInfo : AMessage, IProto
@@ -260,7 +422,7 @@ namespace Fantasy
public uint ErrorCode { get; set; } public uint ErrorCode { get; set; }
} }
/// <summary> /// <summary>
/// 发送聊天 /// 发送消息
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class C2S_SendMessageRequest : AMessage, ICustomRouteRequest, IProto public partial class C2S_SendMessageRequest : AMessage, ICustomRouteRequest, IProto
@@ -271,7 +433,6 @@ namespace Fantasy
} }
public override void Dispose() public override void Dispose()
{ {
Type = default;
Message = default; Message = default;
Target = default; Target = default;
#if FANTASY_NET || FANTASY_UNITY #if FANTASY_NET || FANTASY_UNITY
@@ -284,14 +445,12 @@ namespace Fantasy
[ProtoIgnore] [ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute; public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)] [ProtoMember(1)]
public int Type { get; set; }
[ProtoMember(2)]
public string Message { get; set; } public string Message { get; set; }
[ProtoMember(3)] [ProtoMember(2)]
public long Target { get; set; } public long Target { get; set; }
} }
/// <summary> /// <summary>
/// 发送聊天响应 /// 发送消息响应
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
public partial class S2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto public partial class S2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto
@@ -312,61 +471,6 @@ namespace Fantasy
public uint ErrorCode { get; set; } public uint ErrorCode { get; set; }
} }
/// <summary> /// <summary>
/// 发送聊天
/// </summary>
[ProtoContract]
public partial class C2S_GetOfflineMessageRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_GetOfflineMessageRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_GetOfflineMessageRequest>();
}
public override void Dispose()
{
Type = default;
Message = default;
Target = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2S_GetOfflineMessageRequest>(this);
#endif
}
[ProtoIgnore]
public S2C_GetOfflineMessageResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_GetOfflineMessageRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)]
public int Type { get; set; }
[ProtoMember(2)]
public string Message { get; set; }
[ProtoMember(3)]
public long Target { get; set; }
}
/// <summary>
/// 发送聊天响应
/// </summary>
[ProtoContract]
public partial class S2C_GetOfflineMessageResponse : AMessage, ICustomRouteResponse, IProto
{
public static S2C_GetOfflineMessageResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<S2C_GetOfflineMessageResponse>();
}
public override void Dispose()
{
ErrorCode = default;
Message.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<S2C_GetOfflineMessageResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.S2C_GetOfflineMessageResponse; }
[ProtoMember(1)]
public List<ChatMessageInfo> Message = new List<ChatMessageInfo>();
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// 推送消息 /// 推送消息
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]
@@ -390,58 +494,6 @@ namespace Fantasy
public ChatMessageInfo Message { get; set; } public ChatMessageInfo Message { get; set; }
} }
/// <summary> /// <summary>
/// 获取聊天记录请求
/// </summary>
[ProtoContract]
public partial class C2S_GetChatRecordRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_GetChatRecordRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_GetChatRecordRequest>();
}
public override void Dispose()
{
Target = default;
Type = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2S_GetChatRecordRequest>(this);
#endif
}
[ProtoIgnore]
public S2C_GetChatRecordResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_GetChatRecordRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)]
public long Target { get; set; }
[ProtoMember(2)]
public int Type { get; set; }
}
/// <summary>
/// 获取聊天记录响应
/// </summary>
[ProtoContract]
public partial class S2C_GetChatRecordResponse : AMessage, ICustomRouteResponse, IProto
{
public static S2C_GetChatRecordResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<S2C_GetChatRecordResponse>();
}
public override void Dispose()
{
ErrorCode = default;
Messages.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<S2C_GetChatRecordResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.S2C_GetChatRecordResponse; }
[ProtoMember(1)]
public List<ChatMessageInfo> Messages = new List<ChatMessageInfo>();
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// /////////// ******** 工会 *******///////////// /// /////////// ******** 工会 *******/////////////
/// </summary> /// </summary>
[ProtoContract] [ProtoContract]

34
Entity/Map/MapRoom.cs Normal file
View File

@@ -0,0 +1,34 @@
using Fantasy.Entitas;
namespace NB.Map;
/// <summary>
/// 地图房间
/// </summary>
public class MapRoom : Entity
{
/// <summary>
/// 房间密码
/// </summary>
public string Password;
/// <summary>
/// 房间玩家
/// </summary>
public Dictionary<long, MapUnit> Units = new Dictionary<long, MapUnit>();
/// <summary>
/// 房主
/// </summary>
public long Owner;
/// <summary>
/// 创建时间
/// </summary>
public long CreateTime;
/// <summary>
/// 房间地图
/// </summary>
public int Map;
}

10
Entity/Map/MapUnit.cs Normal file
View File

@@ -0,0 +1,10 @@
using Fantasy.Entitas;
namespace NB.Map;
/// <summary>
/// 地图玩家单元
/// </summary>
public class MapUnit : Entity
{
}

View File

@@ -44,4 +44,9 @@ public class ErrorCode
/// 聊天频道不存在 /// 聊天频道不存在
/// </summary> /// </summary>
public const uint ChatNotChannel = 12011; public const uint ChatNotChannel = 12011;
/// <summary>
/// 没回复前不能再发消息
/// </summary>
public const uint MailNotReply = 12021;
} }

View File

@@ -4,7 +4,7 @@ using Fantasy.Helper;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options; using MongoDB.Bson.Serialization.Options;
namespace NB.Game; namespace NB.Chat;
/// <summary> /// <summary>
/// 玩家邮件组件 /// 玩家邮件组件

View File

@@ -0,0 +1,19 @@
using Fantasy.Entitas;
namespace NB.Chat;
/// <summary>
/// 邮件管理组件
/// </summary>
public class MailManageComponent : Entity
{
/// <summary>
/// 会话列表
/// </summary>
public Dictionary<string, MailConversation> Conversations = new Dictionary<string, MailConversation>();
/// <summary>
/// 缓存了的列表
/// </summary>
public HashSet<long> CacheRoleIds = new HashSet<long>();
}

View File

@@ -1,46 +1,48 @@
using Fantasy.Entitas; using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
using NB.Game;
namespace NB.Game; namespace NB.Chat;
public sealed class Mail : Entity public sealed class Mail : Entity
{ {
/// <summary>
/// 邮件发送者
/// </summary>
[BsonElement("send")] public long Sender;
/// <summary> /// <summary>
/// 邮件拥有者 /// 邮件拥有者
/// </summary> /// </summary>
public long OwnerId; [BsonElement("owner")] public long OwnerId;
/// <summary> /// <summary>
/// 邮件状态 /// 邮件状态
/// </summary> /// </summary>
public MailState State = MailState.None; [BsonElement("state")] public MailState State = MailState.None;
/// <summary> /// <summary>
/// 邮件状态 /// 邮件状态
/// </summary> /// </summary>
public MailType MailType = MailType.None; [BsonElement("type")] public MailType MailType = MailType.None;
/// <summary>
/// 邮件标题
/// </summary>
public string Title;
/// <summary> /// <summary>
/// 邮件内容 /// 邮件内容
/// </summary> /// </summary>
public string Content; [BsonElement("con")] public string Content;
/// <summary> /// <summary>
/// 创建时间 /// 创建时间
/// </summary> /// </summary>
public long CreateTime; [BsonElement("ct")] public long CreateTime;
/// <summary> /// <summary>
/// 过期时间 /// 过期时间
/// </summary> /// </summary>
public long ExpireTime; [BsonElement("et")] public long ExpireTime;
/// <summary> /// <summary>
/// 邮件的附件内容 /// 邮件的附件内容
/// </summary> /// </summary>
public List<AwardItem> Items = new List<AwardItem>(); [BsonElement("item")] public List<AwardItem> Items = new List<AwardItem>();
} }

View File

@@ -1,7 +1,10 @@
using Fantasy.Entitas; using Fantasy.Entitas;
namespace NB.Game; namespace NB.Chat;
/// <summary>
/// 邮件箱,系统群发用
/// </summary>
public class MailBox : Entity public class MailBox : Entity
{ {
/// <summary> /// <summary>

View File

@@ -0,0 +1,57 @@
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
namespace NB.Chat;
public class MailConversation : Entity
{
/// <summary>
/// 第一id
/// </summary>
[BsonElement("id1")] public long FirstId;
/// <summary>
/// 第二id
/// </summary>
[BsonElement("id2")] public long SecondId;
/// <summary>
/// 会话
/// </summary>
[BsonElement("list")] public List<Mail> Mails = new List<Mail>();
/// <summary>
/// 第一个阅读时间
/// </summary>
[BsonElement("ft")] public long FirstReadTime;
/// <summary>
/// 第二阅读时间
/// </summary>
[BsonElement("st")] public long SecondReadTime;
/// <summary>
/// 最后更新时间
/// </summary>
[BsonElement("ut")] public long UpdateTime;
/// <summary>
/// 删除人标志
/// </summary>
[BsonElement("rid")] public HashSet<long> RemoveId = new HashSet<long>();
/// <summary>
/// 会话keyid-id按大小排序
/// </summary>
[BsonIgnore] public string Key = string.Empty;
/// <summary>
/// 最后保存时间
/// </summary>
[BsonIgnore] public long NeedSaveTime = 0;
/// <summary>
/// 需要保存
/// </summary>
[BsonIgnore] public bool NeedSave;
}

View File

@@ -1,4 +1,4 @@
namespace NB.Game; namespace NB.Chat;
public enum MailType public enum MailType
{ {

View File

@@ -8,8 +8,9 @@ public class SocialUnitManageComponent : Entity
{ {
public readonly Dictionary<long, SocialUnit> Units = new(); public readonly Dictionary<long, SocialUnit> Units = new();
/// <summary> // public List<MailBox>
/// 不在线消息缓存 // /// <summary>
/// </summary> // /// 不在线消息缓存
public readonly OneToManyList<long, ChatMessageInfo> NotSendMessage = new(); // /// </summary>
// public readonly OneToManyList<long, ChatMessageInfo> NotSendMessage = new();
} }

View File

@@ -92,6 +92,11 @@ namespace Fantasy.DataBase
return data == null ? 0 : Convert.ToInt64(data["Result"]); return data == null ? 0 : Convert.ToInt64(data["Result"]);
} }
/// <summary>
/// Mongo 注释
/// </summary>
public MongoClient Client => _mongoClient;
#endregion #endregion
#region GetCollection #region GetCollection

View File

@@ -1,16 +0,0 @@
using Fantasy;
namespace NB.Game;
public static class CacheHandler
{
public static List<RoleSimpleInfo> GetPlayerBasicCacheInfos(List<long> id)
{
}
public static RoleSimpleInfo GetPlayerBasicCacheInfos(long id)
{
}
}

View File

@@ -0,0 +1,24 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Game;
public class
S2G_GetPlayerBasicInfoRequestHandler : RouteRPC<Scene, S2G_GetPlayerBasicInfoRequest,
G2S_GetPlayerBasicInfoResponse>
{
protected override async FTask Run(Scene scene, S2G_GetPlayerBasicInfoRequest request,
G2S_GetPlayerBasicInfoResponse response, Action reply)
{
var playerBasicCacheManageComponent = scene.GetComponent<PlayerBasicCacheManageComponent>();
if (playerBasicCacheManageComponent != null)
{
var list = await playerBasicCacheManageComponent.GetPlayerBasicCacheInfos(request.IdList);
if (list != null && list.Count > 0)
{
response.RoleList.AddRange(list);
}
}
}
}

View File

@@ -0,0 +1,49 @@
using Fantasy;
using Fantasy.Async;
namespace NB.Game;
public static class CacheHandler
{
/// <summary>
/// 查询玩家基础信息
/// </summary>
/// <param name="scene"></param>
/// <param name="id"></param>
/// <returns></returns>
public static async FTask<List<RoleSimpleInfo>> GetPlayerBasicCacheInfos(Scene scene, List<long> id)
{
var gameSceneConfig = GameSceneHelper.GetSceneConfig();
var gameRouteId = gameSceneConfig.RouteId;
//连接到游戏中心服
var gameResponse = (G2S_GetPlayerBasicInfoResponse)await scene.NetworkMessagingComponent.CallInnerRoute(
gameRouteId, new S2G_GetPlayerBasicInfoRequest()
{
IdList = id
});
if (gameResponse.ErrorCode != 0)
{
return new List<RoleSimpleInfo>();
}
return gameResponse.RoleList;
}
/// <summary>
/// 获取玩家基础信息
/// </summary>
/// <param name="scene"></param>
/// <param name="id"></param>
/// <returns></returns>
public static async FTask<RoleSimpleInfo?> GetPlayerBasicCacheInfo(Scene scene, long id)
{
var list = await GetPlayerBasicCacheInfos(scene, [id]);
if (list.Count > 0)
{
return list[0];
}
return null;
}
}

View File

@@ -0,0 +1,13 @@
using Fantasy;
using Fantasy.Entitas;
namespace NB.Game;
public class PlayerBasicCacheFactory
{
public static PlayerBasicCache Create(Scene scene, long id)
{
var player = Entity.Create<PlayerBasicCache>(scene, id, true, true);
return player;
}
}

View File

@@ -0,0 +1,130 @@
using System.Diagnostics;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
namespace NB.Game;
public class PlayerBasicCacheManageComponentAwakeSystem : AwakeSystem<PlayerBasicCacheManageComponent>
{
protected override void Awake(PlayerBasicCacheManageComponent self)
{
// var timerId = self.Scene.TimerComponent.Net.RepeatedTimer(1000 * 60, new TestEvent());
}
}
public class PlayerBasicCacheManageComponentDestroySystem : DestroySystem<PlayerBasicCacheManageComponent>
{
protected override void Destroy(PlayerBasicCacheManageComponent self)
{
foreach (var (_, player) in self.Players)
{
player.Dispose();
}
self.Players.Clear();
}
}
public static class PlayerBasicCacheManageComponentSystem
{
/// <summary>
/// 获取一组玩家基本信息
/// </summary>
/// <param name="manage"></param>
/// <param name="list"></param>
/// <returns></returns>
public static async FTask<List<RoleSimpleInfo>> GetPlayerBasicCacheInfos(
this PlayerBasicCacheManageComponent manage,
List<long> list)
{
var ret = new List<RoleSimpleInfo>();
var notCacheIdList = new List<long>();
foreach (var id in list)
{
var info = GetPlayerBasicCacheInfos(manage, id);
if (info != null)
{
ret.Add(info);
}
else
{
notCacheIdList.Add(id);
}
}
if (notCacheIdList.Count > 0)
{
//查数据库
var dbDataList = await LoadPlayerBasicCacheByDB(manage, notCacheIdList);
foreach (var playerBasicCache in dbDataList)
{
ret.Add(playerBasicCache.ToInfo());
}
}
return ret;
}
/// <summary>
/// 获取缓存的单个玩家基本信息
/// </summary>
/// <param name="manage"></param>
/// <param name="id"></param>
/// <returns></returns>
public static RoleSimpleInfo? GetPlayerBasicCacheInfos(this PlayerBasicCacheManageComponent manage,
long id)
{
if (manage.Players.TryGetValue(id, out var cache))
{
return cache.ToInfo();
}
return null;
}
/// <summary>
/// 从数据库中加载玩家基本信息
/// </summary>
/// <param name="manage"></param>
/// <param name="ids"></param>
/// <returns></returns>
public static async FTask<List<PlayerBasicCache>> LoadPlayerBasicCacheByDB(
this PlayerBasicCacheManageComponent manage,
List<long> ids)
{
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
var ret = new List<PlayerBasicCache>();
//TODO:需要考虑如果数量过大是否需要分页
List<Player> players =
await manage.Scene.World.DataBase.QueryByPage<Player>(d => ids.Contains(d.Id), 1, ids.Count);
foreach (var player in players)
{
var cache = manage.UpdateCache(player);
ret.Add(cache);
}
return ret;
}
public static PlayerBasicCache UpdateCache(this PlayerBasicCacheManageComponent manage, Player player)
{
if (!manage.Players.TryGetValue(player.Id, out var cache))
{
cache = PlayerBasicCacheFactory.Create(manage.Scene, player.Id);
manage.Players.Add(player.Id, cache);
}
cache.NickName = player.NickName;
cache.Country = player.Country;
cache.Head = player.Head;
cache.Level = player.Level;
cache.IsVip = player.IsVip;
cache.ExpirationTime = TimeHelper.Now + TimeHelper.OneDay; //更新则过期时间增加一天
return cache;
}
}

View File

@@ -0,0 +1,33 @@
using Fantasy;
using Fantasy.Entitas.Interface;
namespace NB.Game;
public class PlayerBasicCacheDestroySystem : DestroySystem<PlayerBasicCache>
{
protected override void Destroy(PlayerBasicCache self)
{
self.Country = string.Empty;
self.NickName = string.Empty;
self.Head = string.Empty;
self.Level = 0;
self.IsVip = false;
self.ExpirationTime = 0;
}
}
public static class PlayerBasicCacheSystem
{
public static RoleSimpleInfo ToInfo(this PlayerBasicCache player)
{
var ret = new RoleSimpleInfo();
ret.NickName = player.NickName;
ret.Country = player.Country;
ret.Head = player.Head;
ret.Level = player.Level;
ret.Vip = player.IsVip;
ret.RoleId = player.Id;
return ret;
}
}

View File

@@ -8,13 +8,16 @@ namespace NB.Game;
public static class GameSceneHelper public static class GameSceneHelper
{ {
private static SceneConfig GetSceneConfig() #region 线 线
public static SceneConfig GetSceneConfig()
{ {
var gameSceneConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game); var gameSceneConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game);
return gameSceneConfigs.First(); return gameSceneConfigs.First();
} }
public static async FTask<(long, RoleSimpleInfo?)> Online(Scene scene, long accountID, long gateRuntimeId) public static async FTask<(long, RoleSimpleInfo?)> Online(Scene scene, long accountID, long gateRuntimeId)
{ {
var gameSceneConfig = GetSceneConfig(); var gameSceneConfig = GetSceneConfig();
@@ -38,4 +41,8 @@ public static class GameSceneHelper
public static async FTask Offline(Scene scene, long accountId, long gateRuntimeId) public static async FTask Offline(Scene scene, long accountId, long gateRuntimeId)
{ {
} }
#endregion
} }

View File

@@ -103,7 +103,7 @@ public static class PlayerManageComponentSystem
} }
} }
account.Statistics.LoginTime = TimeHelper.Now; // account.Statistics.LoginTime = TimeHelper.Now;
await account.Save(); await account.Save();

View File

@@ -19,16 +19,16 @@ public sealed class PlayerDestroySystem : DestroySystem<Player>
self.IsVip = false; self.IsVip = false;
self.Head = string.Empty; self.Head = string.Empty;
self.ItemContainer.Dispose(); // self.ItemContainer.Dispose();
self.ItemContainer = null; // self.ItemContainer = null;
self.FishContainer.Dispose(); // self.FishContainer.Dispose();
self.FishContainer = null; // self.FishContainer = null;
self.Wallet.Dispose(); // self.Wallet.Dispose();
self.Wallet = null; // self.Wallet = null;
self.Vip.Dispose(); // self.Vip.Dispose();
self.Vip = null; // self.Vip = null;
self.Statistics.Dispose(); // self.Statistics.Dispose();
self.Statistics = null; // self.Statistics = null;
self.SessionRunTimeId = 0; self.SessionRunTimeId = 0;
} }

View File

@@ -12,31 +12,31 @@ public static class PlayerHelper
public static void InitializeChildEntity(this Player self) public static void InitializeChildEntity(this Player self)
{ {
if (self.ItemContainer == null) // if (self.ItemContainer == null)
{ // {
self.ItemContainer = Entity.Create<ItemContainer>(self.Scene, true, true); // self.ItemContainer = Entity.Create<ItemContainer>(self.Scene, true, true);
} // }
//
if (self.FishContainer == null) // if (self.FishContainer == null)
{ // {
self.FishContainer = Entity.Create<FishContainer>(self.Scene, true, true); // self.FishContainer = Entity.Create<FishContainer>(self.Scene, true, true);
} // }
//
if (self.Wallet == null) // if (self.Wallet == null)
{ // {
self.Wallet = Entity.Create<PlayerWallet>(self.Scene, true, true); // self.Wallet = Entity.Create<PlayerWallet>(self.Scene, true, true);
} // }
//
if (self.Vip == null) // if (self.Vip == null)
{ // {
self.Vip = Entity.Create<PlayerVip>(self.Scene, true, true); // self.Vip = Entity.Create<PlayerVip>(self.Scene, true, true);
} // }
//
if (self.Statistics == null) // if (self.Statistics == null)
{ // {
self.Statistics = Entity.Create<PlayerStatistics>(self.Scene, true, true); // self.Statistics = Entity.Create<PlayerStatistics>(self.Scene, true, true);
self.Statistics.LoginTime = self.Statistics.CreateTime = TimeHelper.Now; // self.Statistics.LoginTime = self.Statistics.CreateTime = TimeHelper.Now;
} // }
} }
public static async FTask SaveImmediately(this Player self) public static async FTask SaveImmediately(this Player self)
@@ -156,8 +156,8 @@ public static class PlayerHelper
return new GameAccountInfo() return new GameAccountInfo()
{ {
CreateTime = self.Statistics.CreateTime, // CreateTime = self.Statistics.CreateTime,
LoginTime = self.Statistics.LoginTime // LoginTime = self.Statistics.LoginTime
}; };
} }
@@ -194,8 +194,8 @@ public static class PlayerHelper
if (self.IsVip) if (self.IsVip)
{ {
ret.VipInfo = new VipInfo(); ret.VipInfo = new VipInfo();
ret.VipInfo.OpenTime = self.Vip.GetTime; // ret.VipInfo.OpenTime = self.Vip.GetTime;
ret.VipInfo.ExpirationTime = self.Vip.ExpirationTime; // ret.VipInfo.ExpirationTime = self.Vip.ExpirationTime;
} }
return ret; return ret;

View File

@@ -13,6 +13,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Social\Chat\" />
<Folder Include="Social\Club\" />
<Folder Include="Social\Mail\Handler\Inner\" />
<Folder Include="Utils\" /> <Folder Include="Utils\" />
</ItemGroup> </ItemGroup>

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using Fantasy; using Fantasy;
using Fantasy.Async; using Fantasy.Async;
using Fantasy.Entitas; using Fantasy.Entitas;
@@ -73,6 +74,46 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
} }
case SceneType.Game: case SceneType.Game:
{ {
// // Begins transaction
// using (var session = mongoClient.StartSession())
// {
// session.StartTransaction();
// try
// {
// // Creates sample data
// var book = new Book
// {
// Title = "Beloved",
// Author = "Toni Morrison",
// InStock = true
// };
// var film = new Film
// {
// Title = "Star Wars",
// Director = "George Lucas",
// InStock = true
// };
// // Inserts sample data
// books.InsertOne(session, book);
// films.InsertOne(session, film);
// // Commits our transaction
// session.CommitTransaction();
// }
// catch (Exception e)
// {
// Console.WriteLine("Error writing to MongoDB: " + e.Message);
// return;
// }
// // Prints a success message if no error thrown
// Console.WriteLine("Successfully committed transaction!");
// }
// var client = self.Scene.World.DataBase;
// List<FTask> tasks = new List<FTask>();
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
// for (int i = 0; i < 100; i++) // for (int i = 0; i < 100; i++)
// { // {
// var accountId = scene.EntityIdFactory.Create; // var accountId = scene.EntityIdFactory.Create;
@@ -83,9 +124,15 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
// account.Country = "cn"; // account.Country = "cn";
// account.Exp = 999; // account.Exp = 999;
// account.Head = "xxx.png"; // account.Head = "xxx.png";
// await account.Save(); // tasks.Add(account.Save());
// } // }
// await FTask.WaitAll(tasks);
// // self.Scene.World.DataBase.InsertBatch()
// //
// stopwatch.Stop();
// Log.Info($"创建100个号入库耗时={stopwatch.ElapsedMilliseconds}ms");
break; break;
} }
case SceneType.Gate: case SceneType.Gate:

View File

@@ -36,6 +36,7 @@ public class OnSceneCreate_Init : AsyncEventSystem<OnCreateScene>
{ {
//用于管理玩家的组件 //用于管理玩家的组件
scene.AddComponent<PlayerManageComponent>(); scene.AddComponent<PlayerManageComponent>();
scene.AddComponent<PlayerBasicCacheManageComponent>();
break; break;
} }
case SceneType.Social: case SceneType.Social:
@@ -43,6 +44,7 @@ public class OnSceneCreate_Init : AsyncEventSystem<OnCreateScene>
//用于管理玩家的组件 //用于管理玩家的组件
scene.AddComponent<SocialUnitManageComponent>(); scene.AddComponent<SocialUnitManageComponent>();
scene.AddComponent<ChatChannelCenterComponent>(); scene.AddComponent<ChatChannelCenterComponent>();
scene.AddComponent<MailManageComponent>();
break; break;
} }
} }

View File

@@ -0,0 +1,24 @@
// using Fantasy;
// using Fantasy.Async;
// using Fantasy.Network.Interface;
//
// namespace NB.Chat;
//
// public class
// C2S_GetOfflineMessageRequestHandler : RouteRPC<SocialUnit, C2S_GetOfflineMessageRequest,
// S2C_GetOfflineMessageResponse>
// {
// protected override async FTask Run(SocialUnit entity, C2S_GetOfflineMessageRequest request,
// S2C_GetOfflineMessageResponse response,
// Action reply)
// {
// var chatUnitManage = entity.Scene.GetComponent<SocialUnitManageComponent>();
// if (chatUnitManage.NotSendMessage.TryGetValue(entity.Id, out var list))
// {
// response.Message.AddRange(list);
// chatUnitManage.NotSendMessage.RemoveByKey(entity.Id);
// }
//
// await FTask.CompletedTask;
// }
// }

View File

@@ -0,0 +1,155 @@
using System.Diagnostics;
using System.Text;
using Fantasy;
using Fantasy.Async;
using Fantasy.Helper;
using Fantasy.Network.Interface;
using NB.Game;
namespace NB.Chat;
public sealed class
C2S_SendMessageRequestHandler : RouteRPC<SocialUnit, C2S_SendMessageRequest, S2C_SendMessageResponse>
{
protected override async FTask Run(SocialUnit socialUnit, C2S_SendMessageRequest request,
S2C_SendMessageResponse response, Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
SocialSceneHelper.BroadcastChannel(socialUnit.Scene, request.Target, new ChatMessageInfo()
{
SendTime = TimeHelper.Now,
Content = request.Message,
});
// if (request.Type == 0) //频道聊天
// {
// }
// else if (request.Type == 1) //私聊
// {
// //发送私聊
// SocialSceneHelper.PrivateMessage(socialUnit.Scene, socialUnit.Id, request.Target, new ChatMessageInfo()
// {
// SendTime = TimeHelper.Now,
// Content = request.Message,
// });
// }
// var list = new List<long>()
// {
// 337951357380329472,
// 337951357380329473,
// 337951357380329474,
// 337951357380329475,
// 337951357380329476,
// 337951357380329477,
// 337951357380329478,
// 337951357380329479,
// 337951357380329480,
// 337951357380329481,
// 337951357380329482,
// 337951357380329483,
// 337951357380329484,
// 337951357380329485,
// 337951357380329486,
// 337951357380329487,
// 337951357380329488,
// 337951357380329489,
// 337951357380329490,
// 337951357380329491,
// 337951357380329492,
// 337951357380329493,
// 337951357380329494,
// 337951357380329495,
// 337951357380329496,
// 337951357380329497,
// 337951357380329498,
// 337951357380329499,
// 337951357380329500,
// 337951357380329501,
// 337951357380329502,
// 337951357380329503,
// 337951357380329504,
// 337951357380329505,
// 337951357380329506,
// 337951357380329507,
// 337951357380329508,
// 337951357380329509,
// 337951357380329510,
// 337951357380329511,
// 337951357380329512,
// 337951357380329513,
// 337951357380329514,
// 337951357380329515,
// 337951357380329516,
// 337951357380329517,
// 337951357380329518,
// 337951357380329519,
// 337951357380329520,
// 337951357380329521,
// 337951357380329522,
// 337951357380329523,
// 337951357380329524,
// 337951357380329525,
// 337951357380329526,
// 337951357380329527,
// 337951357380329528,
// 337951357380329529,
// 337951357380329530,
// 337951357380329531,
// 337951357380329532,
// 337951357380329533,
// 337951357380329534,
// 337951357380329535,
// 337951357380329536,
// 337951357380329537,
// 337951357380329538,
// 337951357380329539,
// 337951357380329540,
// 337951357380329541,
// 337951357380329542,
// 337951357380329543,
// 337951357380329544,
// 337951357380329545,
// 337951357380329546,
// 337951357380329547,
// 337951357380329548,
// 337951357380329549,
// 337951357380329550,
// 337951357380329551,
// 337951357380329552,
// 337951357380329553,
// 337951357380329554,
// 337951357380329555,
// 337951357380329556,
// 337951357380329557,
// 337951357380329558,
// 337951357380329559,
// 337951357380329560,
// 337951357380329561,
// 337951357380329562,
// 337951357380329563,
// 337951357380329564,
// 337951357380329565,
// 337951357380329566,
// 337951357380329567,
// 337951357380329568,
// 337951357380329569,
// 337951357380329570,
// 337951357380329571
// };
//
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
// var infoList = await CacheHandler.GetPlayerBasicCacheInfos(socialUnit.Scene,list);
// stopwatch.Stop();
// Log.Info($"查询数量={infoList.Count} 耗时={stopwatch.ElapsedMilliseconds}");
//
await FTask.CompletedTask;
}
}

View File

@@ -17,7 +17,7 @@ public static class ChatUnitManageComponentSystem
/// <param name="message"></param> /// <param name="message"></param>
public static void SaveOfflineMessage(this SocialUnitManageComponent self, long targetId, ChatMessageInfo message) public static void SaveOfflineMessage(this SocialUnitManageComponent self, long targetId, ChatMessageInfo message)
{ {
self.NotSendMessage.Add(targetId, message); // self.NotSendMessage.Add(targetId, message);
} }
#endregion #endregion

View File

@@ -1,24 +0,0 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Chat;
public class
C2S_GetOfflineMessageRequestHandler : RouteRPC<SocialUnit, C2S_GetOfflineMessageRequest,
S2C_GetOfflineMessageResponse>
{
protected override async FTask Run(SocialUnit entity, C2S_GetOfflineMessageRequest request,
S2C_GetOfflineMessageResponse response,
Action reply)
{
var chatUnitManage = entity.Scene.GetComponent<SocialUnitManageComponent>();
if (chatUnitManage.NotSendMessage.TryGetValue(entity.Id, out var list))
{
response.Message.AddRange(list);
chatUnitManage.NotSendMessage.RemoveByKey(entity.Id);
}
await FTask.CompletedTask;
}
}

View File

@@ -1,41 +0,0 @@
using System.Text;
using Fantasy;
using Fantasy.Async;
using Fantasy.Helper;
using Fantasy.Network.Interface;
namespace NB.Chat;
public sealed class
C2S_SendMessageRequestHandler : RouteRPC<SocialUnit, C2S_SendMessageRequest, S2C_SendMessageResponse>
{
protected override async FTask Run(SocialUnit socialUnit, C2S_SendMessageRequest request,
S2C_SendMessageResponse response, Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
if (request.Type == 0) //频道聊天
{
SocialSceneHelper.BroadcastChannel(socialUnit.Scene, request.Target, new ChatMessageInfo()
{
SendTime = TimeHelper.Now,
Content = request.Message,
});
}
else if (request.Type == 1) //私聊
{
//发送私聊
SocialSceneHelper.PrivateMessage(socialUnit.Scene, socialUnit.Id, request.Target, new ChatMessageInfo()
{
SendTime = TimeHelper.Now,
Content = request.Message,
});
}
await FTask.CompletedTask;
}
}

View File

@@ -0,0 +1,44 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Chat;
public class C2S_DeleteMailRequestHandler : RouteRPC<SocialUnit, C2S_DeleteMailRequest, S2C_DeleteMailResponse>
{
protected override async FTask Run(SocialUnit entity, C2S_DeleteMailRequest request,
S2C_DeleteMailResponse response, Action reply)
{
if (request.Id < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
if (mailManageComponent == null)
{
Log.Error("组件不存在 MailManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Id);
if (conversation == null)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
conversation.RemoveId.Add(entity.Id);
if (conversation.RemoveId.Count > 1)
{
//都删除了,则吧会话直接移除掉
await mailManageComponent.DeleteConversation(entity.Id, request.Id);
}
else
{
await conversation.Save();
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Diagnostics;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Chat;
public class
C2S_GetConversationsRequestHandler : RouteRPC<SocialUnit, C2S_GetConversationsRequest, S2C_GetConversationsResponse>
{
protected override async FTask Run(SocialUnit entity, C2S_GetConversationsRequest request,
S2C_GetConversationsResponse response, Action reply)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
var list = await mailManageComponent.GetConversations(entity.Id);
response.List = await list.ToInfo(entity.Scene, entity.Id);
stopwatch.Stop();
Log.Info($"查询会话列表耗时={stopwatch.ElapsedMilliseconds}");
}
}

View File

@@ -0,0 +1,68 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Chat;
public class C2S_SendMailRequestHandler : RouteRPC<SocialUnit, C2S_SendMailRequest, S2C_SendMailResponse>
{
protected override async FTask Run(SocialUnit entity, C2S_SendMailRequest request, S2C_SendMailResponse response,
Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
if (mailManageComponent == null)
{
Log.Error("组件不存在 MailManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var chatUnitManage = entity.Scene.GetComponent<SocialUnitManageComponent>();
if (chatUnitManage == null)
{
Log.Error("组件不存在 SocialUnitManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Target);
if (conversation == null)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
//检查是否可以发消息,如果会话只有一句,则不允许再发
if (!conversation.CanSend(entity.Id))
{
response.ErrorCode = ErrorCode.MailNotReply;
return;
}
var mail = MailFactory.Create(entity.Scene, request.Content);
mail.Sender = entity.Id;
mail.OwnerId = request.Target;
await conversation.Add(mail);
var res = new S2C_HaveMail()
{
Mail = mail.ToMailInfo(),
Key = conversation.Key
};
//同步客户端
entity.Scene.NetworkMessagingComponent.SendInnerRoute(entity.GateRouteId, res);
var chatUnit = chatUnitManage.Get(request.Target);
if (chatUnit != null)
{
//对方在线
entity.Scene.NetworkMessagingComponent.SendInnerRoute(chatUnit.GateRouteId, res);
}
}
}

View File

@@ -1,8 +1,9 @@
using Fantasy; using Fantasy;
using Fantasy.Entitas; using Fantasy.Entitas;
using Fantasy.Helper; using Fantasy.Helper;
using NB.Game;
namespace NB.Game; namespace NB.Chat;
public static class MailBoxFactory public static class MailBoxFactory
{ {
@@ -42,14 +43,13 @@ public static class MailBoxFactory
/// <param name="sendAccountId"></param> /// <param name="sendAccountId"></param>
/// <param name="expireTime"></param> /// <param name="expireTime"></param>
/// <param name="accountIds"></param> /// <param name="accountIds"></param>
/// <param name="title"></param>
/// <param name="content"></param> /// <param name="content"></param>
/// <param name="items"></param> /// <param name="items"></param>
/// <returns></returns> /// <returns></returns>
public static MailBox Create(Scene scene, long sendAccountId, int expireTime, List<long> accountIds, string title, public static MailBox Create(Scene scene, long sendAccountId, int expireTime, List<long> accountIds,
string content, List<AwardItem> items = null) string content, List<AwardItem> items = null)
{ {
var mail = MailFactory.Create(scene, title, content, items); var mail = MailFactory.Create(scene, content, items);
return Create(scene, sendAccountId, mail, expireTime, accountIds); return Create(scene, sendAccountId, mail, expireTime, accountIds);
} }
} }

View File

@@ -0,0 +1,38 @@
using Fantasy;
using Fantasy.Async;
using NB.Game;
namespace NB.Chat;
public static class MailConversationHelper
{
/// <summary>
/// 从数据库中读取GameAccount
/// </summary>
/// <param name="scene"></param>
/// <param name="firstId"></param>
/// <param name="secondId"></param>
/// <returns></returns>
public static async FTask<MailConversation> LoadDataBase(Scene scene, long firstId, long secondId)
{
var conversation =
await scene.World.DataBase.First<MailConversation>(d => d.FirstId == firstId && d.SecondId == secondId);
if (conversation == null)
{
return null;
}
conversation.Deserialize(scene);
return conversation;
}
/// <summary>
/// 从数据库中移除
/// </summary>
/// <param name="scene"></param>
/// <param name="id"></param>
public static async FTask DeleteDataBase(Scene scene,long id)
{
await scene.World.DataBase.Remove<MailConversation>(id);
}
}

View File

@@ -2,17 +2,17 @@
using Fantasy.Entitas; using Fantasy.Entitas;
using Fantasy.Helper; using Fantasy.Helper;
using Fantasy.Serialize; using Fantasy.Serialize;
using NB.Game;
namespace NB.Game; namespace NB.Chat;
public static class MailFactory public static class MailFactory
{ {
private static readonly ISerialize _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson); private static readonly ISerialize _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson);
public static Mail Create(Scene scene, string title, string content, List<AwardItem> items = null) public static Mail Create(Scene scene, string content, List<AwardItem> items = null)
{ {
var mail = Entity.Create<Mail>(scene, true, true); var mail = Entity.Create<Mail>(scene, true, true);
mail.Title = title;
mail.Content = content; mail.Content = content;
mail.State = MailState.Unread; mail.State = MailState.Unread;
mail.CreateTime = TimeHelper.Now; mail.CreateTime = TimeHelper.Now;

View File

@@ -1,13 +1,14 @@
using Fantasy; using Fantasy;
using Fantasy.Async; using Fantasy.Async;
namespace NB.Game; namespace NB.Chat;
/// <summary> /// <summary>
/// 发送邮件接口 /// 发送邮件接口
/// </summary> /// </summary>
public static class MailHelper public static class MailHelper
{ {
public static async FTask Send(Scene scene, MailBox mailBox) public static async FTask Send(Scene scene, MailBox mailBox)
{ {
if (mailBox.BoxType == MailBoxType.None) if (mailBox.BoxType == MailBoxType.None)

View File

@@ -1,6 +1,6 @@
using Fantasy.Entitas.Interface; using Fantasy.Entitas.Interface;
namespace NB.Game; namespace NB.Chat;
public class MailBoxDestroySystem : DestroySystem<MailBox> public class MailBoxDestroySystem : DestroySystem<MailBox>
{ {

View File

@@ -3,7 +3,7 @@ using Fantasy.Async;
using Fantasy.Entitas.Interface; using Fantasy.Entitas.Interface;
using Fantasy.Helper; using Fantasy.Helper;
namespace NB.Game; namespace NB.Chat;
public class MailComponentDestroySystem : DestroySystem<MailComponent> public class MailComponentDestroySystem : DestroySystem<MailComponent>
{ {
@@ -42,7 +42,7 @@ public static class MailComponentSystem
if (sync) if (sync)
{ {
//同步客户端 //同步客户端
self.Scene.NetworkMessagingComponent.SendInnerRoute(0,new Game2C_HaveMail() self.Scene.NetworkMessagingComponent.SendInnerRoute(0,new S2C_HaveMail()
{ {
Mail = mail.ToMailInfo(), Mail = mail.ToMailInfo(),
}); });
@@ -65,7 +65,7 @@ public static class MailComponentSystem
if (sync) if (sync)
{ {
//同步客户端 //同步客户端
self.Scene.NetworkMessagingComponent.SendInnerRoute(0,new Game2C_MailState() self.Scene.NetworkMessagingComponent.SendInnerRoute(0,new S2C_MailState()
{ {
MailState = (int)MailState.Deleted, MailState = (int)MailState.Deleted,
MailId = mailId, MailId = mailId,

View File

@@ -0,0 +1,126 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB.Game;
namespace NB.Chat;
public class MailConversationDeserializeSystem : DeserializeSystem<MailConversation>
{
protected override void Deserialize(MailConversation self)
{
self.Key = $"{self.FirstId}-{self.SecondId}";
}
}
public class MailConversationDestroySystem : DestroySystem<MailConversation>
{
protected override void Destroy(MailConversation self)
{
foreach (var mail in self.Mails)
{
mail.Dispose();
}
self.Mails.Clear();
self.FirstId = 0;
self.SecondId = 0;
self.Key = string.Empty;
}
}
public static class MailConversationSystem
{
public static async FTask Add(this MailConversation self, Mail mail)
{
self.Mails.Add(mail);
if (self.Mails.Count > AppConfig.MaxConversationCount)
{
self.Mails.RemoveAt(0);
}
if (mail.Items != null && mail.Items.Count > 0)
{
//有附件需要立马保存
await self.Save(true);
}
else
{
await self.Save(false);
}
}
public static async FTask Save(this MailConversation self, bool forceSave = true)
{
// self.NeedSave = true;
// self.NeedSaveTime = TimeHelper.Now + AppConfig.PlayerDataAutoSaveTime;
if (forceSave)
{
self.UpdateTime = TimeHelper.Now;
await self.Scene.World.DataBase.Save(self);
}
else
{
self.NeedSave = true;
self.NeedSaveTime = TimeHelper.Now + AppConfig.ChatDataAutoSaveTime;
}
}
/// <summary>
/// 是否可以发送邮件
/// </summary>
/// <param name="self"></param>
/// <param name="sendId"></param>
/// <returns></returns>
public static bool CanSend(this MailConversation self, long sendId)
{
if (self.Mails.Count < 1) return true;
foreach (var mail in self.Mails)
{
if (mail.Sender != sendId)
{
return true;
}
}
return false;
}
#region
public static async FTask<List<ConversationInfo>> ToInfo(this List<MailConversation> self, Scene scene, long selfId)
{
List<ConversationInfo> ret = new List<ConversationInfo>();
HashSet<long> ids = new HashSet<long>();
foreach (var conversation in self)
{
if (conversation.RemoveId.Contains(selfId)) continue;
ids.Add(conversation.FirstId);
ids.Add(conversation.SecondId);
}
ids.Remove(selfId);
var infos = await CacheHandler.GetPlayerBasicCacheInfos(scene, ids.ToList());
foreach (var conversation in self)
{
if (conversation.RemoveId.Contains(selfId)) continue;
var item = new ConversationInfo();
item.List = conversation.Mails.ToMailInfo();
var otherId = conversation.FirstId == selfId ? conversation.SecondId : conversation.FirstId;
var info = infos.Find(t => t.RoleId == otherId);
if (info != null)
{
item.RoleInfo = info;
}
ret.Add(item);
}
return ret;
}
#endregion
}

View File

@@ -0,0 +1,93 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB.Game;
namespace NB.Chat;
public class MailManageComponentDestroySystem : DestroySystem<MailManageComponent>
{
protected override void Destroy(MailManageComponent self)
{
foreach (var (_, conversation) in self.Conversations)
{
conversation.Dispose();
}
self.Conversations.Clear();
}
}
public static class MailManageComponentSystem
{
public static async FTask DeleteConversation(this MailManageComponent self, long selfId, long otherId)
{
var firstId = selfId;
var secondId = otherId;
if (otherId < selfId)
{
firstId = otherId;
secondId = selfId;
}
var key = $"{firstId}-{secondId}";
if (self.Conversations.Remove(key, out var conversation))
{
await MailConversationHelper.DeleteDataBase(conversation.Scene, conversation.Id);
conversation.Dispose();
}
}
public static async FTask<MailConversation?> GetConversation(this MailManageComponent self, long selfId,
long otherId)
{
var firstId = selfId;
var secondId = otherId;
if (otherId < selfId)
{
firstId = otherId;
secondId = selfId;
}
var key = $"{firstId}-{secondId}";
if (!self.Conversations.TryGetValue(key, out var conversation))
{
//检查数据库中是否存在
conversation = await MailConversationHelper.LoadDataBase(self.Scene, firstId, secondId);
if (conversation == null)
{
//检查id是否合法
var roleInfo = await CacheHandler.GetPlayerBasicCacheInfo(self.Scene, otherId);
if (roleInfo == null)
{
return null;
}
conversation = Entity.Create<MailConversation>(self.Scene, true, true);
conversation.FirstId = firstId;
conversation.SecondId = secondId;
conversation.Key = key;
await conversation.Save(false);
}
self.Conversations.Add(key, conversation);
}
return conversation;
}
public static async FTask<List<MailConversation>> GetConversations(this MailManageComponent self, long id)
{
List<MailConversation> players =
await self.Scene.World.DataBase.QueryByPageOrderBy<MailConversation>(
d => d.FirstId == id || d.SecondId == id, 1, 50,
d => d.UpdateTime);
return players;
}
}

View File

@@ -1,14 +1,15 @@
using Fantasy; using Fantasy;
using Fantasy.Entitas.Interface; using Fantasy.Entitas.Interface;
using NB.Game;
namespace NB.Game; namespace NB.Chat;
public class MailDestroySystem : DestroySystem<Mail> public class MailDestroySystem : DestroySystem<Mail>
{ {
protected override void Destroy(Mail self) protected override void Destroy(Mail self)
{ {
self.OwnerId = 0; self.OwnerId = 0;
self.Title = string.Empty; self.Sender = 0;
self.Content = string.Empty; self.Content = string.Empty;
self.ExpireTime = 0; self.ExpireTime = 0;
self.CreateTime = 0; self.CreateTime = 0;
@@ -30,9 +31,7 @@ public static class MailSystem
return new MailInfo() return new MailInfo()
{ {
Id = mail.Id, Id = mail.Id,
Title = mail.Title,
Content = mail.Content, Content = mail.Content,
ExpireTime = mail.ExpireTime,
CreateTime = mail.CreateTime, CreateTime = mail.CreateTime,
MailState = (int)mail.State, MailState = (int)mail.State,
MailType = (int)mail.MailType, MailType = (int)mail.MailType,

View File

@@ -24,8 +24,10 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFilterDefinition_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8ea7d078decf4c90ba8835b5c94f73f224de00_003Fbb_003F26ba78ed_003FFilterDefinition_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFilterDefinition_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8ea7d078decf4c90ba8835b5c94f73f224de00_003Fbb_003F26ba78ed_003FFilterDefinition_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpListenerContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F39685ddee93747a69e157aaf821b46b74ec00_003F0c_003F83013c19_003FHttpListenerContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpListenerContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F39685ddee93747a69e157aaf821b46b74ec00_003F0c_003F83013c19_003FHttpListenerContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpResponseWritingExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fdd7bbb1eb6cb4178a82cd5136b2606b812978_003Fdf_003Fade31cc3_003FHttpResponseWritingExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpResponseWritingExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fdd7bbb1eb6cb4178a82cd5136b2606b812978_003Fdf_003Fade31cc3_003FHttpResponseWritingExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAsyncCursorExtensions_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5111d10f571f4f52a6ca7377a3b36b4324f600_003Fa0_003Fd24abc7c_003FIAsyncCursorExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAsyncDisposable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003Fa8_003Feab3ddd8_003FIAsyncDisposable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAsyncDisposable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003Fa8_003Feab3ddd8_003FIAsyncDisposable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIBufferWriter_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F075adf13af424892b7e940211f3b0a6a24c00_003F64_003F718198a3_003FIBufferWriter_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIBufferWriter_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F075adf13af424892b7e940211f3b0a6a24c00_003F64_003F718198a3_003FIBufferWriter_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIClientSessionHandle_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5111d10f571f4f52a6ca7377a3b36b4324f600_003F59_003F467b6a12_003FIClientSessionHandle_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AICriticalNotifyCompletion_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F77fc0eb92b774686bbae91cb92331703d83600_003F45_003Fc4c5e164_003FICriticalNotifyCompletion_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AICriticalNotifyCompletion_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F77fc0eb92b774686bbae91cb92331703d83600_003F45_003Fc4c5e164_003FICriticalNotifyCompletion_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMemoryOwner_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F29_003Fb2f873cf_003FIMemoryOwner_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMemoryOwner_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F29_003Fb2f873cf_003FIMemoryOwner_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMongoCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8ea7d078decf4c90ba8835b5c94f73f224de00_003F61_003F088d42d6_003FIMongoCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMongoCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8ea7d078decf4c90ba8835b5c94f73f224de00_003F61_003F088d42d6_003FIMongoCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@@ -36,6 +38,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonIgnoreAttribute_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7e62198beab24380bbac29171862d1d8adf10_003F0e_003F062c5ada_003FJsonIgnoreAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonIgnoreAttribute_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7e62198beab24380bbac29171862d1d8adf10_003F0e_003F062c5ada_003FJsonIgnoreAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJwtSecurityToken_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fae7f2ab4cba14312a0d93e2c5adc801b16648_003Fe4_003F74042d58_003FJwtSecurityToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJwtSecurityToken_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fae7f2ab4cba14312a0d93e2c5adc801b16648_003Fe4_003F74042d58_003FJwtSecurityToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKCPServerNetworkChannel_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F24_003F76109cf3_003FKCPServerNetworkChannel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKCPServerNetworkChannel_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F24_003F76109cf3_003FKCPServerNetworkChannel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALazy_00601_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F76803a04e31b4fee99d90bcbfc5a6bdde8e930_003Fcc_003F5b99d83c_003FLazy_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003Fac_003F37a729a2_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003Fac_003F37a729a2_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F77fc0eb92b774686bbae91cb92331703d83600_003F73_003F35ac318d_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F77fc0eb92b774686bbae91cb92331703d83600_003F73_003F35ac318d_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryMarshal_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F74_003F8c8beed7_003FMemoryMarshal_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryMarshal_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F74_003F8c8beed7_003FMemoryMarshal_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@@ -44,6 +47,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryPool_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F075adf13af424892b7e940211f3b0a6a24c00_003F44_003Fbf566ef7_003FMemoryPool_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryPool_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F075adf13af424892b7e940211f3b0a6a24c00_003F44_003Fbf566ef7_003FMemoryPool_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemory_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F47_003F6e33d1b5_003FMemory_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemory_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F47_003F6e33d1b5_003FMemory_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMiMalloc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F60d0203982134324aae0d2ca760a88a54400_003F2e_003F39679261_003FMiMalloc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMiMalloc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F60d0203982134324aae0d2ca760a88a54400_003F2e_003F39679261_003FMiMalloc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef6258830955486e8fb0f971e12b16b183200_003F6e_003F2a3d5471_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F21_003Fa6a0aafd_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F21_003Fa6a0aafd_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef6258830955486e8fb0f971e12b16b183200_003F6e_003F2a3d5471_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef6258830955486e8fb0f971e12b16b183200_003F6e_003F2a3d5471_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMvcServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7bc6d1e2e4b14ffd826a34ca3c8eac755a00_003F20_003F93fe3d76_003FMvcServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMvcServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7bc6d1e2e4b14ffd826a34ca3c8eac755a00_003F20_003F93fe3d76_003FMvcServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Id":331929091475505154}

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002}

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Target":337951357380329486,"Content":"\u5206\u516C\u53F8\u7535\u996D\u9505\u7535\u996D\u9505"}

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Target":324468767642091522,"Content":"\u7B2C\u4E09\u65B9\u7B2C\u4E09\u65B9\u4EE3\u53D1111"}