完成离线消息发送和上线获取离线消息

This commit is contained in:
2025-08-13 23:44:59 +08:00
parent f8b876ca2f
commit 022cc1ac3e
39 changed files with 499 additions and 85 deletions

View File

@@ -12,10 +12,21 @@ message Game2G_EnterResponse // IRouteResponse
int64 RoleRouteId = 1; //角色实体的路由id
RoleSimpleInfo RoleInfo = 2; //角色信息
}
message G2Game_ExitRequest // IRouteRequest,Game2G_ExitResponse
{
int64 AccountId = 1; //账号id
int64 GateRouteId = 2;//网关路由地址
}
message Game2G_ExitResponse // IRouteResponse
{
}
///通知游戏服角色进入该聊天服
message G2Chat_EnterRequest // IRouteRequest,Game2G_EnterResponse
message G2Chat_EnterRequest // IRouteRequest,Chat2G_EnterResponse
{
RoleSimpleInfo Role = 1; //角色信息
int64 GateRouteId = 2;//网关路由地址
@@ -26,9 +37,22 @@ message Chat2G_EnterResponse // IRouteResponse
int64 RoleRouteId = 1; //角色实体的路由id
}
message G2Chat_ExitRequest // IRouteRequest,Chat2G_ExitResponse
{
int64 AccountId = 1; //账号id
int64 GateRouteId = 2;//网关路由地址
}
message Chat2G_ExitResponse // IRouteResponse
{
}
message Chat2G_ChatMessage // IRouteMessage
{
ChatMessageInfo Message = 1; //聊天内容
repeated int64 IdList = 2; // 群发列表
}
///创建聊天频道

View File

@@ -65,6 +65,18 @@ message Caht2C_SendMessageResponse // ICustomRouteResponse
}
///获取离线时的未读私聊
message C2Chat_GetOfflineMessageRequest // ICustomRouteRequest,Caht2C_GetOfflineMessageResponse,ChatRoute
{
}
///发送聊天响应
message Caht2C_GetOfflineMessageResponse // ICustomRouteResponse
{
repeated ChatMessageInfo Message = 1;
}
///推送消息
message Chat2C_Message // ICustomRouteMessage,ChatRoute
{

View File

@@ -11,13 +11,13 @@ message ClubInfo
}
///请求创建工会
message C2S_CreateRequest // ICustomRouteRequest,Caht2C_GetChatRecordResponse,SocialRoute
message C2S_CreateClubRequest // ICustomRouteRequest,S2C_CreateClubResponse,SocialRoute
{
string Name = 1; //工会名称
}
///创建工会响应
message S2C_CreateResponse // ICustomRouteResponse
message S2C_CreateClubResponse // ICustomRouteResponse
{
ClubInfo Club = 1; //创建的工会信息
}

View File

@@ -10,7 +10,7 @@ message ChatUserInfo
message ChatMessageInfo
{
int32 Type = 1; //消息类型
int32 Source = 2; //消息来源
int64 Source = 2; //消息来源
ChatUserInfo Trigger = 3; //触发者
string Content = 4; //内容
}

View File

@@ -1,8 +1,17 @@
using Fantasy.Entitas;
using Fantasy;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
namespace NB.Chat;
public class ChatUnitManageComponent : Entity
{
public readonly Dictionary<long, ChatUnit> ChatUnits = new();
/// <summary>
/// 不在线消息缓存
/// </summary>
public readonly OneToManyList<long, ChatMessageInfo> NotSendMessage = new();
public readonly OneToManyList<string, ChatMessageInfo> PrivateMessage = new();
}

View File

@@ -5,4 +5,5 @@ namespace NB.Gate;
public sealed class GateUnitSessionComponent : Entity
{
public long AccountID;
public long SessionId;
}

View File

@@ -260,6 +260,52 @@ namespace Fantasy
public uint ErrorCode { get; set; }
}
/// <summary>
/// 获取离线时的未读私聊
/// </summary>
[ProtoContract]
public partial class C2Chat_GetOfflineMessageRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2Chat_GetOfflineMessageRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2Chat_GetOfflineMessageRequest>();
}
public override void Dispose()
{
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2Chat_GetOfflineMessageRequest>(this);
#endif
}
[ProtoIgnore]
public Caht2C_GetOfflineMessageResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2Chat_GetOfflineMessageRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.ChatRoute;
}
/// <summary>
/// 发送聊天响应
/// </summary>
[ProtoContract]
public partial class Caht2C_GetOfflineMessageResponse : AMessage, ICustomRouteResponse, IProto
{
public static Caht2C_GetOfflineMessageResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<Caht2C_GetOfflineMessageResponse>();
}
public override void Dispose()
{
ErrorCode = default;
Message.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Caht2C_GetOfflineMessageResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.Caht2C_GetOfflineMessageResponse; }
[ProtoMember(1)]
public List<ChatMessageInfo> Message = new List<ChatMessageInfo>();
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// 推送消息
/// </summary>
[ProtoContract]

View File

@@ -57,7 +57,7 @@ namespace Fantasy
[ProtoMember(1)]
public int Type { get; set; }
[ProtoMember(2)]
public int Source { get; set; }
public long Source { get; set; }
[ProtoMember(3)]
public ChatUserInfo Trigger { get; set; }
[ProtoMember(4)]

View File

@@ -67,6 +67,47 @@ namespace Fantasy
[ProtoMember(3)]
public uint ErrorCode { get; set; }
}
[ProtoContract]
public partial class G2Game_ExitRequest : AMessage, IRouteRequest, IProto
{
public static G2Game_ExitRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<G2Game_ExitRequest>();
}
public override void Dispose()
{
AccountId = default;
GateRouteId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<G2Game_ExitRequest>(this);
#endif
}
[ProtoIgnore]
public Game2G_ExitResponse ResponseType { get; set; }
public uint OpCode() { return InnerOpcode.G2Game_ExitRequest; }
[ProtoMember(1)]
public long AccountId { get; set; }
[ProtoMember(2)]
public long GateRouteId { get; set; }
}
[ProtoContract]
public partial class Game2G_ExitResponse : AMessage, IRouteResponse, IProto
{
public static Game2G_ExitResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<Game2G_ExitResponse>();
}
public override void Dispose()
{
ErrorCode = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Game2G_ExitResponse>(this);
#endif
}
public uint OpCode() { return InnerOpcode.Game2G_ExitResponse; }
[ProtoMember(1)]
public uint ErrorCode { get; set; }
}
/// <summary>
/// 通知游戏服角色进入该聊天服
/// </summary>
@@ -86,7 +127,7 @@ namespace Fantasy
#endif
}
[ProtoIgnore]
public Game2G_EnterResponse ResponseType { get; set; }
public Chat2G_EnterResponse ResponseType { get; set; }
public uint OpCode() { return InnerOpcode.G2Chat_EnterRequest; }
[ProtoMember(1)]
public RoleSimpleInfo Role { get; set; }
@@ -115,6 +156,47 @@ namespace Fantasy
public uint ErrorCode { get; set; }
}
[ProtoContract]
public partial class G2Chat_ExitRequest : AMessage, IRouteRequest, IProto
{
public static G2Chat_ExitRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<G2Chat_ExitRequest>();
}
public override void Dispose()
{
AccountId = default;
GateRouteId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<G2Chat_ExitRequest>(this);
#endif
}
[ProtoIgnore]
public Chat2G_ExitResponse ResponseType { get; set; }
public uint OpCode() { return InnerOpcode.G2Chat_ExitRequest; }
[ProtoMember(1)]
public long AccountId { get; set; }
[ProtoMember(2)]
public long GateRouteId { get; set; }
}
[ProtoContract]
public partial class Chat2G_ExitResponse : AMessage, IRouteResponse, IProto
{
public static Chat2G_ExitResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<Chat2G_ExitResponse>();
}
public override void Dispose()
{
ErrorCode = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Chat2G_ExitResponse>(this);
#endif
}
public uint OpCode() { return InnerOpcode.Chat2G_ExitResponse; }
[ProtoMember(1)]
public uint ErrorCode { get; set; }
}
[ProtoContract]
public partial class Chat2G_ChatMessage : AMessage, IRouteMessage, IProto
{
public static Chat2G_ChatMessage Create(Scene scene)
@@ -124,6 +206,7 @@ namespace Fantasy
public override void Dispose()
{
Message = default;
IdList.Clear();
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Chat2G_ChatMessage>(this);
#endif
@@ -131,6 +214,8 @@ namespace Fantasy
public uint OpCode() { return InnerOpcode.Chat2G_ChatMessage; }
[ProtoMember(1)]
public ChatMessageInfo Message { get; set; }
[ProtoMember(2)]
public List<long> IdList = new List<long>();
}
/// <summary>
/// 创建聊天频道

View File

@@ -4,8 +4,12 @@ namespace Fantasy
{
public const uint G2Game_EnterRequest = 1073751825;
public const uint Game2G_EnterResponse = 1207969553;
public const uint G2Chat_EnterRequest = 1073751826;
public const uint Chat2G_EnterResponse = 1207969554;
public const uint G2Game_ExitRequest = 1073751826;
public const uint Game2G_ExitResponse = 1207969554;
public const uint G2Chat_EnterRequest = 1073751827;
public const uint Chat2G_EnterResponse = 1207969555;
public const uint G2Chat_ExitRequest = 1073751828;
public const uint Chat2G_ExitResponse = 1207969556;
public const uint Chat2G_ChatMessage = 939534097;
public const uint Club2Chat_CreateChannel = 939534098;
}

View File

@@ -12,32 +12,34 @@ namespace Fantasy
public const uint Caht2C_JoinChannelResponse = 2415929107;
public const uint C2Chat_SendMessageRequest = 2281711380;
public const uint Caht2C_SendMessageResponse = 2415929108;
public const uint C2Chat_GetOfflineMessageRequest = 2281711381;
public const uint Caht2C_GetOfflineMessageResponse = 2415929109;
public const uint Chat2C_Message = 2147493651;
public const uint C2Chat_GetChatRecordRequest = 2281711381;
public const uint Caht2C_GetChatRecordResponse = 2415929109;
public const uint C2Chat_GetChatRecordRequest = 2281711382;
public const uint Caht2C_GetChatRecordResponse = 2415929110;
public const uint C2A_LoginRequest = 268445457;
public const uint A2C_LoginResponse = 402663185;
public const uint C2G_LoginRequest = 268445458;
public const uint G2C_LoginResponse = 402663186;
public const uint G2C_RepeatLogin = 134227729;
public const uint C2Game_GetRoleInfoRequest = 2281711382;
public const uint Game2C_GetRoleInfoResponse = 2415929110;
public const uint C2S_CreateRequest = 2281711383;
public const uint S2C_CreateResponse = 2415929111;
public const uint C2S_GetClubInfoRequest = 2281711384;
public const uint S2C_GetClubInfoResponse = 2415929112;
public const uint C2S_GetMemberListRequest = 2281711385;
public const uint S2C_GetMemberListResponse = 2415929113;
public const uint C2S_GetClubListRequest = 2281711386;
public const uint S2C_GetClubListResponse = 2415929114;
public const uint C2S_JoinClubRequest = 2281711387;
public const uint S2C_JoinClubResponse = 2415929115;
public const uint C2S_LeaveClubRequest = 2281711388;
public const uint S2C_LeaveClubResponse = 2415929116;
public const uint C2S_DissolveClubRequest = 2281711389;
public const uint S2C_DissolveClubResponse = 2415929117;
public const uint C2S_DisposeJoinRequest = 2281711390;
public const uint S2C_DisposeJoinResponse = 2415929118;
public const uint C2Game_GetRoleInfoRequest = 2281711383;
public const uint Game2C_GetRoleInfoResponse = 2415929111;
public const uint C2S_CreateClubRequest = 2281711384;
public const uint S2C_CreateClubResponse = 2415929112;
public const uint C2S_GetClubInfoRequest = 2281711385;
public const uint S2C_GetClubInfoResponse = 2415929113;
public const uint C2S_GetMemberListRequest = 2281711386;
public const uint S2C_GetMemberListResponse = 2415929114;
public const uint C2S_GetClubListRequest = 2281711387;
public const uint S2C_GetClubListResponse = 2415929115;
public const uint C2S_JoinClubRequest = 2281711388;
public const uint S2C_JoinClubResponse = 2415929116;
public const uint C2S_LeaveClubRequest = 2281711389;
public const uint S2C_LeaveClubResponse = 2415929117;
public const uint C2S_DissolveClubRequest = 2281711390;
public const uint S2C_DissolveClubResponse = 2415929118;
public const uint C2S_DisposeJoinRequest = 2281711391;
public const uint S2C_DisposeJoinResponse = 2415929119;
public const uint S2C_ClubChange = 2147493652;
}
}

View File

@@ -50,22 +50,22 @@ namespace Fantasy
/// 请求创建工会
/// </summary>
[ProtoContract]
public partial class C2S_CreateRequest : AMessage, ICustomRouteRequest, IProto
public partial class C2S_CreateClubRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2S_CreateRequest Create(Scene scene)
public static C2S_CreateClubRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2S_CreateRequest>();
return scene.MessagePoolComponent.Rent<C2S_CreateClubRequest>();
}
public override void Dispose()
{
Name = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2S_CreateRequest>(this);
GetScene().MessagePoolComponent.Return<C2S_CreateClubRequest>(this);
#endif
}
[ProtoIgnore]
public Caht2C_GetChatRecordResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_CreateRequest; }
public S2C_CreateClubResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2S_CreateClubRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.SocialRoute;
[ProtoMember(1)]
@@ -75,21 +75,21 @@ namespace Fantasy
/// 创建工会响应
/// </summary>
[ProtoContract]
public partial class S2C_CreateResponse : AMessage, ICustomRouteResponse, IProto
public partial class S2C_CreateClubResponse : AMessage, ICustomRouteResponse, IProto
{
public static S2C_CreateResponse Create(Scene scene)
public static S2C_CreateClubResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<S2C_CreateResponse>();
return scene.MessagePoolComponent.Rent<S2C_CreateClubResponse>();
}
public override void Dispose()
{
ErrorCode = default;
Club = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<S2C_CreateResponse>(this);
GetScene().MessagePoolComponent.Return<S2C_CreateClubResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.S2C_CreateResponse; }
public uint OpCode() { return OuterOpcode.S2C_CreateClubResponse; }
[ProtoMember(1)]
public ClubInfo Club { get; set; }
[ProtoMember(2)]

View File

@@ -21,6 +21,7 @@ public class
}
var channel = await channelCenter.Create(entity);
response.ChannelId = channel.Id;
}
}

View File

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

View File

@@ -13,6 +13,11 @@ public class
protected override async FTask Run(ChatUnit entity, C2Chat_JoinChannelRequest request,
Caht2C_JoinChannelResponse response, Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
var channelCenter = entity.Scene.GetComponent<ChatChannelCenterComponent>();
if (channelCenter == null)
{

View File

@@ -11,18 +11,35 @@ public sealed class
protected override async FTask Run(ChatUnit chatUnit, C2Chat_SendMessageRequest request,
Caht2C_SendMessageResponse response, Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
if (request.Type == 0) //频道聊天
{
ChatSceneHelper.BroadcastChannel(chatUnit.Scene, request.Target, new ChatMessageInfo()
{
Content = request.Message,
});
}
else if (request.Type == 1) //私聊
{
//发送私聊
ChatSceneHelper.PrivateMessage(chatUnit.Scene, chatUnit.Id, request.Target, new ChatMessageInfo()
{
Content = request.Message,
});
}
ChatSceneHelper.Broadcast(chatUnit.Scene, new ChatMessageInfo()
else if (request.Type == 3) //广播聊天
{
Content = request.Message,
});
ChatSceneHelper.BroadcastAll(chatUnit.Scene, new ChatMessageInfo()
{
Content = request.Message,
});
}
await FTask.CompletedTask;
}
}

View File

@@ -12,13 +12,11 @@ public class G2Chat_EnterRequestHandler : RouteRPC<Scene, G2Chat_EnterRequest, C
{
var roleId = request.Role.RoleId;
Log.Debug($"收到 G2Chat_EnterRequestHandler {roleId}");
// 在缓存中检查该账号是否存在
var chatUnitManageComponent = scene.GetComponent<ChatUnitManageComponent>();
var account = await chatUnitManageComponent.Online(scene, request.Role, request.GateRouteId);
response.RoleRouteId = account.RuntimeId;
await FTask.CompletedTask;
}
}

View File

@@ -0,0 +1,16 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
namespace NB.Chat;
public class G2Chat_ExitRequestHandler : RouteRPC<Scene, G2Chat_ExitRequest, Chat2G_ExitResponse>
{
protected override async FTask Run(Scene scene, G2Chat_ExitRequest request, Chat2G_ExitResponse response,
Action reply)
{
// 在缓存中检查该账号是否存在
var chatUnitManageComponent = scene.GetComponent<ChatUnitManageComponent>();
await chatUnitManageComponent.Offline(scene, request.AccountId, request.GateRouteId);
}
}

View File

@@ -8,22 +8,107 @@ public static class ChatSceneHelper
{
#region
/// <summary>
/// 发送一条私聊
/// </summary>
/// <param name="scene"></param>
/// <param name="selfId"></param>
/// <param name="targetId"></param>
/// <param name="message"></param>
public static void PrivateMessage(Scene scene, long selfId, long targetId, ChatMessageInfo message)
{
var chatUnitManage = scene.GetComponent<ChatUnitManageComponent>();
if (chatUnitManage == null) return;
var chatUnit = chatUnitManage.Get(targetId);
message.Type = 1;
message.Source = selfId;
if (chatUnit != null)
{
//对方在线
BroadcastAll(scene, message, [targetId]);
}
else
{
//对方不在线,存入待领取列表,等待玩家下次登录领取
chatUnitManage.SaveOfflineMessage(targetId, message);
}
}
/// <summary>
/// 发送一条地图消息
/// </summary>
/// <param name="scene"></param>
/// <param name="mapId"></param>
/// <param name="message"></param>
public static void BroadcastMap(Scene scene, long mapId, ChatMessageInfo message)
{
var chatUnitManage = scene.GetComponent<ChatUnitManageComponent>();
if (chatUnitManage == null) return;
HashSet<long> targets = new HashSet<long>();
foreach (var (_, chatUnit) in chatUnitManage.ChatUnits)
{
if (chatUnit.MapId == mapId)
{
targets.Add(chatUnit.Id);
}
}
if (targets.Count < 1)
{
Log.Info("地图在线人数为0群发取消");
return;
}
BroadcastAll(scene, message, targets);
}
/// <summary>
/// 发送一条频道消息
/// </summary>
/// <param name="scene"></param>
/// <param name="channelId"></param>
/// <param name="message"></param>
public static void BroadcastChannel(Scene scene, long channelId, ChatMessageInfo message)
{
var chatUnitManage = scene.GetComponent<ChatUnitManageComponent>();
if (chatUnitManage == null) return;
HashSet<long> targets = new HashSet<long>();
foreach (var (_, chatUnit) in chatUnitManage.ChatUnits)
{
if (chatUnit.CurrentChannel == channelId)
{
targets.Add(chatUnit.Id);
}
}
if (targets.Count < 1)
{
Log.Info("频道在线人数为0群发取消");
return;
}
BroadcastAll(scene, message, targets);
}
/// <summary>
/// 广播消息给所有人
/// </summary>
/// <param name="scene"></param>
/// <param name="message"></param>
public static void Broadcast(Scene scene, ChatMessageInfo message)
/// <param name="targets"></param>
public static void BroadcastAll(Scene scene, ChatMessageInfo message, HashSet<long>? targets = null)
{
Log.Info("广播消息===");
//发送给所有Gate服务器让Gate转发给其他客户端
var gateConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Gate);
var sendMessage = new Chat2G_ChatMessage()
{
Message = message
Message = message,
};
if (targets != null && targets.Count > 0)
{
sendMessage.IdList.AddRange(targets);
}
var networkMessagingComponent = scene.NetworkMessagingComponent;
foreach (var config in gateConfigs)
{
@@ -37,7 +122,7 @@ public static class ChatSceneHelper
#region 线线
public static async FTask<long> Online(Scene scene, RoleSimpleInfo roleSimple, long gateRuntimeId)
public static async FTask<(long, long)> Online(Scene scene, RoleSimpleInfo roleSimple, long gateRuntimeId)
{
var gameSceneConfig = GetSceneConfig();
var gameRouteId = gameSceneConfig.RouteId;
@@ -51,10 +136,30 @@ public static class ChatSceneHelper
if (gameResponse.ErrorCode != 0)
{
return 0;
return (0, 0);
}
return gameResponse.RoleRouteId;
return (gameResponse.RoleRouteId, gameRouteId);
// return gameRouteId;
}
public static async FTask Offline(Scene scene, long accountId, long gateRuntimeId, long sceneRouteId)
{
for (int i = 0; i < 10; i++)
{
var gameResponse = (Chat2G_ExitResponse)await scene.NetworkMessagingComponent.CallInnerRoute(
sceneRouteId, new G2Chat_ExitRequest()
{
AccountId = accountId,
GateRouteId = gateRuntimeId
});
if (gameResponse.ErrorCode == 0)
{
return;
}
}
Log.Error("重试多次还是退出失败,需检查");
}
private static SceneConfig GetSceneConfig()

View File

@@ -37,7 +37,11 @@ public static class ChatChannelCenterComponentSystem
//查数据库
channel = await self.Scene.World.DataBase.Query<ChatChannel>(channelId, true);
self.Channels.Add(channel.Id, channel);
if (channel != null)
{
self.Channels.Add(channel.Id, channel);
}
return channel;
}

View File

@@ -6,6 +6,21 @@ namespace NB.Chat;
public static class ChatUnitManageComponentSystem
{
#region
/// <summary>
/// 离线消息,进入待领取队列
/// </summary>
/// <param name="self"></param>
/// <param name="targetId"></param>
/// <param name="message"></param>
public static void SaveOfflineMessage(this ChatUnitManageComponent self, long targetId, ChatMessageInfo message)
{
self.NotSendMessage.Add(targetId, message);
}
#endregion
#region 线线
/// <summary>
@@ -15,7 +30,8 @@ public static class ChatUnitManageComponentSystem
/// <param name="scene"></param>
/// <param name="roleSimpleInfo"></param>
/// <param name="gateRouteId"></param>
public static async FTask<ChatUnit?> Online(this ChatUnitManageComponent self, Scene scene, RoleSimpleInfo roleSimpleInfo,
public static async FTask<ChatUnit?> Online(this ChatUnitManageComponent self, Scene scene,
RoleSimpleInfo roleSimpleInfo,
long gateRouteId)
{
var accountId = roleSimpleInfo.RoleId;
@@ -30,14 +46,22 @@ public static class ChatUnitManageComponentSystem
account.GateRouteId = gateRouteId;
account.Role = roleSimpleInfo;
}
await FTask.CompletedTask;
return account;
}
public static async FTask Offline(this ChatUnitManageComponent self, Scene scene, long accountId)
public static async FTask Offline(this ChatUnitManageComponent self, Scene scene, long accountId, long gateRouteId)
{
self.Remove(accountId);
if (self.TryGet(accountId, out var unit) && unit != null)
{
if (unit.GateRouteId == gateRouteId)
{
Log.Info("退出当前聊天服==");
self.Remove(accountId); //如果当前网关和下线的网关一致
}
}
await FTask.CompletedTask;
}

View File

@@ -34,4 +34,8 @@ public static class GameSceneHelper
return (gameResponse.RoleRouteId, gameResponse.RoleInfo);
}
public static async FTask Offline(Scene scene, long accountId, long gateRuntimeId)
{
}
}

View File

@@ -15,14 +15,34 @@ public class Chat2G_ChatMessageHandler : Route<Scene, Chat2G_ChatMessage>
{
Message = message.Message,
};
var idList = message.IdList;
bool isAll = !(idList != null && idList.Count > 0);
var gateUnitManage = scene.GetComponent<GateUnitManageComponent>();
foreach (var session in gateUnitManage.ForEachUnitSession())
if (isAll)
{
session.Send(chatMessage);
foreach (var session in gateUnitManage.ForEachUnitSession())
{
session.Send(chatMessage);
}
}
else
{
if (idList == null) return;
foreach (var (_, gateUnit) in gateUnitManage.Units)
{
if (gateUnit.AccountID > 0 && idList.Contains(gateUnit.AccountID))
{
Session session = gateUnit.Session;
if (session != null)
{
session.Send(chatMessage);
}
}
}
}
await FTask.CompletedTask;
}

View File

@@ -29,10 +29,8 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
// 在缓存中检查该账号是否存在
var gateUnitManageComponent = scene.GetComponent<GateUnitManageComponent>();
if (!gateUnitManageComponent.TryGet(accountId, out var gateUnit))
{
gateUnit = gateUnitManageComponent.Add(session, accountId);
}
var gateUnit = gateUnitManageComponent.Online(session, accountId);
if (gateUnit == null)
{
@@ -40,11 +38,11 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
session.Dispose();
return;
}
response.ErrorCode = await GateLoginHelper.Online(gateUnit);
Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}");
// var gameSceneConfig = GameSceneHelper.GetSceneConfig(session);
//
// // 通过chatSceneConfig拿到这个Scene的RouteId
@@ -71,6 +69,5 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
// // 给当前Session添加一个组件当Session销毁的时候会销毁这个组件。
// var accountFlagComponent = session.AddComponent<SessionPlayerComponent>();
// accountFlagComponent.AccountID = accountId;
}
}

View File

@@ -40,6 +40,7 @@ public static class GateLoginHelper
}
gateUnitSessionComponent.AccountID = gateUnit.AccountID;
gateUnitSessionComponent.SessionId = session.RuntimeId;
//安排游戏服务器,并通知进入
@@ -56,14 +57,15 @@ public static class GateLoginHelper
//安排进入的聊天服
var chatRouteId = await ChatSceneHelper.Online(session.Scene, roleSimpleInfo, session.RuntimeId);
var (chatRouteId, sceneRouteId) =
await ChatSceneHelper.Online(session.Scene, roleSimpleInfo, session.RuntimeId);
if (chatRouteId <= 0)
{
return ErrorCode.OnlineSceneFailed;
}
routeComponent.AddAddress(RouteType.ChatRoute, chatRouteId);
gateUnit.ChatSceneRouteId = chatRouteId;
gateUnit.ChatSceneRouteId = sceneRouteId;
Log.Info($"连接聊天服成功gameRouteId:{gameRouteId}");
return ErrorCode.Successful;
}
@@ -75,12 +77,15 @@ public static class GateLoginHelper
/// <summary>
/// 网关通知其他服务器下线
/// </summary>
/// <param name="self"></param>
/// <param name="gateUnit"></param>
public static async FTask<uint> Offline(GateUnit gateUnit)
/// <param name="sessionId"></param>
public static async FTask<uint> Offline(GateUnit gateUnit, long sessionId)
{
await FTask.CompletedTask;
//通知服务器下线
Log.Info($"断线的session id={sessionId} ChatSceneRouteId={gateUnit.ChatSceneRouteId}");
await GameSceneHelper.Offline(gateUnit.Scene, gateUnit.AccountID, sessionId);
await ChatSceneHelper.Offline(gateUnit.Scene, gateUnit.AccountID, sessionId,
gateUnit.ChatSceneRouteId);
return ErrorCode.Successful;
}

View File

@@ -9,7 +9,7 @@ namespace NB.Gate;
public static class GateUnitManageComponentSystem
{
public static GateUnit Add(this GateUnitManageComponent self, Session session, long accountId)
public static GateUnit Online(this GateUnitManageComponent self, Session session, long accountId)
{
if (self.Units.TryGetValue(accountId, out var unit))
{
@@ -34,11 +34,12 @@ public static class GateUnitManageComponentSystem
return self.Units.TryGetValue(accountId, out unit);
}
public static async FTask Remove(this GateUnitManageComponent self, long accountId, bool isDispose = true)
public static async FTask Offline(this GateUnitManageComponent self, long accountId, long sessionId,
bool isDispose = true)
{
if (!self.Units.TryGetValue(accountId, out var unit)) return;
//通知其他服务器下线
var result = await GateLoginHelper.Offline(unit);
var result = await GateLoginHelper.Offline(unit, sessionId);
if (result != 0)
{
Log.Error($"通知其他服务器下线失败,错误码:{result}");
@@ -52,9 +53,10 @@ public static class GateUnitManageComponentSystem
unit.Dispose();
}
}
/// <summary>
/// 话迭代器
/// 话迭代器
/// </summary>
/// <param name="self"></param>
/// <returns></returns>

View File

@@ -9,7 +9,7 @@ public class GateUnitSessionComponentSystem : DestroySystem<GateUnitSessionCompo
var gateUnitManageComponent = self.Scene.GetComponent<GateUnitManageComponent>();
if (gateUnitManageComponent != null)
{
_ = gateUnitManageComponent.Remove(self.AccountID);
_ = gateUnitManageComponent.Offline(self.AccountID, self.SessionId);
}
self.AccountID = 0;

View File

@@ -13,6 +13,8 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABsonElementAttribute_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_003F3be33698cf8a4c6ea48ef124c9ddacad81800_003Ff5_003F5d71aba0_003FBsonElementAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABsonIgnoreAttribute_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_003F39988e239fb94b73b8bdb00ab8b87d1f82400_003F63_003Fca262714_003FBsonIgnoreAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AControllerBase_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0207e94f3a3e4dca931382ccf94981471de930_003Fd2_003Fe3b49283_003FControllerBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADeserializeSystem_00601_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003Fba_003Fb30c4cb2_003FDeserializeSystem_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADestroySystem_00601_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F41_003F9b0e4a72_003FDestroySystem_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_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_003FSourcesCache_003F326268ddb927895dce924c78646b4d4ce2b05971ed1d8c9be99051ad1d2_003FDictionary_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_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_003Fdb_003F02b9a6a5_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_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_003Feb_003F3472606c_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@@ -1 +1 @@
{"Server":"127.0.0.1:20001","Heartbeat":5,"ProtocolScriptPath":"D:\\work\\Fishing2\\Assets\\Scripts\\Generate","Accounts":["test002"]}
{"Server":"127.0.0.1:20001","Heartbeat":5,"ProtocolScriptPath":"D:\\myself\\Games\\Fishing2\\Assets\\Scripts\\Generate\\NetworkProtocol","Accounts":["test002","test003"]}

View File

@@ -0,0 +1 @@
{"ResponseType":null,"Username":"test002","Password":"test002","LoginType":1,"Region":3}

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Type":1,"Message":"\u4F1A\u8986\u76D644545","Target":0}

View File

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

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Type":1,"Message":"11111\u5927\u6CD5\u5E08\u7684\u65B9\u6CD5343411","Target":323063059205849090}

View File

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

View File

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

View File

@@ -0,0 +1 @@
{"ResponseType":null,"RouteType":1002,"Type":0,"Message":"\u554A\u6536\u5230\u53D1\u65AF\u8482\u82AC334","Target":323063059205849090}