using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Sog; using ProtoCSStruct; using Google.Protobuf.Collections; namespace Friend { /// /// 好友推荐 /// public static class FriendRecommenTableSvc { public static void Tick(long nowSec) { var m_allTable = FriendServerUtils.GetFriendRecommendTable(); if (nowSec < m_allTable.nextTickSec) { return; } TraceLog.Trace("FriendRecommenTableSvc.Tick {0}", m_allTable.m_recommendInfoTable.Count); // 1分钟更新一次 m_allTable.nextTickSec = nowSec + 60; foreach(FriendRecommendInfo m_table in m_allTable.m_recommendInfoTable.Values) { for (int i = 0; i < m_table.uidHash.Length; i++) { m_table.uidList[i].Clear(); foreach (long uid in m_table.uidHash[i].ToList()) { ref FriendCacheInfoStruct friendInfo = ref FriendOp.GetFriendInfoByUid(uid); if (friendInfo.IsNull()) { TraceLog.Trace("FriendRecommenTableSvc.Tick uid {0} no friendInfo", uid); m_table.uidHash[i].Remove(uid); continue; } // 淘汰离线玩家 PlayerInfoFriend player = FriendServerUtils.GetPlayerTableOp().GetPlayerInfo(uid); if (player == null || player.IsOnline == false) { m_table.uidHash[i].Remove(uid); continue; } TraceLog.Trace("FriendRecommenTableSvc.Tick uid {0} friendList {1}" , friendInfo.Self.Uid, friendInfo.FriendList.iCount); if (FriendSvc.IsFriendListFull(ref friendInfo)) { m_table.uidHash[i].Remove(friendInfo.Self.Uid); continue; } int idx = friendInfo.Self.Level / 10; if (idx != i) { m_table.uidHash[i].Remove(friendInfo.Self.Uid); continue; } m_table.uidList[i].Add(ref friendInfo.Self.Uid); } if (m_table.uidList[i].Count > 0) { TraceLog.Trace("FriendRecommenTableSvc.Tick level {0} list count {1} hash count {2}" , i, m_table.uidList[i].Count, m_table.uidHash[i].Count); } } } } public static FriendRecommendInfo GetOrCreateRecommendInfo(int logicWorldId) { var m_logicTable = FriendServerUtils.GetFriendRecommendTable().m_recommendInfoTable; if (!m_logicTable.ContainsKey(logicWorldId)) { FriendRecommendInfo newInfo = new FriendRecommendInfo(logicWorldId); m_logicTable.Add(logicWorldId, newInfo); TraceLog.Debug("FriendRecommenTableSvc.GetOrCreateRecommendInfo create FriendRecommendInfo {0}", logicWorldId); } return m_logicTable[logicWorldId]; } // add的时候只要新队列里面没有就加入, 不处理老队列, 等tick时移除 public static void Add(ref FriendCacheInfoStruct friendInfo) { if (FriendSvc.IsFriendListFull(ref friendInfo)) { return; } int logicWorldId = FriendServerUtils.GetLogicWorldId(friendInfo.Self.RealmId); if(logicWorldId <= 0) { return; } var m_table = GetOrCreateRecommendInfo(logicWorldId); int idx = friendInfo.Self.Level / 10; if (idx < m_table.uidHash.Length && m_table.uidHash[idx].Count < FriendRecommendInfo.NumPerLevel && !m_table.uidHash[idx].Contains(friendInfo.Self.Uid)) { m_table.uidHash[idx].Add(friendInfo.Self.Uid); if (!m_table.uidList[idx].IsFull()) { m_table.uidList[idx].Add(ref friendInfo.Self.Uid); } TraceLog.Trace("FriendRecommenTableSvc.Add idx {0} uid {1} hash count {2} uidList count {3}" , idx, friendInfo.Self.Uid, m_table.uidHash[idx].Count, m_table.uidList[idx].Count); } } public static List GetRecommendUid(ref FriendCacheInfoStruct selfInfo, int level, int need) { if (need <= 0) { return null; } int logicWorldId = FriendServerUtils.GetLogicWorldId(selfInfo.Self.RealmId); if (logicWorldId <= 0) { return null; } var m_table = GetOrCreateRecommendInfo(logicWorldId); int idx = level / 10; if (idx >= m_table.uidList.Length) { return null; } if (m_table.uidList[idx].Count == 0) { return null; } var uidPool = new List(m_table.uidList[idx].Count); // 去掉自己和好友,以及黑名单的 for (int i = 0; i < m_table.uidList[idx].Count; i++) { if (m_table.uidList[idx][i] != selfInfo.Self.Uid && FriendOp.IsAlreadyBeenFriend(ref selfInfo, m_table.uidList[idx][i]) != 1 && !selfInfo.Self.BlackList.Contains(m_table.uidList[idx][i])) { uidPool.Add(m_table.uidList[idx][i]); } } // 推荐列表不够 if (uidPool.Count <= need) { return uidPool; } var random = FriendServerUtils.GetApp().Rand; // gap是随机间隔 int gap = uidPool.Count / need - 1; if (gap <= 0) { gap = 1; } else if (gap > 1) { gap = random.Next(gap) + 1; } // 随机开始位置和间隔 return GetRandList(uidPool, random.Next(uidPool.Count), gap, need); } private static List GetRandList(List uidPool, int startIdx, int gap, int need) { gap = gap <= 0 ? 1 : gap; var list = new List(need); for (int i = 0; i < need; i++) { startIdx = (startIdx + gap) % uidPool.Count; list.Add(uidPool[startIdx]); } return list; } } }