package timer import ( "context" "go_dreamfactory/comm" "go_dreamfactory/modules" "go_dreamfactory/pb" "go_dreamfactory/sys/db" "sync" "sync/atomic" "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 //推荐用户信息 tlock sync.RWMutex teams map[string][]*pb.DBRaceMember timerlock int32 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.timerlock = 1 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("*/10 * * * * ?", this.match); 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, Maxhp: 6, Currhp: 6, Isai: true, }) } this.ulock.Unlock() } return } //加入匹配中 func (this *ParkourComp) join(ctx context.Context, req *pb.RPCParkourJoinMatchReq, resp *pb.RPCParkourJoinMatchResp) (err error) { this.tlock.Lock() this.teams[req.Captainid] = req.Member this.total += int32(len(req.Member)) this.tlock.Unlock() if this.total >= 6 && atomic.LoadInt32(&this.timerlock) == 1 { go this.match() } return } //加入匹配中 func (this *ParkourComp) cancel(ctx context.Context, req *pb.RPCParkourCancelMatchReq, resp *pb.RPCParkourCancelMatchResp) (err error) { this.tlock.Lock() delete(this.teams, req.Captainid) this.tlock.Unlock() return } //定时匹配处理 func (this *ParkourComp) match() { // this.module.Debug("执行一次匹配!") if !atomic.CompareAndSwapInt32(&this.timerlock, 1, 2) { //正在执行,就不要在进来了 return } startime := time.Now() defer func() { atomic.StoreInt32(&this.timerlock, 1) //执行完毕释放 log.Debug("Parkour Match", log.Field{Key: "t", Value: time.Since(startime).Milliseconds()}, ) }() // this.module.Errorf("捕羊大赛 定时匹配,%d", this.total) if this.total == 0 { return } 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 ) this.tlock.Lock() 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.tlock.Unlock() this.ulock.RLock() 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.RUnlock() 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() //做多执行三次即可 } } this.tlock.RLock() for _, v := range red { reduser = append(reduser, this.teams[v]...) } for _, v := range bule { buleuser = append(buleuser, this.teams[v]...) } this.tlock.RUnlock() 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 } this.tlock.Lock() for _, v := range red { delete(this.teams, v) } for _, v := range bule { delete(this.teams, v) } this.total -= int32(rednum) this.total -= int32(bulenum) this.tlock.Unlock() } // 从远程库查询用户 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 }