package lord import ( actorRemote "f1-game/internal/actor_remote" capp "f1-game/internal/cherry_app" "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" "f1-game/internal/event" "f1-game/internal/extend/times" "f1-game/internal/extend/utils" facade "f1-game/internal/facade" nameActor "f1-game/internal/name/actor" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" "f1-game/nodes/game/internal/db" ctime "github.com/cherry-game/cherry/extend/time" cfacade "github.com/cherry-game/cherry/facade" clog "github.com/cherry-game/cherry/logger" cproto "github.com/cherry-game/cherry/net/proto" ) var srv = &service{} func Service() *service { return srv } type service struct { facade.PlayerServiceBase[*db.PlayerTable] } func (p *service) OnLogin(playerTable *db.PlayerTable, session *cproto.Session) { playerTable.Stats.LastLoginIP = session.Ip // 默认赛季1 if playerTable.Lord.SeasonID <= 0 { playerTable.Lord.SeasonID = 1 } playerTable.Save2Queue() // 检测玩家头像 p.CheckPlayerShow(playerTable) clog.Debugf("[lord.OnLogin] PlayerID = %d, IP = %s", playerTable.PlayerID, session.Ip) } func (p *service) OnLogined(playerTable *db.PlayerTable, session *cproto.Session) { // 更新玩家最后登录信息 p.syncLastPlayer(playerTable) } func (*service) OnLogout(playerTable *db.PlayerTable) { now := ctime.Now() loginTime := ctime.NewMillisecond(playerTable.Stats.LastLoginTime) second := loginTime.DiffInSeconds(&now) if second > 0 { // 累计在线时间 playerTable.Stats.TotalOnlineSecond += second } // 最后登出时间 playerTable.Stats.LastLogoutTime = now.ToMillisecond() playerTable.Save2Queue() clog.Debugf("[lord.OnLogout] PlayerID = %d, OnlineTime = %d(s)", playerTable.PlayerID, second) } func (*service) OnReset(playerTable *db.PlayerTable, curTime *ctime.CherryTime, byLogin bool) { // 判断当前时间是否开启时间 openTime, err := times.ParseDateFormat(data.Const.MailDaysOpenTime) if err != nil { clog.Warnf("send daily mail fail. err:%+v", err) return } openTimeSecond := openTime.Unix() // 当前时间还没到 if curTime.ToSecond() < openTimeSecond { return } // 如果是 则获取已领取的每日邮件天数 days := playerTable.Stats.DailyMailDays + 1 mailDailyRow, found := data.MailDaily.GetByLoginDays(days) if !found { return } // 更新已领取天数 playerTable.Stats.DailyMailDays = days playerTable.Save2Queue() // 发送邮件 actorRemote.GameMail.Send(playerTable.NodeID, &pb.SendMail{ ToPlayerID: playerTable.PlayerID, TemplateID: constant.MailID_DailyMail, Rewards: mailDailyRow.Rewards.ToProto(), TemplateParams: utils.ToStringSlice(days), }) clog.Debugf("send daily mail finish. playerID:%d, day:%d", playerTable.PlayerID, days) } func (p *service) Push(playerTable *db.PlayerTable, session *cproto.Session) { proto := playerTable.Lord.ToProto() sessions.PushWithSession(session, nameRoute.PushGamePlayer_Lord, proto) // 推送外显列表 showRsp := &pb.LordShows{} for showID, show := range playerTable.Shows.ShowMap { showRsp.Shows = append(showRsp.Shows, show.ToProto(showID)) } sessions.PushWithSession(session, nameRoute.PushGamePlayer_LordShow, showRsp) } // ChangePush 外显变更推送 func (p *service) ChangePush(playerID int64, updateShowIDs ...int32) { if len(updateShowIDs) <= 0 { return } var ( playerTable, _ = db.GetPlayerTable(playerID) rsp = &pb.LordShows{} ) for _, showID := range updateShowIDs { show, found := playerTable.Shows.GetShow(showID) if !found { continue } rsp.Shows = append(rsp.Shows, show.ToProto(showID)) } sessions.PushPlayer(playerID, nameRoute.PushGamePlayer_LordShowAdd, rsp) } // 检测外显过期 func (p *service) CheckShowExpireTimer(playerID int64, nowSecond int64) { playerTable, _ := db.GetPlayerTable(playerID) if playerTable.Shows.ShowMap.Empty() { return } expireShowIDs, changeShows := playerTable.CheckShowExpire(nowSecond) if len(expireShowIDs) <= 0 { return } // 推送删除外显列表 expireResp := &pb.I32List{ List: expireShowIDs, } sessions.PushPlayer(playerID, nameRoute.PushGamePlayer_LordShowExpire, expireResp) // 推送外显变更列表 if len(changeShows) > 0 { changeShowsResp := &pb.I32I32List{ List: changeShows, } sessions.PushPlayer(playerID, nameRoute.PushGamePlayer_LordShowChange, changeShowsResp) } playerTable.Save2Queue() } func (p *service) AddExp(playerID int64, exp int64) int32 { var ( playerTable, _ = db.GetPlayerTable(playerID) lord = &playerTable.Lord seasonID = playerTable.Lord.SeasonID maxLevel = data.LordLevel.GetLevelLimitBySeason(seasonID) levelUp bool ) // 已满级 if lord.Level >= maxLevel { return code.OK } lord.Exp += exp // 是否升级 for lord.Level < maxLevel { row, ok := data.LordLevel.GetByLevel(lord.Level) if !ok { return code.ConfigNotFound_LordLevel } if row.Exp > lord.Exp { break } lord.Exp -= row.Exp lord.Level++ // 等级已达上限,设置经验为0 if lord.Level >= maxLevel { lord.Exp = 0 } levelUp = true } // 保存 playerTable.Save2Queue() // 推送 if session, found := sessions.GetSession(playerID); found { p.Push(playerTable, session) } // 抛升级事件 if levelUp { capp.PostEvent(event.NewLordLevelUp(playerID, lord.Level)) // 发送系统消息事件 capp.PostEvent(event.NewChatSystemMsg(playerID, enum.ChatMsgType_LordUp, nil, nil, lord.Level)) } return code.OK } // syncLastPlayer 同步最后登录信息 func (p *service) syncLastPlayer(playerTable *db.PlayerTable) { protoUpdatePlayer := &pb.UpdateLastPlayer{ PID: playerTable.PID, OpenID: playerTable.OpenID, UID: playerTable.UID, GameNodeID: playerTable.NodeID, PlayerID: playerTable.PlayerID, PlayerName: playerTable.Lord.Name, PlayerLevel: playerTable.Lord.Level, Icon: 0, } actorRemote.CenterPlayer.UpdateLastPlayer(protoUpdatePlayer) } // 更新领主声望 // TODO 后面模块多了需要把功能整成模块 而不是现在这样所有模块在一个方法中枚举类型作为service_type的类型 func (p *service) UpdatePrestige(playerID int64) { var ( playerTable, _ = db.GetPlayerTable(playerID) mapNodeID = playerTable.Map.MapNodeID ) // 没有地图不算 if len(mapNodeID) <= 0 { return } prestiges := map[int32]int32{} // 计算英雄星级增加 heroTable := db.GetHeroTable(playerID) heroStars := heroTable.Heroes.GetHeroStarCount() for star, count := range heroStars { heroStarRow, found := data.HeroStar.GetByStar(star) if !found { clog.Warnf("[UpdateLordPrestige] hero star config not found. playerID:%d, star:%d", playerID, star) continue } prestiges[int32(enum.Prestige_Type_HeroStar)] += heroStarRow.AddPrestige * count } // TODO 其他模块计算 // 判断是否存在地图,如果存在地图则通知地图 target := cfacade.NewChildPath(mapNodeID, nameActor.Map_Player, playerID) capp.Call(target, nameRemote.MapPlayer_UpdatePrestige, &pb.I32Map{ Value: prestiges, }) clog.Infof("[UpdateLordPrestige] prestiges:%+v", prestiges) } func (p *service) CheckPlayerShow(playerTable *db.PlayerTable) { // 检测初始化外显 for _, lordShow := range data.LordShow.List() { if lordShow.ActiveCondition.Key <= 0 { if _, found := playerTable.Shows.GetShow(lordShow.ShowID); !found { playerTable.Shows.ActiveShow(lordShow.ShowID, lordShow.ExpireTime) } } } // 检测外显过期 playerTable.CheckShowExpire(ctime.Now().ToSecond()) }