package timer import ( "context" "go_dreamfactory/comm" "go_dreamfactory/modules" "go_dreamfactory/pb" "go_dreamfactory/sys/db" "sync" "time" "go_dreamfactory/lego/base" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/cron" "go_dreamfactory/lego/sys/log" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) /* 捕羊大赛 维护服务 */ type ParkourComp struct { modules.MCompConfigure service base.IRPCXService module *Timer refresh time.Time //上一次刷新时间 ulock sync.RWMutex users []*pb.DBRaceMember //推荐用户信息 lock sync.RWMutex teams map[string][]*pb.DBRaceMember total int32 } //组件初始化接口 func (this *ParkourComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.MCompConfigure.Init(service, module, comp, options) this.service = service.(base.IRPCXService) this.module = module.(*Timer) this.teams = make(map[string][]*pb.DBRaceMember) return } //自由跨服环境下开启此功能 func (this *ParkourComp) Start() (err error) { err = this.MCompConfigure.Start() if db.IsCross() { this.refreshlist() this.service.RegisterFunctionName(string(comm.RPC_ParkourJoinMatch), this.join) this.service.RegisterFunctionName(string(comm.RPC_ParkourCancelMatch), this.cancel) if _, err = cron.AddFunc("5 * * * * ?", this.timer); err != nil { this.module.Errorf("cron.AddFunc err:%v", err) } if _, err = cron.AddFunc("1 1 * * * ?", this.refreshlist); err != nil { this.module.Errorf("cron.AddFunc err:%v", err) } } return } //刷新推荐列表 func (this *ParkourComp) refreshlist() { var ( c *mongo.Cursor conn *db.DBConn err error ) if conn, err = db.Local(); err != nil { return } if c, err = conn.Mgo.Find(core.SqlTable(comm.TableParkour), bson.M{}, options.Find().SetSort(bson.D{{"integral", -1}}).SetSkip(0).SetLimit(100)); err != nil { this.module.Errorln(err) return } else { result := make([]*pb.DBParkour, 0, c.RemainingBatchLength()) for c.Next(context.Background()) { tmp := &pb.DBParkour{} if err = c.Decode(tmp); err != nil { log.Errorln(err) } else { result = append(result, tmp) } } this.ulock.Lock() this.users = this.users[:0] for _, v := range result { this.users = append(this.users, &pb.DBRaceMember{ Uid: v.Uid, Mount: v.Dfmount, Hp: 6, Isai: true, }) } this.ulock.Unlock() } return } //加入匹配中 func (this *ParkourComp) join(ctx context.Context, req *pb.RPCParkourJoinMatchReq, resp *pb.RPCParkourJoinMatchResp) (err error) { this.lock.Lock() defer this.lock.Unlock() this.teams[req.Captainid] = req.Member this.total += int32(len(req.Member)) if this.total >= 6 { var ( teams1 []string = make([]string, 0) teams2 []string = make([]string, 0) teams3 []string = make([]string, 0) red []string = make([]string, 0) reduser []*pb.DBRaceMember = make([]*pb.DBRaceMember, 0) bule []string = make([]string, 0) buleuser []*pb.DBRaceMember = make([]*pb.DBRaceMember, 0) ) for k, v := range this.teams { if len(v) == 1 { teams1 = append(teams1, k) } else if len(v) == 2 { teams2 = append(teams2, k) } else { teams3 = append(teams3, k) } } //找红队 if len(teams3) > 0 { red = append(red, teams3[0]) teams3 = teams3[1:] } else if len(teams2) > 0 && len(teams1) > 0 { red = append(red, teams2[0], teams1[0]) teams2 = teams2[1:] teams1 = teams1[1:] } else if len(teams1) >= 3 { red = append(red, teams1[0], teams1[1], teams1[2]) teams1 = teams1[3:] } if len(red) == 0 { return } //找蓝队 if len(teams3) > 0 { bule = append(bule, teams3[0]) teams3 = teams3[1:] } else if len(teams2) > 0 && len(teams1) > 0 { bule = append(bule, teams2[0], teams1[0]) teams2 = teams2[1:] teams1 = teams1[1:] } else if len(teams1) >= 3 { bule = append(bule, teams1[0], teams1[1], teams1[2]) teams1 = teams1[3:] } if len(bule) == 0 { return } for _, v := range red { reduser = append(reduser, this.teams[v]...) } for _, v := range bule { buleuser = append(reduser, this.teams[v]...) } ctx, _ := context.WithTimeout(context.Background(), time.Second*2) if err = this.service.RpcCall(ctx, comm.Service_Worker, string(comm.RPC_ParkourMatchSucc), &pb.RPCParkourMatchSuccReq{Red: reduser, Bule: buleuser}, &pb.RPCParkourMatchSuccResp{}, ); err != nil { this.module.Errorln(err) return } for _, v := range red { delete(this.teams, v) } for _, v := range bule { delete(this.teams, v) } this.total -= 6 } return } //加入匹配中 func (this *ParkourComp) cancel(ctx context.Context, req *pb.RPCParkourCancelMatchReq, resp *pb.RPCParkourCancelMatchResp) (err error) { this.lock.Lock() delete(this.teams, req.Captainid) this.lock.Unlock() return } //定时匹配处理 func (this *ParkourComp) timer() { this.module.Errorf("捕羊大赛 定时匹配,%d", this.total) if this.total == 0 { return } this.ulock.RLock() this.ulock.RUnlock() this.lock.Lock() defer this.lock.Unlock() var ( ok bool err error users []*pb.DBRaceMember teams1 []string = make([]string, 0) teams2 []string = make([]string, 0) teams3 []string = make([]string, 0) left int32 = this.total red []string = make([]string, 0) rednum int = 0 reduser []*pb.DBRaceMember = make([]*pb.DBRaceMember, 0) bule []string = make([]string, 0) bulenum int = 0 buleuser []*pb.DBRaceMember = make([]*pb.DBRaceMember, 0) order bool = false ) for k, v := range this.teams { if len(v) == 1 { teams1 = append(teams1, k) } else if len(v) == 2 { teams2 = append(teams2, k) } else { teams3 = append(teams3, k) } } this.ulock.Lock() users = make([]*pb.DBRaceMember, 0, len(this.users)) for _, v1 := range this.users { ok = false for _, v := range this.teams { for _, v2 := range v { if v1.Uid == v2.Uid { ok = true } } } if !ok { //过滤掉已存在的人员 users = append(users, v1) } } this.ulock.Unlock() if len(users)+int(this.total) < 6 { //人员不足 return } var fn = func() { if order { //找红队 if rednum <= 0 && len(teams3) > 0 { red = append(red, teams3[0]) teams3 = teams3[1:] rednum = 3 left -= 3 } else if rednum <= 1 && len(teams2) > 0 { red = append(red, teams2[0]) teams2 = teams2[1:] rednum = 2 left -= 2 } else if rednum <= 2 && len(teams1) > 0 { red = append(red, teams1[0]) teams1 = teams1[1:] rednum = 1 left -= 1 } //找蓝队 if bulenum <= 0 && len(teams3) > 0 { bule = append(bule, teams3[0]) teams3 = teams3[1:] bulenum = 3 left -= 3 } else if bulenum <= 1 && len(teams2) > 0 { bule = append(bule, teams2[0]) teams2 = teams2[1:] bulenum = 2 left -= 2 } else if bulenum <= 2 && len(teams1) > 0 { bule = append(bule, teams1[0]) teams1 = teams1[1:] bulenum = 1 left -= 1 } } else { //找蓝队 if bulenum <= 0 && len(teams3) > 0 { bule = append(bule, teams3[0]) teams3 = teams3[1:] bulenum = 3 left -= 3 } else if bulenum <= 1 && len(teams2) > 0 { bule = append(bule, teams2[0]) teams2 = teams2[1:] bulenum = 2 left -= 2 } else if bulenum <= 2 && len(teams1) > 0 { bule = append(bule, teams1[0]) teams1 = teams1[1:] bulenum = 1 left -= 1 } //找红队 if rednum <= 0 && len(teams3) > 0 { red = append(red, teams3[0]) teams3 = teams3[1:] rednum = 3 left -= 3 } else if rednum <= 1 && len(teams2) > 0 { red = append(red, teams2[0]) teams2 = teams2[1:] rednum = 2 left -= 2 } else if rednum <= 2 && len(teams1) > 0 { red = append(red, teams1[0]) teams1 = teams1[1:] rednum = 1 left -= 1 } } order = !order } fn() if (rednum < 3 || bulenum < 3) && left > 0 { _lt := left fn() if left < _lt { fn() //做多执行三次即可 } } for _, v := range red { reduser = append(reduser, this.teams[v]...) } for _, v := range bule { buleuser = append(buleuser, this.teams[v]...) } if len(users)+rednum+bulenum < 6 { return } //补充人员 if len(reduser) < 3 { n := len(reduser) reduser = append(reduser, users[0:(3-len(reduser))]...) users = users[(3 - n):] for _, v := range reduser[rednum:3] { if v.Name == "" { //同步用户数据 if user, err := this.getuser(v.Uid); err != nil { this.module.Errorln(err) return } else { v.Name = user.Name v.Avatar = user.Avatar v.Lv = user.Lv } } } } if len(buleuser) < 3 { n := len(buleuser) buleuser = append(buleuser, users[0:(3-len(buleuser))]...) users = users[(3 - n):] for _, v := range buleuser[bulenum:3] { if v.Name == "" { //同步用户数据 if user, err := this.getuser(v.Uid); err != nil { this.module.Errorln(err) return } else { v.Name = user.Name v.Avatar = user.Avatar v.Lv = user.Lv } } } } ctx, _ := context.WithTimeout(context.Background(), time.Second*2) if err = this.service.RpcCall(ctx, comm.Service_Worker, string(comm.RPC_ParkourMatchSucc), &pb.RPCParkourMatchSuccReq{Red: reduser, Bule: buleuser}, &pb.RPCParkourMatchSuccResp{}, ); err != nil { this.module.Errorln(err) return } for _, v := range red { delete(this.teams, v) } for _, v := range bule { delete(this.teams, v) } this.total -= int32(rednum) this.total -= int32(bulenum) } // 从远程库查询用户 func (this *ParkourComp) getuser(uid string) (user *pb.DBUser, err error) { var ( model *db.DBModel ) if model, err = this.module.getDBModelByUid(uid, comm.TableUser); err != nil { return } user = &pb.DBUser{} if err = model.Get(uid, user); err != nil { this.module.Errorln(err) } return }