package sociaty import ( "context" "errors" "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/core" event_v2 "go_dreamfactory/lego/sys/event/v2" "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" "go_dreamfactory/pb" cfg "go_dreamfactory/sys/configure/structs" "go_dreamfactory/utils" "sort" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" ) type Tag string const ( Log_Job Tag = `%s玩家已经将%s玩家设为了%s` //职位变动 Log_Quit Tag = "%s玩家已经退出了公会" //退出 Log_Add Tag = `%s玩家加入了公会` //加入 Log_Upgrade Tag = "公会已经升为%s级" //升级 Log_Discharge Tag = "%s玩家已经将%s玩家逐出了公会" //踢出 ) type ModelSociaty struct { modules.MCompModel moduleSociaty *Sociaty service core.IService EventApp *event_v2.App } type SociatyListen struct { event_v2.App sociatyId string name string lv int32 activity int32 ctime int64 } func (this *ModelSociaty) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.TableName = comm.TableSociaty err = this.MCompModel.Init(service, module, comp, options) this.moduleSociaty = module.(*Sociaty) this.service = service this.EventApp = event_v2.NewApp() this.EventApp.Listen(comm.EventSociatyRankChanged, this.rankDataChanged) return } // 创建公会 func (this *ModelSociaty) create(sociaty *pb.DBSociaty) error { if sociaty == nil { return fmt.Errorf("sociaty is nil") } _id := primitive.NewObjectID().Hex() sociaty.Id = _id sociaty.Ctime = time.Now().Unix() sociaty.Lv = 1 //默认1级 if sociaty.Icon == "" { sociaty.Icon = "1000" //默认图标 } if sociaty.ApplyLv == 0 { sociaty.ApplyLv = 1 //默认玩家入会等级 } return this.AddList(comm.RDS_SOCIATY, sociaty.Id, sociaty) } // 公会列表 func (this *ModelSociaty) list(uid string, filter pb.SociatyListFilter) (list []*pb.DBSociaty) { user, err := this.moduleSociaty.ModuleUser.GetRemoteUser(uid) if err != nil { return } if user == nil { return } switch filter { case pb.SociatyListFilter_ALL: //所有 if err := this.GetList(comm.RDS_SOCIATY, &list); err != nil { log.Errorf("sociaty list err:%v", err) return } case pb.SociatyListFilter_CONDI: //满足条件 //玩家等级大于等于公会的申请等级限制 if err := this.GetList(comm.RDS_SOCIATY, &list); err != nil { log.Errorf("sociaty list err:%v", err) return } var newList []*pb.DBSociaty for _, v := range list { if user.Lv >= v.ApplyLv { newList = append(newList, v) } } return newList case pb.SociatyListFilter_NOAPPLY: //无需审批 filter := bson.M{ "isApplyCheck": false, } cur, err := this.DB.Find(comm.TableSociaty, filter) for cur.Next(context.TODO()) { sociaty := &pb.DBSociaty{} if err = cur.Decode(sociaty); err == nil { list = append(list, sociaty) } } case pb.SociatyListFilter_APPLYING: //申请中 if err := this.GetList(comm.RDS_SOCIATY, &list); err != nil { log.Errorf("sociaty list err:%v", err) return } var newList []*pb.DBSociaty for _, v := range list { for _, apply := range v.ApplyRecord { if apply.Uid == uid { newList = append(newList, v) } } } return newList } return } // 搜索公会 func (this *ModelSociaty) findByName(name string) *pb.DBSociaty { filter := bson.M{ "name": name, } sr := this.DB.FindOne(comm.TableSociaty, filter) sociaty := &pb.DBSociaty{} if err := sr.Decode(sociaty); err != nil { if err != mongo.ErrNoDocuments { return nil } } return sociaty } // 获取公会 func (this *ModelSociaty) getSociaty(sociatyId string) (sociaty *pb.DBSociaty) { sociaty = &pb.DBSociaty{} if err := this.GetListObj(comm.RDS_SOCIATY, sociatyId, sociaty); err != nil { this.moduleSociaty.Errorf("sociaty [%s] found err:%v", sociatyId, err) return } return } // 获取玩家所在的公会 func (this *ModelSociaty) getUserSociaty(uid string) (sociaty *pb.DBSociaty) { sociaty = &pb.DBSociaty{} userEx, err := this.moduleSociaty.ModuleUser.GetRemoteUserExpand(uid) if err != nil { return } if userEx.SociatyId != "" { return this.getSociaty(userEx.SociatyId) } return } // 申请公会 func (this *ModelSociaty) apply(uid string, sociaty *pb.DBSociaty) error { // 判断公会审批设置 if sociaty.IsApplyCheck { //需要审核 sociaty.ApplyRecord = append(sociaty.ApplyRecord, &pb.ApplyRecord{ Uid: uid, Ctime: time.Now().Unix(), }) update := map[string]interface{}{ "applyRecord": sociaty.ApplyRecord, } return this.updateSociaty(sociaty.Id, update) } else { //无需审核直接入会 if err := this.addMember(uid, sociaty); err != nil { return err } //初始玩家公会任务 this.moduleSociaty.modelSociatyTask.initSociatyTask(uid, sociaty.Id) } return nil } // 设置公会 func (this *ModelSociaty) setting(sociaty *pb.DBSociaty) error { update := map[string]interface{}{ "icon": sociaty.Icon, "notice": sociaty.Notice, "isApplyCheck": sociaty.IsApplyCheck, "applyLv": sociaty.ApplyLv, } return this.updateSociaty(sociaty.Id, update) } // 申请撤销 func (this *ModelSociaty) applyCancel(uid, sociatyId string) error { sociaty := this.getSociaty(sociatyId) if sociaty.Id == "" { return fmt.Errorf("sociatyId: %s 公会不存在", sociatyId) } return this.delFromApplyRecord(uid, sociaty) } // 是否已申请 func (this *ModelSociaty) isApplied(uid string, sociaty *pb.DBSociaty) bool { for _, v := range sociaty.ApplyRecord { if v.Uid == uid { return true } } return false } // 申请列表 func (this *ModelSociaty) applyList(sociaty *pb.DBSociaty) (list []*pb.SociatyMemberInfo) { for _, r := range sociaty.ApplyRecord { user, err := this.moduleSociaty.ModuleUser.GetRemoteUser(r.Uid) if err != nil || user.Uid == "" { continue } list = append(list, &pb.SociatyMemberInfo{ Uid: user.Uid, Name: user.Name, Avatar: user.Avatar, Lv: user.Lv, }) } return } // 是否公会成员 func (this *ModelSociaty) isMember(uid string, sociaty *pb.DBSociaty) bool { for _, m := range sociaty.Members { if m.Uid == uid { return true } } return false } func (this *ModelSociaty) isInJobs(job pb.SociatyJob, jobs ...pb.SociatyJob) bool { for _, j := range jobs { if j == job { return true } } return false } // 是否有执行权限 func (this *ModelSociaty) isRight(uid string, sociaty *pb.DBSociaty, jobs ...pb.SociatyJob) bool { for _, m := range sociaty.Members { if m.Uid == uid { return this.isInJobs(m.Job, jobs...) } } return false } // 更新公会 func (this *ModelSociaty) updateSociaty(sociatyId string, update map[string]interface{}) error { return this.ChangeList(comm.RDS_SOCIATY, sociatyId, update) } // 退出公会 func (this *ModelSociaty) quit(uid string, sociaty *pb.DBSociaty) error { for i, m := range sociaty.Members { if m.Uid == uid { sociaty.Members = append(sociaty.Members[:i], sociaty.Members[i+1:]...) } } update := map[string]interface{}{ "members": sociaty.Members, } return this.updateSociaty(sociaty.Id, update) } // 解散公会 func (this *ModelSociaty) dismiss(sociaty *pb.DBSociaty) error { err := this.DelListlds(comm.RDS_SOCIATY, sociaty.Id) return err } //删除请求记录 func (this *ModelSociaty) delFromApplyRecord(uid string, sociaty *pb.DBSociaty) error { for i, ar := range sociaty.ApplyRecord { if ar.Uid == uid { sociaty.ApplyRecord = append(sociaty.ApplyRecord[:i], sociaty.ApplyRecord[i+1:]...) } } update := map[string]interface{}{ "applyRecord": sociaty.ApplyRecord, } return this.updateSociaty(sociaty.Id, update) } //添加成员 func (this *ModelSociaty) addMember(uid string, sociaty *pb.DBSociaty) error { defer this.moduleSociaty.modelSociatyLog.addLog(Log_Add, sociaty.Id, uid) sociaty.Members = append(sociaty.Members, &pb.SociatyMember{ Uid: uid, Job: pb.SociatyJob_MEMBER, Ctime: time.Now().Unix(), }) update := map[string]interface{}{ "members": sociaty.Members, } if err := this.updateSociaty(sociaty.Id, update); err != nil { return err } // 更新玩家公会 updateEx := map[string]interface{}{ "sociatyId": sociaty.Id, } return this.moduleSociaty.ModuleUser.ChangeRemoteUserExpand(uid, updateEx) } // 成员列表 func (this *ModelSociaty) members(sociaty *pb.DBSociaty) (list []*pb.SociatyMemberInfo) { for _, m := range sociaty.Members { user, err := this.moduleSociaty.ModuleUser.GetRemoteUser(m.Uid) if err != nil || user.Uid == "" { continue } list = append(list, &pb.SociatyMemberInfo{ Uid: user.Uid, Name: user.Name, Avatar: user.Avatar, Lv: user.Lv, Job: m.Job, OfflineTime: user.Offlinetime, }) } return } // 同意 func (this *ModelSociaty) agree(uid string, sociaty *pb.DBSociaty) error { if this.isMember(uid, sociaty) { return fmt.Errorf("已是该公会成员 uid:%s sociatyId:%s", uid, sociaty.Id) } //删除申请记录 if err := this.delFromApplyRecord(uid, sociaty); err != nil { return err } //添加成员 if err := this.addMember(uid, sociaty); err != nil { return err } //初始玩家公会任务 return this.moduleSociaty.modelSociatyTask.initSociatyTask(uid, sociaty.Id) } //拒绝 func (this *ModelSociaty) refuse(uid string, sociaty *pb.DBSociaty) error { if this.isMember(uid, sociaty) { return fmt.Errorf("已是该公会成员 uid:%s sociatyId:%s", uid, sociaty.Id) } return this.delFromApplyRecord(uid, sociaty) } // 转让公会 // targetId 目标玩家ID // srcId 玩家ID 会长 func (this *ModelSociaty) assign(srcId, targetId string, sociaty *pb.DBSociaty) error { if !this.isMember(targetId, sociaty) { return fmt.Errorf("不是该公会成员 uid:%s sociatyId:%s", targetId, sociaty.Id) } for _, m := range sociaty.Members { if m.Uid == srcId { m.Uid = targetId } else if m.Uid == targetId { m.Uid = srcId } } update := map[string]interface{}{ "members": sociaty.Members, } return this.updateSociaty(sociaty.Id, update) } // 踢出公会 // targetId 踢出目标 // 不允许踢出会长 func (this *ModelSociaty) discharge(targetId string, sociaty *pb.DBSociaty) error { for i, m := range sociaty.Members { if m.Uid == targetId { if m.Job == pb.SociatyJob_PRESIDENT { return fmt.Errorf("会长 %s 不可以被踢出", targetId) } sociaty.Members = append(sociaty.Members[:i], sociaty.Members[i+1:]...) } } update := map[string]interface{}{ "members": sociaty.Members, } return this.updateSociaty(sociaty.Id, update) } //获取职位数 func (this *ModelSociaty) getJobCount(job pb.SociatyJob, sociaty *pb.DBSociaty) (count int) { for _, m := range sociaty.Members { if m.Job == job { count++ } } return } // 设置职位 func (this *ModelSociaty) settingJob(targetId string, job pb.SociatyJob, sociaty *pb.DBSociaty) error { for _, m := range sociaty.Members { if m.Uid == targetId { m.Job = job } } update := map[string]interface{}{ "members": sociaty.Members, } return this.updateSociaty(sociaty.Id, update) } // 获取会长信息 func (this *ModelSociaty) getMasterInfo(sociaty *pb.DBSociaty) *pb.SociatyMemberInfo { for _, m := range sociaty.Members { if m.Job == pb.SociatyJob_PRESIDENT { user, err := this.moduleSociaty.ModuleUser.GetRemoteUser(m.Uid) if err != nil || user.Uid == "" { continue } return &pb.SociatyMemberInfo{ Uid: user.Uid, Name: user.Name, Lv: user.Lv, Avatar: user.Avatar, OfflineTime: user.Offlinetime, } } } return nil } // 弹劾会长 func (this *ModelSociaty) accuse(sociaty *pb.DBSociaty) error { master := this.getMasterInfo(sociaty) if master == nil { return errors.New("会长不存在") } user, err := this.moduleSociaty.ModuleUser.GetRemoteUser(master.Uid) if err != nil { return err } //会长离线时间 now := time.Now().Unix() left := now - user.Offlinetime if left < 7*3600 || user.Offlinetime == 0 { return errors.New("会长很称职,无需弹劾") } return nil } // 签到 func (this *ModelSociaty) sign(uid string, sociaty *pb.DBSociaty) error { if !this.isMember(uid, sociaty) { return fmt.Errorf("不是该公会成员 uid:%s sociatyId:%s", uid, sociaty.Id) } sociaty.SignIds = append(sociaty.SignIds, uid) update := map[string]interface{}{ "signIds": sociaty.SignIds, } return this.updateSociaty(sociaty.Id, update) } // 是否已签到 func (this *ModelSociaty) IsSign(uid string, sociaty *pb.DBSociaty) bool { if _, ok := utils.Findx(sociaty.SignIds, uid); ok { return ok } return false } // 获取玩家任务列表 func (this *ModelSociaty) getUserTaskList(uid, sociatyId string) (sociatyTask *pb.DBSociatyTask) { sociatyTask = &pb.DBSociatyTask{} this.moduleSociaty.modelSociatyTask.GetListObj(sociatyId, uid, sociatyTask) return } // 更新公会资源 活跃度、经验 func (this *ModelSociaty) updateResourceFromTask(sociaty *pb.DBSociaty, conf *cfg.GameGuildTaskData) error { if conf == nil { return errors.New("配置未找到") } exp := sociaty.Exp //经验 activity := sociaty.Activity //活跃度 for _, v := range conf.SociatyReward { if v.T == "guildactive" { activity += v.N } else if v.T == "guildexp" { exp += v.N } } update := map[string]interface{}{ "exp": exp, "activity": activity, } return this.updateSociaty(sociaty.Id, update) } // 更新经验 func (this *ModelSociaty) updateSociatyExp(val int32, sociaty *pb.DBSociaty) error { exp := sociaty.Exp //经验 exp += val update := map[string]interface{}{ "exp": exp, } return this.updateSociaty(sociaty.Id, update) } // 更新成员贡献值 // 任务领取时更新 func (this *ModelSociaty) updateMemberContribution(uid string, val int32, sociaty *pb.DBSociaty) error { for _, m := range sociaty.Members { if m.Uid == uid { m.Contribution += val } } update := map[string]interface{}{ "members": sociaty.Members, } return this.updateSociaty(sociaty.Id, update) } func (this *ModelSociaty) sort(list []*pb.DBSociatyRank) []*pb.DBSociatyRank { sort.SliceStable(list, func(i, j int) bool { if list[i].Lv == list[j].Lv { if list[i].Activity == list[j].Activity { return list[i].Ctime > list[j].Ctime } else { return list[i].Activity < list[j].Activity } } return list[i].Lv < list[j].Lv }) return list } // 公会等级变化 // 更新排行榜 func (this *ModelSociaty) rankDataChanged(event interface{}, next func(event interface{})) { var list []*pb.DBSociatyRank if err := this.GetList(comm.RDS_SOCIATYRANK, &list); err != nil { log.Errorf("sociaty list err:%v", err) return } data := event.(*SociatyListen) newRank := &pb.DBSociatyRank{ SociatyId: data.sociatyId, Name: data.name, Lv: data.lv, Activity: data.activity, Ctime: data.ctime, } if len(list) == 0 || len(list) > 0 && len(list) < 20 { if data != nil { this.AddList(comm.RDS_SOCIATYRANK, data.sociatyId, newRank) } } else { this.AddList(comm.RDS_SOCIATYRANK, data.sociatyId, newRank) if err := this.GetList(comm.RDS_SOCIATYRANK, &list); err != nil { log.Errorf("sociaty list err:%v", err) return } // 排名 tmp := this.sort(list) //找出20条之后的数据 lastData := append(tmp[:19], tmp[len(tmp)-1:]...) //删除20之后的数据 delIds := []string{} for _, v := range lastData { delIds = append(delIds, v.SociatyId) } this.DelListlds(comm.RDS_SOCIATYRANK, delIds...) } } // 排行榜 func (this *ModelSociaty) rank() (rank []*pb.DBSociatyRank) { var list []*pb.DBSociaty if err := this.GetList(comm.RDS_SOCIATYRANK, &list); err != nil { log.Errorf("sociaty list err:%v", err) return nil } for _, v := range list { rank = append(rank, &pb.DBSociatyRank{ Name: v.Name, Lv: v.Lv, Activity: v.Activity, Ctime: v.Ctime, }) } rank = this.sort(rank) rank = append(rank[:0], rank[19:]...) return } func (this *ModelSociaty) isInCDHour(userCdTime int64) bool { if userCdTime == 0 { return false } return time.Now().Unix() < userCdTime }