go_dreamfactory/modules/pvp/module.go
2023-06-06 13:55:33 +08:00

496 lines
13 KiB
Go

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
}