using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Sog; using Sog.Service; using ProtoCSStruct; namespace Mail { public class MailMsgHandler : BaseReloadableService { public override int GetServiceType() { return MailServiceType.MailMsgHandler; } //销毁的时候置空 public override void Dispose() { } public void Tick() { var data = MailServerUtils.GetMailServerData(); var queue = data.m_threadSafePacketQueue; int max = 500; //每次处理消息数,一般都是中转消息修改,不会处理复杂逻辑,这个值可以先大点,后续看性能情况 while (max > 0 && queue.TryDequeue(out var msg)) { HandlerPacket(msg.RemoteApp, msg.Packet); max--; } } public bool IsCanStop() { var data = MailServerUtils.GetMailServerData(); var queue = data.m_threadSafePacketQueue; if(!queue.IsEmpty) { TraceLog.Debug("MailMsgHandler.IsCanStop queue count {0}", queue.Count); return false; } return true; } public void HandlerPacket(uint remoteAppID, StructPacket packet) { TraceLog.TraceDetail("MailMsgHandler.HandlerPacket MsgID {0}", packet.MsgID); switch (packet.MsgID) { case (int)SSGameMsgID.MailOpRes: OnMailOpRes(remoteAppID, packet); break; case (int)SSGameMsgID.QueryMailVersionRes: OnQueryMailVersionRes(remoteAppID, packet); break; default: TraceLog.Error("MailMsgHandler.HandlerPacket unknow MsgID {0}", packet.MsgID); break; } } public void HandlerMessage(uint remoteAppID, MessageData message) { StructPacket packet; bool bSuccess = MailServerUtils.GetProtoPacker().UnpackMessage(message, out packet); if(bSuccess == false) { TraceLog.Error("MailMsgHandler.HandlerMessage ,unpack msg failed {0}, remoteAppID {1}", message.Header.Type, remoteAppID); return; } packet = packet.Clone(); //预先判断,提高效率 if (TraceLog.GetLogLevel() <= (int)Sog.Log.LogLevel.TraceDetail && TraceLog.IsSkipLogMsgID(packet.MsgID) == false) { TraceLog.TraceDetail("MailMsgHandler recv message from server {0}, message type {1} length {2} : {3}->{4}" , ServerIDUtils.IDToString(remoteAppID) , message.Header.Type , message.Header.Length , packet.MessageName() , packet.ToString()); } int iTaskIndex = 0; switch (packet.MsgID) { case (int)SSGameMsgID.AddServerTimeSync: OnAddServerTimeSync(remoteAppID, packet); //不往后走了,直接return return; case (int)SSGameMsgID.RoleLoginSuccessNotify: OnRoleLoginSuccessNotify(remoteAppID, packet); return; case (int)SSGameMsgID.GamePlayerDestroy: OnGamePlayerDestroy(remoteAppID, packet); return; case (int)SSGameMsgID.SendMailWithRule://这个也不能多线程 OnSendMailWithRule(remoteAppID, packet); return; case (int)CSGameMsgID.SetLanguageReq: OnSetPlayerLanguage(remoteAppID, packet); return; case (int)SSGameMsgID.DiscardMailWithRuleReq: MailSendWithRule.OnDiscardMailWithRuleReq(remoteAppID, packet); break; case (int)SSGameMsgID.GetMailWithRuleRes: MailSendWithRule.OnGetMailWithRuleRes(remoteAppID, packet); break; default: long uid = GetUidFromPacket(packet); iTaskIndex = (int)(uid % MessageTaskHandler.MailDBWorkThreadCount); TraceLog.Debug("MailMsgHandler.HandlerMessage GetUidFromPacket MsgID {0} uid {1}", packet.MsgID, uid); break; } //其它单线程处理,实际数据库操作Task多线程 if(packet.MsgID == (int)SSGameMsgID.OperationMailSearchReq || packet.MsgID == (int)SSGameMsgID.QueryMailReq || packet.MsgID == (int)SSGameMsgID.MailOpReq) { MessageTaskDistributor.Instance.Distribute(remoteAppID, packet, iTaskIndex); } } private long GetUidFromPacket(StructPacket packet) { switch (packet.MsgID) { //mail case (int)SSGameMsgID.QueryMailReq: ref SSQueryMailReq querymailreq = ref packet.GetMessage(); return querymailreq.Uid; case (int)SSGameMsgID.OperationMailSearchReq: ref SSOperationSearchMailReq req = ref packet.GetMessage(); return req.Uid; case (int)SSGameMsgID.MailOpReq: ref SSMailOpReq mailopreq = ref packet.GetMessage(); return mailopreq.Mail.Uid; default: TraceLog.Error("MailMsgHandler.GetUidFromPacket unknow MsgID {0}", packet.MsgID); break; } //其他情况一律返回0 return 0; } public void OnSetPlayerLanguage(uint remoteAppID, StructPacket packet) { ref CSSetLanguageReq req = ref packet.GetMessage(); var players = MailServerUtils.GetMailServerData().m_playerTable; long uid = packet.ObjectID; if (players.ContainsKey(uid)) { players[uid].Language = req.Lang.GetString(); } } private void OnMailOpRes(uint remoteAppID, StructPacket packet) { ref SSMailOpRes res = ref packet.GetMessage(); long uid = res.ClientOpUid; var player = MailServerUtils.GetPlayerInfo(uid); if(player == null) { return; } if(player.GameServerID != remoteAppID && res.OpType != (int)MailOpType.MailVerChange) { MailServerUtils.GetPacketSender().SendToServerByID(player.GameServerID, (int)SSGameMsgID.MailOpRes, ref res, packet.ObjectID); } if(res.OpType == (int)MailOpType.MailVerChange) { player.SavedSuccessSeq = res.Seq; } } private void OnQueryMailVersionRes(uint remoteAppID, StructPacket packet) { ref SSQueryMailVersionRes res = ref packet.GetMessage(); TraceLog.TraceDetail("MailMsgHandler.OnQueryMailVersionRes msg {0}", res.ToString()); var player = MailServerUtils.GetPlayerInfo(res.Uid); if(player == null) { return; } //已经查询过了 if(player.isQueryMailVer) { return; } player.lastMailVer = res.Version; player.isQueryMailVer = true; MailSendWithRule.CheckAndSendMailWithRule(player);//检查全局邮件 } public void OnAddServerTimeSync(uint remoteAppID, StructPacket packet) { ref SSAddServerTimeSync sync = ref packet.GetMessage(); TraceLog.Debug("MailMsgHandler.OnAddServerTimeSync serverid {0} offset {1}" , ServerIDUtils.IDToString(remoteAppID), sync.Offset); MailServerUtils.GetApp().Time.SetOffset(sync.Offset); MailServerUtils.GetApp().Time.UpdateTime(); TraceLog.Debug("MailMsgHandler.OnAddServerTimeSync serverid {0} offset {1} set time success" , ServerIDUtils.IDToString(remoteAppID), sync.Offset); } public void OnRoleLoginSuccessNotify(uint remoteAppID, StructPacket packet) { ref SSRoleLoginSuccessNotify req = ref packet.GetMessage(); if(req.Uid < 10000) { return; } TraceLog.Debug("MailMsgHandler.OnRoleLoginSuccessNotify userID {0} login",req.Uid); var players = MailServerUtils.GetMailServerData().m_playerTable; if(players.TryGetValue(req.Uid, out var player)) { player.IsOnline = true; player.RealmID = req.RealmID; player.GameServerID = req.GameServerID; player.ChatServerID = req.ChatServerID; player.LogoutTime = 0; player.Language = req.Language.GetString(); player.ApkVersion = req.ApkVersion.GetString(); } else { player = new PlayerInfoMail(); player.UserID = req.Uid; player.IsOnline = true; player.RealmID = req.RealmID; player.GameServerID = req.GameServerID; player.ChatServerID = req.ChatServerID; player.CreateTime = req.CreateTime; player.LogoutTime = 0; player.Language = req.Language.GetString(); player.ApkVersion = req.ApkVersion.GetString(); players.Add(req.Uid, player); } if(player.isQueryMailVer) //es { MailSendWithRule.CheckAndSendMailWithRule(player);//检查全局邮件 } else { PlayerMailVerSeqSvc.SendQueryMailVer(player); } } public void OnGamePlayerDestroy(uint remoteAppID, StructPacket packet) { ref SSGamePlayerDestroy req = ref packet.GetMessage(); var players = MailServerUtils.GetMailServerData().m_playerTable; if (players.ContainsKey(req.Uid)) { players[req.Uid].IsOnline = false; players[req.Uid].LogoutTime = MailServerUtils.GetTimeSecond(); } } //批量邮件 public void OnSendMailWithRule(uint remoteAppID, StructPacket packet) { MailSendWithRule.GmSendMailWithRule(remoteAppID, packet); } //每分钟检查一次,和消息同属主线程 private static int TickPlayerIndex = 0; public static void TickOneMinute(long nowSec) { var data = MailServerUtils.GetMailServerData(); if(data.m_playerTable.Count == 0) { return; } if(data.m_playerForUpdate == null) { TickPlayerIndex = 0; data.m_playerForUpdate = data.m_playerTable.Values.ToList(); return; } for (int i = 0; i < 100; i++) { if(TickPlayerIndex >= data.m_playerForUpdate.Count) { TickPlayerIndex = 0; data.m_playerForUpdate = data.m_playerTable.Values.ToList(); return; } PlayerInfoMail player = data.m_playerForUpdate[TickPlayerIndex]; TickPlayerIndex++; if(player.IsOnline == false && player.LogoutTime + 1800 >= nowSec && !player.IsDirty()) { data.m_playerTable.Remove(player.UserID); } } } } }