package pvp 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" "google.golang.org/protobuf/proto" ) /* 模块名:支付系统 描述:充值商城 开发:李伟 */ func NewModule() core.IModule { m := new(Pvp) return m } type Pvp struct { modules.ModuleBase service base.IRPCXService battle comm.IBattle practice comm.IPractice apicomp *apiComp modelPvpComp *modelPvpComp lock sync.RWMutex battles map[string]*BattleItem } //模块名 func (this *Pvp) GetType() core.M_Modules { return comm.ModulePvp } //模块初始化接口 注册用户创建角色事件 func (this *Pvp) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { this.battles = make(map[string]*BattleItem) err = this.ModuleBase.Init(service, module, options) this.service = service.(base.IRPCXService) return } func (this *Pvp) Start() (err error) { err = this.ModuleBase.Start() var module core.IModule if module, err = this.service.GetModule(comm.ModuleBattle); err != nil { return } this.battle = module.(comm.IBattle) if module, err = this.service.GetModule(comm.ModulePractice); err != nil { return } this.practice = module.(comm.IPractice) // event.RegisterGO(comm.EventUserLogin, this.userlogin) event.RegisterGO(comm.EventUserOffline, this.useroffline) return } //装备组件 func (this *Pvp) OnInstallComp() { this.ModuleBase.OnInstallComp() this.apicomp = this.RegisterComp(new(apiComp)).(*apiComp) this.modelPvpComp = this.RegisterComp(new(modelPvpComp)).(*modelPvpComp) } func (this *Pvp) QueryBattle(id string) (battle *pb.DBPvpBattle, err error) { battle, err = this.modelPvpComp.querypvp(id) return } //创建Pvp func (this *Pvp) CreatePvp(red, blue *pb.PvpUserInfo, ptype pb.PvpType) (battleId string, errdata *pb.ErrorData) { this.Debug("CreatePvp", log.Field{Key: "ptype", Value: ptype.String()}, log.Field{Key: "red", Value: red.String()}, log.Field{Key: "blue", Value: blue.String()}) var ( battle *BattleItem err error ok bool ) battleId = primitive.NewObjectID().Hex() battle = &BattleItem{ Id: battleId, Ptype: ptype, State: pb.PvpState_ready, Red: red, Blue: blue, readytimer: timewheel.Add(time.Second*60, this.readyTimeOut, battleId), curroperate: &pb.ComWaitInputSkill{}, } if battle.RedSession, ok = this.GetUserSession(red.Uid); !ok { errdata = &pb.ErrorData{ Code: pb.ErrorCode_BattleUserOff, Title: pb.ErrorCode_BattleUserOff.ToString(), } return } if battle.BlueSession, ok = this.GetUserSession(blue.Uid); !ok { errdata = &pb.ErrorData{ Code: pb.ErrorCode_BattleUserOff, Title: pb.ErrorCode_BattleUserOff.ToString(), } return } this.lock.Lock() this.battles[battle.Id] = battle this.lock.Unlock() if err = this.SendMsgToSession(string(comm.ModulePvp), "ready", &pb.PvpReadyPush{ ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Battleid: battle.Id, Red: battle.Red, Blue: battle.Blue, Countdown: 60, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_RpcFuncExecutionError, Title: pb.ErrorCode_RpcFuncExecutionError.ToString(), } } return } //推送战斗输出指令 func (this *Pvp) PvpOutCmdPush(out *pb.PvpOutCmdPush) { this.Debug("PvpOutCmdPush", log.Field{Key: "args", Value: out}) var ( battle *BattleItem ok bool errdata *pb.ErrorData data []byte err error ) this.lock.RLock() battle, ok = this.battles[out.Battleid] this.lock.RUnlock() if ok { battle.lock.Lock() if err = this.SendMsgToSession(string(comm.ModulePvp), "outcmd", &pb.PvpOutCmdPush{ Battleid: battle.Id, Cmd: out.Cmd, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) } battle.lock.Unlock() for _, v := range out.Cmd { if v.Cmdtype == "ComWaitInputSkill" { if err = proto.Unmarshal(v.Value, battle.curroperate); err != nil { this.Errorln(err) } if battle.curroperate.Side == 1 && battle.RedOffline { //已经离线 battle.curroperate.Auto = true data, _ = proto.Marshal(battle.curroperate) if errdata = this.battle.InCmdBattle(&pb.BattleInCmdReq{ Battleid: battle.Id, Side: battle.curroperate.Side, In: &pb.BattleCmd{ Cmdtype: "ComWaitInputSkill", Value: data, }, }); errdata != nil { return } return } if battle.curroperate.Side == 2 && battle.BlueOffline { //已经离线 battle.curroperate.Auto = true data, _ = proto.Marshal(battle.curroperate) if errdata = this.battle.InCmdBattle(&pb.BattleInCmdReq{ Battleid: battle.Id, Side: battle.curroperate.Side, In: &pb.BattleCmd{ Cmdtype: "ComWaitInputSkill", Value: data, }, }); errdata != nil { return } return } } } } } //推送战斗结束 func (this *Pvp) PvpFinishPush(out *pb.BattleFinishPush) { var ( battle *BattleItem err error ok bool ) this.lock.RLock() battle, ok = this.battles[out.Battleid] this.lock.RUnlock() if ok { this.lock.RLock() delete(this.battles, out.Battleid) this.lock.RUnlock() switch battle.Ptype { case pb.PvpType_friends: go this.practice.ChallengeResults(out.Battleid, battle.Red.Uid, battle.Blue.Uid, out.WinSide) break } this.modelPvpComp.delpvp(out.Battleid) this.PutUserSession(battle.RedSession) this.PutUserSession(battle.BlueSession) if err = this.SendMsgToUsers(string(comm.ModulePvp), "finish", &pb.PvpFinishPush{ Battleid: battle.Id, }, battle.Red.Uid, battle.Blue.Uid); err != nil { this.Errorln(err) } } } //准备超时 取消战斗 func (this *Pvp) readyTimeOut(task *timewheel.Task, args ...interface{}) { this.Debug("readyTimeOut", log.Field{Key: "args", Value: args}) var ( id string battle *BattleItem ok bool err error ) id = args[0].(string) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok && battle.State == pb.PvpState_ready { battle.lock.Lock() battle.State = pb.PvpState_cancel battle.lock.Unlock() this.lock.Lock() delete(this.battles, id) this.lock.Unlock() if err = this.SendMsgToSession(string(comm.ModulePvp), "cancel", &pb.PvpCancelPush{ ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Battleid: battle.Id, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) } switch battle.Ptype { case pb.PvpType_friends: var winside int32 = 0 if battle.Redformation != nil { winside = 1 } if battle.Blueformation != nil { winside = 2 } go this.practice.ChallengeResults(battle.Id, battle.Red.Uid, battle.Blue.Uid, winside) break } } } //操作倒计时 func (this *Pvp) operateTimeOut(task *timewheel.Task, args ...interface{}) { this.Debug("operateTimeOut", log.Field{Key: "args", Value: args}) var ( id string battle *BattleItem ok bool errdata *pb.ErrorData data []byte ) id = args[0].(string) this.lock.RLock() battle, ok = this.battles[id] this.lock.RUnlock() if ok && battle.State == pb.PvpState_battle { battle.curroperate.Auto = true data, _ = proto.Marshal(battle.curroperate) if errdata = this.battle.InCmdBattle(&pb.BattleInCmdReq{ Battleid: battle.Id, Side: battle.curroperate.Side, In: &pb.BattleCmd{ Cmdtype: "ComWaitInputSkill", Value: data, }, }); errdata != nil { return } } } //开始战斗 func (this *Pvp) startBattle(battle *BattleItem) { this.Debug("PVPStart", log.Field{Key: "battleId", Value: battle.Id}) var ( record *pb.DBBattleRecord info *pb.BattleInfo errdata *pb.ErrorData err error ) if errdata, record = this.battle.CreateRtPvpBattle(&pb.BattleRTPVPReq{ Ptype: pb.PlayType_friendsmeet, Title: "", RedCompId: battle.Red.Uid, Redformat: []*pb.BattleFormation{battle.Redformation}, BlueCompId: battle.Blue.Uid, Bulefformat: []*pb.BattleFormation{battle.Blueformation}, }); errdata != nil { this.lock.Lock() delete(this.battles, battle.Id) this.lock.Unlock() if err = this.SendMsgToSession(string(comm.ModulePvp), "cancel", &pb.PvpCancelPush{ ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Battleid: battle.Id, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) } return } else { record.Id = battle.Id info = &pb.BattleInfo{ Id: record.Id, Title: record.Title, Rulesid: 111, Btype: record.Btype, Ptype: record.Ptype, RedCompId: record.RedCompId, Redflist: record.Redflist, BlueCompId: record.BlueCompId, Buleflist: record.Buleflist, } if errdata = this.battle.CreateBattleServer(info); errdata != nil { this.lock.Lock() delete(this.battles, battle.Id) this.lock.Unlock() if err = this.SendMsgToSession(string(comm.ModulePvp), "cancel", &pb.PvpCancelPush{ ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Battleid: battle.Id, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) } } else { if err = this.SendMsgToSession(string(comm.ModulePvp), "start", &pb.PvpStartPush{ Info: info, }, battle.RedSession, battle.BlueSession); err != nil { this.Errorln(err) } this.modelPvpComp.addpvp(&pb.DBPvpBattle{ Id: info.Id, ServicePath: fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()), Ptype: battle.Ptype, State: battle.State, Red: battle.Red, Blue: battle.Blue, }) } } } //用户离线处理 弃用 func (this *Pvp) userlogin(session comm.IUserSession) { // var ( // result []*pb.DBPvpBattle // userpvp []*pb.DBPvpBattle // push *pb.PvpListPush // err error // ) // if result, err = this.modelPvpComp.querypvps(); err != nil { // this.Errorln(err) // return // } // userpvp = make([]*pb.DBPvpBattle, 0, len(userpvp)) // for _, v := range result { // if v.Red.Uid == session.GetUserId() || v.Blue.Uid == session.GetUserId() { // userpvp = append(userpvp, v) // } // } // if len(userpvp) <= 0 { // return // } // push = &pb.PvpListPush{} // for _, v := range result { // push.List = append(push.List, &pb.DBPvpBattle{ // Id: v.Id, // ServicePath: v.ServicePath, // Ptype: v.Ptype, // State: v.State, // Red: v.Red, // Blue: v.Blue, // }) // } // session.SendMsg(string(comm.ModulePvp), "list", push) // session.Push() // this.Debug("GetPvpInfo", log.Field{Key: "uid", Value: session.GetSessionId()}, log.Field{Key: "list", Value: push.String()}) } //用户离线处理 func (this *Pvp) useroffline(uid, sessionid string) { var ( result []*pb.DBPvpBattle lockpath string = fmt.Sprintf("%s/%s", this.service.GetType(), this.service.GetId()) service map[string][]string = make(map[string][]string) err error ) if result, err = this.modelPvpComp.querypvps(); err != nil { this.Errorln(err) return } for _, v := range result { if v.Red.Uid == uid || v.Blue.Uid == uid { if service[v.ServicePath] == nil { service[v.ServicePath] = make([]string, 0) } service[v.ServicePath] = append(service[v.ServicePath], v.Id) } } for k, v := range service { if k == lockpath { //在当前服务器上 this.trusteeship(context.Background(), &pb.RPC_PVPTrusteeshipReq{Battleid: v, Uid: uid}, nil) } else { //在别的服务器上 ctx, _ := context.WithTimeout(context.Background(), time.Second*5) _, err = this.service.RpcGo( ctx, comm.Service_Mainte, string(comm.RPC_ParkourJoinMatch), &pb.RPC_PVPTrusteeshipReq{Battleid: v, Uid: uid}, nil) if err != nil { this.Errorln(err) return } } } } //托管 func (this *Pvp) trusteeship(ctx context.Context, req *pb.RPC_PVPTrusteeshipReq, resp *pb.RPC_PVPTrusteeshipResp) (err error) { var ( battle *BattleItem ok bool side int32 data []byte errdata *pb.ErrorData ) for _, bid := range req.Battleid { this.lock.RLock() battle, ok = this.battles[bid] this.lock.RUnlock() if ok { if battle.Red.Uid == req.Uid || battle.Blue.Uid == req.Uid { if req.Uid == battle.Red.Uid { side = 1 battle.RedOffline = true } else { side = 2 battle.BlueOffline = true } if battle.curroperate.Side == side { if battle.operatetimer != nil { timewheel.Remove(battle.operatetimer) } battle.curroperate.Auto = true data, _ = proto.Marshal(battle.curroperate) if errdata = this.battle.InCmdBattle(&pb.BattleInCmdReq{ Battleid: battle.Id, Side: battle.curroperate.Side, In: &pb.BattleCmd{ Cmdtype: "ComWaitInputSkill", Value: data, }, }); errdata != nil { return } } } } } return }