package parkour import ( "context" "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/base" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/event" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/timewheel" "go_dreamfactory/modules" "go_dreamfactory/pb" cfg "go_dreamfactory/sys/configure/structs" "sync" "time" "go.mongodb.org/mongo-driver/bson/primitive" ) /* 模块名:跑酷系统 描述:捕羊大赛 开发:李伟 */ const moduleName = "补羊大赛" var _ comm.IParkour = (*Parkour)(nil) func NewModule() core.IModule { m := new(Parkour) return m } type Parkour struct { modules.ModuleBase service base.IRPCXService dragon comm.IDragon api *apiComp ai *aiComp matchTrain *matchTrainComp matchrank *matchrankComp configure *configureComp parkourComp *ModelParkourComp lock sync.RWMutex battles map[string]*RaceItem } // 模块名 func (this *Parkour) GetType() core.M_Modules { return comm.ModuleParkour } // 模块初始化 func (this *Parkour) 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.battles = map[string]*RaceItem{} return } func (this *Parkour) Start() (err error) { if err = this.ModuleBase.Start(); err != nil { return } // this.service.RegisterFunctionName(string(comm.RPC_ParkourMatchSucc), this.createbattle) this.service.RegisterFunctionName(string(comm.RPC_ParkourTrusteeship), this.trusteeship) event.RegisterGO(comm.EventUserOffline, this.useroffline) var module core.IModule if module, err = this.service.GetModule(comm.ModuleDragon); err != nil { return } this.dragon = module.(comm.IDragon) return } // 装备组件 func (this *Parkour) OnInstallComp() { this.ModuleBase.OnInstallComp() this.api = this.RegisterComp(new(apiComp)).(*apiComp) this.ai = this.RegisterComp(new(aiComp)).(*aiComp) this.matchTrain = this.RegisterComp(new(matchTrainComp)).(*matchTrainComp) this.matchrank = this.RegisterComp(new(matchrankComp)).(*matchrankComp) this.configure = this.RegisterComp(new(configureComp)).(*configureComp) this.parkourComp = this.RegisterComp(new(ModelParkourComp)).(*ModelParkourComp) } // 匹配成功 创建战斗 func (this *Parkour) createbattle(rtype pb.RaceType, red []*pb.DBRaceMember, bule []*pb.DBRaceMember) (err error) { var ( race *pb.DBRace battle *RaceItem sessions []comm.IUserSession = make([]comm.IUserSession, 0) ) this.Debug("createbattle", log.Field{Key: "red", Value: red}, log.Field{Key: "bule", Value: bule}) race = &pb.DBRace{ Id: primitive.NewObjectID().Hex(), ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Redmember: red, Bulemember: bule, } battle = &RaceItem{ Id: race.Id, Rtype: rtype, Session: make(map[string]comm.IUserSession), } for _, v := range red { v.Currhp = v.Property[comm.Dhp] if !v.Isai { //非AI session, online := this.GetUserSession(v.User.Uid) v.Isoff = !online if online { battle.Session[v.User.Uid] = session } if err = this.parkourComp.Change(v.User.Uid, map[string]interface{}{ "state": pb.RaceTeamState_raceing, "rtype": rtype, "roomid": battle.Id, "roompath": race.ServicePath, }); err != nil { this.Errorln(err) return } } else { v.Ready = true } } battle.RedMember = red for _, v := range bule { v.Currhp = v.Property[comm.Dhp] if !v.Isai { //非AI session, online := this.GetUserSession(v.User.Uid) v.Isoff = !online if online { battle.Session[v.User.Uid] = session } } else { v.Ready = true } } battle.BuleMember = bule for _, v := range battle.Session { sessions = append(sessions, v) } this.lock.Lock() this.battles[race.Id] = battle this.lock.Unlock() if err = this.SendMsgToSession(string(this.GetType()), "racematchsucc", &pb.ParkourRaceMatchSuccPush{ Race: race, }, sessions...); err != nil { this.Errorln(err) } return } func (this *Parkour) startbattle(id string) { this.Debug("startbattle", log.Field{Key: "id", Value: id}) var ( battle *RaceItem ok bool member []*pb.DBRaceMember = make([]*pb.DBRaceMember, 0) sessions []comm.IUserSession = make([]comm.IUserSession, 0) err error ) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { for _, v := range battle.RedMember { if v.Isai { member = append(member, v) } } for _, v := range battle.BuleMember { if v.Isai { member = append(member, v) } } if err = this.ai.createAi(battle.Id, battle.Rtype, member); err != nil { this.Errorln(err) return } for _, v := range battle.Session { sessions = append(sessions, v) } battle.overtimer = timewheel.Add(time.Duration(this.ModuleTools.GetGlobalConf().BuzkashiTime)*time.Second, this.overtimer, battle.Id) if err = this.SendMsgToSession(string(this.GetType()), "racestart", &pb.ParkourRaceStartPush{ Countdown: 3, }, sessions...); err != nil { this.Errorln(err) } } } // 射门 func (this *Parkour) qte(id string, uid string, time float32, conf *cfg.GameBuzkashiQteLvData) { this.Debug("qte", log.Field{Key: "id", Value: id}, log.Field{Key: "time", Value: time}) var ( battle *RaceItem side int32 ok bool member *pb.DBRaceMember teamScores int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) err error ) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { ok = false for _, v := range battle.RedMember { if v.User.Uid == uid { ok = true v.Scores += conf.Value side = 1 member = v break } } if !ok { for _, v := range battle.BuleMember { if v.User.Uid == uid { ok = true v.Scores += conf.Value side = 2 member = v break } } } if !ok { this.Error("qte on found Member !", log.Field{Key: "uid", Value: uid}) return } if side == 1 { battle.RedScore += conf.Value teamScores = battle.RedScore } else { battle.BuleScore += conf.Value teamScores = battle.BuleScore } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "qteoperate", &pb.ParkourQTEOperatePush{ Uid: uid, Time: time, Teamscore: teamScores, Playerscore: member.Scores, }, sessions...); err != nil { this.Errorln(err) } } } // 射门 func (this *Parkour) shot(id string, uid string) { this.Debug("shot", log.Field{Key: "id", Value: id}) var ( battle *RaceItem side int32 ok bool member *pb.DBRaceMember teamScores int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) err error ) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { ok = false for _, v := range battle.RedMember { if v.User.Uid == uid { v.Scores += this.ModuleTools.GetGlobalConf().BuzkashiGoalscore v.Shot++ ok = true side = 1 member = v } } if !ok { for _, v := range battle.BuleMember { if v.User.Uid == uid { v.Scores += this.ModuleTools.GetGlobalConf().BuzkashiGoalscore v.Shot++ ok = true side = 2 member = v } } } if !ok { this.Error("shot on found Member !", log.Field{Key: "uid", Value: uid}) return } if side == 1 { battle.RedScore += this.ModuleTools.GetGlobalConf().BuzkashiGoalteamscore teamScores = battle.RedScore } else { battle.BuleScore += this.ModuleTools.GetGlobalConf().BuzkashiGoalteamscore teamScores = battle.BuleScore } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "shotoperate", &pb.ParkourShotOperatePush{ Uid: uid, Shotnum: member.Shot, Teamscore: teamScores, Playerscore: member.Scores, }, sessions...); err != nil { this.Errorln(err) } } } // 躲避障碍物 func (this *Parkour) avoid(id string, uid string, distance float32, atype int32, conf *cfg.GameBuzkashiGradeData) { this.Debug("shot", log.Field{Key: "id", Value: id}) var ( battle *RaceItem winSide int32 ok bool member *pb.DBRaceMember teamScores int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) err error ) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { ok = false for _, v := range battle.RedMember { if v.User.Uid == uid { member = v ok = true winSide = 1 teamScores = battle.RedScore } } if !ok { for _, v := range battle.BuleMember { if v.User.Uid == uid { member = v ok = true winSide = 2 teamScores = battle.BuleScore } } } if !ok { this.Error("avoid on found Member !", log.Field{Key: "uid", Value: uid}) return } for _, v := range battle.Session { sessions = append(sessions, v) } if conf == nil { member.Currhp -= this.ModuleTools.GetGlobalConf().BuzkashiSpeedbumphp if member.Currhp <= 0 { timewheel.Add(time.Second*time.Duration(this.ModuleTools.GetGlobalConf().BuzkashiResurrection), this.resurrectiontimer, battle.Id, member.User.Uid) } } else { member.Scores += conf.Value member.Energy += conf.Energy member.Weekintegral += conf.Matchvalue if conf.Num == 1 { member.Dodge++ } teamScores += conf.Matchvalue if winSide == 1 { battle.RedScore = teamScores } else { battle.BuleScore = teamScores } } if err = this.SendMsgToSession(string(this.GetType()), "avoidoperate", &pb.ParkourAvoidOperatePush{ Uid: uid, Hp: member.Currhp, Distance: distance, Atype: atype, Teamscore: teamScores, Playerscore: member.Scores, }, sessions...); err != nil { this.Errorln(err) } } } // 恢复hp值 func (this *Parkour) recoverhp(id string, uid string, hp int32) { this.Debug("recoverhp", log.Field{Key: "id", Value: id}, log.Field{Key: "hp", Value: hp}, log.Field{Key: "uid", Value: uid}) var ( battle *RaceItem ok bool player *pb.DBRaceMember teamScores int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) err error ) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { ok = false for _, v := range battle.RedMember { if v.User.Uid == uid { player = v v.Currhp += hp if v.Currhp > v.Property[comm.Dhp] { v.Currhp = v.Property[comm.Dhp] } teamScores = battle.RedScore ok = true break } } for _, v := range battle.BuleMember { if v.User.Uid == uid { player = v v.Currhp += hp if v.Currhp > v.Property[comm.Dhp] { v.Currhp = v.Property[comm.Dhp] } teamScores = battle.BuleScore ok = true break } } if !ok { this.Error("recoverhp on found Member !", log.Field{Key: "uid", Value: uid}) return } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "recoverhpoperate", &pb.ParkourRecoverHpOperatePush{ Uid: uid, Hp: player.Currhp, Teamscore: teamScores, Playerscore: player.Scores, }, sessions...); err != nil { this.Errorln(err) } } } // 战斗结束 func (this *Parkour) overtimer(task *timewheel.Task, args ...interface{}) { this.Debug("overtimer", log.Field{Key: "id", Value: args}) var ( battle *RaceItem ok bool side int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) conf *cfg.GameQualifyingData lvconf *cfg.GameBuzkashiLvData danconf *cfg.GameQualifyingData awards map[string][]*cfg.Gameatn = make(map[string][]*cfg.Gameatn) award map[string][]*pb.UserAtno = make(map[string][]*pb.UserAtno) errdata *pb.ErrorData err error ) id := args[0].(string) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok { this.lock.Lock() delete(this.battles, id) this.lock.Unlock() this.ai.removeAi(id) if battle.RedScore > battle.BuleScore { side = 1 for _, v := range battle.RedMember { if conf, err = this.configure.getActiveRewardById(v.Dan); err != nil { this.Errorln(err) return } v.Integral += conf.WinValue if lvconf, err = this.configure.getGameBuzkashiLv(v.Scores); err != nil { this.Errorln(err) return } v.Rating = lvconf.Num v.Weekintegral += lvconf.Point if !v.Isai { if battle.Rtype == pb.RaceType_ordinary { awards[v.User.Uid] = conf.MatewinReward } else { awards[v.User.Uid] = conf.RankwinReward } } } for _, v := range battle.BuleMember { if conf, err = this.configure.getActiveRewardById(v.Dan); err != nil { this.Errorln(err) return } v.Integral += conf.FailValue if lvconf, err = this.configure.getGameBuzkashiLv(v.Scores); err != nil { this.Errorln(err) return } v.Rating = lvconf.Num v.Weekintegral += lvconf.Point if !v.Isai { if battle.Rtype == pb.RaceType_ordinary { awards[v.User.Uid] = conf.MatefailReward } else { awards[v.User.Uid] = conf.RankfailReward } } } } else { side = 2 for _, v := range battle.RedMember { if conf, err = this.configure.getActiveRewardById(v.Dan); err != nil { this.Errorln(err) return } v.Integral += conf.FailValue if lvconf, err = this.configure.getGameBuzkashiLv(v.Scores); err != nil { this.Errorln(err) return } v.Rating = lvconf.Num v.Weekintegral += lvconf.Point if !v.Isai { if battle.Rtype == pb.RaceType_ordinary { awards[v.User.Uid] = conf.MatefailReward } else { awards[v.User.Uid] = conf.RankfailReward } } } for _, v := range battle.BuleMember { if conf, err = this.configure.getActiveRewardById(v.Dan); err != nil { this.Errorln(err) return } v.Integral += conf.WinValue if lvconf, err = this.configure.getGameBuzkashiLv(v.Scores); err != nil { this.Errorln(err) return } v.Rating = lvconf.Num v.Weekintegral += lvconf.Point if !v.Isai { if battle.Rtype == pb.RaceType_ordinary { awards[v.User.Uid] = conf.MatewinReward } else { awards[v.User.Uid] = conf.RankwinReward } } } } for _, v := range battle.Session { if errdata, award[v.GetUserId()] = this.DispenseAtno(v, awards[v.GetUserId()], true); errdata != nil { this.Errorln(errdata) return } v.SendMsg(string(this.GetType()), "raceover", &pb.ParkourRaceOverPush{ Winside: side, Race: &pb.DBRace{ Id: battle.Id, Redmember: battle.RedMember, Redscores: battle.RedScore, Bulemember: battle.BuleMember, Bulescores: battle.BuleScore, }, Award: award[v.GetUserId()], }) go this.AsynHandleSession(v, func(session comm.IUserSession) { this.WriteUserLog(session.GetUserId(), 0, "ParkourRaceOverPush", award[v.GetUserId()]) }) sessions = append(sessions, v) } for _, v := range battle.RedMember { if !v.Isai { if danconf, err = this.configure.getActiveRewardByS(v.Integral); err != nil { this.Errorln(err) continue } if err = this.parkourComp.Change(v.User.Uid, map[string]interface{}{ "integral": v.Integral, "weekintegral": v.Weekintegral, "dan": danconf.LvId, "state": 0, "roomid": "", "roompath": "", }); err != nil { this.Errorln(err) return } } } for _, v := range battle.BuleMember { if !v.Isai { if danconf, err = this.configure.getActiveRewardByS(v.Integral); err != nil { this.Errorln(err) continue } if err = this.parkourComp.Change(v.User.Uid, map[string]interface{}{ "integral": v.Integral, "weekintegral": v.Weekintegral, "dan": danconf.LvId, "state": 0, "roomid": "", "roompath": "", }); err != nil { this.Errorln(err) return } } } for _, v := range sessions { this.ModuleBuried.TriggerBuried(v, comm.GetBuriedParam(comm.Rtype234, 1)) v.Push() this.PutUserSession(v) } } } // 用户离线处理 func (this *Parkour) useroffline(uid, sessionid string) { var ( info *pb.DBParkour err error ) if info, err = this.parkourComp.queryinfo(uid); err != nil { this.Error("用户离线!", log.Field{Key: "err", Value: err.Error()}) return } if info.State == pb.RaceTeamState_matching { if info.Rtype == pb.RaceType_ordinary { this.matchTrain.CancelMatch(uid) } else { this.matchrank.CancelMatch(uid) } if err = this.parkourComp.Change(uid, map[string]interface{}{ "state": 0, }); err != nil { this.Error("用户离线! 处理数据", log.Field{Key: "uid", Value: uid}, log.Field{Key: "err", Value: err.Error()}) return } } else if info.State == pb.RaceTeamState_raceing { var ( lockpath string = fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()) ) if lockpath != info.Roompath { //在当前房间下 _, err = this.service.RpcGo( context.Background(), info.Roompath, string(comm.RPC_ParkourTrusteeship), &pb.RPC_ParkourTrusteeshipReq{Battleid: info.Roomid, Uid: uid}, nil) if err != nil { this.Errorln(err) return } } else { this.trusteeship(context.Background(), &pb.RPC_ParkourTrusteeshipReq{Battleid: info.Roomid, Uid: uid}, nil) } } } // 托管 func (this *Parkour) trusteeship(ctx context.Context, req *pb.RPC_ParkourTrusteeshipReq, resp *pb.RPC_ParkourTrusteeshipResp) (err error) { var ( battle *RaceItem ok bool ) this.lock.RLock() battle, ok = this.battles[req.Battleid] this.lock.RUnlock() if ok { battle.lock.Lock() for _, v := range battle.BuleMember { if v.User.Uid == v.User.Uid { v.Isoff = true } } for _, v := range battle.RedMember { if v.User.Uid == v.User.Uid { v.Isoff = true } } delete(battle.Session, req.Uid) battle.lock.Unlock() } return } // 定时复活 func (this *Parkour) resurrectiontimer(task *timewheel.Task, args ...interface{}) { var ( battleid string uid string battle *RaceItem member *pb.DBRaceMember sessions []comm.IUserSession = make([]comm.IUserSession, 0) ok bool err error ) battleid = args[0].(string) uid = args[1].(string) this.lock.RLock() battle, ok = this.battles[battleid] this.lock.RUnlock() if ok { ok = false for _, v := range battle.RedMember { if v.User.Uid == uid { member = v ok = true } } if !ok { for _, v := range battle.BuleMember { if v.User.Uid == uid { member = v ok = true } } } if ok { member.Currhp = member.Property[comm.Dhp] for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "revivalplayer", &pb.ParkourRevivalPlayerPush{ Uid: uid, Hp: member.Currhp, }, sessions...); err != nil { this.Errorln(err) } } } else { this.Error("战斗结束 复活失效", log.Field{Key: "bid", Value: battleid}) } }