go_dreamfactory/modules/pvp/module.go
2023-11-16 15:29:15 +08:00

514 lines
14 KiB
Go

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
// }