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" "sync" "time" "go.mongodb.org/mongo-driver/bson/primitive" ) /* 模块名:跑酷系统 描述:捕羊大赛 开发:李伟 */ var _ comm.IParkour = (*Parkour)(nil) func NewModule() core.IModule { m := new(Parkour) return m } type Parkour struct { modules.ModuleBase service base.IRPCXService api *apiComp ai *aiComp configure *configureComp parkourComp *ModelParkourComp raceComp *ModelRaceComp 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) { err = this.ModuleBase.Init(service, module, options) this.service = service.(base.IRPCXService) this.battles = map[string]*RaceItem{} return } func (this *Parkour) Start() (err error) { err = this.ModuleBase.Start() this.service.RegisterFunctionName(string(comm.RPC_ParkourMatchSucc), this.createbattle) event.RegisterGO(comm.EventUserOffline, this.useroffline) return } //装备组件 func (this *Parkour) OnInstallComp() { this.ModuleBase.OnInstallComp() this.api = this.RegisterComp(new(apiComp)).(*apiComp) this.ai = this.RegisterComp(new(aiComp)).(*aiComp) this.configure = this.RegisterComp(new(configureComp)).(*configureComp) this.parkourComp = this.RegisterComp(new(ModelParkourComp)).(*ModelParkourComp) this.raceComp = this.RegisterComp(new(ModelRaceComp)).(*ModelRaceComp) } //添加坐骑资源 func (this *Parkour) AddMounts(session comm.IUserSession, mounts map[string]int32, bPush bool) (errdata *pb.ErrorData) { var ( result *pb.DBParkour err error ) if result, err = this.parkourComp.addUserMounts(session.GetUserId(), mounts); 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()), "infochange", &pb.ParkourInfoChangePush{Info: result}) } return } //匹配 func (this *Parkour) match(team *pb.DBParkour) (err error) { ctx, _ := context.WithTimeout(context.Background(), time.Second*5) err = this.service.RpcCall( ctx, comm.Service_Mainte, string(comm.RPC_ParkourJoinMatch), &pb.RPCParkourJoinMatchReq{Captainid: team.Captainid, Member: team.Member}, &pb.RPCParkourJoinMatchResp{}) if err != nil { this.Errorln(err) return } return } //匹配成功 创建战斗 func (this *Parkour) createbattle(ctx context.Context, req *pb.RPCParkourMatchSuccReq, resp *pb.RPCParkourMatchSuccResp) (err error) { var ( race *pb.DBRace battle *RaceItem sessions []comm.IUserSession = make([]comm.IUserSession, 0) ) this.Debug("createbattle", log.Field{Key: "req", Value: req.String()}) race = &pb.DBRace{ Id: primitive.NewObjectID().Hex(), ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Redmember: req.Red, Bulemember: req.Bule, } battle = &RaceItem{ Id: race.Id, Session: make(map[string]comm.IUserSession), overtimer: timewheel.Add(time.Minute*3, this.overtimer, race.Id), } for _, v := range req.Red { v.Currhp = v.Maxhp if !v.Isai { //非AI session, online := this.GetUserSession(v.Uid) v.Isoff = !online if online { battle.Session[v.Uid] = session } } else { v.Ready = true } } battle.RedMember = req.Red for _, v := range req.Bule { v.Currhp = v.Maxhp if !v.Isai { //非AI session, online := this.GetUserSession(v.Uid) v.Isoff = !online if online { battle.Session[v.Uid] = session } } else { v.Ready = true } } battle.BuleMember = req.Bule for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.raceComp.addrace(race); err != nil { return } 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, member); err != nil { this.Errorln(err) return } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "racestart", &pb.ParkourRaceStartPush{ Countdown: 3, }, 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 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.Uid == uid { ok = true side = 1 } } if !ok { for _, v := range battle.BuleMember { if v.Uid == uid { ok = true side = 2 } } } if side == 1 { battle.RedScore += 3 } else { battle.BuleScore += 3 } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "scorechanage", &pb.ParkourScoreChanagePush{ Redscore: battle.RedScore, Redenergy: battle.RedEnergy, Bluescore: battle.BuleScore, Blueenergy: battle.BuleEnergy, }, sessions...); err != nil { this.Errorln(err) } } } //躲避障碍物 func (this *Parkour) avoid(id string, uid string, dis float32) { this.Debug("shot", log.Field{Key: "id", Value: id}) var ( battle *RaceItem ok bool side int32 member *pb.DBRaceMember 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.Uid == uid { member = v ok = true side = 1 } } if !ok { for _, v := range battle.BuleMember { if v.Uid == uid { member = v ok = true side = 2 } } } if !ok { this.Error("躲避障碍物逻辑异常 未找到玩家!", log.Field{Key: "battleid", Value: id}, log.Field{Key: "uid", Value: uid}) return } for _, v := range battle.Session { sessions = append(sessions, v) } if dis < 0 { member.Currhp-- if member.Currhp <= 0 { timewheel.Add(time.Second*10, this.resurrectiontimer, battle.Id, member.Uid) } } else { if side == 1 { battle.RedEnergy += 3 } else { battle.BuleEnergy += 3 } if err = this.SendMsgToSession(string(this.GetType()), "playerhpchanage", &pb.ParkourScoreChanagePush{ Redscore: battle.RedScore, Redenergy: battle.RedEnergy, Bluescore: battle.BuleScore, Blueenergy: battle.BuleEnergy, }, sessions...); err != nil { this.Errorln(err) } } if err = this.SendMsgToSession(string(this.GetType()), "playerhpchanage", &pb.ParkourPlayerHPChanagePush{ Change: map[string]int32{uid: member.Currhp}, }, sessions...); err != nil { this.Errorln(err) } } } //恢复hp值 func (this *Parkour) recoverhp(id string, hp int32, uids ...string) { this.Debug("recoverhp", log.Field{Key: "id", Value: id}, log.Field{Key: "hp", Value: hp}, log.Field{Key: "uids", Value: uids}) var ( battle *RaceItem ok bool chanage map[string]int32 = make(map[string]int32) 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 { for _, v1 := range uids { if v.Uid == v1 { v.Currhp += hp if v.Currhp > v.Maxhp { v.Currhp = v.Maxhp } chanage[v.Uid] = v.Currhp break } } } for _, v := range battle.BuleMember { for _, v1 := range uids { if v.Uid == v1 { v.Currhp += hp if v.Currhp > v.Maxhp { v.Currhp = v.Maxhp } chanage[v.Uid] = v.Currhp break } } } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "playerhpchanage", &pb.ParkourPlayerHPChanagePush{ Change: chanage, }, sessions...); err != nil { this.Errorln(err) } } } //战斗结束 func (this *Parkour) overtimer(task *timewheel.Task, args ...interface{}) { this.Debug("shot", log.Field{Key: "id", Value: args}) var ( battle *RaceItem ok bool side int32 sessions []comm.IUserSession = make([]comm.IUserSession, 0) 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.raceComp.delrace(id) this.ai.removeAi(id) if battle.RedScore > battle.BuleScore { side = 1 } else { side = 2 } for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "raceover", &pb.ParkourRaceOverPush{ Winside: side, }, sessions...); err != nil { this.Errorln(err) return } for _, v := range battle.RedMember { if !v.Isai { if err = this.parkourComp.Change(v.Uid, map[string]interface{}{ "captainid": "", "state": 0, "invite": []*pb.DBRaceInvite{}, "member": []*pb.DBRaceMember{}, }); err != nil { this.Errorln(err) return } } } for _, v := range battle.BuleMember { if !v.Isai { if err = this.parkourComp.Change(v.Uid, map[string]interface{}{ "captainid": "", "state": 0, "invite": []*pb.DBRaceInvite{}, "member": []*pb.DBRaceMember{}, }); err != nil { this.Errorln(err) return } } } } } //用户离线处理 func (this *Parkour) useroffline(uid, sessionid string) { var ( info *pb.DBParkour team *pb.DBParkour member *pb.DBRaceMember users []string keep bool index int32 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_teaming { if info.Captainid == uid { users = make([]string, 0) for _, v := range info.Member { if v.Uid != uid && !v.Isai { users = append(users, v.Uid) if err = this.parkourComp.Change(v.Uid, map[string]interface{}{ "captainid": "", "state": 0, }); err != nil { this.Error("用户离线! 解散队伍处理", log.Field{Key: "uid", Value: v.Uid}, log.Field{Key: "err", Value: err.Error()}) return } } } info.Invite = info.Invite[:0] info.Member = info.Member[:0] if err = this.parkourComp.Change(uid, map[string]interface{}{ "captainid": "", "state": 0, "Invite": info.Invite, "member": info.Member, }); err != nil { this.Error("用户离线! 处理数据", log.Field{Key: "uid", Value: uid}, log.Field{Key: "err", Value: err.Error()}) return } if len(users) > 0 { if err = this.SendMsgToUsers(string(comm.ModulePvp), "teamdisbandnotice", &pb.ParkourTeamDisbandNoticePush{}, users...); err != nil { this.Errorln(err) } } } else { if team, err = this.parkourComp.queryinfo(info.Captainid); err != nil { this.Error("用户离线!", log.Field{Key: "Captainid", Value: info.Captainid}, log.Field{Key: "err", Value: err.Error()}) return } users = make([]string, 0) for i, v := range team.Member { if v.Uid == uid { index = int32(i) member = v keep = true continue } if v.Uid != uid && !v.Isai { users = append(users, v.Uid) } } if keep { team.Member = append(team.Member[0:index], team.Member[index+1:]...) if err = this.parkourComp.Change(team.Uid, map[string]interface{}{ "member": team.Member, }); err != nil { this.Error("用户离线! 解散队伍处理", log.Field{Key: "uid", Value: team.Uid}, log.Field{Key: "err", Value: err.Error()}) return } if len(users) > 0 { this.SendMsgToUsers(string(this.GetType()), "teamquitnotice", &pb.ParkourTeamQuitNoticePush{Member: member}, users...) this.SendMsgToUsers(string(this.GetType()), "teamchanage", &pb.ParkourTeamChanagePush{Team: team}, users...) } } } } else if info.State == pb.RaceTeamState_matching { if info.Captainid == uid { err = this.service.RpcCall( context.Background(), comm.Service_Mainte, string(comm.RPC_ParkourCancelMatch), &pb.RPCParkourCancelMatchReq{Captainid: info.Captainid}, &pb.RPCParkourCancelMatchResp{}) if err != nil { this.Errorln(err) return } if err = this.parkourComp.Change(uid, map[string]interface{}{ "captainid": "", "state": 0, "Invite": info.Invite, "member": info.Member, }); err != nil { this.Error("用户离线! 处理数据", log.Field{Key: "uid", Value: uid}, log.Field{Key: "err", Value: err.Error()}) return } users = make([]string, 0) for _, v := range info.Member { if v.Uid != uid && !v.Isai { users = append(users, v.Uid) if err = this.parkourComp.Change(v.Uid, map[string]interface{}{ "captainid": "", "state": 0, }); err != nil { this.Error("用户离线! 解散队伍处理", log.Field{Key: "uid", Value: v.Uid}, log.Field{Key: "err", Value: err.Error()}) return } } } if len(users) > 0 { if err = this.SendMsgToUsers(string(comm.ModulePvp), "teamdisbandnotice", &pb.ParkourTeamDisbandNoticePush{}, users...); err != nil { this.Errorln(err) } } } } else if info.State == pb.RaceTeamState_raceing { var ( lockpath string = fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()) result []*pb.DBRace ) if result, err = this.raceComp.queryraces(); err != nil { this.Errorln(err) return } for _, v := range result { for _, v1 := range v.Redmember { if !v1.Isai && v1.Uid == uid { if lockpath == v.ServicePath { this.trusteeship(context.Background(), &pb.RPC_ParkourTrusteeshipReq{Battleid: v.Id, Uid: uid}, nil) return } else { ctx, _ := context.WithTimeout(context.Background(), time.Second*5) _, err = this.service.RpcGo( ctx, comm.Service_Mainte, string(comm.RPC_ParkourJoinMatch), &pb.RPC_ParkourTrusteeshipReq{Battleid: v.Id, Uid: uid}, nil) if err != nil { this.Errorln(err) return } return } } } for _, v1 := range v.Bulemember { if !v1.Isai && v1.Uid == uid { if lockpath == v.ServicePath { this.trusteeship(context.Background(), &pb.RPC_ParkourTrusteeshipReq{Battleid: v.Id, Uid: uid}, nil) return } else { ctx, _ := context.WithTimeout(context.Background(), time.Second*5) _, err = this.service.RpcGo( ctx, comm.Service_Mainte, string(comm.RPC_ParkourJoinMatch), &pb.RPC_ParkourTrusteeshipReq{Battleid: v.Id, Uid: uid}, nil) if err != nil { this.Errorln(err) return } return } } } } } } //托管 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.Uid == v.Uid { v.Isoff = true } } for _, v := range battle.RedMember { if v.Uid == v.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.Uid == uid { member = v ok = true } } if !ok { for _, v := range battle.BuleMember { if v.Uid == uid { member = v ok = true } } } if ok { member.Currhp = 2 for _, v := range battle.Session { sessions = append(sessions, v) } if err = this.SendMsgToSession(string(this.GetType()), "playerhpchanage", &pb.ParkourPlayerHPChanagePush{ Change: map[string]int32{uid: member.Currhp}, }, sessions...); err != nil { this.Errorln(err) } } } else { this.Error("战斗结束 复活失效", log.Field{Key: "bid", Value: battleid}) } }