package pvp import ( "encoding/json" "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/base" "go_dreamfactory/lego/core" "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 gameInvite comm.IGameInvite 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) if err = this.ModuleBase.Init(service, module, options); err != nil { return } this.service = service.(base.IRPCXService) return } func (this *Pvp) Start() (err error) { if err = this.ModuleBase.Start(); err != nil { return } 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.ModuleGameInvite); err != nil { return } this.gameInvite = module.(comm.IGameInvite) 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) // this.service.RegisterFunctionName(string(comm.RPC_PVPTrusteeship), this.trusteeship) 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) CreateRoom(sessions []comm.IUserSession, rulesStr string) (roomid string, err error) { this.Debug("CreatePvp", log.Field{Key: "rulesStr", Value: rulesStr}, log.Field{Key: "sessions", Value: sessions}) var ( rules *pb.DBPvpRules = &pb.DBPvpRules{} battle *BattleItem red, blue *pb.DBUser ) if err = json.Unmarshal([]byte(rulesStr), rules); err != nil { this.Error("解析规则json", log.Field{Key: "err", Value: err.Error()}) return } roomid = primitive.NewObjectID().Hex() battle = &BattleItem{ Id: roomid, Ptype: rules.Ptype, State: pb.PvpState_ready, RedSession: sessions[0], BlueSession: sessions[1], Red: comm.GetUserBaseInfo(red), Blue: comm.GetUserBaseInfo(blue), readytimer: timewheel.Add(time.Second*60, this.readyTimeOut, roomid), curroperate: &pb.ComWaitInputSkill{}, } //发起者 red red, err = this.ModuleUser.GetUser(sessions[0].GetUserId()) if err != nil { this.Error("未找到红方信息", log.Field{Key: "uid", Value: sessions[0].GetUserId()}) return } blue, err = this.ModuleUser.GetUser(sessions[1].GetUserId()) if err != nil { this.Error("未找到蓝方信息", log.Field{Key: "uid", Value: sessions[1].GetUserId()}) 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) } 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 func() { this.gameInvite.GameInviteEnd(3, battle.Red.Uid) 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 func() { this.gameInvite.GameInviteEnd(3, battle.Red.Uid) 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{ Rulesid: 111, 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) 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, // k, // string(comm.RPC_PVPTrusteeship), // &pb.RPC_PVPTrusteeshipReq{Battleid: v, Uid: uid}, // nil) // if err != nil { // this.Errorln(err) // return // } // } // } // } func (this *Pvp) UserOffline(roomid string, uid string) (err error) { var ( battle *BattleItem ok bool side int32 data []byte errdata *pb.ErrorData ) this.lock.RLock() battle, ok = this.battles[roomid] this.lock.RUnlock() if ok { if battle.Red.Uid == uid || battle.Blue.Uid == uid { if 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 } // // 托管 // 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 // }