From 49b6a6a928f9efae8c9c9563f02e3757ffeb291c Mon Sep 17 00:00:00 2001 From: hahwu <31872165+hahwu@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:34:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/db/Mysql.go | 10 ++ src/server/game/friend_func.go | 141 ++++++++++++++++++++++++--- src/server/game/game_type.go | 2 + src/server/game/gm_handler.go | 21 ++++ src/server/game/message_handler.go | 40 +++++++- src/server/game/message_mgr.go | 31 +++++- src/server/game/mod/charge/Charge.go | 7 ++ src/server/game/player_data.go | 1 + src/server/game_util/GoUtil.go | 23 +++++ 9 files changed, 258 insertions(+), 18 deletions(-) diff --git a/src/server/db/Mysql.go b/src/server/db/Mysql.go index efe556ae..af80a370 100644 --- a/src/server/db/Mysql.go +++ b/src/server/db/Mysql.go @@ -442,3 +442,13 @@ func GetCommendPlayerFromDb(uid, login int64, level int) ([]int, error) { } return res, nil } + +func GetDebugPlayer(uid int) ([]int, error) { + sqlStr := "SELECT dwUin FROM t_player_baseinfo WHERE dwUin != ? ORDER BY login_time DESC LIMIT 1000" + var res []int + if err := SqlDb.Select(&res, sqlStr, uid); err != nil { + log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "PlayerBaseInfo", sqlStr, err) + return nil, err + } + return res, nil +} diff --git a/src/server/game/friend_func.go b/src/server/game/friend_func.go index a052fb9b..b85ec513 100644 --- a/src/server/game/friend_func.go +++ b/src/server/game/friend_func.go @@ -1,6 +1,7 @@ package game import ( + "math" "server/db" "server/game/mod/msg" GoUtil "server/game_util" @@ -156,43 +157,153 @@ func GetRecommendPlayer(p *Player, Num int) []int { candidateList = append(candidateList, Uid) } } - baseList := make([]*PlayerSimpleData, 0, len(candidateList)) + levelFilterList := make([]*PlayerSimpleData, 0, len(candidateList)) for _, uid := range candidateList { ps := G_GameLogicPtr.GetSimplePlayerByUid(uid) if ps != nil { - baseList = append(baseList, ps) + levelFilterList = append(levelFilterList, ps) } } - if len(baseList) == 0 { + if len(levelFilterList) == 0 { return nil } BaseMod := p.PlayMod.getBaseMod() level := BaseMod.GetLevel() diffLimit := 10 - filtered := make([]int, 0, len(baseList)) + chargeFilterList := make([]*PlayerSimpleData, 0, len(levelFilterList)) breakNum := 100 + /* + 等级筛选:检索与玩家等级差绝对值小于等于10的用户,若大于5人,则进入下一步筛查,否则逐步放宽等级差限制,直到等级差绝对值小于等于100,仍然无法筛选出5人,则进入下一步筛查 + */ for breakNum > 0 { breakNum-- - filtered = filtered[:0] - for _, ps := range baseList { + chargeFilterList = chargeFilterList[:0] + for _, ps := range levelFilterList { if ps == nil { continue } - diff := level - ps.Level - if diff < 0 { - diff = -diff - } - if diff <= diffLimit { - filtered = append(filtered, ps.Uid) + diff := math.Abs(float64(level - ps.Level)) + if diff <= float64(diffLimit) { + chargeFilterList = append(chargeFilterList, ps) } } - if len(filtered) >= 5 { + if len(chargeFilterList) >= 5 { break } diffLimit++ } - candidateList = filtered - recommendList := GoUtil.RandSliceNum(candidateList, Num) + /* + 付费筛查,判断自身是否为付费用户,若是,则优先推荐付费用户,若不是,则优先推荐非付费用户 + */ + endFilterList := make([]int, 0, len(chargeFilterList)) + chargeFilterFunc := func(filterlist []*PlayerSimpleData, maxCharge float64) []int { + var res []int + type sortData struct { + uid int + maxCharge float64 + } + var filterList2 []sortData + var notChargeList []int + var allList []int + for _, ps := range filterlist { + if ps == nil { + continue + } + allList = append(allList, ps.Uid) + if ps.MaxCharge > 0 { + filterList2 = append(filterList2, sortData{ps.Uid, math.Abs(maxCharge - ps.MaxCharge)}) + } else { + notChargeList = append(notChargeList, ps.Uid) + } + } + sort.Slice(filterList2, func(i, j int) bool { + return filterList2[i].maxCharge < filterList2[j].maxCharge + }) + if len(filterList2) >= 1 { + res = append(res, filterList2[0].uid) + } + if len(filterList2) >= 2 { + res = append(res, filterList2[1].uid) + } + if len(notChargeList) >= 1 { + res = append(res, notChargeList[0]) + } + if len(res) < 3 { + dlist := GoUtil.SubSlices(allList, res) + res = append(res, GoUtil.RandSliceNum(dlist, 3-len(res))...) + } + return res + } + notChargeWatchAdFilterFunc := func(filterlist []*PlayerSimpleData) []int { + var res []int + var notChargeList []int + var chargeList []int + var allList []int + for _, ps := range filterlist { + if ps == nil { + continue + } + allList = append(allList, ps.Uid) + if ps.MaxCharge > 0 { + chargeList = append(chargeList, ps.Uid) + } else { + if ps.AdWatch > 5 { + notChargeList = append(notChargeList, ps.Uid) + } + } + } + if len(notChargeList) >= 1 { + res = append(res, notChargeList[0]) + } + if len(notChargeList) >= 2 { + res = append(res, notChargeList[1]) + } + if len(chargeList) >= 1 { + res = append(res, chargeList[0]) + } + if len(res) < 3 { + dlist := GoUtil.SubSlices(allList, res) + res = append(res, GoUtil.RandSliceNum(dlist, 3-len(res))...) + } + return res + } + notChargeNotWatchAdFilterFunc := func(filterlist []*PlayerSimpleData) []int { + var res []int + var notChargeList []int + var chargeList []int + var allList []int + for _, ps := range filterlist { + if ps == nil { + continue + } + allList = append(allList, ps.Uid) + if ps.MaxCharge > 0 { + chargeList = append(chargeList, ps.Uid) + } else { + notChargeList = append(notChargeList, ps.Uid) + } + } + if len(chargeList) >= 1 { + res = append(res, chargeList[0]) + } + dlist := GoUtil.SubSlices(allList, res) + res = append(res, GoUtil.RandSliceNum(dlist, 3-len(res))...) + return res + } + if diffLimit == 10 && len(chargeFilterList) >= 5 { + MaxCharge := p.GetChargeMod().GetMaxCharge() + if MaxCharge > 0 { + endFilterList = chargeFilterFunc(chargeFilterList, MaxCharge) + } else { + if p.GetChargeMod().GetAdWatch() > 5 { + endFilterList = notChargeWatchAdFilterFunc(chargeFilterList) + } else { + endFilterList = notChargeNotWatchAdFilterFunc(chargeFilterList) + } + } + } + + recommendList := GoUtil.RandSliceNum(endFilterList, Num) for _, Uid := range recommendList { FriendMod.AddRecommend(Uid) } diff --git a/src/server/game/game_type.go b/src/server/game/game_type.go index 1522dbce..109d3eab 100644 --- a/src/server/game/game_type.go +++ b/src/server/game/game_type.go @@ -40,6 +40,8 @@ type PlayerSimpleData struct { Lang int Account string PetFur int + MaxCharge float64 + AdWatch int } type VarGoldCard struct { diff --git a/src/server/game/gm_handler.go b/src/server/game/gm_handler.go index e862356d..ec710984 100644 --- a/src/server/game/gm_handler.go +++ b/src/server/game/gm_handler.go @@ -623,6 +623,27 @@ func ReqGmCommand_(player *Player, Command string) error { SevenMod.MonthResetTime = 0 PlayerBaseMod := player.GetPlayerBaseMod() SevenMod.ZeroUpdate(PlayerBaseMod.GetSevenLoginAdd(), PlayerBaseMod.GetLastLoginTime()) + case "debugLogoutMsg": + Uid, _ := strconv.Atoi(arg[1]) + uidList, err := db.GetDebugPlayer(Uid) + if err != nil { + log.Error("GetDebugPlayer err:%s", err.Error()) + return err + } + for _, uid := range uidList { + FriendMgrSend(&MsgMod.Msg{ + Type: MsgMod.HANDLE_TYPE_APPLY, + SendT: GoUtil.Now(), + From: uid, + To: Uid, + }) + FriendMgrSend(&MsgMod.Msg{ + Type: MsgMod.HANDLE_TYPE_HANDBOOK_COLLECTION, + SendT: GoUtil.Now(), + From: Uid, + To: uid, + }) + } default: return fmt.Errorf("Player %d ReqGmCommand:%v not found", player.M_DwUin, arg) } diff --git a/src/server/game/message_handler.go b/src/server/game/message_handler.go index 5173e4d1..a407d9ea 100644 --- a/src/server/game/message_handler.go +++ b/src/server/game/message_handler.go @@ -525,7 +525,45 @@ func (p *Player) handle(m *msg.Msg) error { case msg.HANDLE_TYPE_FRIEND_SPONSOER: p.AddLog(m.From, friend.LOG_TYPE_FRIEND_SPONSOR_GET, "", m.SendT) case msg.SERVER_PLAYER_SYNC_LOGOUT_MSG: - //p.LoginBackData() + info, ok := m.Extra.(map[string]interface{}) + if !ok { + return nil + } + applyUids, ok := info["applyUids"].([]int64) + if ok && len(applyUids) > 0 { + var faceList []int + var name string + for _, v := range applyUids { + ps := G_GameLogicPtr.GetSimplePlayerByUid(int(v)) + if ps != nil { + faceList = append(faceList, ps.Face) + name = ps.Name + } + } + p.PushClientRes(&proto.ResPlayerLougouMsg{ + Name: name, + Face: GoUtil.IntToInt32(faceList), + Count: GoUtil.Int32(info["apply_count"]), + }) + } + otherUids, ok := info["otherUids"].([]int64) + if ok && len(otherUids) > 0 { + var faceList []int + var name string + for _, v := range otherUids { + ps := G_GameLogicPtr.GetSimplePlayerByUid(int(v)) + if ps != nil { + faceList = append(faceList, ps.Face) + name = ps.Name + } + } + p.PushClientRes(&proto.ResPlayerLougouMsg{ + Type: 1, + Name: name, + Face: GoUtil.IntToInt32(faceList), + Count: GoUtil.Int32(info["other_count"]), + }) + } default: log.Debug("uid : %d, handle msg type : %d not exist", p.M_DwUin, m.Type) } diff --git a/src/server/game/message_mgr.go b/src/server/game/message_mgr.go index 439963ad..20250c36 100644 --- a/src/server/game/message_mgr.go +++ b/src/server/game/message_mgr.go @@ -293,16 +293,43 @@ func PlayerLoginHandler(data *msg.Msg) (interface{}, error) { messages.mu.Unlock() ReplyPlayerMsgASync(data, nil) // 在锁外发送离线消息 + var applyUids []int64 + var otherUids []int64 for _, message := range messagesToSend { - message.H = msg.MSG_TYPE_OFFLINE // 标记为离线消息 + if message.Type == msg.HANDLE_TYPE_APPLY { + applyUids = append(applyUids, int64(message.From)) + } else { + otherUids = append(otherUids, int64(message.From)) + } + } + for _, message := range messagesToSend { + if message.Type == msg.HANDLE_TYPE_APPLY && len(applyUids) >= 3 { + message.H = msg.MSG_TYPE_OFFLINE // 标记为离线消息 + } + if message.Type != msg.HANDLE_TYPE_APPLY && len(otherUids) >= 3 { + message.H = msg.MSG_TYPE_OFFLINE // 标记为离线消息 + } SendMsgToNodeAsync(message, node) } + applyUidsFive := applyUids + if len(applyUids) > 5 { + applyUidsFive = applyUids[len(applyUids)-5:] + } + otherUidsFive := otherUids + if len(otherUids) > 5 { + otherUidsFive = otherUids[len(otherUids)-5:] + } SendMsgToNodeAsync(&msg.Msg{ From: data.From, To: data.From, Type: msg.SERVER_PLAYER_SYNC_LOGOUT_MSG, HandleType: msg.HANDLE_MOD_PLAYER_MSG, - Extra: len(messagesToSend), + Extra: map[string]interface{}{ + "apply_uids": applyUidsFive, + "apply_count": len(applyUids), + "other_uids": otherUidsFive, + "other_count": len(otherUids), + }, }, node) // 发送离线消息处理完成通知 log.Debug("[Middleware] Player sync logout message player id: %v, len: %d", data.From, len(messagesToSend)) return nil, nil diff --git a/src/server/game/mod/charge/Charge.go b/src/server/game/mod/charge/Charge.go index 17ba605b..6c793f51 100644 --- a/src/server/game/mod/charge/Charge.go +++ b/src/server/game/mod/charge/Charge.go @@ -39,6 +39,8 @@ type ChargeMod struct { WishList *WishList WeeklyDiscount map[int]int // 每周折扣购买次数 WeeklyEndTime int64 + + AdWatch int // 观看广告次数 } type WishList struct { @@ -132,6 +134,7 @@ func (c *ChargeMod) ZeroUpdate(Emit []int) { c.FreeShop = 0 SpecialGrade := 1 c.TodayCharge = 0 + c.AdWatch = 0 c.SpecialShop = make(map[int]*SepcialShop) SpecialShopCount := chargeCfg.GetSpecialShopCount() for i := 1; i <= 2; i++ { @@ -489,3 +492,7 @@ func (c *ChargeMod) GetWeeklyEndTime() int64 { func (c *ChargeMod) SetWeeklyEndTime(EndTime int64) { c.WeeklyEndTime = EndTime } + +func (c *ChargeMod) GetAdWatch() int { + return c.AdWatch +} diff --git a/src/server/game/player_data.go b/src/server/game/player_data.go index 5ba9077c..1c9439e1 100644 --- a/src/server/game/player_data.go +++ b/src/server/game/player_data.go @@ -1081,6 +1081,7 @@ func (p *Player) UpdateUserInfo() { simple.Lang = int(p.PlayMod.getBaseMod().Lang) simple.Account = p.PlayMod.getBaseMod().Account simple.PetFur = p.PlayMod.getFurMod().GetFurSet() + simple.MaxCharge = p.PlayMod.getChargeMod().GetMaxCharge() //TODO 存储到redis 在新版本中将优化成gob进行压缩 value, _ := json.Marshal(simple) IdStr := GoUtil.String(p.M_DwUin) diff --git a/src/server/game_util/GoUtil.go b/src/server/game_util/GoUtil.go index e825a404..df3eca3a 100644 --- a/src/server/game_util/GoUtil.go +++ b/src/server/game_util/GoUtil.go @@ -210,6 +210,29 @@ func Int(a interface{}) int { return 0 } +func Int32(a interface{}) int32 { + if a == nil { + return 0 + } + switch v := a.(type) { + case int: + return int32(v) + case int32: + return int32(v) + case int64: + return int32(v) + case float64: + return int32(v) + case string: + r, err := strconv.Atoi(v) + if err != nil { + return 0 + } + return int32(r) + } + return 0 +} + func String(a interface{}) string { if a == nil { return ""