// package // 用户 // 赵长远 package user import ( "context" "fmt" "go_dreamfactory/comm" "go_dreamfactory/modules" "go_dreamfactory/pb" "go_dreamfactory/sys/configure" "go_dreamfactory/sys/db" "go_dreamfactory/utils" "strings" "sync" "time" "go_dreamfactory/lego/base" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/event" "go_dreamfactory/lego/sys/log" cfg "go_dreamfactory/sys/configure/structs" "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" ) const ( // 跨服玩家 Rpc_GetAllOnlineUser string = "Rpc_GetAllOnlineUser" // 跨服用户 Rpc_GetCrossUser string = "Rpc_GetCrossUser" // 跨服用户会话 Rpc_GetCrossUserSession string = "Rpc_GetCrossUserSession" // 搜索用户 Rpc_QueryUser = "Rpc_QueryUser" //创建公会 Rpc_CreateSociaty string = "Rpc_CreateSociaty" ) var _ comm.IUser = (*User)(nil) func NewModule() core.IModule { m := new(User) return m } type User struct { modules.ModuleBase chat comm.IChat api *apiComp modelUser *ModelUser modelSession *ModelSession modelSetting *ModelSetting modelExpand *ModelExpand service base.IRPCXService configure *configureComp globalConf *cfg.GameGlobalData modelSign *ModelSign // 签到 timerLock sync.Mutex timerMap map[string]*time.Ticker reddot comm.IReddot notifyUserinfo []string // userinfo change } func (this *User) GetType() core.M_Modules { return comm.ModuleUser } func (this *User) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { if err = this.ModuleBase.Init(service, module, options); err != nil { return } this.service = service.(base.IRPCXService) this.timerMap = make(map[string]*time.Ticker) return } func (this *User) Start() (err error) { if err = this.ModuleBase.Start(); err != nil { return } event.RegisterGO(comm.EventUserOffline, this.CleanSession) this.service.RegisterFunctionName(Rpc_GetAllOnlineUser, this.RpcGetAllOnlineUser) this.service.RegisterFunctionName(Rpc_GetCrossUser, this.RpcGetCrossUser) this.service.RegisterFunctionName(Rpc_GetCrossUserSession, this.RpcGetCrossUserSession) this.service.RegisterFunctionName(Rpc_QueryUser, this.RpcQueryUser) this.service.RegisterFunctionName(string(comm.Rpc_AccountBan), this.Rpc_AccountBan) //date 3.10 this.service.RegisterFunctionName(Rpc_CreateSociaty, this.RpcCreateSociaty) this.globalConf = this.ModuleTools.GetGlobalConf() if this.globalConf == nil { err = errors.New("global config not found") } this.ResetSession() var module core.IModule if module, err = this.service.GetModule(comm.ModuleChat); err != nil { return } this.chat = module.(comm.IChat) if module, err = this.service.GetModule(comm.ModuleReddot); err != nil { return } this.reddot = module.(comm.IReddot) this.notifyUserinfo = append(this.notifyUserinfo, string(comm.ModuleFriend)) // 只要涉及到更新userinof 信息的模块在此注册 return } func (this *User) OnInstallComp() { this.ModuleBase.OnInstallComp() this.api = this.RegisterComp(new(apiComp)).(*apiComp) this.modelUser = this.RegisterComp(new(ModelUser)).(*ModelUser) this.modelSession = this.RegisterComp(new(ModelSession)).(*ModelSession) this.modelSetting = this.RegisterComp(new(ModelSetting)).(*ModelSetting) this.modelExpand = this.RegisterComp(new(ModelExpand)).(*ModelExpand) this.modelSign = this.RegisterComp(new(ModelSign)).(*ModelSign) this.configure = this.RegisterComp(new(configureComp)).(*configureComp) } // 获取用户数据 func (this *User) GetUser(uid string) (user *pb.DBUser, err error) { user, err = this.modelUser.GetUser(uid) return } // 获取用户数据 func (this *User) GetCrossUsers(uid []string) (user []*pb.DBUser, err error) { if !this.IsCross() { return } user, err = this.modelUser.GetCrossUsers(uid) return } // 获取跨服用户数据 func (this *User) GetCrossUser(uid string) (*pb.DBUser, error) { reply := &pb.DBUser{} err := this.service.AcrossClusterRpcCall(context.Background(), this.GetCrossTag(), comm.Service_Worker, Rpc_GetCrossUser, &pb.UIdReq{Uid: uid}, reply) return reply, err } // 获取远程用户数据 func (this *User) getRemoteUser(uid string) (*pb.DBUser, error) { reply := &pb.DBUser{} if err := this.getUserFromRemoteDb(uid, reply); err != nil { this.Errorln("getRemoteUser", err) return nil, err } return reply, nil } // 获取用户会话 func (this *User) GetUserSession(uid string) *pb.CacheUser { return this.modelSession.getUserSession(uid) } // 获取用户会话 func (this *User) GetUserSessions(uids []string) []*pb.CacheUser { return this.modelSession.getUserSessions(uids) } func (this *User) ResetSession() { us, err := this.UserOnlineList() if err != nil { return } for _, v := range us { this.modelSession.DelListlds(comm.RDS_EMPTY, []string{v.Uid}) } this.modelSession.Del(comm.RDS_EMPTY) } // 清除session func (this *User) CleanSession(uid, sessionid string) { // this.stopTicker(uid) if !this.IsCross() { this.modelUser.updateOfflineTime(uid) } // sId := fmt.Sprintf("%s-%s", comm.RDS_EMPTY, session.GetUserId()) // this.modelSession.Del(sId, db.SetDBMgoLog(false)) // this.modelSession.DelListlds(comm.RDS_EMPTY, session.GetUserId()) //确保删除的会话是目标会话 不是就不要删除了 if user := this.modelSession.getUserSession(uid); user != nil && user.SessionId == sessionid { this.modelSession.Del(uid, db.SetDBMgoLog(false)) this.modelSession.DelListlds(comm.RDS_EMPTY, []string{uid}, db.SetDBMgoLog(false)) } this.modelUser.DelByUId(uid, db.SetDBMgoLog(false)) this.modelExpand.DelByUId(uid, db.SetDBMgoLog(false)) this.modelSetting.DelByUId(uid, db.SetDBMgoLog(false)) } // 在线玩家列表 func (this *User) UserOnlineList() ([]*pb.CacheUser, error) { var cache []*pb.CacheUser // if !this.IsCross() { if err := this.modelSession.GetList(comm.RDS_EMPTY, &cache); err != nil { return nil, err } // } else { // var err error // if cache, err = this.CrossUserOnlineList(); err != nil { // return nil, err // } // } return cache, nil } func (this *User) UserRandOnlineList(num int32) ([]*pb.CacheUser, error) { var cache []*pb.CacheUser if err := this.modelSession.RandGetList(comm.RDS_EMPTY, num, &cache); err != nil { return nil, err } return cache, nil } // 跨服玩家列表 func (this *User) CrossUserOnlineList() ([]*pb.CacheUser, error) { conn, err := db.Local() if err != nil { return nil, err } model := db.NewDBModelByExpired(this.service.GetTag(), comm.TableSession, conn) var cache []*pb.CacheUser if err := model.GetList(comm.RDS_EMPTY, &cache); err != nil { return nil, err } this.Debug("在线玩家数FromDB", log.Field{Key: "count", Value: len(cache)}) return cache, nil } func (this *User) crossUser(uid string) (*pb.CacheUser, error) { conn, err := db.Local() if err != nil { return nil, err } model := db.NewDBModelByExpired(this.service.GetTag(), comm.TableSession, conn) cache := &pb.CacheUser{} if err := model.Get(uid, cache); err != nil { return nil, err } return cache, nil } func (this *User) IsOnline(uid string) bool { if this.IsCross() { cache, err := this.crossUser(uid) if err != nil { return false } if cache.Uid == "" { return false } } return true } // 跨服玩家会话 func (this *User) CrossUserSession(uid string) *pb.CacheUser { cacheUser := &pb.CacheUser{} err := this.service.AcrossClusterRpcCall(context.Background(), this.GetCrossTag(), comm.Service_Worker, Rpc_GetCrossUserSession, &pb.UIdReq{Uid: uid}, cacheUser) if err != nil { return nil } return cacheUser } // 跨服创建玩家公会 date 3.10 // Deprecated func (this *User) CrossCreateSociaty(uid, sociatyName string) *pb.DBSociaty { sociaty := &pb.DBSociaty{} this.service.AcrossClusterRpcCall(context.Background(), this.GetCrossTag(), comm.Service_Worker, Rpc_CreateSociaty, &pb.RPCGeneralReqA2{Param1: uid, Param2: sociatyName}, sociaty) return sociaty } // date 3.10 // Deprecated func (this *User) RpcCreateSociaty(ctx context.Context, req *pb.RPCGeneralReqA2, rsp *pb.DBSociaty) error { conn, err := db.Local() if err != nil { return err } model := db.NewDBModel(this.service.GetTag(), comm.TableSociaty, conn) sociaty := &pb.DBSociaty{} _id := primitive.NewObjectID().Hex() sociaty.Creater = req.Param1 sociaty.Name = req.Param2 sociaty.ApplyLv = 1 sociaty.Id = _id sociaty.Ctime = configure.Now().Unix() sociaty.Lv = 1 //默认1级 sociaty.Members = append(sociaty.Members, &pb.SociatyMember{ Uid: req.Param1, Job: pb.SociatyJob_PRESIDENT, Ctime: configure.Now().Unix(), }) if err := model.AddList(comm.RDS_EMPTY, sociaty.Id, sociaty); err != nil { if err != mongo.ErrNoDocuments { return err } } rsp.Id = sociaty.Id return nil } // 跨服搜索用户 func (this *User) CrossSearchUser(nickName string) ([]*pb.DBUser, error) { name := strings.TrimSpace(nickName) if name == "" { return nil, errors.New("search name is empty") } reply := &pb.UserDataListResp{} err := this.service.AcrossClusterRpcCall(context.Background(), this.GetCrossTag(), comm.Service_Worker, Rpc_QueryUser, &pb.NameReq{Name: name}, reply) if err != nil { return nil, err } return reply.Users, nil } // 远程搜索用户 func (this *User) SearchRmoteUser(nickname string) ([]*pb.DBUser, error) { reply := &pb.UserDataListResp{} if err := this.queryUserFromRemoteDb(nickname, reply); err != nil { return nil, err } return reply.Users, nil } // 查询用户属性值 例如 金币 经验 func (this *User) QueryAttributeValue(uid string, attr string) (value int64) { var ( user *pb.DBUser userEx *pb.DBUserExpand err error ) user, err = this.modelUser.GetUser(uid) if err != nil { return } userEx, err = this.GetUserExpand(uid) if err != nil { return } if user == nil || userEx == nil { return } switch attr { case comm.ResGold: return user.Gold case comm.ResExp: return user.Exp case comm.VipExp: return user.Vipexp case comm.StarCoin: return user.Starcoin case comm.ResDiamond: return user.Diamond case comm.ResPs: return int64(user.Ps) case comm.SociatyCoin: return int64(userEx.Guildcoin) case comm.ArenaCoin: return int64(userEx.Arenacoin) case comm.ResFriend: return int64(userEx.FriendPoint) case comm.Moongold: return int64(user.Moongold) case comm.Talent1: return int64(user.Talent1) case comm.Talent2: return int64(user.Talent2) case comm.Talent3: return int64(user.Talent3) case comm.Talent4: return int64(user.Talent4) case comm.Merchantmoney: return int64(user.Merchantmoney) case comm.Integral: return int64(user.Integral) case comm.Profit: return int64(user.Profit) case comm.Consumeexp: return int64(user.Consumeexp) case comm.Consumemoney: return int64(user.Consumemoney) } return } func (this *User) QueryAttributeValues(uid string, attr map[string]int64) { var ( user *pb.DBUser userEx *pb.DBUserExpand err error ) user, err = this.modelUser.GetUser(uid) if err != nil { return } userEx, err = this.GetUserExpand(uid) if err != nil { return } if user == nil || userEx == nil { return } for k, _ := range attr { switch k { case comm.ResGold: attr[k] = user.Gold case comm.ResExp: attr[k] = user.Exp case comm.VipExp: attr[k] = user.Vipexp case comm.StarCoin: attr[k] = user.Starcoin case comm.ResDiamond: attr[k] = user.Diamond case comm.ResPs: attr[k] = int64(user.Ps) case comm.SociatyCoin: attr[k] = int64(userEx.Guildcoin) case comm.ArenaCoin: attr[k] = int64(userEx.Arenacoin) case comm.ResFriend: attr[k] = int64(userEx.FriendPoint) case comm.Moongold: attr[k] = int64(user.Moongold) case comm.Talent1: attr[k] = int64(user.Talent1) case comm.Talent2: attr[k] = int64(user.Talent2) case comm.Talent3: attr[k] = int64(user.Talent3) case comm.Talent4: attr[k] = int64(user.Talent4) case comm.Merchantmoney: attr[k] = int64(user.Merchantmoney) case comm.Integral: attr[k] = int64(user.Integral) case comm.Profit: attr[k] = int64(user.Profit) case comm.Consumeexp: attr[k] = int64(user.Consumeexp) case comm.Consumemoney: attr[k] = int64(user.Consumemoney) } } return } func (this *User) change(session comm.IUserSession, attrs map[string]int32) (atno []*pb.UserAtno, change *pb.UserResChangedPush, errdata *pb.ErrorData) { uid := session.GetUserId() var ( user *pb.DBUser userEx *pb.DBUserExpand vipexpchange bool temp *pb.UserAtno err error ) if ok, userMate := session.GetMate(comm.Session_User); ok { user = userMate.(*pb.DBUser) session.SetMate(comm.Session_User, user) } else { if user, err = this.GetUser(session.GetUserId()); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserSessionNobeing, Title: pb.ErrorCode_UserSessionNobeing.ToString(), Message: err.Error(), } return } } if ok, userMate := session.GetMate(comm.Session_UserExpand); ok { userEx = userMate.(*pb.DBUserExpand) session.SetMate(comm.Session_UserExpand, userEx) } else { if userEx, err = this.GetUserExpand(uid); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserExpandNull, Title: pb.ErrorCode_UserExpandNull.ToString(), Message: err.Error(), } return } } change = &pb.UserResChangedPush{ Gold: user.Gold, Exp: user.Exp, Lv: user.Lv, Vipexp: user.Vipexp, Vip: user.Vip, Diamond: user.Diamond, Friend: userEx.FriendPoint, Starcoin: user.Starcoin, Guildcoin: userEx.Guildcoin, Arenacoin: userEx.Arenacoin, Ps: user.Ps, Moongold: user.Moongold, Talent1: user.Talent1, Talent2: user.Talent2, Talent3: user.Talent3, Talent4: user.Talent4, Merchantmoney: user.Merchantmoney, Integral: user.Integral, Profit: user.Profit, Deposit: user.Deposit, Consumemoney: user.Consumemoney, } atno = make([]*pb.UserAtno, 0, len(attrs)) for attr, add := range attrs { if add == 0 { log.Warn("attr no changed", log.Field{Key: "uid", Value: session.GetUserId()}, log.Field{Key: "attr", Value: attr}, log.Field{Key: "add", Value: add}, ) continue } temp = &pb.UserAtno{ A: comm.AttrType, T: attr, N: add, } switch attr { case comm.ResGold: if add < 0 { if user.Gold+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_GoldNoEnough, Title: pb.ErrorCode_GoldNoEnough.ToString(), } return } } change.Gold += int64(add) case comm.ResExp: var ( lvchange bool loseexp int32 rewards []*cfg.Gameatn ) if add < 0 { if user.Exp+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserExpNoEnough, Title: pb.ErrorCode_UserExpNoEnough.ToString(), } return } } change.Exp += int64(add) if lvchange, loseexp, rewards = this.modelUser.computeLevel(change); lvchange { this.modelUser.changelv(session, change.Lv, change.Exp, user.Name) defer func() { go func() { if err, res := this.DispenseAtno(session, rewards, true); err == nil { this.WriteUserLog(session.GetUserId(), fmt.Sprintf("userlv change"), comm.GMResAddType, "changelv", res) } else { this.Errorf("err:%v", err) } }() }() } temp.N = temp.N - loseexp case comm.VipExp: if add < 0 { if user.Vipexp+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserExpNoEnough, Title: pb.ErrorCode_UserExpNoEnough.ToString(), } return } } change.Vipexp += int64(add) vipexpchange = true case comm.ResDiamond: if add < 0 { if user.Diamond+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DiamondNoEnough, Title: pb.ErrorCode_DiamondNoEnough.ToString(), } return } } change.Diamond += int64(add) case comm.Moongold: if add < 0 { if user.Moongold+int32(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserMoongoldNoEnough, Title: pb.ErrorCode_UserMoongoldNoEnough.ToString(), } pb.ErrorCode_PayRenewTimeErr.Enum().Descriptor().ReservedNames() } } change.Moongold += int32(add) case comm.ResFriend: if add < 0 { if userEx.FriendPoint+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserFriendNoEnough, Title: pb.ErrorCode_UserFriendNoEnough.ToString(), } return } } change.Friend += add case comm.StarCoin: if add < 0 { if user.Starcoin+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserStarCoinNoEnough, Title: pb.ErrorCode_UserStarCoinNoEnough.ToString(), } return } } change.Starcoin += int64(add) case comm.SociatyCoin: if add < 0 { if userEx.Guildcoin+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserSociatyCoinNoEnough, Title: pb.ErrorCode_UserSociatyCoinNoEnough.ToString(), } return } } change.Guildcoin += add case comm.ArenaCoin: if add < 0 { if userEx.Arenacoin+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserArenaCoinNoEnough, Title: pb.ErrorCode_UserArenaCoinNoEnough.ToString(), } return } } change.Arenacoin += add case comm.ResPs: ggd := this.ModuleTools.GetGlobalConf() if ggd == nil { return } if add < 0 { if user.Ps+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserVitNoEnough, Title: pb.ErrorCode_UserVitNoEnough.ToString(), } return } this.recoverUserPs(user) user.Ps += add userEx.ConsumPs += -add change.Ps = user.Ps go this.ModuleUiGame.HDPSTodayConsum(session.GetUserId(), userEx.ConsumPs) } else { if change.Ps+add > ggd.PsUl { change.Ps = ggd.PsUl } else { change.Ps += add } } case comm.Talent1: if add < 0 { if user.Talent1+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserTalent1NoEnough, Title: pb.ErrorCode_UserTalent1NoEnough.ToString(), } return } } change.Talent1 += add case comm.Talent2: if add < 0 { if user.Talent2+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserTalent2NoEnough, Title: pb.ErrorCode_UserTalent2NoEnough.ToString(), } return } } change.Talent2 += add case comm.Talent3: if add < 0 { if user.Talent3+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserTalent3NoEnough, Title: pb.ErrorCode_UserTalent3NoEnough.ToString(), } return } } change.Talent3 += add case comm.Talent4: if add < 0 { if user.Talent4+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserTalent4NoEnough, Title: pb.ErrorCode_UserTalent4NoEnough.ToString(), } return } } change.Talent4 += add case comm.Merchantmoney: if add < 0 { if user.Merchantmoney+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserMerchantNoEnough, Title: pb.ErrorCode_UserMerchantNoEnough.ToString(), } return } } change.Merchantmoney += add case comm.Integral: if add < 0 { if user.Integral+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserMerchantNoEnough, Title: pb.ErrorCode_UserMerchantNoEnough.ToString(), } return } } change.Integral += int64(add) case comm.Profit: if add < 0 { if user.Profit+int64(add) < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserProfitNoEnough, Title: pb.ErrorCode_UserProfitNoEnough.ToString(), } return } } change.Profit += int64(add) case comm.Consumeexp: if add < 0 { if user.Consumeexp+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserProfitNoEnough, Title: pb.ErrorCode_UserProfitNoEnough.ToString(), } return } } change.Consumeexp += add case comm.Consumemoney: if add < 0 { if user.Consumemoney+add < 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserProfitNoEnough, Title: pb.ErrorCode_UserProfitNoEnough.ToString(), } return } } change.Consumemoney += add default: err = errors.New(fmt.Sprintf("%s no supported", attr)) return } atno = append(atno, temp) } if vipexpchange { if this.modelUser.changeVipExp(change) { //vip等级变化 session.SendMsg(string(this.GetType()), UserSubTypeVipChangedPush, &pb.UserVipChangedPush{ Uid: session.GetUserId(), VipExp: change.Exp, VipLv: change.Lv, }) go this.ModulePrivilege.AddVipData(session.Clone(), user.Vip, change.Vip) } } //user update := map[string]interface{}{ comm.ResGold: change.Gold, comm.ResDiamond: change.Diamond, comm.ResExp: change.Exp, comm.Lv: change.Lv, comm.VipExp: change.Vipexp, comm.Vip: change.Vip, comm.StarCoin: change.Starcoin, comm.ResPs: change.Ps, comm.Moongold: change.Moongold, comm.Talent1: change.Talent1, comm.Talent2: change.Talent2, comm.Talent3: change.Talent3, comm.Talent4: change.Talent4, comm.Merchantmoney: change.Merchantmoney, comm.Integral: change.Integral, comm.Profit: change.Profit, comm.Deposit: change.Deposit, comm.Consumeexp: change.Consumeexp, comm.Consumemoney: change.Consumemoney, "lastRecoverPsSec": user.LastRecoverPsSec, } //user ex updateEx := map[string]interface{}{ comm.ResFriend: change.Friend, comm.SociatyCoin: change.Guildcoin, comm.ArenaCoin: change.Arenacoin, "consumPs": userEx.ConsumPs, } if err := this.modelUser.updateUserAttr(uid, update); err != nil { this.Errorf("AddAttributeValue err:%v", err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } user.Gold = change.Gold user.Diamond = change.Diamond user.Exp = change.Exp user.Lv = change.Lv user.Vipexp = change.Vipexp user.Vip = change.Vip user.Starcoin = change.Starcoin user.Ps = change.Ps user.Moongold = change.Moongold user.Talent1 = change.Talent1 user.Talent2 = change.Talent2 user.Talent3 = change.Talent3 user.Talent4 = change.Talent4 user.Merchantmoney = change.Merchantmoney user.Integral = change.Integral user.Profit = change.Profit user.Deposit = change.Deposit user.Consumeexp = change.Consumeexp user.Consumemoney = change.Consumemoney if err := this.modelExpand.ChangeUserExpand(uid, updateEx); err != nil { this.Errorf("AddAttributeValue ex err:%v", err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } userEx.FriendPoint = change.Friend userEx.Guildcoin = change.Guildcoin userEx.Arenacoin = change.Arenacoin return } // 用户资源 func (this *User) AddAttributeValues(session comm.IUserSession, attrs map[string]int32, bPush bool) (atno []*pb.UserAtno, errdata *pb.ErrorData) { var ( tasks []*pb.BuriedParam = make([]*pb.BuriedParam, 0) _change *pb.UserResChangedPush ) atno, _change, errdata = this.change(session, attrs) if errdata != nil { return } for key, add := range attrs { if key == comm.ResPs && add < 0 { //消耗体力 tasks = append(tasks, comm.GetBuriedParam(comm.Rtype213, -add)) } if key == comm.ResGold && add < 0 { //消耗体力 tasks = append(tasks, comm.GetBuriedParam(comm.Rtype68, -add)) } if key == comm.ResDiamond && add < 0 { //消耗钻石 tasks = append(tasks, comm.GetBuriedParam(comm.Rtype104, -add)) } if key == comm.Integral && add > 0 { //积分获取 tasks = append(tasks, comm.GetBuriedParam(comm.Rtype214, add)) } } if bPush { //推送玩家账号信息变化消息 session.SendMsg(string(this.GetType()), "reschanged", _change) } if len(tasks) > 0 { go this.AsynHandleSession(session.Clone(), func(session comm.IUserSession) { this.ModuleBuried.TriggerBuried(session, tasks...) }) } return } func (this *User) GetUserExpand(uid string) (result *pb.DBUserExpand, err error) { return this.modelExpand.GetUserExpand(uid) } func (this *User) ChangeUserExpand(uid string, value map[string]interface{}) error { return this.modelExpand.ChangeUserExpand(uid, value) } // 从远程库查询用户 func (this *User) getUserFromRemoteDb(uid string, rsp *pb.DBUser) error { sid, _, ok := utils.UIdSplit(uid) if !ok { return fmt.Errorf("sid split err,uid: %v", uid) } conn, err := db.ServerDBConn(sid) if err != nil { return err } model := db.NewDBModel(sid, comm.TableUser, conn) if err := model.Get(uid, rsp); err != nil { this.Errorln("Get User:", err) return err } return nil } func (this *User) getUserExpandFromRemoteDb(uid string, rsp *pb.DBUserExpand) error { sid, _, ok := utils.UIdSplit(uid) if !ok { return errors.New("sid split error") } conn, err := db.ServerDBConn(sid) if err != nil { return err } model := db.NewDBModel(sid, comm.TableUserExpand, conn) if err := model.Get(uid, rsp); err != nil { return err } return nil } func (this *User) changeUserExpandFromRemoteDb(uid string, data map[string]interface{}) error { sid, _, ok := utils.UIdSplit(uid) if !ok { return errors.New("sid split error") } conn, err := db.ServerDBConn(sid) if err != nil { return err } model := db.NewDBModel(sid, comm.TableUserExpand, conn) if err := model.Change(uid, data); err != nil { return err } return nil } func (this *User) queryUserFromRemoteDb(name string, reply *pb.UserDataListResp) error { // 区服列表 for _, tag := range db.GetServerTags() { conn, err := db.ServerDBConn(tag) if err != nil { return fmt.Errorf("db tag:%v err:%v", tag, err) } //查询用户 filter := bson.M{ "name": name, } sr := conn.Mgo.FindOne(comm.TableUser, filter) user := &pb.DBUser{} if err = sr.Decode(user); err != nil { if err != mongo.ErrNoDocuments { return err } } if user.Uid != "" { reply.Users = append(reply.Users, user) } } return nil } func (this *User) RpcGetAllOnlineUser(ctx context.Context, args *pb.EmptyReq, reply *pb.UserOnlineResp) error { conn, err := db.Local() if err != nil { return err } model := db.NewDBModelByExpired(this.service.GetTag(), comm.TableSession, conn) var cache []*pb.CacheUser if err := model.GetList(comm.RDS_EMPTY, &cache); err != nil { return err } reply.Users = cache return nil } func (this *User) RpcGetCrossUser(ctx context.Context, req *pb.UIdReq, reply *pb.DBUser) error { return this.getUserFromRemoteDb(req.Uid, reply) } func (this *User) RpcGetCrossUserSession(ctx context.Context, req *pb.UIdReq, reply *pb.CacheUser) error { conn, err := db.Local() if err != nil { return err } model := db.NewDBModelByExpired(this.service.GetTag(), comm.TableSession, conn) if err := model.GetListObj(comm.RDS_EMPTY, req.Uid, reply); err != nil { if err != mongo.ErrNoDocuments { return err } } return nil } func (this *User) RpcQueryUser(ctx context.Context, req *pb.NameReq, reply *pb.UserDataListResp) error { return this.queryUserFromRemoteDb(req.Name, reply) } func (this *User) CheckTujianHero(session comm.IUserSession, heros []string) []bool { sz := make([]bool, len(heros)) index := 0 list := this.ModuleHero.GetHeroList(session.GetUserId()) for _, v1 := range heros { for _, h := range list { if v1 == h.HeroID { sz[index] = true index++ break } } } return sz } func (this *User) BingoSetUserLv(session comm.IUserSession, lv int32) error { if lv <= 0 { return comm.NewCustomError(pb.ErrorCode_ReqParameterError) } if conf := this.configure.GetPlayerlvConfList(); len(conf) > 0 { maxlv := conf[len(this.configure.GetPlayerlvConfList())-1].Lv if lv > maxlv { lv = maxlv } } update := map[string]interface{}{ "lv": lv, "exp": 0, } if err := this.modelUser.Change(session.GetUserId(), update); err == nil { if err := session.SendMsg(string(this.GetType()), UserSubTypeLvChangedPush, &pb.UserLvChangedPush{Uid: session.GetUserId(), Exp: 0, Lv: lv}); err != nil { this.Error("Bingo玩家等级变化 UserSubTypeLvChangedPush推送失败", log.Field{Key: "uid", Value: session.GetUserId()}, log.Field{Key: "exp", Value: 0}, log.Field{Key: "lv", Value: lv}, ) } } this.ModuleSys.CheckOpenCond(session, comm.OpencondTypePlatlv, lv) // 触发埋点 return nil } // 玩家体力恢复 func (this *User) recoverUserPs(user *pb.DBUser) (change bool, total int32, nexttime int64) { var ( yu int32 add int32 ) cur := configure.Now().Unix() ggd := this.ModuleTools.GetGlobalConf() if ggd == nil { return } pconf := this.configure.GetPlayerlvConf(user.Lv) if pconf == nil { return } if user.Ps >= pconf.PsCeiling { user.LastRecoverPsSec = cur return } total = pconf.PsCeiling if user.LastRecoverPsSec == 0 { user.LastRecoverPsSec = cur change = true return } else { diff := cur - user.LastRecoverPsSec yu = int32(diff / int64(ggd.PsRecovery)) } if yu > 0 { total := user.Ps + yu if total > pconf.PsCeiling { add = pconf.PsCeiling - user.Ps } else { add = yu } user.LastRecoverPsSec = cur user.Ps += add change = true } nexttime = user.LastRecoverPsSec + int64(ggd.PsRecovery) return } func (this *User) BingoSetUserVipLv(session comm.IUserSession, lv int32) (errdata *pb.ErrorData) { if lv <= 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), } return } update := map[string]interface{}{ "vip": lv, "vipexp": 0, } // vip 等级校验 if conf := this.configure.GetVipConfigureData(lv); conf == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), } return } if err := this.modelUser.Change(session.GetUserId(), update); err == nil { if err := session.SendMsg(string(this.GetType()), UserSubTypeVipChangedPush, &pb.UserVipChangedPush{Uid: session.GetUserId(), VipExp: 0, VipLv: lv}); err != nil { this.Error("Bingo玩家等级变化 UserVipChangedPush推送失败", log.Field{Key: "uid", Value: session.GetUserId()}, log.Field{Key: "vipexp", Value: 0}, log.Field{Key: "viplv", Value: lv}, ) } } return nil } // 添加用户皮肤数据 func (this *User) AddPer(session comm.IUserSession, pers map[string]int32, bPush bool) (errdata *pb.ErrorData) { var ( err error conf *cfg.GamePlayerInfor_overviewData user *pb.DBUser change map[string]interface{} = make(map[string]interface{}) adds []string = make([]string, 0) iskeep bool ) if ok, userMate := session.GetMate(comm.Session_User); ok { user = userMate.(*pb.DBUser) session.SetMate(comm.Session_User, user) } else { if user, err = this.GetUser(session.GetUserId()); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserSessionNobeing, Title: pb.ErrorCode_UserSessionNobeing.ToString(), Message: err.Error(), } return } } for k, _ := range pers { iskeep = false for _, v1 := range user.Skins { if k == v1 { iskeep = true break } } if !iskeep { if user.CurSkin == "" || user.CurAction == "" || user.CurBg == "" || user.Curaframe == "" { if conf, err = this.configure.GetPlayerOverview(k, user.Gender); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: err.Error(), } return } else { if user.CurSkin == "" && conf.Type == 1 { user.CurSkin = k user.Avatar = conf.Playerhead change["curSkin"] = k change["avatar"] = conf.Playerhead } if user.CurAction == "" && conf.Type == 2 { user.CurAction = k change["curAction"] = k } if user.CurBg == "" && conf.Type == 3 { user.CurBg = k change["curBg"] = k } if user.Curaframe == "" && conf.Type == 4 { user.Curaframe = k change["curaframe"] = k } } } adds = append(adds, k) } } user.Skins = append(user.Skins, adds...) change["skins"] = user.Skins if err = this.modelUser.Change(session.GetUserId(), change); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } if bPush { session.SendMsg(string(this.GetType()), "skinlist", &pb.UserSkinlistPush{ Skins: user.Skins, CurSkin: user.CurSkin, CurAction: user.CurAction, CurBg: user.CurBg, Avatar: user.Avatar, CurAframe: user.Curaframe, }) } return } func (this *User) ConsumePsAddExp(session comm.IUserSession, ps int32) (atno []*pb.UserAtno, errdata *pb.ErrorData) { var addExp int32 if ps <= 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ReqParameterError, Title: pb.ErrorCode_ReqParameterError.ToString(), Message: "ConsumePsAddExp ps is zero", } return } ggd := this.ModuleTools.GetGlobalConf() if ggd == nil { return } //体力消耗,增加玩家经验 addExp = ps * ggd.FightPs attrs := make(map[string]int32, 0) attrs["exp"] = addExp atno, errdata = this.AddAttributeValues(session, attrs, true) return } // 剩余体力 func (this *User) RemainingPS(uid string) (ps int32) { var ( user *pb.DBUser err error ) if user, err = this.GetUser(uid); err != nil { return } ggd := this.ModuleTools.GetGlobalConf() if ggd == nil { return } return ggd.PsUl - user.Ps } // 查询每日红点信息 func (this *User) Reddot(session comm.IUserSession, rid ...comm.ReddotType) (reddot map[comm.ReddotType]*pb.ReddotItem) { var ( user *pb.DBUser info *pb.DBSign progress int32 err error ) reddot = make(map[comm.ReddotType]*pb.ReddotItem) if info, err = this.modelSign.GetUserSign(session.GetUserId()); err != nil { this.Errorln(err) return } for _, v := range rid { switch v { case comm.Reddot27101: if info.Puzzle[info.Day] == 1 { progress = 1 } reddot[comm.Reddot27101] = &pb.ReddotItem{ Rid: int32(comm.Reddot27101), Activated: true, Progress: progress, Total: 1, } break case comm.Reddot30100: // 体力恢复 user, err = this.GetUser(session.GetUserId()) if err != nil { this.Errorln(err) return } change, total, t := this.recoverUserPs(user) reddot[comm.Reddot30100] = &pb.ReddotItem{ Rid: int32(comm.Reddot30100), Activated: true, Nextchanagetime: t, Progress: user.Ps, Total: total, } if change { this.modelUser.Change(session.GetUserId(), map[string]interface{}{ "ps": user.Ps, "lastRecoverPsSec": user.LastRecoverPsSec, }) } break } } return } func (this *User) CleanUserMerchantmoney(session comm.IUserSession) (err error) { return this.modelUser.CleanUserMerchantmoney(session) } func (this *User) ChangeUserCaravanLv(session comm.IUserSession, lv int32) (errdata *pb.ErrorData) { update := map[string]interface{}{ "caravanlv": lv, } if err := this.modelUser.Change(session.GetUserId(), update); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } } return } // 添加用户皮肤数据 func (this *User) AddTitle(session comm.IUserSession, titles map[string]int32, bPush bool) (errdata *pb.ErrorData) { var ( err error user *pb.DBUser change map[string]interface{} = make(map[string]interface{}) iskeep bool ) if user, err = this.GetUser(session.GetUserId()); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_UserSessionNobeing, Title: pb.ErrorCode_UserSessionNobeing.ToString(), Message: err.Error(), } return } for k, _ := range titles { iskeep = false for _, v1 := range user.Titles { if k == v1 { iskeep = true break } } if !iskeep { user.Titles = append(user.Titles, k) change["titles"] = user.Titles } } if len(change) > 0 { if err = this.modelUser.Change(session.GetUserId(), change); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } if bPush { session.SendMsg(string(this.GetType()), "titlelist", &pb.UserTitleListPush{ Titles: user.Titles, Curtitle: user.Curtitle, }) } } return } func (this *User) Rpc_AccountBan(ctx context.Context, req *pb.RPCAccountBan, reply *pb.UserDataListResp) error { var ( err error ) if _, err = this.GetUser(req.Uid); err != nil { return err } if req.Key == 0 { // 封号 bBan := false if req.Value > 0 { bBan = true } update := map[string]interface{}{ "ban": bBan, } if err := this.modelUser.Change(req.Uid, update); err != nil { return err } } else if req.Key == 1 { // 禁言 update := map[string]interface{}{ "prohibition": req.Value, } if err := this.modelUser.Change(req.Uid, update); err != nil { return err } } return err } func (this *User) ChangeUserMoonLv(session comm.IUserSession, lv int32) (errdata *pb.ErrorData) { update := map[string]interface{}{ "moonlv": lv, } if err := this.modelUser.Change(session.GetUserId(), update); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } } return } func (this *User) GMCreatePlayer(session comm.IUserSession, req *pb.UserCreateReq) (errdata *pb.ErrorData) { errdata = this.api.Create(session, req) return } // 体力转经验 func (this *User) PsConvertExp(ps int32) (res *cfg.Gameatn) { res = &cfg.Gameatn{ A: "attr", T: "exp", } if ggd := this.ModuleTools.GetGlobalConf(); ggd != nil { //体力消耗,增加玩家经验 if addExp := ps * ggd.FightPs; addExp > 0 { res.N = addExp } } return }